该消息包含很多示例,时间有点长,但是我希望它能帮助我和其他人更好地掌握Python 2.7中变量和属性查找的全部内容。
我正在将PEP
227(http://www.python.org/dev/peps/pep-0227/)的术语用于代码块(例如模块,类定义,函数定义等)和变量绑定(例如作为赋值,参数声明,类和函数声明,for循环等)
我将术语变量用于可以不带点号调用的名称,将属性用于需要使用对象名称进行限定的名称(例如obj.x用于对象obj的属性x)。
Python中所有代码块都有三个作用域,但有以下功能:
Python中只有四个功能块(根据PEP 227):
将变量绑定到块中并找到它的规则非常简单:
让我知道一些验证此规则的示例,并显示了许多特殊情况。对于每个示例,我都会给出自己的理解。如果我错了,请纠正我。对于最后一个示例,我不了解结果。
范例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 in
module’。然后,在类字典中创建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引用?
用两个词来说,示例5和示例6之间的区别在于,示例5中的变量x
也被分配到相同的范围内,而示例6中没有。这触发了可以由历史原因理解的差异。
这引发了UnboundLocalError:
x = "foo"
def f():
print x
x = 5
f()
而不是打印“
foo”。即使一开始看起来很奇怪,这还是有道理的:函数f()在x
本地定义了变量,即使它在打印之后也是如此,因此x
在同一函数中对它的任何引用都必须是对该局部变量的引用。至少这是有道理的,如果您错误地在本地重用了全局变量的名称,并试图同时使用全局变量和局部变量,则可以避免意外的意外。这是一个好主意,因为这意味着我们可以静态地知道,只要看一眼变量,
这 意味着变量。例如,我们知道这里print x
引用了局部变量(因此可能引发UnboundLocalError):
x = "foo"
def f():
if some_condition:
x = 42
print x
f()
现在,此规则不适用于类级范围:在那里,我们希望表达式x = x
能够正常工作,将全局变量捕获x
到类级范围中。这意味着类级别的作用域不遵循上面的基本规则:例如,我们不知道x
该作用域中是指某个外部变量还是本地定义的x
-–:
class X:
x = x # we want to read the global x and assign it locally
bar = x # but here we want to read the local x of the previous line
class Y:
if some_condition:
x = 42
print x # may refer to either the local x, or some global x
class Z:
for i in range(2):
print x # prints the global x the 1st time, and 42 the 2nd time
x = 42
因此,在类范围内,使用了不同的规则:通常会引发UnboundLocalError的地方—仅在这种情况下—
而是在模块全局变量中查找。仅此而已:它不遵循嵌套作用域链。
为什么不?我实际上怀疑有一个更好的解释是“出于历史原因”。用更专业的术语来说,它可以认为该变量x
既在类作用域中本地定义(因为已被分配给它), 又
应从父作用域作为词法嵌套变量传递(因为已被读取)。可以通过使用与LOAD_NAME
在本地作用域中查找的字节码不同的字节码来实现它,如果未找到,则退回到使用嵌套作用域的引用。
编辑:
感谢wilberforce对http://bugs.python.org/issue532860的引用。如果我们认为毕竟应该修复该问题,那么我们可能有机会用提议的新字节码重新进行一些讨论(错误报告考虑终止对它的支持,x = x
但由于担心破坏太多现有代码而被关闭;相反,我是我建议这里将x = x
在更多情况下进行工作)。否则我可能会错过另一个要点…
EDIT2:
似乎CPython在当前的3.4主干中确实做到了这一点:http :
//bugs.python.org/issue17853 …
…还是不?他们介绍字节码的原因略有不同,因此没有系统地使用它。
问题内容: 在代码中: 现在,将是7,x将是8。但是实际上,我想改变。我可以分配引用吗? 例如,在C ++中,可以达到以下目的: 现在,这两个&将是9 问题答案: 你不能。正如其他答案指出的那样,您可以(ab?)使用可变对象的别名来达到类似的效果。但是,这与C ++参考不是同一回事,我想解释一下为避免误解而实际发生的情况。 您会看到,在C ++(和其他语言)中,变量(以及对象字段以及集合中的条目等
本文向大家介绍解析Python中的变量、引用、拷贝和作用域的问题,包括了解析Python中的变量、引用、拷贝和作用域的问题的使用技巧和注意事项,需要的朋友参考一下 在Python中,变量是没有类型的,这和以往看到的大部分编辑语言都不一样。在使用变量的时候,不需要提前声明,只需要给这个变量赋值即可。但是,当用变量的时候,必须要给这个变量赋值;如果只写一个变量,而没有赋值,那么Python认为这个变量
我正在创建一个解释器(字节码解释器,也是一个编译器),我发现了一个我无法解决的问题。我需要把变量存储在某个地方。将它们存储在字典中并在运行时查找它们可能会很慢,所以我希望将它们存储在寄存器中,并使用它们的索引而不是名称。 所以在编译时,我给每个变量一个索引,并创建一个寄存器数组。这对于单一范围的语言来说很好。但是我正在为其创建解释器的语言具有嵌套范围(和函数调用)。所以另一种方法可能是我有一组全局
问题内容: 我想根据用户选择的值导入一些软件包。 默认值为: 如果用户选择,则应为: 在PHP中,我可以使用变量variable来做到这一点: 如何在Python中执行此操作? 问题答案: Python没有与PHP的“变量变量”直接等效的功能。要获取“变量变量”的值(或任何其他表达式的值),可以使用该函数。 但是,这不能在语句中使用。 可以使用该函数通过变量导入。 相当于
本文向大家介绍Python中的全局变量如何理解,包括了Python中的全局变量如何理解的使用技巧和注意事项,需要的朋友参考一下 Python是一种面向对象的开发语言,在函数中使用全局变量,一般应作全局变量说明,只有在函数内经过说明的全局变量才能使用。 首先应该说明的是需要尽量避免使用Python全局变量。不同的模块都可以自由的访问全局变量,可能会导致全局变量的不可预知性。对全局变量,如果程序员甲修
问题内容: Python文档似乎尚不清楚参数是通过引用还是通过值传递,并且以下代码会产生未更改的值“原始” 我可以做些什么来通过实际引用传递变量吗? 问题答案: 传入的参数实际上是对对象的引用(但引用是通过值传递的) 有些数据类型是可变的,但有些则不是 所以: 如果将可变对象传递给方法,则该方法将获得对该对象的引用,并且可以对其进行突变,但是如果您将该引用重新绑定到该方法中,则外部作用域对此一无所