207 lines
6.7 KiB
Plaintext
207 lines
6.7 KiB
Plaintext
|
PEP: 3130
|
|||
|
Title: Access to Current Module/Class/Function
|
|||
|
Version: $Revision$
|
|||
|
Last-Modified: $Date$
|
|||
|
Author: Jim J. Jewett <jimjjewett@gmail.com>
|
|||
|
Status: Draft
|
|||
|
Type: Standards Track
|
|||
|
Content-Type: text/plain
|
|||
|
Created: 22-Apr-2007
|
|||
|
Python-Version: 3.0
|
|||
|
Post-History: 22-Apr-2007
|
|||
|
|
|||
|
|
|||
|
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:
|