【问题标题】:What is the scope of the variable "a"?变量“a”的作用域是什么?
【发布时间】:2012-10-05 23:14:43
【问题描述】:

可能重复:
Python variable scope question

Python 手册将范围定义为:

范围定义名称在块中的可见性。如果一个本地 变量在块中定义,其范围包括该块。如果 定义发生在功能块中,范围扩展到任何块 包含在定义中,除非包含的块引入 名称的不同绑定。

我有这个程序:

import random
def f():
  a = "Is the scope static?"
  if random.randint(0, 1) == 1:
    del a
  print a

打印失败的概率为 50%:

>>> f()
Is the scope static?
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in f
UnboundLocalError: local variable 'a' referenced before assignment

由此,我认为 print 语句有 50% 的可能性超出了 'a' 的范围,但我可能是错的。 Python中范围的“正确”解释是什么? Python中变量的范围是静态定义的吗?变量“a”的作用域是什么?

【问题讨论】:

  • @Blender 该名称有 50% 的可能性不可见。
  • 范围仅在存在的变量上定义。 del 语句在运行时影响 a,而不是在解释器解析脚本时。
  • @vz0 正如 Blender 所说,在定义时,a 的范围是函数 f 的本地范围。有 50% 的可能性它已被 del 语句显式地从命名空间中删除,但这不同于由于在其范围之外调用它而不可见。
  • @TimothyAWiseman 有什么不同?如果从命名空间中移除,则不在范围内。
  • @vz0 Ben 的回答解释说,这比我能想到的要好,但一种可能会有所帮助的思考方式是:如果在一个区域中定义了某些东西并且执行离开了该区域,那么它就超出了范围。在这里,您并没有离开它定义的区域,而是专门指示解释器将其从命名空间中删除。

标签: python


【解决方案1】:

Python 遵循LEGB 规则:

L: Local          # Current def
E: Enclosing      # Any enclosing def
G: Global         # Globals
B: Built-in       # Built-ins

所以你的问题是L

【讨论】:

  • 你有 L E G G 你的意思是 L E G B - 我无法编辑 b/c 需要 > 6 个字符已更改
【解决方案2】:

名称a 的范围是整个函数f,并且是纯静态的。说“有 50% 的可能性 print 语句超出了a 的范围”是完全不正确的。 “不在范围内”并不是名称查找失败的唯一原因。

注意你从这个函数得到的错误:

>>> def foo():
...   print a
... 
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
NameError: global name 'a' is not defined

这与您的函数执行 del a 时遇到的错误不同。在我的foo 中,a 没有在foo 的本地范围内定义,因此名称查找继续到全局范围,其中a 也没有找到,所以我们得到一个关于没有的异常全球a

您得到的错误清楚地表明 Python 知道名称 af 的局部变量。但是它没有任何价值,因为您删除了它。 (通常这只会发生,因为您在写入之前尝试读取局部变量,这就是错误消息的措辞如此的原因)

还要注意这种情况:

a = 3
>>> def bar():
...   a = 1
...   del a
...   print a
... 
>>> bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in bar
UnboundLocalError: local variable 'a' referenced before assignment

Python 抱怨本地 a 没有值。如果a 根本不在本地范围内,它会在全局范围内查找a 并找到3

>>> a = 8
>>> def baz():
...   print a
... 
>>> baz()
8

这与您在全局范围内del 事物时得到的行为不同:

>>> a = 12
>>> del a
>>> print a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

这里出现了一个异常,好像a 从未存在过一样。造成差异的原因是因为函数的局部作用域是静态。如果函数包含对名称的赋值,则该名称的局部范围是整个函数主体1。即使在第一次赋值之前,或者在您使用 del 删除它之后,在该函数中查找该名称也会尝试获取局部变量的值。


1 除非名称已声明为globalnonlocal

【讨论】:

  • 不错的答案,未定义的全局消息和未分配的本地消息之间的区别是展示 Python 在幕后为查找变量值所做的工作的好方法。
【解决方案3】:

只有类、函数和模块在 Python 中提供范围,ifwhile 和其他循环/分支结构不提供。

来自docs

范围是静态确定的,但是动态使用的。在执行过程中的任何时候,至少有三个嵌套作用域的命名空间是可以直接访问的:

the innermost scope, which is searched first, contains the local names
the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
the next-to-last scope contains the current module’s global names
the outermost scope (searched last) is the namespace containing built-in names

在您的代码中,您在本地命名空间中定义 a 并将其删除。在 if 分支中使用 del 与在函数的其他地方使用它没有任何不同。

【讨论】:

    猜你喜欢
    • 2021-09-06
    相关资源
    最近更新 更多