【Python系列】深入理解函数闭包概念
目录
一、函数
二、闭包
2.1 概念
2.2闭包的应用场景
2.3代码实例
实例 1:简单计数器闭包
实例 2:带参数的闭包
实例 3:闭包用于数据封装和隐藏
一、函数
函数是实现特定功能的代码段的封装,在需要时可以多次调用函数来实现该功能。
Python如下定义一个函数,我们可以通过任何变量来将此函数进行赋值操作,如下:
def greet():
return "Hello!"
# 将方法赋给变量(无括号,得到方法对象)
greet_func = greet
# 调用存储在变量中的方法
print(greet_func())
print(type(greet_func)) # 输出 greet_func 的类型,由于 greet_func 指向的是 greet 函数对象,所以输出结果为 <class 'function'>
print(type(greet_func())) # 先调用 greet_func 所指向的函数,得到返回值 "Hello!",然后输出该返回值的类型,结果为 <class 'str'>。
# 有括号,直接调用方法并将结果赋给变量
greet_result = greet()
print(greet_result)
print(type(greet_result)) # 输出 greet_result 的类型,由于它存储的是字符串,所以输出结果为 <class 'str'>
print(type(greet_result())) # 报错greet_result 存储的是字符串 "Hello!",而不是函数对象,所以不能像调用函数一样在它后面加上括号 ()
在 Python 中,函数是一等公民,这意味着函数可以像其他对象(如整数、字符串等)一样被赋值给变量。这里将
greet
函数对象赋值给了变量 greet_func
。此时 greet_func
实际上指向的是 greet
函数本身,而不是函数的返回值;而 greet_result = greet()
是先调用 greet
方法,然后把返回值赋给 greet_result
变量。
二、闭包
2.1 概念
在 Python 中,闭包(Closure)是一种特殊的函数,它由一个函数和该函数所引用的外部作用域中的变量组成。即使外部函数已经执行完毕,其局部变量的生命周期也会因闭包的存在而得以延长,闭包可以继续访问这些变量。
简单来说,闭包允许函数访问并操作其定义所在的外部作用域中的变量,即使该外部作用域已经结束。
构成闭包需要满足以下三个条件:
2.2 闭包的应用场景
2.3 代码实例
实例 1:简单计数器闭包
def outer_function():
# 外部函数的局部变量
count = 0
def inner_function():
# 声明count为外部函数的局部变量, 以便可以修改它
nonlocal count
count = count + 1
return count
return inner_function
# 创建闭包实例
counter = outer_function()
# 多次调用闭包
print(counter()) # 输出: 1
print(counter()) # 输出: 2
print(counter()) # 输出: 3
代码解释:
outer_function
是外部函数,它定义了局部变量count
并初始化为 0。inner_function
是嵌套在outer_function
内部的函数,它引用了外部函数的 count
变量,并对其进行加 1 操作。nonlocal
关键字用于告诉 Python,count
变量不是当前inner_function
的局部变量,而是外部函数的局部变量,这样才能在内部函数中修改它。outer_function
返回了 inner_function
,形成了闭包。当调用 outer_function()
时,会返回inner_function
的引用并赋值给counter
。每次调用 counter()
时,count
变量的值都会在之前的基础上增加 1,说明 count
变量的状态被闭包保存下来了。
实例 2:带参数的闭包
def multiplier(factor):
print("++++++", factor)
def multiply_by_factor(number):
print("++++++", number)
return number * factor
return multiply_by_factor
# 创建一个乘以 3 的闭包
triple = multiplier(3)
# 调用 __closure__ 内置方法可以查看到两个内存地址,结果返回cell就是闭包,None 则不是闭包,可以看出来其实这是一个元组类型,使用[0].cell_contents可以得到闭合数值,也就闭包所需要的环境变量。
print(triple.__closure__)
# 闭包所需要的环境变量
print(triple.__closure__[0].cell_contents)
print(triple.__class__)
print(triple(5))
代码解释:
multiplier
是外部函数,它接受一个参数 factor
。multiply_by_factor
是嵌套函数,它接受一个参数 number
,并返回 number
乘以 factor
的结果。multiplier
返回 multiply_by_factor
,形成闭包。调用 multiplier(2)
会返回一个闭包,该闭包会将传入的数字乘以 2,将其赋值给 double
。同理,multiplier(3)
返回的闭包会将传入的数字乘以 3,赋值给 triple
。运行结果:
实例 3:闭包用于数据封装和隐藏
def account(initial_balance):
balance = initial_balance
def deposit(amount):
nonlocal balance
balance = balance + amount
return balance
def withdraw(amount):
nonlocal balance
if amount <= balance:
balance = balance - amount
return balance
else:
print("余额不足")
return balance
def get_balance():
return balance
return deposit, withdraw, get_balance
# 创建账户闭包
deposited, withdrawed, get_balanceed = account(1000)
# 存款操作
print(deposited(500)) # 输出: 1500
# 取款操作
print(withdrawed(200)) # 输出: 1300
# 查询余额
print(get_balanceed()) # 输出: 1300
代码解释:
account
是外部函数,它接受一个初始余额 initial_balance
并将其赋值给局部变量 balance
。deposit
、withdraw
和 get_balance
是嵌套函数, 它们 都引用了外 部函数balance
变量。deposit
函数用于存款,withdraw
函数用于取款,get_balance
函数用于查询余额。account
函数返回这三个嵌套函数,形成闭包。通过调用account(1000)
创建了一个账户闭包,并将返回的三个函数分别赋值给 deposited
、withdrawe
和 get_balanceed
。可以通过调用这些函数来进行账户的存款、取款和查询余额操作, 而 balance
变量被封装在闭包内部,外部无法直接访问,实现了数据的封装和隐藏。参考文章:
python小课堂26 – 进阶必修之闭包(一)
https://zhuanlan.zhihu.com/p/55949749
作者:阿龙先生啊