About the scope of python variables
给我你的怀抱
给我你的怀抱 2017-05-18 10:53:10
0
3
736

There is such a function:

def outside():
    x=[]
    print(id(x))
    def inside():
        print(id(x))
        x[:]=[1,2,3]
        print(id(x))
    inside()
    print(id(x))
    print(x)

No problem occurred after calling, output:
140560473157960
140560473157960
140560473157960
140560473157960
[1, 2, 3]

But replace the x inside with a string, as follows:

def outside():
    x='outside'
    print(id(x))
    def inside():
        print(id(x))
        x='inside'
        print(id(x))
    inside()
    print(id(x))
    print(x)

When the call is made again, it becomes:

140560473762872
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in outside
  File "<stdin>", line 5, in inside
UnboundLocalError: local variable 'x' referenced before assignment
  • According to the rules, when entering the inside function, why does x not point to the original 'outside' string?

  • Shouldn’t undefined variables generate NameError? Why not here?

  • I originally thought that strings and lists were similar to pointers in C, but now it seems that is not the case. If possible, I hope to give some introduction to this point, thank you.

给我你的怀抱
给我你的怀抱

reply all(3)
我想大声告诉你

Answers one by one from easy to difficult, because it is my humble opinion, so if someone sees that what is said is incorrect, I hope they can point out
Similar to pointers in C: This is correct, because when py里面, 几乎所有的事物都是对象, 就连变量赋值, 也是先生成对象, 再让变量指向这个对象,而对象还分可变对象不可变对象, 在对可变对象operating, it is It will affect other variables pointing to this object, for example:

o = [1, 2, 3, 4]
b = o
print id(o)
print id(b)
b[1] = 123123
print b
print o
输出:
39946376
39946376
[1, 123123, 3, 4]
[1, 123123, 3, 4]  # o指向的列表也被改变

For 不可变对象, it directly abandons the old object and points to the new object, for example:

s = '123123'
print id(s)
s = '32131'
print id(s)


# 输出:
41392768
41392808

So when you operate a python object, you need to keep in mind what type the object belongs to, and whether your operation will fail or not achieve the desired effect due to these characteristics.

Undefined variables: When python is searching for variables, it will follow the order of LEGB. Only when the search is completed or not found, the NameError exception will be triggered. For this, please refer to one of my blog posts: Python: Scope (scope) and LEGB

UnboundLocalError: This problem is the most common and the most difficult to explain, because we always take it for granted that it will find the variables according to the order of ELGB; in fact, our understanding is not wrong, it is just that we ignore it One point: 赋值语句, if the function code segment does not have an assignment statement, then this problem will not occur, but why does an error occur when an assignment statement appears? This is related to the scope of python. As mentioned in the above article, the scope of python It is not dynamic, but static. You can see it from the indentation of the script file, so in the code:

 x='outside'
    print(id(x))
    def inside():
        print(id(x))
        x='inside'
        print(id(x))

Ininside中, 已经有了赋值语句, 所以对于x,他已经不会从enclosing 或者global甚至bulitin里面去查找, 它已经被认定在local域了, 只是这个值并没有和真正的对象'inside'建立起绑定关系, 因为代码没有运行到真正的赋值语句, 所以, 会触发这个UnboundLocalError. 而为什么那个列表会可以那样做, 因为他们两个是完全不同的操作, 同样都是print(id(x))list的操作字节码是LOAD_DEREF, 而字符串的操作字节码是LOAD_FAST, 而x[:]=[1,2,3]/x='inside'分别对应的字节码又是STORE_SLICE+3STORE_FAST, 前者是在原来的基础上修改, 而后者是重新指向新的对象, 而这两种方式的区别, 决定了,它们在构建函数时, 以怎样的形式存放x, 这个就涉及到python函数构建的原理了, 有兴趣可以看看源码中的object/ceval.c源码, 这是虚拟机运行的原理, 关于这个问题可以简单看我另一篇文章, 比较简单将UnboundLocalError: Let’s talk about the magical UnboundLocalError: local variable x referenced before assignment

某草草

You reassigned a new variable x in the inside function, and the scopes of the two x are different.
The UnboundLocalError is caused because you printed an uninitialized variable in the inside scope.
See this explanation for details:
https://docs.python.org/2/faq...

洪涛

Basically Lin_R has made it very clear.
The domains of outside functions and inside functions are different. Since you assigned a value to x in the inside function, when the variable x is used in the inside function, x is considered to be in the local domain of inside. At this time, x will not use values ​​in other fields. So when printing(x), because x has no initialized value, an error occurs. Although it is possible to use defined but unassigned variables in C, Python does not allow this.

In python3, there is a nonlocal statement to solve this problem.

def outside():
    x='outside'
    print(id(x))
    def inside():
        nonlocal x
        print(id(x))
        x='inside'
        print(id(x))
    inside()
    print(id(x))
    print(x)

Note that it is not possible to use the global statement at this time, because there is no x variable in the global domain.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template