Python:为什么全局只需要赋值而不是读取?

时间:2012-04-28 03:07:09

标签: python global

如果函数需要修改在全局范围内声明的变量,则需要使用全局声明。但是,如果函数只需要读取全局变量,它就可以在不使用全局声明的情况下执行此操作:

X = 10
def foo():
    global X
    X = 20 # Needs global declaration
def bar():
    print( X ) # Does not need global

我的问题是关于Python的设计:为什么Python设计为允许读取全局变量而不使用全局声明?也就是说,为什么只强制赋值具有全局性,为什么不强制全局读取呢? (这会使它变得均匀而优雅。)

注意:我可以看到在阅读时没有歧义,但是在分配时不清楚是否打算创建新的局部变量或分配给全局变量。但是,我希望BDFL对这种不均衡的设计选择有更好的理由或意图。

4 个答案:

答案 0 :(得分:24)

使用嵌套作用域,变量查找很容易。它们出现在从本地开始的链中,通过封闭defs,到模块全局,然后是内置。规则是找到胜利的第一场比赛。因此,您不需要全球"查找声明。

相反,对于写入,您需要指定要写入的范围。否则无法确定" x = 10"在函数中意味着"写入本地命名空间"或者"写入全局命名空间。"

执行摘要,写入您可以选择命名空间,但查找首先找到的规则就足够了。希望这会有所帮助: - )

编辑:是的,就是这种方式"因为BDFL这么说",但是在没有类型声明的其他语言中,为了查找并且只有首先找到的规则,它并不常见需要一个用于非局部写入的修饰符。当你考虑它时,这两个规则导致非常干净的代码,因为范围修饰符仅在最不常见的情况下需要(非局部写入)。

答案 1 :(得分:17)

看看这段代码:

from module import function

def foo(x):
    return function(x)

这里的名称function是全球性的。如果我不得不说global function让这段代码起作用,那将会非常繁琐。

在您说X和我的function不同之前(因为一个是变量而另一个是导入的函数)之前,请记住Python中的所有名称都被视为相同:使用时,它们的值在范围层次结构中查找。如果您需要global X,那么您需要global function。 ICK。

答案 2 :(得分:16)

因为显性优于隐式。

读取变量时没有歧义。在从本地搜索范围到全局范围时,您总能找到第一个找到的。

当您指定时,解释器可能只有两个范围明确地假定您分配给:本地和全局。由于分配到本地是最常见的情况,实际上不鼓励分配给全局,这是默认情况。要分配给全局,您必须明确地执行此操作,告诉解释器无论您在此范围内使用该变量,它都应直接进入全局范围,并且您知道自己在做什么。在Python 3上,您还可以使用“nonlocal”分配到最近的封闭范围。

请记住,当您在Python中分配名称时,此新分配与先前分配给其他名称的名称无关。想象一下,如果没有默认的本地和Python搜索所有范围,试图找到一个具有该名称的变量并分配给它,就像读取时一样。您的函数行为可能不仅基于您的参数而且基于封闭范围而更改。生活会很悲惨。

答案 3 :(得分:6)

你自己说,读取没有歧义,而且有写作。因此,您需要一些机制来解决写入的歧义。

一个选项(可能实际上被许多旧版本的Python使用,IIRC)只是说写总是转到本地范围。然后就不需要global关键字,也不需要含糊不清。但是你根本不能写全局变量(不使用像globals()之类的东西来绕过它们),所以这不会很好。

静态声明变量的语言使用的另一个选项是预先与语言实现进行通信,以查找名称为local的每个范围(您在该范围内声明的范围)以及哪些名称是全局的(在模块范围)。但Python没有声明变量,所以这个解决方案不起作用。

另一个选择是,只有在名称为x = 3的某个外部作用域中没有名称时,才将x分配给局部变量。似乎它会直观地做正确的事情?这会导致一些严重恶劣的角落案件。目前,x = 3将写入的位置由解析器静态确定;要么在同一范围内没有global x而且它是本地写入,要么是global x并且它是全局写入。但是如果它将做什么取决于全局模块范围,则必须等到运行时才能确定写入的位置,这意味着它可以在函数的调用之间进行更改。考虑一下。每次在模块中创建全局时,都会改变模块中所有函数的行为,这些函数恰好使用该名称作为局部变量名。执行一些使用tmp作为临时变量的模块范围计算,并告别在模块中的所有函数中使用tmp。我不禁想到隐藏的错误,包括在您导入的模块上分配属性,然后从该模块调用函数。的

另一个选择是与每个作业的语言实现进行通信,无论它是本地的还是全局的。这就是Python的用武之地。鉴于几乎所有情况都有合理的默认值(写入局部变量),我们将本地分配作为默认值,并使用global明确标出全局分配。


分配存在歧义,需要一些机制来解决它。 global就是这样一种机制。它不是唯一可能的,但在Python的背景下,似乎所有替代机制都是可怕的。我不知道你在寻找什么样的“更好的理由”。