python3 global和nonlocal 关键字_Python 变量,以及global和nonlocal关键字

目录

变量作用域

global

闭包与nonlocal

1. 变量作用域

作为一门动态语言,Python变量在使用的时候,不用申明变量类型,而是直接使用的。

>>> a = 123

>>> print(a)

123

>>> a = 'hello, Python'

>>> print(a)

hello, Python

>>>

当我们在命令行敲入python3的时候,当期模块默认为__main__。

>>> print(__name__)

__main__

>>>

接下来,定义一个函数,对于函数而言,前面的变量a是外层变量,可以理解为默认模块__main__的全局变量。

在函数foo中,直接访问变量a,最终在外层找到了a。如果在函数中给变量a赋值,会覆盖全局变量。

注意,这里相当于定义了一个局部变量a,而不是改写全局变量a。

>>> def foo():

... print(a)

...

>>> foo()

hello, Python

>>>

>>> def foo():

... a = 'in foo'

... print(a)

...

>>> foo()

in foo

>>>

>>> print(a)

hello, Python

>>>

但是下面的方式会报错,因为Python在编译函数bar的时候,会扫描整个函数体,生成字节码,然后执行。在生成字节码的时候,发现a=这样的赋值语句,会认为定义了一个变量a,然后执行print(a)的时候,这时候a = 'in bar‘没有执行,故变量a没有任何绑定值,从而报错。

>>> def bar():

... print(a)

... a = 'in bar'

...

>>> bar()

Traceback (most recent call last):

File "", line 1, in

File "", line 2, in bar

UnboundLocalError: local variable 'a' referenced before assignment

>>>

2. global

上面函数bar中在执行第一条语句的时候,为什么不去访问全局变量a呢?

这是Python语法规定的,当在函数体中有赋值语句时,编译的时候就认为定义了局部变量,从而保证函数封装性。

如果非得要限定为全局变量,可以使用global关键字。但这种代码要小心,因为很容易就改变了全局变量。

如下代码,最后全局变量a变成了'in bar'。

>>> def bar():

... global a

... print(a)

... a = 'in bar'

... print(a)

...

>>> bar()

hello, Python

in bar

>>> print(a)

in bar

>>>

3. 闭包与nonlocal

在这里,不得不提下闭包这个概念。在看过很多概念性定义之后,最后在《你不知道的JavaScript》这本书中,终于有了实质性的收获:

当函数可以记住并访问所在的词法作用域时, 就产生了闭包, 即使函数是在当前词法作用域之外执行。

你没有看错,我引用了一本JavaScript书中的定义。抽象性的东西,很多都能通用。

如下代码,在内层函数add中,访问了外层函数中变量count。

每次调用fn都返回一个函数对象,该对象可以在当前全局模块环境中执行,也就是在fn函数词法作用域之外执行。

>>> def fn():

... count = 0

... def add(dt = 0):

... r = count + dt

... print(r)

... return add

...

>>> fn()

.add at 0x7efcd433e048>

>>> add = fn()

>>> add()

0

>>> add(1)

1

>>> add(123)

123

>>>

>>> some = fn()

>>> some()

0

>>> some(123)

123

>>>

但是,当我们想要在内层函数直接赋值给外层函数中的变量时,问题就来了。下面的代码,遇到了上面一样的错误。语句count += dt给count赋值了,Python认为定义了一个局部变量count,+=运算要先取到count的值,但此时内层函数中count没有绑定值,于是报错了。

>>> def fn():

... count = 0

... def add(dt = 0):

... count += dt

... print(count)

... return add

...

>>> some = fn()

>>> some()

Traceback (most recent call last):

File "", line 1, in

File "", line 4, in add

UnboundLocalError: local variable 'count' referenced before assignment

>>>

可以使用nonlocal来解决这个问题。

注意如下每次函数对象调用的结果,每次调用fn返回的函数对象,该对象持有一份count变量副本,每次调用都针对当前函数对象。

>>> def fn():

... count = 0

... def add(dt = 0):

... nonlocal count

... count += dt

... print(count)

... return add

...

>>> some = fn()

>>> some()

0

>>> some(1)

1

>>> some(123)

124

>>> some(1)

125

>>>

>>> any = fn()

>>> any()

0

>>> any(1)

1

>>> any(1)

2

>>>

转载于:https://my.oschina.net/athantang/blog/1795481

点赞

收藏

分享

文章举报

9acbe271215599f3632e6e6cffe5298a

e1089cbef1b3fe9d76f1d8e0af658b17.png

chipizan9676

发布了0 篇原创文章 · 获赞 0 · 访问量 21

私信

关注

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值