Python:为什么说只引用的变量是隐式全局的?

时间:2014-05-04 16:48:18

标签: python global

Python FAQ,我们可以阅读:

  

在Python中,仅在函数内引用的变量是隐式全局的

Python Tutorial on defining functions开始,我们可以阅读:

  

函数的执行引入了一个用于函数局部变量的新符号表。更确切地说,函数中的所有变量赋值都将值存储在本地符号表中;而变量引用首先在本地符号表中查找,然后在封闭函数的本地符号表中查找,然后在全局符号表中查找,最后在内置名称表中查看

现在我完全理解了教程语句,但后来说variables that are only referenced inside a function are implicitly global对我来说似乎很模糊。

为什么说如果我们真正开始查看本地符号表,然后按照更“通用”的符号表,它们是隐式全局的?这只是一种说法,如果你只想在函数中引用变量,你不必担心它是本地的还是global

4 个答案:

答案 0 :(得分:8)

实施例

(进一步了解摘要)

这意味着如果某个变量从未在函数体中分配给,那么它将被视为全局。

这解释了为什么以下工作(a被视为全局):

a = 1

def fn():
    print a  # This is "referencing a variable" == "reading its value"

# Prints: 1

但是,如果变量被分配到函数体中的某个位置,那么它将被视为整个函数体的本地

这包括在分配之前找到的语句(参见下面的示例)。

这解释了为什么以下工作。在这里,a被视为本地,

a = 1

def fn():
    print a 
    a = 2  # <<< We're adding this

fn()

# Throws: UnboundLocalError: local variable 'a' referenced before assignment

您可以让Python使用语句global a将变量视为全局变量。如果你这样做,那么变量将被视为全局,再次被视为整个函数体

a = 1

def fn():
   global a  # <<< We're adding this
   print a
   a = 2

fn()
print a

# Prints: 1
# Then, prints: 2 (a changed in the global scope too)

摘要

与您的预期不同,如果在本地范围内找不到a,Python将回退到全局范围。

这意味着变量对于整个函数体来说是局部的或全局的 :它不可能是全局的,然后变成本地的。

现在,关于变量是被视为本地变量还是全局变量,Python遵循以下规则。变量是:

  • 全局如果仅引用且从未分配到
  • 全局如果使用global语句
  • 本地如果变量至少分配一次(并且未使用global

进一步说明

事实上,&#34;隐含全球性的&#34;并不真正意味着全球化。这是一个更好的思考方式:

  • &#34;本地&#34;意味着&#34;在函数内的某个地方&#34;
  • &#34;全球&#34;真的意味着&#34;在功能之外的某个地方&#34;

因此,如果变量是&#34;隐含全局&#34; (==&#34;在函数&#34;之外),然后是&#34;封闭范围&#34;将首先查询:

a = 25

def enclosing():
   a = 2
   def enclosed():
       print a
   enclosed()

enclosing()

# Prints 2, as supplied in the enclosing scope, instead of 25 (found in the global scope)

现在,像往常一样,global允许您引用全局范围。

a = 25

def enclosing():
   a = 2
   def enclosed():
       global a  # <<< We're adding this
       print a
   enclosed()

enclosing()

# Prints 25, as supplied in the global scope

现在,如果您需要在a中分配enclosed,并希望在a&#39;中更改enclosing的值范围,但不是在全局范围内,那么你需要{3}这是Python 3中的新功能。在Python 2中,你不能。

答案 1 :(得分:1)

Python的名称解析方案有时在范围之后称为 LEGB 规则 名。

当您在函数中使用非限定名称时,Python最多可搜索四个 范围 - 本地(L)范围,然后是任何封闭的(E) defs的本地范围 lambdas,然后是全局(G)范围,然后是内置的(B)范围 - 并停在 找到名字的第一个地方。如果在此搜索期间找不到该名称,则为Python 报告错误。

  • 默认情况下,名称分配会创建或更改本地名称。
  • 名称参考最多搜索四个范围:本地,然后封闭 函数(如果有的话),然后是全局的,然后是内置的。
  • 在全局和非本地语句中声明的名称映射分配的名称 分别包含模块和功能范围。

换句话说,默认情况下,在函数def语句(或lambda)内指定的所有名称都是本地符号。函数可以自由使用指定的名称 在语法上包含函数和全局范围,但它们必须声明 这样的nonlocalsglobals是为了改变它们。

参考:http://goo.gl/woLW0F

答案 2 :(得分:1)

这令人困惑,文档可以更清晰。

在此上下文中“引用”表示未分配名称但只是从中读取。因此,例如,当a = 1分配给a时,print(a)(Python 3语法)引用a而没有任何分配。

如果引用 a而没有任何赋值,那么Python解释器会递归搜索当前命名空间的父命名空间,直到它到达全局命名空间。

另一方面,如果分配给变量,则该变量仅在本地名称空间内定义,除非使用global关键字进行其他声明。因此a = 1在本地名称空间内创建一个新名称a。这优先于更高名称空间中名为a的任何其他变量。

答案 3 :(得分:1)

与其他一些语言不同,Python不会在本地符号表中查找变量名称,如果在那里找不到它,则会回退到在更大的范围内查找它。通过分配变量(包括作为参数传入),变量在编译时确定为本地,而不是在运行时。任何未分配给(并且未明确声明为global)的名称都被视为全局名称,只能在全局名称空间中查找。这允许Python优化局部变量访问(使用LOAD_FAST字节码),这就是本地人更快的原因。

有一些涉及闭包的皱纹(在Python 3中,nonlocal),但这是一般情况。