出自:https://blog.csdn.net/gavin_john/article/details/50128947
Python作用域基础
既然准备写函数了,就需要更正式地了解Python变量名的含义。
当在一个程序中使用变量名时,Python创建、改变或查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行的。
在代码中给一个变量赋值的地方决定了这个变量将存在于那个命名空间,也就是它的可见范围。
除打包代码之外,函数还为程序增加了一个额外的命名空间层:在默认的情况下,一个函数的所有变量名都是与函数的命名空间相关联的。这意味着:
(1)一个在def内定义的变量名能够被def内的代码使用。不能再函数外部引用这样的变量名。
(2)def之中的变量名与def之外的变量名并不冲突,即使是使用在别处的相同的变量名。一个在def之外被赋值的变量与在这个def之中的赋值的变量x是完全不同的变量。
变量名可以在3个不同的地方分配,分别对应3种不同的作用域:
(1)如果一个变量在def内赋值,它被定为在这个函数之内
(2)如果一个变量在一个嵌套的def中赋值,对于嵌套的函数来说,它是非本地的。
(3)如果在def之外赋值,它就是整个文件全局的。
我们将其称为语义作用域,因为变量的作用域完全是由变量在程序文件中源代码的位置而决定的,而不是由函数调用决定。
========================================================================
作用域法则
函数定义了本地作用域,而模块定义的是全局作用域。这两个作用域有如下关系:
(1)内嵌的模块是全局作用域
(2)全局作用域的作用范围仅限于单个文件
(3)每次对函数的调用都创建了一个新的本地作用域
(4)赋值的变量名除非声明为全局变量或非本地变量,否则均为本地变量
(5)所有其他的变量名都可以归纳为本地、全局或者内置的
========================================================================
变量名解析:LEGB原则
即变量名分为三个作用域进行查找:首先是本地,之后是函数内(如果有的话),之后全局,最后是内置。
- >>> #Global scope
- >>> x = 99
- >>> def func(y):
- #local scope
- z = x+y
- return z
- >>> func(1)
- 100
y和z是本地变量,并且只在函数运行时存在。
========================================================================
global语句
global告诉Python函数打算生成一个或多个全局变量名,也就是存在于整个模块内部的变量名。
需要注意以下3点:
(1)全局变量是位于模块文件内部的顶层的变量名
(2)全局变量如果是在函数内部被赋值的话,必须经过声明!!
(3)全局变量名在函数内部不经过声明也可以被引用。
【即引用不需要声明,但是赋值或者修改都需要声明(其实赋值即为修改)】
如下例想要对全局变量x进行修改:
- x = 99
- def func():
- x+=1
- return x
- func()
- >>> ================================ RESTART ================================
- >>>
- Traceback (most recent call last):
- File "C:/Users/ustc/Desktop/test.py", line 6, in <module>
- func()
- File "C:/Users/ustc/Desktop/test.py", line 3, in func
- x+=1
- UnboundLocalError: local variable 'x' referenced before assignment
- x = 99
- def func():
- global x
- x+=1
- return x
但是不经过声明而直接引用是可以的:
- x = 99
- def func():
- print(x+1)
- func()
- >>> ================================ RESTART ================================
- >>>
- 100
nonlocal语句
nonlocal语句与global语句类似,只不过它用来声明嵌套作用域,而不是全局作用域。
nonlocal语句允许对嵌套的函数作用域中的名称赋值,并且把这样的名称的作用域查找限制在嵌套的def中。
这个例子中,嵌套的def函数可以引用嵌套的def作用域中的名称:
- >>> def tester(start):
- state = start
- def nested(label):
- print(label,state)
- return nested
- >>> F = tester(0)
- >>> F('spam')
- spam 0
- >>> F('egg')
- egg 0
- >>> def tester(start):
- state = start
- def nested(label):
- print(label,state)
- state +=1
- return nested
- >>> F = tester(0)
- >>> F('egg')
- Traceback (most recent call last):
- File "<pyshell#22>", line 1, in <module>
- F('egg')
- File "<pyshell#20>", line 4, in nested
- print(label,state)
- UnboundLocalError: local variable 'state' referenced before assignment
- >>> def tester(start):
- state = start
- def nested(label):
- nonlocal state
- print(label,state)
- state +=1
- return nested
- >>> F = tester(0)
- >>> F('egg')
- egg 0
- >>> F('spam')
- spam 1
需要注意的是,nonlocal语句和global语句也有很大的不同,当执行一条nonlocal语句时,nonlocal名称必须已经在一个嵌套的def作用域中赋值过,否则会得到一个错误——不能通过在嵌套的作用域中付给它们一个新值来创建它们:
- >>> def tester(start):
- def nested(label):
- nonlocal state
- SyntaxError: no binding for nonlocal 'state' found
但是global是可以的:
- >>> def tester(start):
- def nested(label):
- global state
- state = 0
- print(label,state)
- return nested
- >>> F = tester(0)
- >>> F('abc')
- abc 0
- >>> state
- 0
- >>> spam = 99
- >>> def tester():
- def nested():
- nonlocal spam
- SyntaxError: no binding for nonlocal 'spam' found