Quirk difference between classes and functions

eryk sun eryksun at gmail.com
Tue Feb 26 20:22:33 EST 2019


On 2/26/19, Gregory Ewing <greg.ewing at canterbury.ac.nz> wrote:
> Thomas Jollans wrote:
>> I imagine there's a justification for the difference in behaviour to do
>> with the fact that the body of a class is only ever executed once, while
>> the body of a function is executed multiple times.
>
> I suspect there isn't any deep reason for it, rather it's just
> something that fell out of the implementation, in particular
> the decision to optimise local variable access in functions
> but not other scopes.

At the module level, this goes unnoticed since globals and locals are
the same dict, but we can observe it in an exec() call if we use
separate globals and locals . For example:

    >>> x = 0
    >>> locals = {}
    >>> exec('x = x + 1', globals(), locals)
    >>> x
    0
    >>> locals
    {'x': 1}

In terms of implementation, the LOAD_NAME instruction that's used in
unoptimized code looks in the locals, globals, and builtins scopes, in
that order. The intent is to allow locals to shadow globals and
builtins, and globals to shadow builtins. It also allows for temporary
shadowing. Optimized code supports the former (via LOAD_GLOBAL), but
not the latter. For example:

unoptimized:

    >>> exec(r'''
    ... len = lambda x: 42
    ... print(len('spam'))
    ... del len
    ... print(len('spam'))
    ... ''')
    42
    4

optimized:

    >>> def f():
    ...     len = lambda x: 42
    ...     print(len('spam'))
    ...     del len
    ...     print(len('spam'))
    ...
    >>> f()
    42
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 5, in f
    UnboundLocalError: local variable 'len' referenced before assignment


More information about the Python-list mailing list