一、Python中变量查找原则
在Python中,变量查找遵循LGB原则, 即优先在局部作用域(local scope)中对变量进行查找, 失败则在全局作用域(global scope)中进行查找, 最后尝试在内建作用域(build-in scope)内查找,如果还未找到的话,则抛出异常。后来由于闭包和内嵌函数的出现,作用域又增加了外部作用域( Enclosing scope),这样变量的查找作用域优先级变为LEGB:局部、外部、全局和内建。作用域由def, class, lambda语句产生, if, try, for等语句并不会产生新的作用域。
示例:
def scope1_f1(): def f2(): print local_v local_v = 'local' f2() print globl_v if __name__ == "__main__": global_v = 'global' scope1_f1()
在函数scope1_f1()中我们并未对global_v进行赋值(即scope1_f1()函数的局部定义域中并不存在变量global_v),同样在函数f2()中我们并未对local_v变量赋值且变量local_v并不在函数f2()的局部定义域内, 的那是程序正常输出结果'local'和‘global’
二、关于变量应注意一下几点:
1 局部作用域中不应对全局变量进行赋值
需要注意的是虽然我们可以在函数中对全局的变量进行访问, 但是一旦局部作用域中对全局变量进行了赋值操作,python解释器就不会从全局作用域中查找, 而会抛出UnboundeLocalError错误。该规则在由局部作用域想外部作用域查找时同样有效
示例:
def scope1_f1(): print global_v global_v = 'local' if __name__ == '__admin__': global_v = 'global' scope1_f1()
运行程序我们会得到:UnboundeLocalError: local variable 'global_v' referenced before assignment
有资料将该规则描述为“局部作用域中全局变量应是只读”是不正确的
。因为如果变量为list等类型,我们可以通过append这样的方法来修改全局变量,而不影响局部作用域对变量的访问
示例:
def scope1_f1(): print global_v global_v.append('local') if __name__ == '__admin__': global_v = ['global'] scope1_f1()
2 局部作用域中使用global实现对全局变量进行赋值
如果确实需要对全局变量进行赋值的话, 应在局部作用中使用global来修饰变量, python2.6中global对变量的修饰可以在函数的任意地方进行,但是global在赋值之后的花,解释器会提示SyntaxWaring
示例:
def lobal4(): ... global_v = 'lobal' ... global global_v ... print global_v ... <stdin>:3: SyntaxWarning: name 'global_v' is assigned to before global declaration
示例2:
def scope1_f1(): global global_v print global_v global_v = 'local' if __name__ == '__main__': global_v = 'global' scope1_f1()
3 继承类优先使用第一个基类中的变量
在没有对变量初始化的情况下, 继承类会优先使用第一个基类中的变量。下面的例子会输出1而不是2.(说明:如果继承类为初始化函数, 会优先调第一个基类中初始化函数, 如果前面的基类都没有的话才会调后面基类的初始化函数,初始化函数对变量的修改不在本文讨论范围)
class sclass1(): a = 1 def run(self): print self.a class sclass2(): a = 2 def run(self): print self.a class dclass(sclass1, sclass2): def run(self): print self.a if __name__ == '__main__': a = dclass() a.run()
4 全局作用域指的是本模块而不是程序
早变量查找时只会在本模块范围阿你进行变量的查找,即使使用from xxx import * 也不会跨模块查找。在python中导入一个模块可以理解为是将另一个模块个变量赋值给当前模块的同名变量, 对当前模块中变量的赋值不会影响到导入模块的变量