为避免意外修改全局变量,python在分配给全局变量之前需要显式global
语句。但是,通过调用其方法来修改全局变量可以在没有任何额外语句的情况下完成:
x = [1, 2]
y = [1, 2]
def f():
global x
x = x + [3] # won't affect global variable without global statement
y.append(3) # will affect global variable without global statement
这似乎有些不一致。之所以做出这样的设计选择,是因为与用一个全新的对象替换它们相比,通过方法调用来修改全局可变对象时,它被认为不那么危险/不太糟糕。如果是这样,为什么?
答案 0 :(得分:1)
在Python中,仅在函数内引用的变量是 隐式全球。 如果在任何地方为变量分配值 在函数体内,它被认为是本地的,除非 明确声明为全局。
在您的情况下,y
在函数内部被引用,因此隐式全局。另一方面,x
被赋予一个值,因此除非另有明确声明,否则它必须是本地的。
文档更进一步回答你的问题:
虽然起初有点令人惊讶,但片刻的考虑解释了 这个。一方面,要求全局分配变量提供了一个 禁止意外的副作用。另一方面,如果是全球性的话 所有全局引用都需要,你将全局使用全局 时间。您必须将每个对内置的引用声明为全局 功能或导入模块的组件。这种混乱会 打败全球宣言的有用性 副作用。
答案 1 :(得分:0)
它并不是真正关于价值层面的可变性,这就是你如何看待它;它是关于变量引用的可变性,即命名项(变量)指向的内容。
x = [1, 2]
print(id(x)) # 57226944
y = [1, 2]
print(id(y)) # 57262728
def f():
global x
x = x + [3]
print(id(x)) # 57306648 - CHANGED
y.append(3)
print(id(y)) # 57262728 - UNCHANGED
f()
请注意名称' x'现在指向一个新事物(一个新创建的列表),而y上的.append操作没有改变名称' y'指着。
答案 2 :(得分:0)
用一句话说:
“没有明确声明,python不会让你改变全局变量的reference
。”
现在让我们解释一下你刚才读到的内容,将对象赋值给一个变量实际上是一个reference
,这是一个内存地址到对象放在内存中的位置。
当我们写:
x = [1, 2]
实际上,在内存中的某个地方,list对象被分配了它的所有函数引用和成员以及其他shit。这个地址实际上保存在x
。
我们可以使用函数id(object)
来注意更改:
x = [1, 2]
def foo():
print id(x) # an address like 50075016
y = [1, 2, 3]
print id(y) # another address like 50075272
x = y # won't work without declaring 'global x'
# because we try to change the address stored in x
# from 50075016 to 50075272.
x.append(3) # works
print id(x) # same address 50075016