new super redux (better late than never?)
I was looking at the reference implementation in PEP 3135 (New Super), and I was inspired to put together a slightly different implementation that doesn't fiddle with bytecode. I know that the new super() in python 3000 doesn't follow the reference implementation in the PEP, but the code intrigued me enough to offer up this little tidbit, which can be easily be used in python 2.5. What I did was borrow the idea of using a metaclass to do a post-definition fix-up on the methods, but added a new function decorator called autosuper_method. Like staticmethod or classmethod, the decorator wraps the function using the non-data descriptor protocol. The method wrapped by the decorator will receive an extra implicit argument (super) inserted before the instance argument (self). One caveat about the decorator: it must be the first decorator in the list (i.e. the outermost wrapper), or else the metaclass will not recognize the wrapped function as an instance of the decorator class. I think this implementation strikes me as more pythonic than the spooky behavior of the new python 3000 super() built-in, and it is more flexible because of the implicit argument design. This allows things like the ability to use the super argument in inner functions without worrying about the 'first argument' assumption of python 3000's super(). The implementation follows, which is also called autosuper in deference to the original reference implementation. It includes a demonstration of some of its flexibility: ------------------------------------------------------------ #!/usr/bin/env python # # autosuper.py class autosuper_method(object): def __init__(self, func, cls=None): self.func = func self.cls = cls def __get__(self, obj, type=None): # return self if self.cls is not set yet if self.cls is None: return self if obj is None: # class binding - assume first argument is instance, # and insert superclass before it def newfunc(*args, **kwargs): if not len(args): raise TypeError('instance argument missing') return self.func(super(self.cls, args[0]), *args, **kwargs) else: # instance binding - insert superclass as first # argument, and instance as second def newfunc(*args, **kwargs): return self.func(super(self.cls, obj), obj, *args, **kwargs) return newfunc class autosuper_meta(type): def __init__(cls, name, bases, clsdict): # set cls attribute of all instances of autosuper_method for v in clsdict: o = getattr(cls, v) if isinstance(o, autosuper_method): o.cls = cls class autosuper(object): __metaclass__ = autosuper_meta if __name__ == '__main__': class A(autosuper): def f(self): return 'A' # Demo - standard use class B(A): @autosuper_method def f(super, self): return 'B' + super.f() # Demo - reference super in inner function class C(A): @autosuper_method def f(super, self): def inner(): return 'C' + super.f() return inner() # Demo - define function before class definition @autosuper_method def D_f(super, self): return 'D' + super.f() class D(B, C): f = D_f # Demo - define function after class definition class E(B, C): pass # don't use @autosuper_method here! The metaclass has already # processed E, so it won't be able to set the cls attribute def E_f(super, self): return 'E' + super.f() # instead, use the extended version of the decorator E.f = autosuper_method(E_f, E) d = D() assert d.f() == 'DBCA' # Instance binding assert D.f(d) == 'DBCA' # Class binding e = E() assert e.f() == 'EBCA' # Instance binding assert E.f(e) == 'EBCA' # Class binding ------------------------------------------------------------ P.S. I know that using the word 'super' as an argument name might be frowned upon, but I'm just copying what I've seen done in the standard python library (e.g. using 'list' as a local variable name :). Anyway, it doesn't really hurt anything unless you wanted to call the original super() built-in from the decorated method, which would kind of defeat the purpose. P.P.S. Something like this might have been offered up already. I've been searching the mail list archives for a while, and found a few reference to using decorators, but didn't find any full implementations. This implementation also has the advantage of being compatible with existing code.
participants (2)
-
Anthony Tolle
-
Guido van Rossum