act i: exposition where we meet our characters and the world they live in

Post on 26-Mar-2015

214 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Composabilitythrough Multiple Inheritance

A drama in Three Actsby Łukasz Langa

Act I: Expositionwhere we meet our characters and the world they

live in

Composability

Compositionality

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 | ...

Godtfred Kirk Christiansen

Joe Armstrong

Joe Armstrong

grep REGEX <file >matches

Quality

Robert M. Pirsig

Jamie Zawinski

Quality

ComposabilityCompositiona

lity

Act II: Rising Actionwhere we learn how inheritance in Python works

If you use old-style classes

You’re gonna have a bad time

Method Resolution Order

>>> class A(object):... pass... ... >>> A.mro()[<class '__main__.A'>, <type 'object'>]

Method Resolution Order

object

A

Method Resolution Order

>>> class A(object): pass... >>> class B(object): pass... >>> class AB(A, B): pass...

The Diamond Problem

object

A B

AB

The Diamond ”Problem”

object

A B

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'

Cooperative Inheritance

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): # ???

Cooperative Inheritance

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)

Cooperative Inheritance

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'

Cooperative Inheritance

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’

Cooperative Inheritance

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'>]

Cooperative Inheritance

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))

Cooperative Inheritance

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'>]

A.__init__(self, arg_a)

super(AB, self).__init__(arg_a)

Cooperative Inheritance

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))

Cooperative Inheritance

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)

Cooperative Inheritance

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)

THIS SHIT IS HARD

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’s still different!

>>> c=C('1.0')>>> c.arg_au'd'>>> c.arg_bu'0'

Cooperative Inheritance

Don’t omit super(C, self).__init__() even if your base class is object

Don’t assume you know what arguments you’re going to get

Don’t assume you know what arguments you should pass to super always pass all arguments you received

on to super if classes can take differing arguments,

always accept **kwargs

If you mix Class.__init__ and super()

You’re gonna have a bad time

Mixins

Not meant for instantiation on their own

Enhance classes with independent functionality

Not a form of specialisation but collection of functionality

Like interfaces with built-in implementation

Very reusable if orthogonal to the main type

InterludeDjango ORM inheritance model

sucks

The Diamond Problem

M1

M2 M3

M4

Polymorphism

M1

M2

M3 M

4

Liskov substitution principle

M1

M2

M3 M

4

Act III: The Climax

Yep,here comes the demo.

And by the way

Just so you know.

Jamie Zawinski

Questions?

ambvat #python-dev IRC

@llangaon Twitter

lukasz@langa.plas a last resort

top related