Act I: Exposition where we meet our characters and the world they live in.

56
Composability through Multiple Inheritance A drama in Three Acts by Łukasz Langa

Transcript of Act I: Exposition where we meet our characters and the world they live in.

Page 1: Act I: Exposition where we meet our characters and the world they live in.

Composabilitythrough Multiple Inheritance

A drama in Three Actsby Łukasz Langa

Page 2: Act I: Exposition where we meet our characters and the world they live in.

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

live in

Page 3: Act I: Exposition where we meet our characters and the world they live in.
Page 4: Act I: Exposition where we meet our characters and the world they live in.

Composability

Page 5: Act I: Exposition where we meet our characters and the world they live in.

Compositionality

Page 6: 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

Page 7: 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

Page 8: Act I: Exposition where we meet our characters and the world they live in.

Unix pipes

$ command1 | command2 | command3 | ...

Page 9: Act I: Exposition where we meet our characters and the world they live in.

Godtfred Kirk Christiansen

Page 10: Act I: Exposition where we meet our characters and the world they live in.
Page 11: Act I: Exposition where we meet our characters and the world they live in.

Joe Armstrong

Page 12: Act I: Exposition where we meet our characters and the world they live in.

Joe Armstrong

grep REGEX <file >matches

Page 13: Act I: Exposition where we meet our characters and the world they live in.

Quality

Page 14: Act I: Exposition where we meet our characters and the world they live in.
Page 15: Act I: Exposition where we meet our characters and the world they live in.

Robert M. Pirsig

Page 16: Act I: Exposition where we meet our characters and the world they live in.

Jamie Zawinski

Page 17: Act I: Exposition where we meet our characters and the world they live in.

Quality

ComposabilityCompositiona

lity

Page 18: Act I: Exposition where we meet our characters and the world they live in.

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

Page 19: Act I: Exposition where we meet our characters and the world they live in.

If you use old-style classes

You’re gonna have a bad time

Page 20: Act I: Exposition where we meet our characters and the world they live in.

Method Resolution Order

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

Page 21: Act I: Exposition where we meet our characters and the world they live in.

Method Resolution Order

object

A

Page 22: Act I: Exposition where we meet our characters and the world they live in.

Method Resolution Order

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

Page 23: Act I: Exposition where we meet our characters and the world they live in.

The Diamond Problem

object

A B

AB

Page 24: Act I: Exposition where we meet our characters and the world they live in.

The Diamond ”Problem”

object

A B

AB

Page 25: Act I: Exposition where we meet our characters and the world they live in.

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

Page 26: Act I: Exposition where we meet our characters and the world they live in.

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'

Page 27: Act I: Exposition where we meet our characters and the world they live in.

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

Page 28: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 29: Act I: Exposition where we meet our characters and the world they live in.

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'

Page 30: Act I: Exposition where we meet our characters and the world they live in.

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’

Page 31: Act I: Exposition where we meet our characters and the world they live in.

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

Page 32: Act I: Exposition where we meet our characters and the world they live in.

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

Page 33: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 34: Act I: Exposition where we meet our characters and the world they live in.

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

Page 35: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 36: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 37: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 38: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 39: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 40: Act I: Exposition where we meet our characters and the world they live in.

THIS SHIT IS HARD

Page 41: Act I: Exposition where we meet our characters and the world they live in.

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)

Page 42: Act I: Exposition where we meet our characters and the world they live in.

It’s still different!

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

Page 43: Act I: Exposition where we meet our characters and the world they live in.

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

Page 44: Act I: Exposition where we meet our characters and the world they live in.

If you mix Class.__init__ and super()

You’re gonna have a bad time

Page 45: Act I: Exposition where we meet our characters and the world they live in.

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

Page 46: Act I: Exposition where we meet our characters and the world they live in.

InterludeDjango ORM inheritance model

sucks

Page 47: Act I: Exposition where we meet our characters and the world they live in.

The Diamond Problem

M1

M2 M3

M4

Page 48: Act I: Exposition where we meet our characters and the world they live in.

Polymorphism

M1

M2

M3 M

4

Page 49: Act I: Exposition where we meet our characters and the world they live in.

Liskov substitution principle

M1

M2

M3 M

4

Page 50: Act I: Exposition where we meet our characters and the world they live in.

Act III: The Climax

Page 51: Act I: Exposition where we meet our characters and the world they live in.

Yep,here comes the demo.

Page 52: Act I: Exposition where we meet our characters and the world they live in.

And by the way

Just so you know.

Page 53: Act I: Exposition where we meet our characters and the world they live in.
Page 54: Act I: Exposition where we meet our characters and the world they live in.
Page 55: Act I: Exposition where we meet our characters and the world they live in.

Jamie Zawinski

Page 56: Act I: Exposition where we meet our characters and the world they live in.

Questions?

ambvat #python-dev IRC

@llangaon Twitter

[email protected] a last resort