Upload
eunchong-yu
View
378
Download
0
Embed Size (px)
Citation preview
유은총
● Developing with Python for Food
● StyleShare (2011-2012)
● SmartStudy (2012-)
● http://blog.materialistic.kr/
● https://github.com/kroisse
Extend
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']
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']
super(Class, self)
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)
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)
Diamond Problem
class A(object)
class B(A) class C(A)
class D(B, C)
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
MRO
● Method Resolution Order
● linearize class hierarchy○ using C3 algorithm
● only for new-style classes
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)
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
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
super(Class, self)to find current position
of the MROto traverseentire MRO
super(Class, self)
● only for new-style classes
● because classic classes don't have MRO
Why You Should Use super()
Though It SucksThough It Sucks
Diamond, Again
class A(object)
class B(A) class C(A)
class D(B, C)
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)
super(Class, self)
● Does not call the superclass
● Call the next method in the MRO
● You can't expect what will be next
Remember #1:
● Don't change the method signature
OR
● Send all received arguments to super()
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
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)
Initialize
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???
C.__mro__ == (C, A, B, object)
object
class A(object) class B(object)
class C(A, B)
C.__mro__ == (C, A, B, object)
object
class A(object) class B(object)
class C(A, B)
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>
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
Remember #2:
● Don't forget super(C, self).__init__()
● but how about arguments?
super(Me, self).__init__()
vs.Parent.__init__(self)
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
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.
Plenty of pitfalls in super()
● verbose syntax — fragile on copy & paste :)
● can't use: super(C, self)[0]
● super(C) ≠ super(C, C)
...but we should use super()
● It's a standard.
● Safer to multiple inheritance
● If you mix with classic style,
everything will be broken.
References:● https://fuhm.net/super-harmful/
● https://groups.google.com/forum/?hl=en&fromgroups=#!topic/comp.lang.
python/qswq2zIKS7I
● http://www.python.org/download/releases/2.2.3/descrintro/#cooperation
● http://docs.python.org/2/reference/datamodel.html#newstyle
● http://www.python.org/dev/peps/pep-3135/
● http://freshfoo.com/blog/object__init__takes_no_parameters