python闭包函数捕获变量问题_一篇文章学会 Python 中闭包与变量作用域

1. 作用域

Python的作用域可以分为四种:L (Local) 局部作用域

E (Enclosing) 闭包函数外的函数中

G (Global) 全局作用域

B (Built-in) 内建作用域

变量/函数 的查找顺序:

L –> E –> G –>B

意思是,在局部找不到的,便去局部外的局部作用域找(例如 闭包),再找不到的就去全局作业域里找,再找不到就去内建作业域中找。

会影响 变量/函数 作用范围的有函数:def 或 lambda

类:class

关键字:global nogloba

文件:*py

推导式:[],{},()等,仅限Py3.x中,Py2.x会出现变量泄露。

1、赋值在前,引用在后

# ------同作用域内------

name = "MING"

print(name)

# ------不同作用域内------

name = "MING"

def main():

print(name)

2、引用在前,赋值在后(同一作用域内)

print(name)

name = "MING"

# UnboundLocalError: local variable 'name' referenced before assignment

3、赋值在低层,引用在高层

# L -> E -> G -> B

# 从左到右,由低层到高层

def main():

name = "MING"

print(name)

# NameError: name 'name' is not defined

2. 闭包

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。其实装饰函数,很多都是闭包。

好像并不难理解,为什么初学者会觉得闭包难以理解呢?

我解释一下,你就明白了。

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

你可以看下面这段代码,就构成了闭包。在内函数里可以引用外函数的变量

def deco():

name = "MING"

def wrapper():

print(name)

return wrapper

deco()()

# 输出:MING

3. 改变作用域

变量的作用域,与其定义(或赋值)的位置有关,但不是绝对相关。

因为我们可以在某种程度上去改变向上的作用范围。

关键字:global

将 局部变量 变为全局变量

关键字:nonlocal

可以在闭包函数中,引用并使用闭包外部函数的变量(非全局的噢)

global好理解,这里只讲下nonlocal。

先来看个例

def deco():

age = 10

def wrapper():

age += 1

return wrapper

deco()()

运行一下,会报错。

# UnboundLocalError: local variable 'age' referenced before assignment

但是这样就OK

def deco():

age = 10

def wrapper():

nonlocal age

age += 1

return wrapper

deco()()

# 输出:11

其实,你如果不使用 +=、-=等一类的操作,不加nonlocal也没有关系。这就展示了闭包的特性

def deco():

age = 10

def wrapper():

print(age)

return wrapper

deco()()

# 输出:10

4. 变量集合

在Python中,有两个内建函数,你可能用不到,但是需要知道globals() :以dict的方式存储所有全局变量

locals():以dict的方式存储所有局部变量

globals()

def foo():

print("I am a func")

def bar():

foo="I am a string"

foo_dup = globals().get("foo")

foo_dup()

bar()

# 输出

# I am a func

locals()

other = "test"

def foobar():

name = "MING"

gender = "male"

for key,value in locals().items():

print(key, "=", value)

foobar()

# 输出

# name = MING

# gender = male

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值