Reputation: 1200
I have 2 classes: A
and B
, both of them instantiated by __new__
with different set of arguments (like a
for A
, and foo, bar
for B
). Now I want to implement class C
, inherited from A
and B
, and instantiate it with 3 args: a, foo, bar
, passing correspondent arguments to super classes __new__
, but things goes wrong from here.
If we have no arguments I just call super(C, cls).__new__()
and object of class C
successfully created (it calls both A.__new__()
and B.__new__()
and combines it somehow). But how to do it 'by hands'? So I want to pass a
to A.__new__
, foo, bar
to B.__new__
and combine somehow returned instances (is this right way to get object of class C
at the end?).
Anyway I can't do both.
Fist - calling A.__new__
raises incorrect number of arguments exception in o = super(A, cls).__new__(cls)
in A.__new__()
(but A
can be instantiated as standalone)
Second - I have no idea how to combine even successfully instantiated object of classes A
and B
into object of class C
.
So could please someone to explain what is going on here?
class A(object):
def __new__(cls, a):
o = super(A, cls).__new__(cls)
setattr(o, 'a', a)
return o
class B(object):
def __new__(cls, foo, bar):
o = super(B, cls).__new__(cls)
setattr(o, 'foo', foo)
setattr(o, 'bar', bar)
return o
print A(1) # ok, <__main__.A object at 0x00000000022F1630>
print B(2,3) # ok, <__main__.B object at 0x00000000022F1630>
class C(A,B):
def __new__(cls, a, foo, bar):
o1 = A.__new__(cls, a) #fail - exception while calling super.new in A
o2 = B.__new__(cls, foo, bar) #fail - exception while calling super.new in A
# return # What? How to combine o1 o2 even if they are created succesfuly?
# # return super(C, cls).__new__(cls, ?????)
print C(1,2,3)
Upvotes: 2
Views: 1530
Reputation: 422
Just do return super().__new__(cls)
in __new__
of derived class.
See following code snippet:
class A:
def __new__(cls, *args, **kwargs):
print('A new')
return super().__new__(cls)
class B:
def __new__(cls, *args, **kwargs):
print('B new')
return super().__new__(cls)
class C(A, B):
def __new__(cls, *args, **kwargs):
print('D new')
return super().__new__(cls)
c = C()
print([isinstance(c, cls) for cls in [A, B, C]])
Output:
D new
A new
B new
[True, True, True]
Upvotes: 0
Reputation: 22324
The method __new__
is what creates your instance, you should not call super(...).__new__
multiple times as it would create multiple instances.
What you want to do it use __init__
which initializes your already created instance.
class A(object):
def __init__(self, a):
self.a = a
class B(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
class C(A, B):
def __init__(self, a, foo, bar):
A.__init__(self, a)
B.__init__(self, foo, bar)
In particular, I want to point out that it is not true that on multiple inheritance Python will call both A.__new__
andB.__new__
and "combine somehow". Have a look at this code
class A(object):
def __new__(*args):
print('A.__new__ was called')
return type(*args) # This is what ultimately creates every object in Python
class B(object):
def __new__(*args):
print('B.__new__ was called')
return type(*args)
# As expected the following is printed when instances are created
a = A() # Prints 'A.__new__ was called'
b = B() # Prints 'B.__new__ was called'
class C(A, B):
pass
c = C() # Prints 'A.__new__ was called'
So we observe that B.__new__
was never called. On multiple inheritance, Python will inherit the method from the left-most class that has this method. In this case, C
inherited A.__new__
.
Upvotes: 3