jiraiya1024

如果习惯了C/C++,Java这类静态语言的作用域规则,那么在Python中就要格外注意。在代码中,我们经常会碰到同一个变量名出现在多个地方,它的作用域可能是不一样的。Python中有四种作用域:局部作用域,嵌套作用域(也就是闭包),全局作用域和内建作用域。在Python代码的任意位置,都应遵循这样的搜索规则:局部 > 嵌套 > 全局 > 内建,这种搜索顺序也被称为: LEGB(4个单词首字母缩写)。Python中作用域由def, class, lambda 等语句产生,而 if, try, for等语句并不会产生新的作用域。下面以代码说明下这种名字搜索域规则:

    >>> x = 9          # x是全局变量
    >>> def func():   
            print x    # x是局部变量
        x += 1     

       
    >>> func()
    Traceback (most recent call last):
      File "<pyshell#7>", line 1, in <module>
        func()
      File "<pyshell#6>", line 2, in func
        print x
    UnboundLocalError: local variable \'x\' referenced before assignment


解释器报错,告诉我们print x 这句出错,原因是局部变量x 引用时未被赋值。我们用上面的作用域规则来分析:
    1. print x 所在的代码位置是函数内,解释器从当前位置按LEGB的顺序去找x这个变量,发现在当前函数内有一个局部变量x。那么,此时就停止名字搜索;
    2. print x 所处函数的第一行,尽管x是在本函数内找到了,但是在执行 print x 这条语句时,x 是未被赋值的。所以引发一个异常。这也是上面报错原因。

    如果像上面的函数内有个局部变量和函数外的全局变量同名,此时想引用全局变量,则要使用global关键字,来申明你在函数中使用全局变量:
   

>>> x = 9          # x是全局变量
>>> def func():   
        global x
        print x    # x是全局变量
        x += 1   
        return x

       
>>> func()
    10
    11


但是上面的这种写法不太好,更好的写法是用类封装起来,如:
   

>>> class var_x(object):
        x = 9

       
>>> def func():
        print var_x.x  #类的全局变量
        x = 0
        var_x.x = 8    #局部变量
        print x

       
>>> func()
    9
    0


我们再来看下嵌套作用域下变量是如何被执行的。这里所说的嵌套,是指函数的嵌套,也就是所谓的闭包。如:
   

>>> def foo():                                
        func = lambda: \'value of x: %s\' % x   # 嵌套函数
        try:
            print func()
        except Exception, e:
            print \'ERROR:\', e
        x = 10
        print func()
        x = \'spam\'
        print func()

       
>>> foo()
    ERROR: free variable \'x\' referenced before assignment in enclosing scope
    value of x: 10
    value of x: spam


上面函数中的嵌套函数是lambda,不要忘了lambda是匿名函数。当第一次打印 func()时,父作用域中的x还未赋值,所以报错。而后面两次的调用,x已经有值,所以正常打印出结果。可以看出嵌套函数可以访问上级函数父作用域中的变量。

如果你非要看有def定义的函数嵌套觉得会更清楚,那么:
   

>>> def outer_func():
            x = 3
            def inner_func1():
                print \'inner func 1:\', x
            def inner_func2():
                x = \'hello\'
                print \'inner func 2:\', x
            inner_func1()
            inner_func2()
            print \'outer func:\', x

            
>>> outer_func()
    inner func 1: 3
    inner func 2: hello
    outer func: 3



总结:
    1. Python 对名字的搜索顺序是:Local > Enclosing > Global > Built-in;
    2. 在函数内引用全局变量时,要使用global关键字先声明。或者通过类对变量进行封装;
    3. 嵌套作用域中的嵌套函数,可以访问父级作用域中的变量;

分类:

技术点:

相关文章:

  • 2021-07-31
  • 2022-12-23
  • 2021-11-29
  • 2021-06-05
  • 2022-12-23
  • 2022-03-03
猜你喜欢
  • 2021-10-10
  • 2022-01-18
  • 2021-10-26
  • 2021-07-09
相关资源
相似解决方案