Python中在定义及使用函数时会遇到“局部变量”和“全局变量”。
在函数内部定义的变量是“局部变量”;在函数外部定义的变量是“全局变量”。准确地说,作用域是全局范围的变量是“全局变量”;作用域是局部范围的变量是“局部变量”。
1.作用域
作用域也叫命名空间。在函数外部(比如在一个py文件中)通过赋值语句可以定义一个变量,例:x=1。可以将变量视为指向值的名称,这有点儿像字典,字典中是键指向值。
在py文件中,存在着一个“看不见的字典”,其中储存着跟py文件相关的特殊变量(如__name__)。当定义一个变量时,该“字典”中会自动创建一个键值对(变量名为键,变量指向的值为值),来存储变量。这个“看不见的字典”就称为作用域或命名空间。
而当在py文件中调用定义好的函数时会创建一个新的命名空间,这个命名空间只能在函数内部使用,它是供函数内部定义自己的变量使用的,即是函数的局部命名空间。
因此,就存在了全局命名空间和局部命名空间。这时再来看局部变量和全局变量的定义就很清楚了。局部变量是在局部命名空间中定义的变量,全局变量是在全局命名空间中定义的变量。
在函数内部,可以同时接触到全局命名空间和局部命名空间,也因此函数可以在其内部使用全局变量。但当函数的局部空间中存在了与全局空间同名的变量的话,函数中的局部变量就会遮盖全局变量,因此我们修改与全局变量同名的局部变量不会对全局变量产生任何影响,因为操作的根本就不是同一个变量。
函数内部调用变量时,会优先在自己的命名空间中查找。只有找不到时,才会去全局命名空间中查找。并且函数内定义变量时,可以通过关键字 global 声明其后的变量是在全局命名空间中定义的。
2.globals()和locals()
可以通过globals()方法访问全局变量,该方法返回全局命名空间的“看不见的字典”;通过locals()方法能够访问局部变量,该方法返回局部命名空间的“看不见的字典”。
name = 'David' # 在函数外部定义变量,可以通过globals()方法访问
def print_name(): # 定义函数
name = 2 # 函数内部定义变量,为局部变量,会遮盖同名的全局变量
print(locals()) # locals()返回字典,里面储存着局部变量,locals() = {'name': 2}
print(name)
print(vars()) # vars()同globals()返回字典,里面储存着全局变量
print(globals()) # globals()返回字典,里面储存着全局变量
print_name()
print(locals()) # 此时的locals()返回的局部命名空间即是全局命名空间
程序结果:可以看出变量name和函数print_name都是全局命名空间的成员
vars() = globals() = {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000136841685F8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python28/Python project/project/practice/01_func_global_param.py', '__cached__': None, 'name': 'David', 'print_name': <function print_name at 0x00000136842698C8>}
3.总结
局部变量与全局变量,对应着局部命名空间和全局命名空间。全局命名空间里也存放着__name__,__file__等跟程序文件相关的特殊变量,也可以直接调用使用它们。
函数的局部命名空间只创建一次,哪怕是多次调用。
4.作用域补充
Python中的作用域一共有4种,分别是:
1)L(Local):局部作用域;
2)E(Enclosing):闭包函数外的函数中(嵌套作用域);
3)G(Global):全局作用域;
4)B(Built-in):内置作用域(内置函数所在模块的范围);
在Python中,程序的变量并不是在哪个位置都可以访问的,访问的权限决定于这个变量是在哪个作用域中被赋值的。并且变量所在的作用域也决定了在程序的哪一部分可以访问到它。
Python中的作用域遵循LEGB原则:查找变量,先在L作用域查找,找不到便会去E作用域查找,再找不到去G作用域查找,再者去B作用域查找。
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域。其它的代码块(如 if/elif/else/、try/except、for/while等)不会引入新的作用域,也因此这些语句内定义的变量,外部也可以直接访问。
Python的内置作用域,作用范围很广,每新建一个py文件它就处于内置作用域中。通过以下方式可以查看内置作用域:
import builtins
print(dir(builtins))
# 返回一个列表,其中包含内置作用域中各个内置对象,包括:
1)各种异常类;比如'SyntaxError', 'SyntaxWarning', 'SystemError';
2)各种特殊属性;比如'__name__', '__package__', '__spec__';
3)各个内置函数;比如'id', 'input', 'int', 'isinstance';