36
Why You Should Use super() Though It Sucks Eunchong YU [email protected]

Why you should use super() though it sucks

Embed Size (px)

Citation preview

Page 1: Why you should use super() though it sucks

Why You Should Use super()

Though It SucksEunchong YU

[email protected]

Page 2: Why you should use super() though it sucks

유은총

● Developing with Python for Food

● StyleShare (2011-2012)

● SmartStudy (2012-)

● http://blog.materialistic.kr/

● https://github.com/kroisse

Page 3: Why you should use super() though it sucks

Extend

Page 4: Why you should use super() though it sucks

class A: def parts(self): return ['plate', 'nail']

class B(A): def parts(self): # old-way (before Python 2.2) base = A.parts(self) return base + ['screw']

>>> b = B()>>> b.parts()['plate', 'nail', 'screw']

Page 5: Why you should use super() though it sucks

class A(object): # new-style class def parts(self): return ['plate', 'nail']

class B(A): def parts(self): base = super(B, self).parts() return base + ['screw']

>>> b = B()>>> b.parts()['plate', 'nail', 'screw']

Page 6: Why you should use super() though it sucks

super(Class, self)

Page 7: Why you should use super() though it sucks

Old-fashioned way

class B(A): def parts(self, lamp): base = A.parts(self, lamp) return base + [lamp]

class C(B): def parts(self, lamp): base = B.parts(self, lamp) return sorted(base)

Page 8: Why you should use super() though it sucks

Using super() with new-style classes

class B(A): def parts(self, lamp): base = super(B, self).parts(lamp) return base + [lamp]

class C(B): def parts(self, lamp): base = super(C, self).parts(lamp) return sorted(base)

Page 9: Why you should use super() though it sucks

Diamond Problem

class A(object)

class B(A) class C(A)

class D(B, C)

Page 10: Why you should use super() though it sucks

class A(object): def say(self): print 'A',

class C(A): def say(self): print 'C', A.say(self)

class B(A): def say(self): print 'B', A.say(self)

class D(B, C): def say(self): print 'D', B.say(self) C.say(self)

>>> D().say()D B A C A

Page 11: Why you should use super() though it sucks

MRO

● Method Resolution Order

● linearize class hierarchy○ using C3 algorithm

● only for new-style classes

Page 12: Why you should use super() though it sucks

class A(object)

class B(A) class C(A)

class D(B, C)

D.__mro__ == (D, B, C, A, object)C.__mro__ == (C, A, object)B.__mro__ == (B, A, object)A.__mro__ == (A, object)

Page 13: Why you should use super() though it sucks

I.__mro__ == (I, H, D, B, F, G, C, A, E, object)H.__mro__ == (H, D, B, F, G, C, A, E, object)D.__mro__ == (D, B, C, A, object)B.__mro__ == (B, A, object)F.__mro__ == (F, C, A, E, object)G.__mro__ == (G, C, A, object)C.__mro__ == (C, A, object)A.__mro__ == (A, object)E.__mro__ == (E, object)

object

A

E

B

C

D

F

G H

I

Page 14: Why you should use super() though it sucks

class A(object): def say(self): print 'A',

class C(A): def say(self): print 'C', super(C, self).say()

class B(A): def say(self): print 'B', super(B, self).say()

class D(B, C): def say(self): print 'D', super(D, self).say()

D.__mro__ == (D, B, C, A, object)

>>> D().say()D B C A

Page 15: Why you should use super() though it sucks

super(Class, self)to find current position

of the MROto traverseentire MRO

Page 16: Why you should use super() though it sucks

super(Class, self)

● only for new-style classes

● because classic classes don't have MRO

Page 17: Why you should use super() though it sucks

Why You Should Use super()

Though It SucksThough It Sucks

Page 18: Why you should use super() though it sucks

Diamond, Again

class A(object)

class B(A) class C(A)

class D(B, C)

Page 19: Why you should use super() though it sucks

class A(object): def say(self): print 'A',

class B(A): def say(self): print 'B', super(B, self).say()

class C(A): def say(self, arg): print 'C(%s)' % arg, super(C, self).say()

class D(B, C): def say(self, arg): print 'D(%s)' % arg, super(D, self).say(arg)

D.__mro__ == (D, B, C, A, object)>>> D().say(1)D(1)Traceback (most recent call last): File "<stdin>", line 1, in <module> File "...", line ..., in sayTypeError: say() takes exactly 1 argument (2 given)

Page 20: Why you should use super() though it sucks

super(Class, self)

● Does not call the superclass

● Call the next method in the MRO

● You can't expect what will be next

Page 21: Why you should use super() though it sucks

Remember #1:

● Don't change the method signature

OR

● Send all received arguments to super()

Page 22: Why you should use super() though it sucks

class A(object): def say(self, arg): print 'A',

class B(A): def say(self, arg): print 'B', super(B, self).say(arg)

class C(A): def say(self, arg): print 'C(%s)' % arg, super(C, self).say(arg)

class D(B, C): def say(self, arg): print 'D(%s)' % arg, super(D, self).say(arg)

>>> D().say(1)D(1) B C(1) A

Page 23: Why you should use super() though it sucks

class A(object): def say(self, *args, **kwargs): print 'A',

class B(A): def say(self, *args, **kwargs): print 'B', super(B, self).say(*args, **kwargs)

class C(A): def say(self, arg, *args, **kwargs): print 'C(%s)' % arg, super(C, self).say(arg, *args, **kwargs)

class D(B, C): def say(self, arg, *args, **kwargs): print 'D(%s)' % arg, super(D, self).say(arg, *args, **kwargs)

Page 24: Why you should use super() though it sucks

Initialize

Page 25: Why you should use super() though it sucks

class A(object): def __init__(self): print 'A: init'

class B(object): def __init__(self): print 'B: init'

class C(A, B): def __init__(self): super(C, self).__init__()

>>> C()A: init<__main__.C object at 0x10157f150>>>> # so where is B???

Page 26: Why you should use super() though it sucks

C.__mro__ == (C, A, B, object)

object

class A(object) class B(object)

class C(A, B)

Page 27: Why you should use super() though it sucks

C.__mro__ == (C, A, B, object)

object

class A(object) class B(object)

class C(A, B)

Page 28: Why you should use super() though it sucks

class A(object): def __init__(self): print 'A: init' super(A, self).__init__()

class B(object): def __init__(self): print 'B: init' super(B, self).__init__()

class C(A, B): def __init__(self): super(C, self).__init__()

>>> C()A: initB: init<__main__.C object at 0x10157f150>

Page 29: Why you should use super() though it sucks

class A(object): def __init__(self, *args, **kwargs): print 'A: init' super(A, self).__init__(*args, **kwargs)

class B(object): def __init__(self, *args, **kwargs): print 'B: init' super(B, self).__init__(*args, **kwargs)

class C(A, B): def __init__(self, *args, **kwargs): super(C, self).__init__(*args, **kwargs)

>>> C('hello')A: initB: initTypeError: object.__init__() takes no parameters

Page 30: Why you should use super() though it sucks

Remember #2:

● Don't forget super(C, self).__init__()

● but how about arguments?

Page 31: Why you should use super() though it sucks

super(Me, self).__init__()

vs.Parent.__init__(self)

Page 32: Why you should use super() though it sucks

class A(object): def say(self): print 'A',

class B(A): def say(self): print 'B', A.say(self)

class C(A): def say(self): print 'C', super(C, self).say()

class D(B, C): def say(self): print 'D', super(D, self).say()

D.__mro__ == (D, B, C, A, object)

>>> D().say()D B A

Page 33: Why you should use super() though it sucks

Remember #3:

● Don't mix both style

● Caution: classic classes (before Python 2.1)○ obsoleted in Python 3.x

○ remained in some standard libs of Python 2.x

● Whether using super() or notis a method signature.

Page 34: Why you should use super() though it sucks

Plenty of pitfalls in super()

● verbose syntax — fragile on copy & paste :)

● can't use: super(C, self)[0]

● super(C) ≠ super(C, C)

Page 35: Why you should use super() though it sucks

...but we should use super()

● It's a standard.

● Safer to multiple inheritance

● If you mix with classic style,

everything will be broken.