Permalink
Cannot retrieve contributors at this time
239 lines (170 sloc)
6.78 KB
| 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: |