[Python-3000] [Python-ideas] PEP 30xx: Access to Module/Class/Function Currently Being Defined (this) (original) (raw)

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:55056Revision: 55056 Revision:55056 Last-Modified: Date:2007−05−0112:35:45−0700(Tue,01May2007)Date: 2007-05-01 12:35:45 -0700 (Tue, 01 May 2007) Date:2007050112:35:450700(Tue,01May2007) 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 thisclass) 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 thisclass) 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 thismodule, thisclass, and thisfunction, (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/browsefrm/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