1

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.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • No, `a` is a closure instead. – Martijn Pieters Mar 01 '14 at 12:12
  • Related: [python closure weird behavior](http://stackoverflow.com/a/10815128) and [How to access a function inside a function?](http://stackoverflow.com/a/17395350) – Martijn Pieters Mar 01 '14 at 12:13
  • @MartijnPieters I want to know how names is evaluating at run-time, but not about closures. – St.Antario Mar 01 '14 at 12:16
  • 1
    http://eli.thegreenplace.net/2010/09/18/python-internals-symbol-tables-part-1/ – Ashwini Chaudhary Mar 01 '14 at 12:16
  • @St.Antario: That is how names are resolved; the compiler has marked them as closures. – Martijn Pieters Mar 01 '14 at 12:17
  • @MartijnPieters OK, but why execution frame object contains a dictionaries of a local variables and a reference to the enclosing execution frame? What is the sense of it? – St.Antario Mar 01 '14 at 12:20
  • Locals are looked up by bytecode by index (the `LOAD_FAST` opcode), but closures are not locals. The frame references are there for producing tracebacks, among others. Nested functions cannot use these as they can be returned without being called, then need access to the closures when you call the returned function object later on. – Martijn Pieters Mar 01 '14 at 12:25
  • @MartijnPieters Did you mean that a is closure for bar, but local for foo? – St.Antario Mar 01 '14 at 12:29
  • Yes, `a` is a local in `foo`. – Martijn Pieters Mar 01 '14 at 12:31
  • @St.Antario The *function* (bar here) is the closure, not any of names. But yes, in bar it's a closed-over non-local while in foo it's local. –  Mar 01 '14 at 12:31

1 Answers1

2

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.