【发布时间】:2013-12-13 08:01:15
【问题描述】:
这个消息有点长,有很多例子,但我希望它 将帮助我和其他人更好地掌握变量的全部内容 和 Python 2.7 中的属性查找。
我使用的是 PEP 227 的条款 (http://www.python.org/dev/peps/pep-0227/) 用于代码块(例如 模块、类定义、函数定义等)和 变量绑定(例如赋值、参数声明、类 和函数声明,for循环等)
我将术语变量用于可以在没有名称的情况下调用的名称 点,以及需要用对象限定的名称的属性 名称(如对象 obj 的属性 x 为 obj.x)。
所有代码块在 Python 中都有三个作用域,但函数:
- 本地
- 全球
- 内置
Python 中有四个块仅用于函数(根据 PEP 227):
- 本地
- 封闭函数
- 全球
- 内置
变量绑定并在块中找到它的规则是 很简单:
- 任何将变量绑定到块中的对象都会使该变量 此块的本地变量,除非变量被声明为全局变量(在那个 如果变量属于全局范围)
- 使用规则 LGB(本地, 全局,内置)适用于所有块,但函数
- 使用规则 LEGB(本地, 封闭、全局、内置)仅用于函数。
让我知道以验证此规则的示例为例,并展示了许多 特别案例。对于每个例子,我都会给出我的理解。请 如果我错了,请纠正我。对于最后一个例子,我不明白 结果。
示例 1:
x = "x in module"
class A():
print "A: " + x #x in module
x = "x in class A"
print locals()
class B():
print "B: " + x #x in module
x = "x in class B"
print locals()
def f(self):
print "f: " + x #x in module
self.x = "self.x in f"
print x, self.x
print locals()
>>>A.B().f()
A: x in module
{'x': 'x in class A', '__module__': '__main__'}
B: x in module
{'x': 'x in class B', '__module__': '__main__'}
f: x in module
x in module self.x in f
{'self': <__main__.B instance at 0x00000000026FC9C8>}
类(规则 LGB)和函数没有嵌套范围 一个类不能访问该类的属性而不使用 限定名称(本例中为 self.x)。这在 PEP227。
示例 2:
z = "z in module"
def f():
z = "z in f()"
class C():
z = "z in C"
def g(self):
print z
print C.z
C().g()
f()
>>>
z in f()
z in C
这里使用 LEGB 规则查找函数中的变量,但如果 一个类在路径中,类参数被跳过。又是在这里, 这就是 PEP 227 所解释的。
示例 3:
var = 0
def func():
print var
var = 1
>>> func()
Traceback (most recent call last):
File "<pyshell#102>", line 1, in <module>
func()
File "C:/Users/aa/Desktop/test2.py", line 25, in func
print var
UnboundLocalError: local variable 'var' referenced before assignment
我们期望像 python 这样的动态语言,一切都是 动态解决。但对于函数来说,情况并非如此。当地的 变量是在编译时确定的。 PEP 227 和 http://docs.python.org/2.7/reference/executionmodel.html 描述这个 这种行为方式
"如果名称绑定操作发生在代码块中的任何位置,则所有 块内名称的使用被视为对 当前区块。”
示例 4:
x = "x in module"
class A():
print "A: " + x
x = "x in A"
print "A: " + x
print locals()
del x
print locals()
print "A: " + x
>>>
A: x in module
A: x in A
{'x': 'x in A', '__module__': '__main__'}
{'__module__': '__main__'}
A: x in module
但是我们在这里看到 PEP227 中的这条语句“如果名称绑定 操作发生在代码块中的任何位置,名称的所有使用 块内被视为对当前块的引用。”是 当代码块是一个类时出错。此外,对于课程,似乎 本地名称绑定不是在编译时进行的,而是在 使用类命名空间执行。在这方面, PEP227 和 Python 文档中的执行模型具有误导性,并且对于 有些地方不对。
示例 5:
x = 'x in module'
def f2():
x = 'x in f2'
def myfunc():
x = 'x in myfunc'
class MyClass(object):
x = x
print x
return MyClass
myfunc()
f2()
>>>
x in module
我对这段代码的理解如下。指令 x = x 首先查找表达式右手 x 所指的对象 到。在这种情况下,在类中本地查找对象,然后 遵循 LGB 规则,在全局范围内查找它,即 字符串“模块中的 x”。那么 MyClass 的局部属性 x 是 在类字典中创建并指向字符串对象。
示例 6:
现在这是一个我无法解释的例子。 它非常接近示例 5,我只是在更改本地 MyClass 从 x 到 y 的属性。
x = 'x in module'
def f2():
x = 'x in f2'
def myfunc():
x = 'x in myfunc'
class MyClass(object):
y = x
print y
return MyClass
myfunc()
f2()
>>>
x in myfunc
为什么在这种情况下 MyClass 中的 x 引用在 最里面的功能?
【问题讨论】:
-
很难用缩进的方式说出最后几个示例中应该发生的事情 - 你能解决它吗? (请记住,4 个空格的缩进会创建一个代码块 - 之后的每个空格在代码示例中都显示为空格)。
-
这看起来是一个非常有趣的问题,但请修正缩进。
-
@SeanVieira 感谢您的关注。我有很多制表符而不是空格。现在已经修复了。
-
一个 优秀 问题 - 我希望它可以投票 10 次,但是 +1 直到我可以!
-
作为一个编写了很多 python 却没有解构 PEP(从不擅长阅读用户手册)的人说话,示例 6 对我来说似乎很直观,而示例 5 似乎违反了最小意外原则——不是反过来。类作用域应该离开函数作用域行为并检查全局作用域 before 封闭作用域,这似乎是不直观的。毫无疑问,有(历史?)原因。但是触发它的特定示例,
x=x无论如何都是一个非常讨厌的、不可维护的习语。
标签: python variables python-2.7 scope python-internals