Multiple Inheritance and super() (was Re: [Merge] lp:~vila/bzr/389648-hook-calls-base into lp:~bzr/bzr/trunk)
John Arbash Meinel
john at arbash-meinel.com
Sat Nov 7 23:36:53 GMT 2009
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Ivan Sagalaev wrote:
> John Arbash Meinel wrote:
>> In python2.5 you could have written this as:
>>
>> class Mixin1(object):
>> def __init__(self, keyword1=None, **kwargs):
>> super(Mixin1, self).__init__(**kwargs)
>> self.keyword1 = keyword1
>>
>> class Mixin2(object):
>> def __init__(self, keyword2=None, **kwargs):
>> super(Mixin2, self).__init__(**kwargs)
>> self.keyword2 = keyword2
>>
>> class Mixed(Mixin1, Mixin2):
>> def __init__(self, keyword1=None, keyword2=None, **kwargs):
>> super(Mixed, self).__init__(keyword1=keyword1, keyword2=keyword2,
>> **kwargs)
>>
>> And it would have worked, and the parameters would have been passed to
>> the appropriate base class.
>>
>> In Python2.6 this fails because object.__init__() doesn't take any
>> parameters.
>
> John, I've copy-pasted this exact code and added:
>
> mixed = Mixed(keyword1='test1', keyword2='test2')
> print mixed.__dict__
>
> It works well under Python 2.6.4 giving
>
> {'keyword2': 'test1', 'keyword1': 'test2'}
>
So you're right. In the above code, the Mixin1 strips the 'keyword1'
argument out of the list, and Mixin2 strips the 'keyword2' argument.
When I was testing it originally, I did:
class Mixin1(object):
def __init__(self, keyword1=None, **kwargs):
super(Mixin1, self).__init__(keyword1=keyword1, **kwargs)
self.keyword1 = keyword1
class Mixin2(object):
def __init__(self, keyword2=None, **kwargs):
super(Mixin2, self).__init__(keyword2=keyword2, **kwargs)
self.keyword2 = keyword2
class Mixed(Mixin1, Mixin2):
def __init__(self, keyword1=None, keyword2=None, **kwargs):
super(Mixed, self).__init__(keyword1=keyword1, keyword2=keyword2,
**kwargs)
And *that* fails. (Because it ends up trying to pass the keyword1 and
keyword2 arguments to object.__init__().)
I'm not 100% sure what is 'correct' here. Consider this case:
class Mixin1(object):
def __init__(self, keyword1=None, **kwargs):
super(Mixin1, self).__init__(**kwargs)
self.keyword1 = keyword1
class Mixin2(object):
def __init__(self, keyword2=None, **kwargs):
super(Mixin2, self).__init__(**kwargs)
self.keyword2 = keyword2
class Mixin3(object):
def __init__(self, keyword1=None, **kwargs):
super(Mixin3, self).__init__(**kwargs)
if keyword1 is not None:
self.happy_fun = True
else:
self.happy_fun = False
class Mixed(Mixin1, Mixin2, Mixin3):
def __init__(self, keyword1=None, keyword2=None, **kwargs):
super(Mixed, self).__init__(keyword1=keyword1, keyword2=keyword2,
**kwargs)
In this case:
>>> m = Mixed(1, 2)
>>> print m.__dict__
{'happy_fun': False, 'keyword1': 1, 'keyword2': 2}
'happy_fun' doesn't get set because keyword1 isn't getting being pushed
to all other parents. (It is getting 'stripped' in the Mixin1.__init__
call.)
Note also that if you chose a different method for handling keyword
arguments, things would break again:
class Mixin1(object):
def __init__(self, **kwargs):
super(Mixin1, self).__init__(**kwargs)
self.keyword1 = kwargs.get('keyword1', None)
class Mixin2(object):
def __init__(self, **kwargs):
super(Mixin2, self).__init__(**kwargs)
self.keyword2 = kwargs.get('keyword2', None)
class Mixed(Mixin1, Mixin2, Mixin3):
def __init__(self, keyword1=None, keyword2=None, **kwargs):
super(Mixed, self).__init__(keyword1=keyword1, keyword2=keyword2,
**kwargs)
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAkr2BJUACgkQJdeBCYSNAAOiYwCgn7cB5d87a1AkH5YaDyJUYCI+
HVYAoNnUJCiF1tmgP/nyN9791d6YHsPp
=tKhE
-----END PGP SIGNATURE-----
More information about the bazaar
mailing list