240 lines
6.8 KiB
ReStructuredText
240 lines
6.8 KiB
ReStructuredText
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/x-rst
|
|
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
|
|
https://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:
|