在 Python 里,闭包是一种特殊的函数,它能记住并访问其所在的封闭作用域中的变量,即便该封闭作用域已经执行完毕。将函数作为返回值返回,也是一种高阶函数,这种高阶函数称为闭包。通过创建闭包可以创建一些只有当前函数能访问的变量,可以将一些私有的数据藏到闭包中。
闭包由以下几个部分构成:
一个简单的闭包示例
def fn() :
def inner () :
print('这是一个内部函数')
return inner
# 接受结果
r = fn()
#调用
r()
# 结果:
这是一个内部函数
***Repl Closed***
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
result = closure(5)
print(result)
# 结果
15
***Repl Closed***
在这个例子中,outer_function 是外部函数,它接收一个参数 x。inner_function 是内部函数,它引用了外部函数的变量 x。outer_function 返回 inner_function。调用 outer_function(10) 会返回一个闭包,这个闭包记住了 x 的值为 10。之后调用这个闭包并传入参数 5,就会得到 10 + 5 的结果
def counter():
count = 0
def increment():
nonlocal count
count = count + 1
return count
return increment
c = counter()
print(c())
print(c())
在这个例子中,count 变量被封装在 counter 函数内部,外部无法直接访问它。只能通过调用闭包 c 来增加 count 的值。
def power_factory(n):
def power(x):
return x ** n
return power
square = power_factory(2)
cube = power_factory(3)
print(square(5))
print(cube(5))
在这个例子中,power_factory 是一个函数工厂,它依据传入的参数 n 生成不同的幂函数
def outer():
x = 10
def inner():
nonlocal x
x = x + 1
return x
return inner
f = outer()
print(f())
装饰器本质上是一个函数,它接收一个函数作为参数,并且返回一个新的函数,如下
def my_decorator(func):
def wrapper():
print("在函数执行前做一些操作")
func()
print("在函数执行后做一些操作")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
# 结果:
在函数执行前做一些操作
Hello!
在函数执行后做一些操作
***Repl Closed***
在这个例子中,my_decorator 就是一个装饰器,它接收 say_hello 函数作为参数,返回 wrapper 函数。使用 @my_decorator 语法糖可以将 say_hello 函数传递给 my_decorator
如果被装饰的函数带有参数,装饰器需要能够处理这些参数。可以用过在wrapper函数中使用*args和**kwargs来实现
def my_decorator(func):
def wrapper(*args, **kwargs):
print("在函数执行前做一些操作")
result = func(*args, **kwargs)
print("在函数执行后做一些操作")
return result
return wrapper
@my_decorator
def add_numbers(a, b):
return a + b
result = add_numbers(3, 5)
print(result)
# 结果
在函数执行前做一些操作
在函数执行后做一些操作
8
***Repl Closed***
装饰器本身也可以的带有参数。这需要定义一个返回装饰器的函数:
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say_hi():
print("Hi!")
say_hi()
# 结果:
Hi!
Hi!
Hi!
***Repl Closed***
在这个例子中,repeat 函数接收一个参数 n,并返回一个装饰器 decorator。
可以对一个函数应用多个装饰器:
def decorator1(func):
def wrapper():
print("装饰器1: 在函数执行前做一些操作")
func()
print("装饰器1: 在函数执行后做一些操作")
return wrapper
def decorator2(func):
def wrapper():
print("装饰器2: 在函数执行前做一些操作")
func()
print("装饰器2: 在函数执行后做一些操作")
return wrapper
@decorator1
@decorator2
def say_goodbye():
print("Goodbye!")
say_goodbye()
# 结果:
装饰器1: 在函数执行前做一些操作
装饰器2: 在函数执行前做一些操作
Goodbye!
装饰器2: 在函数执行后做一些操作
装饰器1: 在函数执行后做一些操作
***Repl Closed***
装饰器的应用顺序是从下往上,也就是先应用 decorator2,再应用 decorator1。
除了函数装饰器,还可以使用类来实现装饰器
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("在函数执行前做一些操作")
result = self.func(*args, **kwargs)
print("在函数执行后做一些操作")
return result
@MyDecorator
def say_cheers():
print("Cheers!")
say_cheers()
# 结果:
在函数执行前做一些操作
Cheers!
在函数执行后做一些操作
***Repl Closed***
在这个例子中,MyDecorator 类实现了 call 方法,使其实例可以像函数一样被调用