闭包与装饰器
1"""
2Author: wangy325
3Date: 2024-07-22 00:25:10
4Description: 闭包(closure)与装饰器(注解 decorator)
5"""
6from contextlib import contextmanager
7
8
9# 闭包 closure
10# 闭包是一个特殊的函数
11# 闭包有一个'内嵌'函数
12# 闭包返回这个内嵌函数
13# 内置函数可以访问外部的函数的变量
14
15# 以下用闭包解一个一元一次方程 a*x + b = y
16
17
18def liner(a, b):
19 def coordinate(x):
20 return a * x + b
21
22 return coordinate
23
24
25# 3x + 4 = ?
26f = liner(3, 4)
27# 3 * 2 + 4 = ?
28print(f(2))
29# 所以闭包就等价于
30g = (liner(3, 4)(x) for x in range(2, 3))
31for e in g:
32 print(e)
33
34# ############# #
35# 装饰器 #
36# ############# #
37'''
38装饰器是python的一种语法糖
39使用@开头, 类似于Java的注解
40装饰器的作用, 很强
41可以改变方法的行为, 而不直接修改方法的代码
42可以实现类似AOP的功能
43'''
44
45
46# 装饰器应用场景:
47# • 日志记录: 在函数执行之前和之后添加日志记录。
48# • 计时器: 记录函数执行时间。
49# • 权限控制: 检查用户权限,只有满足条件才能执行函数。
50# • 缓存: 缓存函数的返回值,避免重复计算。
51# • 异常处理: 在函数执行过程中捕获并处理异常。
52
53
54# 装饰器的基本写法
55def timer(func):
56 def wrapper(*args, **kwargs):
57 start = time.perf_counter()
58 print(f'函数{func.__name__}开始执行, 开始时间: {start}')
59 rel = func(*args, **kwargs)
60 time.sleep(1)
61 end = time.perf_counter()
62 print(f'函数{func.__name__}执行结束, 运行耗时: {end - start}')
63 return rel
64
65 return wrapper
66
67
68# 可以看到, 装饰器其实使用了闭包
69
70
71@timer
72def add(x, y):
73 return x + y
74
75
76i = add(1, 3)
77
78# 结合上面闭包的概念, 实际上使用装饰器相当于调用闭包:
79# 把函数的运行推迟
80# 而在运行前,后做一些事情
81j = timer(lambda x, y: x + y)(1, 3)
82
83
84print(f"i:{i}, j:{j}")
85
86
87# ##
88# 装饰器当然可以传递参数
89# 使用了多层闭包
90# ##
91def log(level):
92 def inner(func):
93 def wrapper(*args, **kwargs):
94 print(f'[{level}]: fun {func.__name__} start...')
95 rel = func(*args, **kwargs)
96 print(f'[{level}]: fun {func.__name__} done... ')
97 return rel
98
99 return wrapper
100
101 return inner
102
103
104@log("INFO")
105def cal(x, y):
106 return x * y
107
108
109cal(3, 6)
110
111
112#
113# 或者, 更加灵活地处理装饰器的参数
114# 装饰器参数作为装饰器的业务逻辑
115#
116def decorator(profile=False, logger=False):
117 def inner(func):
118 def wrapper(*args, **kwargs):
119 if profile:
120 start_time = time.time()
121 result = func(*args, **kwargs)
122 if profile:
123 end_time = time.time()
124 print(f"{func.__name__} took {end_time - start_time} seconds")
125 if logger:
126 print(f"calling {func.__name__} with args: {args}, kwargs: {kwargs}")
127 return result
128
129 return wrapper
130
131 return inner
132
133
134@decorator(profile=True, logger=True)
135def say_hi():
136 time.sleep(1)
137 print("Hi")
138
139
140say_hi()
141
142
143# ############# #
144# with语句 #
145# ############# #
146
147# with语句除了自动关闭文件/资源之外
148# 还可以用作'上下文管理器类'
149# https://docs.python.org/zh-cn/3/reference/compound_stmts.html#the-with-statement
150#
151
152class MyContextManager:
153 def __enter__(self):
154 print('进入上下文管理器类')
155 return self
156
157 def __exit__(self, ext_type, ext_value, exc_tb):
158 print('退出上下文管理器')
159
160
161with MyContextManager() as m:
162 print('在上下文管理器中执行操作')
163
164
165@contextmanager
166def my_context_manager():
167 print("进入上下文管理器")
168 try:
169 yield "上下文管理器中的值"
170 finally:
171 print("退出上下文管理器")
172
173
174with my_context_manager() as value:
175 print(f"在上下文管理器中获取值:{value}")