[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