[英]Python += versus .extend() inside a function on a global variable
我已经阅读了其他一些 SO( PythonScope和globals 不需要 global )但似乎没有像我想要的那样明确解释,而且我在精神上难以筛选PyDocs是否告诉我我的问题的答案:
myList = [1]
def foo():
myList = myList + [2, 3]
def bar():
myList.extend([2, 3])
def baz():
myList += [2, 3]
现在,可以理解的是,
>>> foo()
UnboundLocalError: local variable 'myList' referenced before assignment
和
bar() # works
myList # shows [1, 2, 3]
但是之后
>>> baz()
UnboundLocalError: local variable 'myList' referenced before assignment
然而,我认为像+=
这样的东西隐式调用了方法操作符,在这种情况下是extend()
,但错误意味着由于某种原因它实际上并没有将+=
视为extends()
。 这与 Python 解析的工作方式一致吗?
我原以为调用与方法运算符等效的函数,它们在所有情况下都是等效的。 相反,它似乎将+=
视为实际的赋值运算符。 除此之外,这并不完全正确,因为如果我做某事(无可否认是人为的):
myList = range(50000000) # wait a second or two on my laptop before returning
myList += [0] # returns instantly
myList = myList + [1] # wait a second or two before returning
所有这些都是预期的,如果+=
实际上只是调用了extend()
。
是否有一些更细微的区别(或非常明显的点......)我遗漏了这清楚表明baz()
中的myList
需要被视为局部变量,因此+=
不能隐式转换为extend()
这样它就可以识别全局变量?
+=
不会隐式调用extend()
。 首先,它是一个增广赋值运算符。
如果您查看assignment
部分,它会说:
将对象分配给单个目标的递归定义如下。
如果目标是标识符(名称):
如果名称未出现在当前代码块的全局语句中:名称绑定到当前本地命名空间中的对象。 否则:名称绑定到当前全局命名空间中的对象。
由于增广分配是:
增广赋值是在单个语句中组合二元运算和赋值语句:
它遵循相同的规则。 如你看到的:
>>> def baz():
myList += [2, 3]
>>> dis.dis(baz)
2 0 LOAD_FAST 0 (myList)
3 LOAD_CONST 1 (2)
6 LOAD_CONST 2 (3)
9 BUILD_LIST 2
12 INPLACE_ADD
13 STORE_FAST 0 (myList)
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
扩充赋值计算目标(与普通赋值语句不同,它不能是解包语句)和表达式列表,对两个操作数执行特定于赋值类型的二元运算,并将结果分配给原始目标。 目标只评估一次..
第一次调用尝试评估myList
,这导致LOAD_FAST
因为没有global
语句它被假定为局部变量:
LOAD_FAST(var_num)
将本地
co_varnames[var_num]
的引用co_varnames[var_num]
入堆栈。
找不到它,因此引发了错误。 如果它被找到,那么我们会得到 oppcode INPLACE_ADD
,它调用myList.__iadd__
方法myList.__iadd__
完成扩展工作,一旦这个操作完成,结果将被分配回变量,但我们永远不会myList.__iadd__
这myList.__iadd__
。
无论如何,您不应该真正操作global
s,从您的函数返回新结果或将其作为参数传递。
当你改变列表时,你应该说 global myList。 通过 mutate 我的意思是改变引用。 第一个示例和第三个示例基本相同,您只需使用 += 进行速记
myList = [1]
def foo():
global myList
myList = myList + [2, 3]
def bar():
myList.extend([2, 3])
def baz():
global myList
myList += [2, 3]
foo()
bar()
baz()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.