[Python-3000] [Python-ideas] PEP 30xx: Access to Module/Class/Function Currently Being Defined (this)
Guido van Rossum
guido at python.org
Thu May 3 03:29:53 CEST 2007
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 <jimjjewett at 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__]
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/)
More information about the Python-3000
mailing list