函数与闭包基础
在 Python 中,函数是一等公民,这意味着函数可以像其他对象(如整数、字符串)一样被赋值给变量。我们可以通过任何变量来引用此函数,如下所示:
def greet(): return "Hello!"
# 将方法赋给变量(无括号,得到方法对象)
greet_func = greet
# 调用存储在变量中的方法
print(greet_func())
print(type(greet_func)) # 输出 <class 'function'>
# 有括号,直接调用方法并将结果赋给变量
greet_result = greet()
print(greet_result)
print(type(greet_result)) # 输出 <class 'str'>
# print(greet_result()) # 报错,因为 greet_result 存储的是字符串,不是函数对象
这里将 greet 函数对象赋值给了变量 greet_func。此时 greet_func 实际上指向的是 greet 函数本身,而不是函数的返回值;而 greet_result = greet() 是先调用 greet 方法,然后把返回值赋给 greet_result 变量。
什么是闭包
在 Python 中,闭包(Closure)是一种特殊的函数,它由一个函数和该函数所引用的外部作用域中的变量组成。即使外部函数已经执行完毕,其局部变量的生命周期也会因闭包的存在而得以延长,闭包可以继续访问这些变量。
简单来说,闭包允许函数访问并操作其定义所在的外部作用域中的变量,即使该外部作用域已经结束。
构成闭包需要满足以下三个条件:
- 存在一个嵌套函数,即在一个函数内部定义另一个函数。
- 嵌套函数引用了外部函数的局部变量。
- 外部函数返回嵌套函数。
应用场景
- 数据封装和隐藏:可以将数据隐藏在闭包内部,只通过闭包提供的接口来访问和修改数据。
- 实现回调函数:在事件驱动编程中,闭包可以作为回调函数,保存一些上下文信息。
- 实现装饰器:装饰器是闭包的一种常见应用,用于在不修改原函数代码的情况下,为函数添加额外的功能。
实战示例
简单计数器闭包
def outer_function():
count = 0
def inner_function():
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 引用了外部的 count 变量,并使用 nonlocal 关键字告诉 Python,count 不是当前函数的局部变量,而是外部函数的局部变量,这样才能在内部函数中修改它。
当调用 outer_function() 时,会返回 inner_function 的引用并赋值给 counter。每次调用 counter() 时,count 变量的值都会在之前的基础上增加 1,说明 count 变量的状态被闭包保存下来了。
带参数的闭包
def multiplier(factor):
def multiply_by_factor(number):
return number * factor
return multiply_by_factor
triple = multiplier(3)
print(triple.__closure__) # 查看闭包环境
print(triple.__closure__[0].cell_contents) # 获取闭合数值
print(triple(5)) # 输出:15
multiplier 接受一个参数 factor,返回嵌套函数 multiply_by_factor。调用 multiplier(3) 会返回一个闭包,该闭包会将传入的数字乘以 3。我们可以使用 __closure__ 内置方法查看内存地址,结果返回的 cell 就是闭包,它是一个元组类型,使用 [0].cell_contents 可以得到闭合数值。
数据封装和隐藏
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, withdrawn, get_balanceed = account(1000)
print(deposited(500)) # 输出:1500
print(withdrawn(200)) # 输出:1300
print(get_balanceed()) # 输出:1300
account 函数接受初始余额,定义了存款、取款和查询余额的三个嵌套函数。它们都引用了外部的 balance 变量。account 函数返回这三个嵌套函数,形成闭包。通过调用 account(1000) 创建了一个账户闭包,balance 变量被封装在闭包内部,外部无法直接访问,实现了数据的封装和隐藏。

