闭包和装饰器
引子
内部函数和外部函数之间的关系在于内部函数被嵌套在外部函数内。
这种嵌套关系使得内部函数能够访问外部函数的变量,形成了闭包,提供了一种有趣而强大的编程模式。这种嵌套关系使得内部函数能够访问外部函数的变量,形成了闭包,提供了一种有趣而强大的编程模式。
like this:
def outer_function(x):
# 内部函数
def inner_function(y):
return x + y
return inner_function
# 创建闭包
closure_example = outer_function(10)
# 使用闭包
result = closure_example(5)
print(result) # 输出15
在这个例子中,outer_function
是外部函数,它接受一个参数 x
。在外部函数内,有一个内部函数 inner_function
,它引用了外部函数的参数 x
。当 outer_function(10)
被调用时,它返回了内部函数的引用,形成了闭包。这个闭包被赋值给变量 closure_example
。
然后,我们调用闭包 closure_example(5)
,这实际上调用了内部函数,并传递了参数 y
。由于内部函数引用了外部函数的变量 x
,所以它可以访问并使用 x
的值,最后返回 x + y
的结果。在这个例子中,结果是 15。
再看个闭包栗子👇
# 定义闭包函数
def my_decorator(func):
# 内部函数,接受任意参数并传递给原始函数
def wrapper(*args, **kwargs):
print("在函数调用之前, 做一些事情")
# 调用原始函数
result = func(*args, **kwargs)
print("在函数调用之后, 做一些事情")
return result
return wrapper
def say_hello(name):
print(f"Hello, {name}!")
outer = my_decorator(say_hello)
outer("sunshine")
代码运行结果如下:
在这个例子中,my_decorator
是一个外部函数,它接受一个函数func
作为参数,并返回一个新的函数 wrapper
。wrapper
是一个闭包,它引用了外部函数 my_decorator
的参数 func
。在 wrapper
中,我们可以在原始函数调用之前和之后添加额外的操作。
换个写法
# 定义装饰器函数
def my_decorator(func):
# 内部函数,接受任意参数并传递给原始函数
def wrapper(*args, **kwargs):
print("在函数调用之前, 做一些事情")
# 调用原始函数
result = func(*args, **kwargs)
print("在函数调用之后, 做一些事情")
return result
return wrapper
# 使用装饰器
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
# 调用被装饰后的函数
say_hello("Alice")
是的,这就是装饰器。对比一下@
写法与闭包写法,瞬间了然,就是换个写法。
装饰器传参
# 装饰器工厂函数,接受参数
def my_decorator_factory(prefix):
# 实际的装饰器函数,接受被装饰的函数作为参数
def my_decorator(func):
# 内部函数,接受任意参数并传递给原始函数
def wrapper(*args, **kwargs):
print(f"{prefix}: 在函数调用之前, 做一些事情")
# 调用原始函数
result = func(*args, **kwargs)
print(f"{prefix}: 在函数调用之后, 做一些事情")
return result
return wrapper
return my_decorator
# 使用装饰器工厂创建装饰器
@my_decorator_factory(prefix="DEBUG")
def say_hello(name):
print(f"Hello, {name}!")
# 调用被装饰后的函数
say_hello("Alice")
在这个例子中my_decorator_factory
是一个装饰器工厂函数,它接受一个参数prefix
。这个工厂函数返回了实际的装饰器函数my_decorator
,而my_decorator
返回了内部函数wrapper
。
当我们使用@my_decorator_factory("DEBUG")
语法应用装饰器时,实际上是调用了装饰器工厂函数,将参数"DEBUG"
传递给它,得到了装饰器函数my_decorato
。
然后,my_decorator
被应用于 say_hello
函数。
当调用 say_hello("Alice")
时,实际上是调用了经过装饰后的函数 wrapper
。这样,我们可以在装饰器内部使用传递的参数,实现更加灵活的装饰器行为。
总结
函数装饰器是 Python 中一种强大的工具,主要用于修改或扩展函数的行为。装饰器可以在不改变原始函数代码的情况下,动态地为函数添加额外的功能或修改其行为。以下是一些常见的装饰器的作用:
- 代码重构: 装饰器可以将一些通用的行为封装在一个函数中,然后通过装饰器应用到多个函数上,实现代码重用。
- 日志记录:装饰器可以用于记录函数的调用信息,如输入参数、执行时间等,用于调试或日志记录。
- 性能分析:装饰器可以用于测量函数的执行时间,帮助进行性能分析。
- 权限控制:装饰器可以用于检查用户权限或其他条件,并决定是否允许执行函数。
示例
代码重构
def my_decorator(func): def wrapper(*args, **kwargs): print("Something is happening before the function is called.") result = func(*args, **kwargs) print("Something is happening after the function is called.") return result return wrapper
我们可以将此装饰器作用于不同函数
@my_decorator def say_hello(name): print(f"Hello, {name}!")
@my_decorator def say_goodbye(name): print(f"Goodbye, {name}!")
日志记录
def log_decorator(func): def wrapper(*args, **kwargs): print(f"调用 {func.__name__} 的参数是: {args}, kwargs: {kwargs}") result = func(*args, **kwargs) print(f"{func.__name__} 返回值是: {result}") return result return wrapper
@log_decorator def add(x, y): return x + y
性能分析
import time def timing_decorator(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"{func.__name__} 花费了 {end_time - start_time} 秒") return result return wrapper
@timing_decorator def slow_function(): time.sleep(2) print("函数执行结束")
权限控制
def permission_required(permission): def decorator(func): def wrapper(*args, **kwargs): if check_permission(permission): return func(*args, **kwargs) else: print("权限未通过") return wrapper return decorator
@permission_required("admin") def admin_function(): print("Admin function executed.")
每日一句:有什么胜利可言,挺住意味着一切。 –里尔克
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: