super() and automatic method combination
Steven Bethard
steven.bethard at gmail.com
Wed May 18 15:16:55 EDT 2005
Laszlo Zsolt Nagy wrote:
> I tested this and I realized that if you change the parameter list in
> the descendants then it is not wise to use super.
> I'm going to publish the example below, I hope others can learn from it
> too.
>
[snip and fixed formatting]
>
> Example (bad):
>
> class A(object):
> def f(self):
> print "A.f called"
> class B(A):
> def f(self,what):
> super(B,self).f()
> print "B.f called (%s)" % what
> class C(A):
> def f(self):
> super(C,self).f()
> print "C.f called"
> class D(B,C):
> def f(self):
> super(D,self).f()
> print "D.f called"
>
> d = D()
> d.f()
>
> Will result in:
>
> C:/Python24/pythonw.exe -u "C:/Python/Projects/Test4/test4.py"
> Traceback (most recent call last):
> File "C:/Python/Projects/Test4/test4.py", line 22, in ?
> d.f()
> File "C:/Python/Projects/Test4/test4.py", line 17, in f
> super(D,self).f()
> TypeError: f() takes exactly 2 arguments (1 given)
Yeah, this problem has been discussed before. It's a restriction of
super that the method signature may not change the number of parameters
in this way in the inheritance hierarchy.
The above is clearly a toy example. Do you really have a need for B to
accept a parameter than none of the others accept? Makes it sounds like
B.f might be better off as a different method. If the 'what' parameter
is necessary for B.f, is it potentially applicable to the other f
functions? Could you make 'what' a paramter in the other functions that
defaults to, say, None?
One other possible (but IMHO somewhat ugly) solution:
py> class A(object):
... def f(self, *args, **kwargs):
... print 'A.f'
...
py> class B(A):
... def f(self, what, *args, **kwargs):
... super(B, self).f(what, *args, **kwargs)
... print 'B.f', what
...
py> class C(A):
... def f(self, *args, **kwargs):
... super(C, self).f(*args, **kwargs)
... print 'C.f'
...
py> class D(B, C):
... def f(self, what, *args, **kwargs):
... super(D, self).f(what, *args, **kwargs)
... print 'D.f', what
...
py> d = D()
py> d.f(42)
A.f
C.f
B.f 42
D.f 42
py> d.f(what=13)
A.f
C.f
B.f 13
D.f 13
The problem is that you need to know when you create A that some of the
methods in the subclasses might change the signature. Or you need to do
this to every method, which is kinda nasty.
Definitely take a moment to read Guido's comments on this issue:
http://mail.python.org/pipermail/python-dev/2005-January/050656.html
The main point is that by adding parameters to functions in a subclass,
you violate the Liskov Substitutability Principle.
STeVe
More information about the Python-list
mailing list