Python 全局变量:赋值与方法调用

Python 全局变量:赋值与方法调用,python,python-3.x,scope,namespaces,Python,Python 3.x,Scope,Namespaces,为了避免意外修改全局变量,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 state

为了避免意外修改全局变量,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
这似乎有点不一致。之所以选择这种设计,是因为通过方法调用修改全局可变对象与用一个全新对象替换它们相比,被认为不太危险/不太糟糕吗?如果是,原因是什么?

来自:

在Python中,仅在函数中引用的变量是 隐式全局如果在任何地方为变量赋值 在函数体中,被假定为局部函数 明确声明为全局

在您的例子中,
y
在函数内部被引用,因此是隐式全局的。另一方面,
x
被分配了一个值,因此它必须是本地的,除非另有明确声明

文档进一步回答了您的问题:

虽然一开始有点令人惊讶,但考虑一下就可以解释 这一方面,要求指定变量为全局变量提供了 禁止意外副作用。另一方面,如果全球 对于所有全局引用都是必需的,您将在所有 时间。您必须将对内置的每个引用声明为全局引用 函数或导入模块的组件。这种杂乱无章的东西 挫败《全球宣言》在确定 副作用


这并不是关于价值层面上的可变性,这是你如何看待它的;这是关于变量引用的易变性,即命名项(变量)指向的对象

x=[1,2]
打印(id(x))57226944
y=[1,2]
打印(id(y))#57262728
def():
全球x
x=x+[3]
打印(id(x))#57306648-更改
y、 附加(3)
打印(id(y))#57262728-未更改
f()
请注意,名称“x”现在指向一个新事物(新创建的列表),而y上的.append操作没有改变名称“y”指向的对象。

一句话:

“如果不显式声明,python将不允许您更改全局变量的
引用”

现在让我们来解释一下刚才读到的内容,将对象赋值给变量实际上是在做一个
引用
,这是对象在内存中所处的内存地址

当我们写作时:

x = [1, 2]
实际上,在内存中的某个地方,list对象被分配了它的所有函数引用、成员和其他垃圾。这个地址实际上保存在
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

这有帮助。啊,所以我的问题不是说更改
y
是安全的,只是python解释器很难清楚地将其与访问导入模块组件的相对安全的情况区分开来?我认为这不仅对python解释器是困难的,对任何解释器都是困难的。本质上,除了我们在自己的头脑中创造的不同之外,没有什么不同<代码>全局
也是避免名称冲突的基础,否则我们必须为要编写的每个函数创建不同的名称。这是有意义的。当然,但我想我的问题是,为什么修改对象的风险比更改变量指向的对象要小。