Summary for the impatient: -1; the PEP is insufficiently motivated and poorly specified.
> PEP: 3130 > Title: Access to Current Module/Class/Function > Version: $Revision: 55056 $ > Last-Modified: $Date: 2007-05-01 12:35:45 -0700 (Tue, 01 May 2007) $ > Author: Jim J. Jewett <[EMAIL PROTECTED]> > 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__] You're making this way too complicated. sys.modules[__name__] always works. > 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 > ... PEP 3122 is already rejected. > Rationale for __class__ > > Class methods are passed the current instance; from this they can "current instance" is confusing when talking about class method. I'll assume you mean "class". > determine self.__class__ (or cls, for class methods). > Unfortunately, this reference is to the object's actual class, Why unforunately? All the semantics around self.__class__ and the cls argument are geared towards the instance's class, not the lexically current 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. Do you have any other use cases? Because Tim Delaney's 'super' implementation doesn't need this. I also note that the name __class__ is a bit confusing because it means "the object's class" in other contexts. > 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. Often? Private storage can just as well be placed in the class or module. The recursion use case just doesn't occur as a problem in reality (hasn't since we introduced properly nested namespaces in 2.1). > 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) It makes no sense to put dangling references like this in motivating examples. Without the definion of @annotate the example is meaningless. > def counter(): > # Assume name counter is never rebound: Why do you care so much about this? It's a vanishingly rare situation in my experience. > counter.total += 1 > return counter.total You're abusing function attributes here IMO. Function attributes are *metadata* about the function; they should not be used as per-function global storage. > # class exists only to provide storage: If you don't need a class, use a module global. That's what they're for. Name it with a leading underscore to flag the fact that it's an implementation detail. > 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. That is a completely insufficient attempt at describing the semantics. > 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. Sorry, bytecode hacks don't count as a semantic specification. > 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? What do __class__ and __function__ refer to inside a nested class or function? > 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: --- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-3000 mailing list [email protected] http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com
