[Python-ideas] new super redux (better late than never?)
Guido van Rossum
guido at python.org
Wed Mar 5 04:24:35 CET 2008
Ehhh! The PEP's "reference implementation" is useless and probably
doesn't even work. The actual implementation is completely different.
If you want to help, a rewrite of the PEP to match reality would be
most welcome!
On Tue, Mar 4, 2008 at 6:36 PM, Anthony Tolle <artomegus at gmail.com> wrote:
> 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.
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/mailman/listinfo/python-ideas
>
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-ideas
mailing list