215 lines
6.9 KiB
Plaintext
215 lines
6.9 KiB
Plaintext
PEP: 3130
|
||
Title: Access to Current Module/Class/Function
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: Jim J. Jewett <jimjjewett@gmail.com>
|
||
Status: Rejected
|
||
Type: Standards Track
|
||
Content-Type: text/plain
|
||
Created: 22-Apr-2007
|
||
Python-Version: 3.0
|
||
Post-History: 22-Apr-2007
|
||
|
||
|
||
Rejection Notice
|
||
|
||
This PEP is rejected. It is not clear how it should be
|
||
implemented or what the precise semantics should be in edge cases,
|
||
and there aren't enough important use cases given. response has
|
||
been lukewarm at best.
|
||
|
||
|
||
Abstract
|
||
|
||
It is common to need a reference to the current module, class,
|
||
or function, but there is currently no entirely correct way to
|
||
do this. This PEP proposes adding the keywords __module__,
|
||
__class__, and __function__.
|
||
|
||
|
||
Rationale for __module__
|
||
|
||
Many modules export various functions, classes, and other objects,
|
||
but will perform additional activities (such as running unit
|
||
tests) when run as a script. The current idiom is to test whether
|
||
the module's name has been set to magic value.
|
||
|
||
if __name__ == "__main__": ...
|
||
|
||
More complicated introspection requires a module to (attempt to)
|
||
import itself. If importing the expected name actually produces
|
||
a different module, there is no good workaround.
|
||
|
||
# __import__ lets you use a variable, but... it gets more
|
||
# complicated if the module is in a package.
|
||
__import__(__name__)
|
||
|
||
# So just go to sys modules... and hope that the module wasn't
|
||
# hidden/removed (perhaps for security), that __name__ wasn't
|
||
# changed, and definitely hope that no other module with the
|
||
# same name is now available.
|
||
class X(object):
|
||
pass
|
||
|
||
import sys
|
||
mod = sys.modules[__name__]
|
||
mod = sys.modules[X.__class__.__module__]
|
||
|
||
Proposal: Add a __module__ keyword which refers to the module
|
||
currently being defined (executed). (But see open issues.)
|
||
|
||
# XXX sys.main is still changing as draft progresses. May
|
||
# really need sys.modules[sys.main]
|
||
if __module__ is sys.main: # assumes PEP (3122), Cannon
|
||
...
|
||
|
||
|
||
Rationale for __class__
|
||
|
||
Class methods are passed the current instance; from this they can
|
||
determine self.__class__ (or cls, for class methods).
|
||
Unfortunately, this reference is to the object's actual class,
|
||
which may be a subclass of the defining class. The current
|
||
workaround is to repeat the name of the class, and assume that the
|
||
name will not be rebound.
|
||
|
||
class C(B):
|
||
|
||
def meth(self):
|
||
super(C, self).meth() # Hope C is never rebound.
|
||
|
||
class D(C):
|
||
|
||
def meth(self):
|
||
# ?!? issubclass(D,C), so it "works":
|
||
super(C, self).meth()
|
||
|
||
Proposal: Add a __class__ keyword which refers to the class
|
||
currently being defined (executed). (But see open issues.)
|
||
|
||
class C(B):
|
||
def meth(self):
|
||
super(__class__, self).meth()
|
||
|
||
Note that super calls may be further simplified by the "New Super"
|
||
PEP (Spealman). The __class__ (or __this_class__) attribute came
|
||
up in attempts to simplify the explanation and/or implementation
|
||
of that PEP, but was separated out as an independent decision.
|
||
|
||
Note that __class__ (or __this_class__) is not quite the same as
|
||
the __thisclass__ property on bound super objects. The existing
|
||
super.__thisclass__ property refers to the class from which the
|
||
Method Resolution Order search begins. In the above class D, it
|
||
would refer to (the current reference of name) C.
|
||
|
||
|
||
Rationale for __function__
|
||
|
||
Functions (including methods) often want access to themselves,
|
||
usually for a private storage location or true recursion. While
|
||
there are several workarounds, all have their drawbacks.
|
||
|
||
def counter(_total=[0]):
|
||
# _total shouldn't really appear in the
|
||
# signature at all; the list wrapping and
|
||
# [0] unwrapping obscure the code
|
||
_total[0] += 1
|
||
return _total[0]
|
||
|
||
@annotate(total=0)
|
||
def counter():
|
||
# Assume name counter is never rebound:
|
||
counter.total += 1
|
||
return counter.total
|
||
|
||
# class exists only to provide storage:
|
||
class _wrap(object):
|
||
|
||
__total = 0
|
||
|
||
def f(self):
|
||
self.__total += 1
|
||
return self.__total
|
||
|
||
# set module attribute to a bound method:
|
||
accum = _wrap().f
|
||
|
||
# This function calls "factorial", which should be itself --
|
||
# but the same programming styles that use heavy recursion
|
||
# often have a greater willingness to rebind function names.
|
||
def factorial(n):
|
||
return (n * factorial(n-1) if n else 1)
|
||
|
||
Proposal: Add a __function__ keyword which refers to the function
|
||
(or method) currently being defined (executed). (But see open
|
||
issues.)
|
||
|
||
@annotate(total=0)
|
||
def counter():
|
||
# Always refers to this function obj:
|
||
__function__.total += 1
|
||
return __function__.total
|
||
|
||
def factorial(n):
|
||
return (n * __function__(n-1) if n else 1)
|
||
|
||
|
||
Backwards Compatibility
|
||
|
||
While a user could be using these names already, double-underscore
|
||
names ( __anything__ ) are explicitly reserved to the interpreter.
|
||
It is therefore acceptable to introduce special meaning to these
|
||
names within a single feature release.
|
||
|
||
|
||
Implementation
|
||
|
||
Ideally, these names would be keywords treated specially by the
|
||
bytecode compiler.
|
||
|
||
Guido has suggested [1] using a cell variable filled in by the
|
||
metaclass.
|
||
|
||
Michele Simionato has provided a prototype using bytecode hacks
|
||
[2]. This does not require any new bytecode operators; it just
|
||
modifies the which specific sequence of existing operators gets
|
||
run.
|
||
|
||
|
||
Open Issues
|
||
|
||
- Are __module__, __class__, and __function__ the right names? In
|
||
particular, should the names include the word "this", either as
|
||
__this_module__, __this_class__, and __this_function__, (format
|
||
discussed on the python-3000 and python-ideas lists) or as
|
||
__thismodule__, __thisclass__, and __thisfunction__ (inspired
|
||
by, but conflicting with, current usage of super.__thisclass__).
|
||
|
||
- Are all three keywords needed, or should this enhancement be
|
||
limited to a subset of the objects? Should methods be treated
|
||
separately from other functions?
|
||
|
||
|
||
References
|
||
|
||
[1] Fixing super anyone? Guido van Rossum
|
||
http://mail.python.org/pipermail/python-3000/2007-April/006671.html
|
||
|
||
[2] Descriptor/Decorator challenge, Michele Simionato
|
||
http://groups.google.com/group/comp.lang.python/browse_frm/thread/a6010c7494871bb1/62a2da68961caeb6?lnk=gst&q=simionato+challenge&rnum=1&hl=en#62a2da68961caeb6
|
||
|
||
|
||
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:
|