[Python-3000] 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-3000
mailing list