[Python-Dev] New Super PEP - draft 2

Jim Jewett jimjjewett at gmail.com
Sun Apr 29 23:15:33 CEST 2007


(Adding python-3000 to the Cc, since that is where  much of the recent
discussion occurred)

Calvin's full proposal is archived at:
http://mail.python.org/pipermail/python-dev/2007-April/072835.html

> Abstract
> ========

> The PEP defines the proposal to enhance the super builtin to work implicitly
> upon the class within which it is used and upon the instance the current
> function was called on. The premise of the new super usage suggested is as
> follows:

>     super.foo(1, 2)

> to replace the old:

>     super(Foo, self).foo(1, 2)

The alternatives section needs to explain why "super.foo(*args)" is
the right level of simplification.  Alternatives include

(1)    No changes

Con:  fragility in name binding

(2)    super(__this_class__, self).foo(*args)

Con:  The "(__this_class__, self)" is boilerplate.

Note that the __this_class__ PEP should be referenced, if only as a
possible explanation for what is happening under the covers.

(3)    self.__super__.foo(*args)   # or super.foo(*args)

Con:  Shouldn't need a __double_underscore_name__ in normal functions.
Con:  __super__ (even if renamed super) is not a simple attribute; it
is a property representing a partially applied function (that gets
further applied by the "self")

(4)  super(self, *args)    # ?  or __super__(self, *args)

Actually, I sort of like this one, as it allows the upcall signature
to exactly match the method definition signature.

Con:  super is still not a simple attribute.
Con:  changing the method name becomes a hassle.

(5)  super.foo(self, *args)    # ?  or __super__.foo(self, *args)

Con:  self isn't really an argument just to super.foo -- it is an
argument to super which is used to find/instantiate foo in the first
place.  (Plus the objections to partially applied function
attributes.)

(6)  super     # ? or super()

Pro:  matches java; doesn't require a repeat of *args
Con:  doesn't match anything else in python, needs to be a keyword
(and would still need object support).

In the first example:

        class A(object):
            def f(self):
                return 'A'

        class B(A):
            def f(self):
                return 'B' + super.f()

        class C(A):
            def f(self):
                return 'C' + super.f()

        class D(B, C):
            def f(self):
                return 'D' + super.f()

        assert D().f() == 'DBCA'

You should probably include tests that fail with some of the more
obvious (but wrong) solutions, such as

        class A(object):
            def f(self):
                return 'A'

        class Bempty(A): # Make sure it doesn't call the A or B method twice
            pass

        class B(Bempty):
            def f(self):
                return 'B' + super.f()

        class C(A):
            def f(self):
                return 'C' + super.f()

        class D(B, C):
            def f(self):
                return 'D' + super.f()

        assert D().f() == 'DBCA'

        class E(C, B):    # Show that B can point to C as next or vice versa
            def f(self):
                return 'E' + super.f()

        assert E().f() == 'ECBA'

        class F(D):    # show that the instance may not be a direct instance
            pass

        assert D().f() == 'DBCA'


> The enhancements to the super type will define a new __getattr__ classmethod
> of the super type,

Did you really mean, it gets the class of builtin.super, but no info
on which class is using super?  If not, it isn't a classmethod of the
super type.  It may be a classmethod of the
currently-being-defined-type (__this_class__).

> which must look backwards to the previous frame and locate
> the instance object.

frame manipulation is fragile.  Even if it didn't cause problems for
other implementations, it causes problems for nested functions and
callbacks.

    def f(self, button, *args):
        def callback(*args):
            super(__this_class__, self).f(*args)
        button.callback=callback

When this gets called, the appropriate self won't be in the frame,
except as a lexically scoped variable (which might have a different
name).

Also, note that this fails on most of Thomas Wouters' advanced usages.
 While you say that super shouldn't be called outside a method, you
can't really keep the super object itself from getting returned.

> "Every class will gain a new special attribute, __super__, which refers to an
> instance of the associated super object for that class" In this capacity, the
> new super also acts as its own descriptor, create an instance-specific super
> upon lookup.

If you didn't say instance-specific, this would be equivalent to a
class decorator, translating

    class A(object): ...

into

    class A(object): ...

    A.__super__=super(A)

As is, it gets a bit trickier, since you need to I think the
translation is closer to

    class A(object):...
        @property
        def __super__(self):
            return __this_class__.__supermaker()

    A.__supermaker=super(A)

I don't see a good non-magical way to pass both the instance and the
class-at-time-of-writing (as opposed to class of calling instance),
which is why the other solutions used bytecode hacks or name mangling.

> Much of this was discussed in the thread of the python-dev list, "Fixing super
> anyone?" [1]_.

I assume you meant the python-3000 list.

-jJ


More information about the Python-Dev mailing list