Python 嵌套函数 global变量 nonlocal变量

1. 基本嵌套函数

一个函数内部可以包含子函数,并在内部调用

def main():
	def sub():
		print('sub')
	
	print('main')
	sub()

main()

结果

main
sub

2. 内部函数参照外部变量

def main():
    var = 1

    def sub():
        print('sub-var: ' + str(var))

    print('main-var: ' + str(var))
    sub()

main()

结果

main-var: 1
sub-var: 1

3. 内部函数修改外部变量

3.1 失败例子1

直接修改外部变量var (编译阶段会提示报错)

def main():
	var = 1
	
	def sub():
		var = var + 1
		print('sub-var: ' + str(var))
	
	print('main-var-begin: ' + str(var))
	sub()
	print('main-var-end: ' + str(var))

main()

期待结果

main-var-begin: 1
sub-var: 2
main-var-end: 2

实际结果: 异常 (实际上在pyCharm中也会有红线提示)

line 5, in sub
var = var + 1
UnboundLocalError: local variable ‘var’ referenced before assignment

原因分析

当一个函数内部出现变量赋值(比如 var=…)时,会忽视外部所有的变量,重新初始化一个函数内闭包的变量名,所以当出现 var = var + 1时, 提示等号后面的var没有初始值

3.2 失败例子2

将var用global修饰(编译阶段不会提示报错)

def main():
	var = 1
	
	def sub():
		global var
		var = var + 1
		print('sub-var: ' + str(var))
	
	print('main-var-begin: ' + str(var))
	sub()
	print('main-var-end: ' + str(var))

main()

期待结果

main-var-begin: 1
sub-var: 2
main-var-end: 2

实际结果: 异常

line 6, in sub
var = var + 1
NameError: name ‘var’ is not defined

原因分析

global用法的理解有错,以为是将sub函数外部的var变量提升成全局变量。正确的用法是:global关键字的意思是从独立于所有函数(包括这里的main()函数)的变量中去寻找指定的变量,这里正确的做法是使用nonlocal关键字

3.3 成功例子1

将var变量提提升为全局变量(与main()函数同级别)

var = 1
def main():

	def sub():
		global var
		var = var + 1
		print('sub-var: ' + str(var))
	
	print('main-var-begin: ' + str(var))
	sub()
	print('main-var-end: ' + str(var))

main()

结果

main-var-begin: 1
sub-var: 2
main-var-end: 2

3.4 成功例子2

将var的当前值通过变量传入,sub函数中的var变量只是sub内部闭包的变量,与外部变量var没有任何关系,计算完成的值通过return向外部传递, 在外部去修改变量值。

def main():
	var = 1
	
	def sub(var):
		var = var + 1
		print('sub-var: ' + str(var))
		return var
	
	print('main-var-begin: ' + str(var))
	var = sub(var)
	print('main-var-end: ' + str(var))

main()

结果

main-var-begin: 1
sub-var: 2
main-var-end: 2

3.5 成功例子3

外部变量的值不能改变(变量的引用的地址),但是可以更改其引用对象的值(修改其属性或者元素)

def main():
    var = {'var': 1}  # 这里可以为对象,数组,字典

    def sub():
        var['var'] = var['var'] + 1  # 只要不出现 var=... 即可
        print('sub-var: ' + str(var['var']))

    print('main-var-begin: ' + str(var['var']))
    sub()
    print('main-var-end: ' + str(var['var']))

main()

结果

main-var-begin: 1
sub-var: 2
main-var-end: 2

3.6 成功例子4

使用 nonlocal关键字可以在内部函数中操作外部函数的变量

def main():
	var = 1
	
	def sub():
	    nonlocal var
		var = var + 1
		print('sub-var: ' + str(var))
	
	print('main-var-begin: ' + str(var))
	sub()
	print('main-var-end: ' + str(var))

main()

4. 结论

从上面的例子可以得到以下结论

  • 针对外部变量:
    • 内部函数可以参照外部变量
    • 内部函数可以修改外部变量(引用对象)的属性元素
    • 使用nonlocal关键字,内部函数可以替换外部变量(的引用)
  • 针对全局变量:
    • 内部函数可以参照全局变量
    • 内部函数可以修改外部变量(引用对象)的属性元素
    • 使用global关键字,内部函数可以替换全局变量(的引用)
  • 当形参(函数参数)与外部变量或全局变量名称相同时,此时形参变量生效,忽略其他地方的同名变量
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值