Python命名空间和作用域的基本认识和一点小魔法

作为初学者,简单总结自己对Python命名空间(namespace)和作用域(scope)的认识。

Python在名称空间搜寻变量和函数的顺序可以认为是:

函数内部 -> (嵌套)父函数内部 -> 模块内部 ->  built_in内置模块

1. 函数内部(local)

简单举例说明:

x = 123

def func():
    x = 456
    print 'inner x =', x

func()
print 'outer x =', x

输出:

inner x = 456
outer x = 123

模块级变量x的值是123,而在函数func内部,local变量x的值是456。可以看到,函数是没有改变外部x的值的。

2. 父函数内部

x = 123

def func():
    x = 456
    print 'inner x =', x

    def child_func():
        print 'x from parent function =', x

    child_func()

func()
print 'outer x =', x

输出为:

inner x = 456
x from parent function = 456
outer x = 123

child_func是func的嵌套函数,它的x值,来自其父函数func内部,而非模块级变量。

3.模块内部

模块内也就是我们常说的全局变量。

x = 123

def func():
    print 'inner x =', x

func()
print 'outer x =', x

输出为:

inner x = 123
outer x = 123

func内部没有命名变量x,print语句使用的x来自函数外的模块级变量x。

4. Built_in内置模块

print abs(-123)

def abs(x):
    return x + 100

print abs(-123)

输出:

123
-23

这里第一次调用的abs函数来自__builtins__。第二次调用来自模块内部。

5. 神奇的global关键字

global用于向函数中引入全局变量,这个关键字是非常神奇的。

x = 123

def func():
    x = 333
    if False:
        global x
    print 'inner x = ', x

func()
print 'outer x = ', x

按照一般的理解,global x声明位于x变量使用之后,并且,它永远不可能得到执行,那么前面x = 333使用的是local变量才是。但最终的运行结果很出乎意料:

SyntaxWarning: name 'x' is assigned to before
 global declaration
  global x
inner x =  333
outer x =  333

Python会给出一个警告,但打印出的结果却显示,函数中使用了模块级变量(全局变量)x。这说明,只要有global语句在源代码中,不管这条语句是否执行,也不管你把这句代码放在函数的哪个位置,python解释器都将使用全局变量。文档中提到:

the language definition is evolving towards static name resolution, at “compile” time, so don’t rely on dynamic name resolution!

6. 被调用函数无法共享调用函数的命名空间

def caller():
    x = 123
    callee()

def callee():
    print 'callee inner x', x

caller()

执行时将出现NameError: global name ‘x’ is not defined

《Python命名空间和作用域的基本认识和一点小魔法》上有1条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注