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