Python闭包
名词来源?“闭包”这个术语源自于数学领域,它指的是一个函数与其相关的引用环境的组合。在计算机科学中,闭包通常指的是一个函数与其引用的非局部变量的组合。
什么是闭包? 在 Python 中,关于闭包, 是这样解释的:对于一个嵌套定义的函数,外层的函数的返回值是内层函数,而在内层函数中又引用了外层函数的局部变量,在外层函数执行后,其局部变量并非被回收,而会同返回的内层函数一同存在,而这一现象被称为闭包(closure)。在 Python 中,当一个内部函数引用了外部函数中定义的变量时,就会创建一个闭包。闭包函数“封闭”了对外部变量的访问,使得这些变量即使在外部函数返回后仍然可以被访问。当一个内部函数引用了外部函数中定义的变量时,就会创建一个闭包。闭包函数“封闭”了对外部变量的访问,使得这些变量即使在外部函数返回后仍然可以被访问。
为什么叫闭包? 这个特性之所以称为“闭包”,是因为它“封闭”了对外部变量的访问,使得这些变量可以在外部函数返回后继续存在。你可以将闭包看作是一种特殊的函数,它携带了一些额外的变量,这些变量可以在多次调用闭包函数时保持其值。
使用场景? 闭包有许多用途,它可以用来实现一些特殊的功能,例如计数器、累加器等。闭包还可以用来实现数据封装和装饰器等高级功能。
下面是一些使用闭包的例子:
- 计数器:我们可以使用闭包来创建一个简单的计数器,如下所示:
def create_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counterA = create_counter()
print(counterA()) # 1
print(counterA()) # 2
print(counterA()) # 3
counterB = create_counter()
print(counterB()) # 1
print(counterB()) # 2
在这个例子中,create_counter 函数返回了一个 counter 函数,它可以访问 create_counter 函数中定义的 count 变量。每次调用 counter 函数时,它都会递增 count 变量并返回其值。
- 数据封装:我们可以使用闭包来实现数据封装,即将数据和操作数据的函数捆绑在一起。例如,下面的代码演示了如何使用闭包来创建一个简单的银行账户:
def create_account(name, balance):
def deposit(amount):
nonlocal balance
balance += amount
return balance
def withdraw(amount):
nonlocal balance
if amount > balance:
return 'Insufficient balance'
balance -= amount
return balance
def get_balance():
return balance
return {'name': name, 'deposit': deposit, 'withdraw': withdraw, 'get_balance': get_balance}
account = create_account('John', 100)
print(account['get_balance']()) # 100
print(account['deposit'](50)) # 150
print(account['withdraw'](200)) # Insufficient balance
print(account['withdraw'](50)) # 100
在这个例子中,create_account 函数返回了一个字典,其中包含了存款、取款和查询余额等操作。这些操作都是通过闭包函数实现的,它们可以访问 create_account 函数中定义的 balance 变量。
- 装饰器:装饰器是一种高级功能,它允许你在不修改函数代码的情况下增强函数的功能。装饰器通常使用闭包来实现。例如,下面的代码演示了如何使用装饰器来记录函数的调用时间:
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f'{func.__name__} took {end - start:.6f} seconds to run.')
return result
return wrapper
@timer
def my_function(n):
total = 0
for i in range(n):
total += i * i
return total
my_function(1000000)
在这个例子中,timer 函数是一个装饰器,它接受一个函数作为参数,并返回一个新的函数。新函数会在调用原始函数之前记录当前时间,在调用原始函数之后计算运行时间并打印结果。你可以使用 @timer 语法糖来应用装饰器,这样就可以在不修改 my_function 函数代码的情况下增强其功能。