Python——作用域基础

44 篇文章 0 订阅
44 篇文章 21 订阅
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
在这个例子中,x和func是全局变量名,注意函数名也是变量名,def语句将一个函数对象赋值给了变量名func。
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
因为在函数func内部对x进行修改,必须声明x为全局变量。
x = 99
def func():
    global x
    x+=1
    return x
这时候调用func()就不会报错了。

但是不经过声明而直接引用是可以的:
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
如果要进行修改,必须要使用nonlocal声明:
>>> 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
这时已经报异常说没有找到state.
但是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
其次,nonlocal限制作用域查找仅为嵌套的def,nonlocal不会在嵌套的模块的全局作用域或所有def之外的内置作用域中查找,即便已经有了这些作用域:

>>> spam = 99
>>> def tester():
	def nested():
		nonlocal spam
		
SyntaxError: no binding for nonlocal 'spam' found
如上例所示,spam是全局变量,存在模块文件中,但嵌套的def内使用nonlocal语句声明spam会报错,因为nonlocal限制作用域查找仅为嵌套的def内

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值