Correct an oopsie -- Calvin's New Super PEP was already checked in as 367.
This commit is contained in:
parent
868901e5d8
commit
cb39215dad
|
@ -128,7 +128,6 @@ Index by Category
|
|||
S 3130 Access to Current Module/Class/Function Jewett
|
||||
S 3131 Supporting Non-ASCII Identifiers von Löwis
|
||||
S 3132 Extended Iterable Unpacking Brandl
|
||||
S 3133 New Super Spealman
|
||||
S 3141 A Type Hierarchy for Numbers Yasskin
|
||||
|
||||
Finished PEPs (done, implemented in Subversion)
|
||||
|
@ -503,7 +502,6 @@ Numerical Index
|
|||
S 3130 Access to Current Module/Class/Function Jewett
|
||||
S 3131 Supporting Non-ASCII Identifiers von Löwis
|
||||
S 3132 Extended Iterable Unpacking Brandl
|
||||
S 3133 New Super Spealman
|
||||
S 3141 A Type Hierarchy for Numbers Yasskin
|
||||
|
||||
|
||||
|
|
254
pep-3133.txt
254
pep-3133.txt
|
@ -1,254 +0,0 @@
|
|||
PEP: 3133
|
||||
Title: New Super
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Calvin Spealman <ironfroggy@gmail.com>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 28-Apr-2007
|
||||
Python-Version: 2.6
|
||||
Post-History: 28-Apr-2007, 29-Apr-2007
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
The current usage of super requires an explicit passing of both the class and
|
||||
instance it must operate from, requiring a breaking of the DRY (Don't Repeat
|
||||
Yourself) rule. This hinders any change in class name, and is often considered
|
||||
a wart by many.
|
||||
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
Within the specification section, some special terminology will be used to
|
||||
distinguish similar and closely related concepts. "Super type" will refer to
|
||||
the actual builtin type named "super". "Next Class/Type in the MRO" will refer
|
||||
to the class where attribute lookups will be performed by super, for example,
|
||||
in the following, A is the "Next class in the MRO" for the use of super.
|
||||
|
||||
::
|
||||
|
||||
class A(object):
|
||||
def f(self):
|
||||
return 'A'
|
||||
|
||||
class B(A):
|
||||
def f(self):
|
||||
super(B, self).f() # Here, A would be out "Next class in the
|
||||
# MRO", of course.
|
||||
|
||||
A "super object" is simply an instance of the super type, which is associated
|
||||
with a class and possibly with an instance of that class. Finally, "new super"
|
||||
refers to the new super type, which will replace the original.
|
||||
|
||||
Replacing the old usage of super, calls to the next class in the MRO (method
|
||||
resolution order) will be made without an explicit super object creation,
|
||||
by simply accessing an attribute on the super type directly, which will
|
||||
automatically apply the class and instance to perform the proper lookup. The
|
||||
following example demonstrates the use of this.
|
||||
|
||||
::
|
||||
|
||||
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'
|
||||
|
||||
The proposal adds a dynamic attribute lookup to the super type, which will
|
||||
automatically determine the proper class and instance parameters. Each super
|
||||
attribute lookup identifies these parameters and performs the super lookup on
|
||||
the instance, as the current super implementation does with the explicit
|
||||
invokation of a super object upon a class and instance.
|
||||
|
||||
The enhancements to the super type will define a new __getattr__ classmethod
|
||||
of the super type, which must look backwards to the previous frame and locate
|
||||
the instance object. This can be naively determined by located the local named
|
||||
by the first argument to the function. Using super outside of a function where
|
||||
this is a valid lookup for the instance can be considered undocumented in its
|
||||
behavior. This special method will actually be invoked on attribute lookups to
|
||||
the super type itself, as opposed to super objects, as the current
|
||||
implementation works. This may pose open issues, which are detailed below.
|
||||
|
||||
"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.
|
||||
|
||||
Much of this was discussed in the thread of the python-dev list, "Fixing super
|
||||
anyone?" [1]_.
|
||||
|
||||
Open Issues
|
||||
-----------
|
||||
|
||||
__call__ methods
|
||||
''''''''''''''''
|
||||
|
||||
Backward compatability of the super type API raises some issues. Names, the
|
||||
lookup of the __call__ of the super type itself, which means a conflict with
|
||||
doing an actual super lookup of the __call__ attribute. Namely, the following
|
||||
is ambiguous in the current proposal:
|
||||
|
||||
::
|
||||
|
||||
super.__call__(arg)
|
||||
|
||||
Which means the backward compatible API, which involves instansiating the super
|
||||
type, will either not be possible, because it will actually do a super lookup
|
||||
on the __call__ attribute, or there will be no way to perform a super lookup on
|
||||
the __call__ attribute. Both seem unacceptable, so any suggestions are welcome.
|
||||
|
||||
Actually keeping the old super around in 2.x and creating a completely new super
|
||||
type seperately may be the best option. A future import or even a simple import
|
||||
in 2.x of the new super type from some builtin module may offer a way to choose
|
||||
which each module uses, even mixing uses by binding to different names. Such a
|
||||
builtin module might be called 'newsuper'. This module is also the reference
|
||||
implementation, which I will present below.
|
||||
|
||||
super type's new getattr
|
||||
''''''''''''''''''''''''
|
||||
|
||||
To give the behavior needed, the super type either needs a way to do dynamic
|
||||
lookup of attributes on the super type object itself or define a metaclass for
|
||||
the builtin type. This author is unsure which, if either, is possible with C-
|
||||
defined types.
|
||||
|
||||
When should we create __super__ attributes?
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
They either need to be created on class creation or on __super__ attribute
|
||||
lookup. For the second, they could be cached, of course, which seems like it
|
||||
may be the best idea, if implicit creation of a super object for every class is
|
||||
considered too much overhead.
|
||||
|
||||
|
||||
Reference Implementation
|
||||
========================
|
||||
|
||||
This implementation was a cooperative contribution in the original thread [1]_.
|
||||
|
||||
::
|
||||
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# newsuper.py
|
||||
|
||||
import sys
|
||||
|
||||
class SuperMetaclass(type):
|
||||
def __getattr__(cls, attr):
|
||||
calling_frame = sys._getframe().f_back
|
||||
instance_name = calling_frame.f_code.co_varnames[0]
|
||||
instance = calling_frame.f_locals[instance_name]
|
||||
return getattr(instance.__super__, attr)
|
||||
|
||||
class Super(object):
|
||||
__metaclass__ = SuperMetaclass
|
||||
def __init__(self, type, obj=None):
|
||||
if isinstance(obj, Super):
|
||||
obj = obj.__obj__
|
||||
self.__type__ = type
|
||||
self.__obj__ = obj
|
||||
def __get__(self, obj, cls=None):
|
||||
if obj is None:
|
||||
raise Exception('only supports instances')
|
||||
else:
|
||||
return Super(self.__type__, obj)
|
||||
def __getattr__(self, attr):
|
||||
mro = iter(self.__obj__.__class__.__mro__)
|
||||
for cls in mro:
|
||||
if cls is self.__type__:
|
||||
break
|
||||
for cls in mro:
|
||||
if attr in cls.__dict__:
|
||||
x = cls.__dict__[attr]
|
||||
if hasattr(x, '__get__'):
|
||||
x = x.__get__(self, cls)
|
||||
return x
|
||||
raise AttributeError, attr
|
||||
|
||||
class autosuper(type):
|
||||
def __init__(cls, name, bases, clsdict):
|
||||
cls.__super__ = Super(cls)
|
||||
|
||||
if __name__ == '__main__':
|
||||
class A(object):
|
||||
__metaclass__ = autosuper
|
||||
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, arg=None):
|
||||
var = None
|
||||
return 'D' + Super.f()
|
||||
|
||||
assert D().f() == 'DBCA'
|
||||
|
||||
|
||||
History
|
||||
=======
|
||||
29-Apr-2007 - Changed title from "Super As A Keyword" to "New Super"
|
||||
- Updated much of the language and added a terminology section
|
||||
for clarification in confusing places.
|
||||
- Added reference implementation and history sections.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Fixing super anyone?
|
||||
(http://mail.python.org/pipermail/python-3000/2007-April/006667.html)
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
sentence-end-double-space: t
|
||||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
Loading…
Reference in New Issue