faqts : Computers : Programming : Languages : Python : Snippets

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

4 of 4 people (100%) answered Yes
Recently 3 of 3 people (100%) answered Yes

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