1

I was looking for a way to initialise the derived class using copy constructor and () operator like in C++

class Rectangle {
    int width, height;
  public:
    Rectangle (int,int);
    int area () {return (width*height);}
};

Rectangle::Rectangle (int a, int b) {
  width = a;
  height = b;
}

r = Rectangle(2,3)
s = Rectangle(r) /* <--using copy constructor to initialize*/

and then I was thinking how would I implement this way of intitialisation in case I have a class derived from the other two plus members of its own and came up with the below:

class MyBase1(object):
    def __init__(self, *args, **kwargs):
        self.x = kwargs.get('x')
        self.y = kwargs.get('y')
        print("mybase1 {}".format(kwargs))

    def print_base1(self):
        pass


class MyBase2(object):
    def __init__(self, *args, **kwargs):
        self.s = kwargs.get('s')
        self.p = kwargs.get('p')
        print("mybase2 {}".format(kwargs))

    def print_base2(self):
        pass


class MyChild(MyBase1, MyBase2):

    def __init__(self, **kwargs):
        MyBase1.__init__(self, **kwargs)
        MyBase2.__init__(self, **kwargs)
        self.function_name = kwargs.get('function')


    def __call__(self, my_base1, my_base2, **kwargs):
        initialization_dictionary = dict(vars(my_base1), **vars(my_base2))
        initialization_dictionary = dict(initialization_dictionary, **kwargs)
        newInstance = MyChild(**initialization_dictionary)
        return newInstance

calling then:

base1 = MyBase1(x=1, y=2)
base2 = MyBase2(s=3, p=4)

child = MyChild()(base1, base2, function='arcsine') #<--initialising 

[stm for stm in dir(child) if not stm.startswith('__')]
# gives:['function_name', 'p', 'print_base1', 'print_base2', 's', 'x', 'y']

vars(child)
# gives:{'function_name': 'arcsine', 'p': 4, 's': 3, 'x': 1, 'y': 2}

So I was wondering by how much this is non-pythonic way? And if there is a better way (or no-way) to do the same?

2
  • In python, you would define a __copy__ and __deepcopy__ special methods, to be used with the copy.copy and copy.deepcopy functions. Commented Mar 27, 2017 at 22:18
  • See, for example, this question Commented Mar 27, 2017 at 22:19

1 Answer 1

1

Well, you wouldn't want to create an instance to create a new instance so, you probably want a classmethod or staticmethod. This isn't the place for using __call__ either.

I might do this:

class MyChild(MyBase1, MyBase2):
    @classmethod
    def build_from_bases(klass, base1, base2, **kwargs):
        kwargs.update(base1.__dict__)
        # Note if base2 has values for x and y, they will clobber what was in base1
        kwargs.update(base2.__dict__)
        return klass(**kwargs)

But using an instance of Base1 and Base2 to build an instance of MyChild doesn't feel like something I'd do in python. Much more likely to use the obvious:

mychild = MyChild(x=base1.x, y=base1.y, s=base2.s, p=base2.p, function='foo')

Really I'd prefer that, now I don't have to be concerned about clobbering values, or other weirdness.

You could combine both, if you really want the short cut method:

class MyChild(MyBase1, MyBase2):
    @classmethod
    def build_from_bases(klass, base1, base2, **kwargs):
       return klass(x=base1.x, y=base1.y, s=base2.s, p=base2.p, **kwargs)

In python less "clever" is frequently "better"

Sign up to request clarification or add additional context in comments.

1 Comment

thank you! I had the implementation with the @classmethod in my drafts, just indeed was trying to do "clever" with the () operator, which is I clearly see is no-good.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.