命名空间
全局变量和局部变量
全局变量:在函数外定义,在任何一个函数内都可使用。
只在函数体内(某个范围)起作用的变量称为局部变量。
>>> x = 2 # 全局变量 >>> def func(): ... x = 9 # 局部变量 ... print('这是局部变量x=', x) ... >>> func() 这是局部变量x= 9 >>> print('这是全局变量x=', x) 这是全局变量x= 2
局部(函数内)作用域内声明全局变量:
>>> x = 2 >>> def func(): ... global x # 在函数体内声明全局变量,即声明此处的x是全局变量 ... x = 9 # x是全局变量,修改的也是全局变量的值 ... print('这是局部变量x=', x) ... >>> func() 这是局部变量x= 9 >>> print('这是全局变量x=', x) 这是全局变量x= 9
如果函数内部没有global关键字,则函数内部对于全局变量能读取,不能重新赋值;当函数内部用global声明了全局变量后,才能在函数内部整体修改全局变量。
而当全局变量是可变类型的对象时,在不用global关键字的情况下,依然是不能对可变类型的全局变量重新赋值,或者进行整体修改。但是却能够修改可变类型全局变量的内容,即对其内部进行操作。比如全局变量是个列表,在函数内部没有global的情况下,可以向此全局变量列表中增加或删除或修改列表中的内容。如果想将可变类型的全局变量整体修改了(或重新赋值),则依然要用global声明。
>>> num = [22, 33, 55] # 可变类型列表作为全局变量 >>> def func(): ... num.append('python') # 函数内实现对列表全局变量的修改 ... >>> func() >>> print(num) [22, 33, 55, 'python'] # 局部内成功的修改了可变类型的全局变量
>>> name = ['zhangsan', 'lisi'] >>> def func(): ... name = ['wang', 'yang'] # 函数内对列表重新赋值,不能改变全局变量,此处为新的同名变量 ... print(name) # 局部变量name ... >>> print(name) # 打印全局变量name ['zhangsan', 'lisi'] >>> func() ['wang', 'yang'] # 局部同名变量name >>> print(name) # 全局变量不会被整体修改 ['zhangsan', 'lisi']
>>> name = ['zhangsan', 'lisi'] >>> def func(): ... global name # 加上global声明全局变量 ... name = ['wang', 'yang'] # 整体修改可变类型的全局变量 ... print(name) ... >>> print(name) # 打印全局变量 ['zhangsan', 'lisi'] >>> func() # 执行函数,全局变量被整体修改 ['wang', 'yang'] >>> print(name) # 打印修改后的全局变量 ['wang', 'yang'] >>> def func(): # 定义删除列表全局变量中的元素的函数 ... del name[0] # 删除列表全局变量的第一个元素 ... >>> print(name) ['wang', 'yang'] >>> func() >>> print(name) # 列表全局变量内部被修改 ['yang']
操作列表全局变量时,运算符+和+=的区别:
>>> num = [100, 'java'] >>> def func(num): # 定义函数,将列表全局变量num传给函数 ... num += num # 实现了列表全局变量内部的修改,相当于num.append(num) ... print(num) # 打印的是修改后的列表全局变量 ... >>> print(num) # 打印原列表全局变量 [100, 'java'] >>> func(num) # 执行函数,函数内列表全局变量内部会被修改 [100, 'java', 100, 'java'] >>> print(num) # 打印修改后的列表全局变量 [100, 'java', 100, 'java'] >>> num = [100, 'java'] >>> def func(num): # 定义函数,将列表全局变量num传给函数 ... num = num + num # 以这种方式,不会修改列表全局变量,而是新创建一个同名局部变量 ... print(num) # 打印局部变量 ... >>> print(num) # 打印列表全局变量 [100, 'java'] >>> func(num) [100, 'java', 100, 'java'] >>> print(num) # 列表全局变量没有被修改 [100, 'java']
全局变量要慎用,因为这往往容易引起变量的混乱。
全局变量全部大写;局部变量全部小写。
局部变量和全局变量是在不同的范围内起作用,即变量产生作用的区域,简称作用域。
作用域
python中的作用域属于静态作用域,即python中的变量作用域由它在程序中的位置决定的。
python的作用域可划分为四个层级:
Local:局部作用域,或称为本地作用域。
Enclosing:嵌套作用域。
Global:全局作用域。
Built-in:内建作用域。
对于一个变量,python是按照上述从前到后的顺序,在不同的作用域中查找。
在python中,变量的作用域在函数、类中才能被改变。
命名空间(Namespace)
命名空间的分类:
本地命名空间(Function&Class: Local Namespace):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数结束或抛出了异常,则本地命名空间也结束了。
全局命名空间(Module: Global Namespace):每个模块创建自己所拥有的全局命名空间,不同模块的全局命名空间彼此相互独立,不会互相干扰。
内置命名空间:python运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以我们可以在任何程序中直接运行它们。
三种命名空间从里到外的顺序是本地命名空间、全局命名空间、内置命名空间。
访问本地命名空间使用locals(),访问全局命名空间使用globals()。命名空间中的数据存储结构和字典是一样的。
对于不同的命名空间,有不同的查找顺序(从里到外)和不同的生命周期。
作用域综合:
在局部中直接使用全局变量:
>>> x = 2 # 全局变量 >>> def func(y): ... print(x+y) # 函数中直接使用全局变量 ... >>> func(7) 9
警告:像这样在局部中直接使用全局变量的方式是众多bug的根源,务必慎用全局变量。
局部中定义同名变量,覆盖全局变量:
>>> x = 2 # 全局变量 >>> def func(y): ... x = 9 # 局部变量 ... print(x+y) ... >>> func(9) 18 >>> print(x) # 全局域中,x是全局变量 2
局部中声明全局变量:
>>> x = 2 >>> def func(y): ... global x # 函数内声明全局变量 ... x = 9 # 这是全局变量 ... print(x+y) ... >>> func(9) 18 >>> print(x) 9
在全局中可使用globals()来访问全局变量,这个函数类似于函数vars()在全局中,返回一个包含全局变量的字典。
>>> globals() # 返回一个包含全局变量的字典 {'__loader__': <class '_frozen_importlib.BuiltinImporter'>, 'func': <function func at 0x7f34c0a30840>, '__spec__': None, 'name': 'Jack', '__package__': None, '__name__': '__main__', '__doc__': None, 'x': 9, '__builtins__': <module 'builtins' (built-in)>} >>> globals()['name'] # 从返回的包含全局变量的字典中取出数据 'Jack' >>> vars() # 类似于vars()在全局中 {'__loader__': <class '_frozen_importlib.BuiltinImporter'>, 'func': <function func at 0x7f34c0a308c8>, '__spec__': None, 'name': 'Jack', '__package__': None, '__name__': '__main__', '__doc__': None, 'x': 9, '__builtins__': <module 'builtins' (built-in)>} >>> vars()['name'] 'Jack'
在局部中可使用locals()返回一个局部变量的字典。类似于函数vars()在局部中。
>>> def func(): ... age = 22 ... lang = 'python' ... print(locals()) # 返回一个包含局部变量的字典 ... print(vars()) # 类似于vars()在局部中 ... >>> func() {'age': 22, 'lang': 'python'} {'age': 22, 'lang': 'python'}
Help on built-in function vars in module builtins:
vars(...)
vars([object]) -> dictionary
Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.