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