[Python-ideas] Access to function objects

Guido van Rossum guido at python.org
Sun Aug 7 15:07:02 CEST 2011

On Sun, Aug 7, 2011 at 8:46 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> On Sun, Aug 7, 2011 at 10:10 PM, Guido van Rossum <guido at 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.

> 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)


>> - 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)

More information about the Python-ideas mailing list