
On Sun, Aug 7, 2011 at 8:46 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Sun, Aug 7, 2011 at 10:10 PM, Guido van Rossum <guido@python.org> wrote:
On the rest of that rejected PEP:
- I'm not actually sure how easy it is to implement the setting of __function__ when the frame is created. IIRC the frame creation is rather far removed from the function object, as there are various cases where there is no function object (class bodies, module-level code) and in other cases the function is called via a bound method. Someone should write a working patch to figure out if this is a problem in practice.
With a PEP 3135 closure style solution, the cell reference would be filled in at function definition time, so that part shouldn't be an issue.
Yes, I was thinking of something like that (though honestly I'd forgotten some of the details :-).
- The primary use case for __function__ to me seems to access function attributes, but I'm not sure what's wrong with referencing these via the function name. Maybe it's when there's a method involved, since then you'd have to write <classname>.<methodname>.<attrname>.
That does raise an interesting question, though: in a function wrapped via decorators, should __function__ refer to the innermost function or the outermost one?
IMO there is no doubt that if __function__ were to exist it should reference the innermost function, i.e. the thing that was created by the 'def' statement before any decorators were applied.
Reference by name lazily accesses the outermost one, but doesn't care how the decorators are applied (i.e. as part of the def statement or via post decoration).
What do you mean here by lazily?
A __class__ style cell reference to the result of the 'def' statement would behave differently in the post decoration case.
Oh you were thinking of making it reference the result after decoration? Maybe I know too much about the implementation, but I would find that highly confusing. Do you even have a use case for that? If so, I think it should be a separate name, e.g. __decorated_function__.
While referencing the innermost function would likely be wrong in any case involving function attributes, having the function in a valid state during decoration will likely mandate filling in the cell reference before invoking any decorators. Perhaps the best solution would be to syntactically reference the innermost function, but provide a clean way in functools to shift the cell reference to a different function (with functools.wraps doing that automatically).
Hm, making it dynamic sounds wrong. I think it makes more sense to just share the attribute dict (which is easily done through assignment to the wrapping function's __dict__).
This does seem like an area ripe for subtle decoration related bugs though, especially by contrast with lazy name based lookup.
TBH, personally I am in most cases unhappy with the aggressive copying of docstring and other metadata from the wrapped function to the wrapper function, and wish the idiom had never been invented.
- It seems that the "current class" question has already been solved for super(). If more is needed I'd be okay with extending the machinery used by super() so that you can access the magic "current class" variable explicitly too.
No need to extend it, that info is already available for explicit reference:
class C: ... def f(self): ... print(__class__) ... C().f() <class '__main__.C'>
(see postscript for more details)
Awesome.
- For "current module" I've encountered a number of use cases, mostly having to do with wanting to define new names dynamically. Somehow I have found:
globals()[x] = y # Note that x is a variable, not a literal
cumbersome; I'd rather write:
setattr(__this_module__, x, y)
There are IIRC also some use cases where an API expects a module object (or at least something whose attributes it can set and/or get) and passing the current module is clumsy:
foo(sys.modules[__name__])
While this may sound a little hypocritical coming from the author of PEPs 366 and 395, I'm wary of adding new implicit module globals for problems with relatively simple and robust alternatives. In this case, it's fairly easy to get access to the current module using the idiom Guido quoted:
import sys _this = sys.modules[__name__]
(or using dict-style access on globals())
Yeah, well, in most cases I find having to reference sys.modules a distraction and an unwarranted jump into the implementation. It may not even work: there are some recipes that replace sys.modules[__name__] with some wrapper object. If __this_module__ existed it would of course refer to the "real" module object involved. -- --Guido van Rossum (python.org/~guido)