Question

We can see the NameError and UnboundLocalError at runtime when the name is not defined and unbound respectively. But it is not clear how does name evaluating occuring at run time? I assume the following:

Consider example of code snippet

def foo():
    a=3
    def bar():
        return a
    tmp=bar()
    res=a+tmp
    return res

When bar function is invoked we have that new execution frame is created. Denote this frame as bar_frame. There is no elements contained in an bar_frame.f_local dictionary. But bar_frame.f_back.f_locals contains 4 name-value pairs. And so

My understanding: We have the following algorithm of name evaluation:

  1. Trying to find name in the currentframe.f_locals

    1.1 If currentframe.f_locals corresponding to a global namespace and suitable name is not found then throw NameError

    1.1 If suitable name is found and it is bounded then return currentframe.f_locals[name]

    1.2 If suitable name is found and it is unbounded throw UnboundLocalName error.

  2. Trying to find name in the currentframe.f_back.f_locals

Please check my understanding.

No correct solution

OTHER TIPS

The algorithm you describe behaves in a manner known as dynamic scoping, where non-local names are taken from the caller's environment at run time. But Python does not use dynamic scoping. It uses lexical scoping. That means non-local names are resolved from the lexically surrounding function. For example, the function returned from this function f:

def f():
    x = 5
    def g():
        print(x)
    return g

... always prints 5, even if it's called like this:

def h():
    g = f()
    x = 10
    g()

g is called a closure. Which names are non-local, and how "far up" they refer (you can have a function inside a function inside a function), is decided by the bytecode compiler, not at runtime. The bytecode contains all this information, so at runtime, the interpreter does not search through anything, much less multiple frames, while resolving the names. It always knows exactly where to look, from the kind of bytecode instruction used.

Addendum: The reason frame objects exist, have the names and values of all locals, and refer to their caller's frames, is unrelated. The locals are stored to facilitate debugging (and some nasty hacks that involve affecting the locals of calling functions). f_back exists is debugging and dark magic too, most prominently it is necessary for stack traces to work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top