560 likes | 690 Vues
This engaging drama in three acts explores the intricacies of composability and multiple inheritance in Python. Act I introduces characters embodying various programming concepts, illustrating Unix pipes and foundational principles like compositionality. Act II rises through the challenges of inheritance, depicting the Method Resolution Order and the Diamond Problem with creative examples and insightful Python classes. Act III culminates in a resolution that highlights the balance of inheritance and cooperative design, leaving the audience contemplating the essence of code quality and structure.
E N D
Composabilitythrough Multiple Inheritance A drama in Three Actsby Łukasz Langa
Act I: Exposition where we meet our characters and the world they live in
Unix pipes $ ps aux | grep celery | grep -v grep |awk '{print $2}' | xargs kill -9
Unix pipes $ ps aux | grep celery | grep -v grep |awk '{print $2}' | xargs kill -9
Unix pipes $ command1 | command2 | command3 | ...
Joe Armstrong grep REGEX <file >matches
Composability Compositionality Quality
Act II: Rising Action where we learn how inheritance in Python works
Ifyouuseold-style classes You’re gonna have a badtime
Method Resolution Order >>> class A(object): ... pass ... ... >>> A.mro() [<class '__main__.A'>, <type 'object'>]
Method Resolution Order >>> class A(object): pass ... >>> class B(object): pass ... >>> class AB(A, B): pass ...
The Diamond Problem • AB
The Diamond ”Problem” >>> class A(object): pass ... >>> class B(object): pass ... >>> class AB(A, B): pass ... >>> AB.mro() [<class '__main__.AB'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>]
Method Resolution Order >>> class A(object): ... def say(self, what): ... return what + 'a’ ... >>> class B(object): ... def say(self, what): ... return what + 'b’ ... >>> class AB(A, B): pass ... >>> class BA(B, A): pass ... >>> AB().say('hello:') 'hello:a' >>> BA().say('hey:') 'hey:b'
CooperativeInheritance class A(object): def __init__(self, arg_a): self.arg_a = arg_a class B(object): def __init__(self, arg_b): self.arg_b = arg_b class AB(A, B): def __init__(self, arg_a, arg_b): # ???
CooperativeInheritance class A(object): def __init__(self, arg_a): self.arg_a = arg_a class B(object): def __init__(self, arg_b): self.arg_b = arg_b class AB(A, B): def __init__(self, arg_a, arg_b): A.__init__(self, arg_a) B.__init__(self, arg_b)
CooperativeInheritance class AB(A, B): def __init__(self, arg_a, arg_b): A.__init__(self, arg_a) B.__init__(self, arg_b) >>> ab= AB('a', 'b') >>> ab.arg_a 'a' >>> ab.arg_b 'b'
CooperativeInheritance class AB(A, B): def __init__(self, arg_a, arg_b): A.__init__(self, arg_a) B.__init__(self, arg_b) class C(D, AB): def __init__(self, arg_c): D.__init__(self) AB.__init__(self, *arg_c.split('.', 1)) >>> c=C('1.0') >>> c.arg_a '1' >>> c.arg_b '0’
CooperativeInheritance class AB(A, B): def __init__(self, arg_a, arg_b): A.__init__(self, arg_a) B.__init__(self, arg_b) class C(D, AB): def __init__(self, arg_c): D.__init__(self) AB.__init__(self, *arg_c.split('.', 1)) >>> C.mro() [<class '__main__.C'>, <class '__main__.D'>, <class '__main__.AB'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>]
CooperativeInheritance class AB(A, B): def __init__(self, arg_a, arg_b): A.__init__(self, arg_a) B.__init__(self, arg_b) class D(A): def __init__(self): A.__init__(self, 'd') class C(D, AB): def __init__(self, arg_c): D.__init__(self) AB.__init__(self, *arg_c.split('.', 1))
CooperativeInheritance A.__init__(self, arg_a) super(AB, self).__init__(arg_a) class AB(A, B): def __init__(self, arg_a, arg_b): A.__init__(self, arg_a) B.__init__(self, arg_b) class C(D, AB): def __init__(self, arg_c): D.__init__(self) AB.__init__(self, *arg_c.split('.', 1)) >>> C.mro() [<class '__main__.C'>, <class '__main__.D'>, <class '__main__.AB'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>]
CooperativeInheritance class AB(A, B): def __init__(self, arg_a, arg_b): super(AB, self).__init__(arg_a=arg_a, arg_b=arg_b) class D(A): def __init__(self): super(D, self).__init__(arg_a='d') class C(D, AB): def __init__(self, arg_c): super(C, self).__init__( *arg_c.split('.', 1))
CooperativeInheritance class D(A): def __init__(self): super(D, self).__init__(arg_a='d') class C(D, AB): def __init__(self, arg_c): super(C, self).__init__( *arg_c.split('.', 1)) >>> C('1.0') Traceback (most recent call last): File "<input>", line 1, in <module> File "mrosuper.py", line 27, in __init__ super(C, self).__init__(*arg_c.split('.', 1)) TypeError: __init__() takes exactly 1 argument (3 given)
CooperativeInheritance class D(A): def __init__(self): super(D, self).__init__(arg_a='d') class C(D, AB): def __init__(self, arg_c): super(C, self).__init__( *arg_c.split('.', 1)) >>> C('1.0') Traceback (most recent call last): File "<input>", line 1, in <module> File "mrosuper.py", line 27, in __init__ super(C, self).__init__(*arg_c.split('.', 1)) TypeError: __init__() takes exactly 1 argument (3 given)
class A(object): def __init__(self, arg_a, **kwargs): self.arg_a = arg_a super(A, self).__init__(**kwargs) class B(object): def __init__(self, arg_b, **kwargs): self.arg_b = arg_b super(B, self).__init__(**kwargs) class AB(A, B): def __init__(self, arg_a, arg_b, **kwargs): super(AB, self).__init__(arg_a=arg_a, arg_b=arg_b, **kwargs) class D(A): def __init__(self, **kwargs): super(D, self).__init__(arg_a='d', **kwargs) class C(D, AB): def __init__(self, arg_c, **kwargs): super(C, self).__init__(*arg_c.split('.', 1), **kwargs)
class A(object): def __init__(self, arg_a, **kwargs): self.arg_a = arg_a super(A, self).__init__(**kwargs) class B(object): def __init__(self, arg_b, **kwargs): self.arg_b = arg_b super(B, self).__init__(**kwargs) class AB(A, B): def __init__(self, arg_a, arg_b, **kwargs): super(AB, self).__init__(arg_a=arg_a, arg_b=arg_b, **kwargs) class D(A): def __init__(self, **kwargs): super(D, self).__init__(arg_a='d', **kwargs) class C(D, AB): def __init__(self, arg_c, **kwargs): super(C, self).__init__(*arg_c.split('.', 1), **kwargs)
class A(object): def __init__(self, arg_a, **kwargs): self.arg_a = arg_a super(A, self).__init__(**kwargs) class B(object): def __init__(self, arg_b, **kwargs): self.arg_b = arg_b super(B, self).__init__(**kwargs) class AB(A, B): def __init__(self, arg_a, arg_b, **kwargs): super(AB, self).__init__(arg_a=arg_a, arg_b=arg_b, **kwargs) class D(A): def __init__(self, **kwargs): super(D, self).__init__(arg_a='d', **kwargs) class C(D, AB): def __init__(self, arg_c, **kwargs): super(C, self).__init__(*arg_c.split('.', 1), **kwargs)
class A(object): def __init__(self, arg_a, **kwargs): self.arg_a = arg_a super(A, self).__init__(**kwargs) class B(object): def __init__(self, arg_b, **kwargs): self.arg_b = arg_b super(B, self).__init__(**kwargs) class AB(A, B): def __init__(self, arg_a, arg_b, **kwargs): kwargs['arg_a'], kwargs['arg_b'] = arg_a, arg_b super(AB, self).__init__(**kwargs) class D(A): def __init__(self, **kwargs): kwargs['arg_a'] = 'd' super(D, self).__init__(**kwargs) class C(D, AB): def __init__(self, arg_c, **kwargs): kwargs['arg_a'], kwargs['arg_b'] = arg_c.split('.', 1) super(C, self).__init__(**kwargs)
It’sstilldifferent! >>> c=C('1.0') >>> c.arg_a u'd' >>> c.arg_b u'0'
CooperativeInheritance • Don’tomitsuper(C, self).__init__() evenifyourbaseclassisobject • Don’tassumeyouknowwhatargumentsyou’regoing to get • Don’tassumeyouknowwhatargumentsyoushould pass to super • always pass allargumentsyoureceivedon to super • ifclassescantakedifferingarguments, alwaysaccept**kwargs
Ifyou mix Class.__init__ and super() You’re gonna have a badtime
Mixins Not meant for instantiation on theirown Enhanceclasses with independent functionality Not a form of specialisation but collection of functionality Likeinterfaces with built-in implementation Veryreusableiforthogonal to the maintype
Interlude Django ORM inheritance model sucks
The Diamond Problem • M4