Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
205 views
in Technique[技术] by (71.8m points)

python - How print statement create a local variables

Question are at the end of this post.

First snippet: empty local variable dictionary.

def outer():
    x = 1
    def inner():
        print "Local variables: %s" % locals()
    return inner()
print outer()

Output: Local variables: {}

Second snippet: print inside inner() function and creating local variable entry.

def outer():
    x = 1
    def inner():
        print x
        print "Local variables: %s" % locals()
    return inner()
print outer()

Output:

1
Local variables: {'x': 1}

Third Snippet: del x from inside the inner function:

def outer():
    x = 1
    def inner():
        print x
        print "Local variables: %s" % locals()
        del x
    return inner()
print outer()

Output:

>>> outer()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in outer
  File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'x' referenced before assignment
>>>

Questions :

  1. In Second Snippet, how print statement create local variable.
  2. If it creates local variable inside inner function why I am not able to delete it.

Could someone please help me understanding this.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In Python, unless you specify otherwise (with a global statement, or a nonlocal statement in 3.0+), a variable is in locals if you modify it (assign to it, del it, etc.) anywhere in the function.*

In the first snippet, you never modify x, or even access it, so it's not local. In fact, it doesn't even exist. That's easy.

The second version is the tricky one. x is not local to inner, because you don't modify it in inner. So, Python goes looking for it, moving outward scope by scope, until it finds it a scope that has that variable. And it finds it as a local variable in outer. Which means it's a closure variable or free variable in inner. Since the locals function includes closure variables as well as local variables, you see it.

The third version, by doing del x, makes x local to inner.** So, it appears in locals. However, you try to print it without having ever assigned anything to it, so there is no value yet. So you get an UnboundLocalError.

Generally, once you understand the basic idea Python is trying to accomplish here, it's usually obvious what kind of variable you have. But if it's ever unclear, the detailed rules are defined in Naming and Binding.


If you want to understand how closures work under the covers, you can start by inspecting the function objects. Try this:

def outer():
    x = 1
    def inner():
        print x
        print "Local variables: %s" % locals()
    return inner
inner = outer()
print inner.func_closure
print inner.func_code.co_freevars
print outer.func_code.co_cellvars

The inspect module docs list all of the important members of function, code, and other "under the covers" objects.

Using the dis module to look at the bytecode for outer and inner may also be helpful.*** For example, if you run this code, you'll see a LOAD_FAST for the local, LOAD_DEREF for the cell, and LOAD_GLOBAL for the global.

But if you really want to understand how all of this really works, the series of articles on symbol tables at Eli Bendersky's "Python internals" blog covers just about everything very nicely. (Thanks to Ashwini Chaudhary for locating it and pointing it out in a comment.)


* This is checked at compile time, not execution time, so trying to confuse it with, e.g., exec can successfully confuse both Python and yourself.

** Note that del counts as both an modification and an access. This can be surprising, but you can see that def foo(): del x will raise an UnboundLocalError because the del makes x local, and the very same del fails to find a value.

*** … assuming you're using a Python implementation that uses CPython-style bytecode, like CPython itself (of course) or PyPy.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...