Entry
Smalltalk-like 'super' (was: Python aka. Smalltalk Lite?)
Jan 1st, 2004 07:23
Matthias Urlichs, Nathan Wallace, Hans Nowak, Snippet 374, Just van Rossum
With Python 2.2, you can auto-add a __super attribute which goes to the
superclass. From <http://www.python.org/2.2.3/descrintro.html>:
class autosuper(type):
def __init__(cls, name, bases, dict):
super(autosuper, cls).__init__(name, bases, dict)
setattr(cls, "_%s__super" % name, super(cls))
class A:
__metaclass__ = autosuper
def meth(self):
return "A"
class B(A):
def meth(self):
return "B" + self.__super.meth()
class C(A):
def meth(self):
return "C" + self.__super.meth()
class D(C, B):
def meth(self):
return "D" + self.__super.meth()
assert D().meth() == "DCBA"
With older Python versions, you'll have to jump through a few hoops..:
"""
Packages: oop
"""
"""
>>Here's are some whimper inducing things for me:
>> No class methods
>> No super
>
>Yeah, I've been able to work around these, but they're somewhat
>annoying. Note that I believe that Smalltalk has only single
>inheritance, so adopting super may be a bit difficult in Python.
Last time I tried to (not) get my head exploded about 'super' I realized
it's more subtle than that. I managed to implement it in Python, but it's
*majorly* ugly and inneficient. For entertainment, I've appended the code.
I'm not sure anymore if it's even correct...
Just
"""
import sys
from types import FunctionType, MethodType
def getbasemethod(method):
assert type(method) == MethodType
for base in method.im_class.__bases__:
try:
basemethod = getattr(base, method.__name__)
except AttributeError:
pass
else:
assert type(basemethod) == MethodType
# XXX no can't do, see below:
# basemethod.im_self = method.im_self
return basemethod
else:
raise AttributeError, method.__name__
def findclass(klass, code):
for value in klass.__dict__.values():
if type(value) == FunctionType:
if value.func_code is code:
return klass
for base in klass.__bases__:
k = findclass(base, code)
if k:
return k
def super():
try:
1/0
except:
frame = sys.exc_info()[2].tb_frame.f_back
selfname = frame.f_code.co_varnames[0]
self = frame.f_locals[selfname]
klass = self.__class__
code = frame.f_code
methodname = frame.f_code.co_name
klass = findclass(klass, code)
if not klass:
raise AttributeError, methodname
# would be even better if we could bind it to "self"
return getbasemethod(getattr(klass, methodname))
class A:
def foo(self):
try:
print super()
except AttributeError:
print "no super method foo"
class B(A):
def foo(self):
s = super()
print s
s(self)
class C(B):
def foo(self):
s = super()
print s
s(self)
i = C()
i.foo()