装饰器
装饰器是一个以函数为参数的函数,是将传入的函数进行包装,为其添加更多的功能。
可以很方便的在需要执行的函数前或函数后添加很多功能,或者做异常处理,但是可读性却不是很好。
奇怪的函数装饰器
def outer(fun):
print("=========================")
print("this is outer before func1")
fun()
print("this is outer after func1")
print("=========================")
@outer
def func1():
print("this is func1")
func1
=========================
this is outer before func1
this is func1
this is outer after func1
=========================
普通的函数装饰器
def outer2(fun):
a = 10
def inner():
print("=========================")
print("this is outer before func2")
nonlocal a
a -= 1
print(a)
fun()
print("this is outer after func2")
print("=========================")
return inner
@outer2
def func2():
print("this is func2")
@outer2
def func3():
print("this is func3")
func2()
func2()
func3()
func3()
=========================
this is outer before func2
9
this is func2
this is outer after func2
=========================
=========================
this is outer before func2
8
this is func2
this is outer after func2
=========================
=========================
this is outer before func2
9
this is func3
this is outer after func2
=========================
=========================
this is outer before func2
8
this is func3
this is outer after func2
=========================
类作为装饰器
class ExceptionHandler:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
try:
print("=========================")
print(f"this is before {self.func.__name__}")
ret = self.func(*args, **kwargs)
print(f"this is after {self.func.__name__}")
print("=========================")
return ret
except Exception as e:
print(e)
@ExceptionHandler
def func2(a):
print("this is func2")
print(1/a)
return 9
# 等价于
# func2 = ExceptionHandler(func2)
if __name__ == '__main__':
print(func2(1))
print(func2(0))
=========================
this is before func2
this is func2
1.0
this is after func2
=========================
9
=========================
this is before func2
this is func2
division by zero
None
类加上参数作为装饰器
class ExceptionHandler:
def __init__(self, pre):
self.pre = pre
def __call__(self, func):
def inner(*args, **kwargs):
try:
print("=========================")
print(f"this is before {func.__name__}")
print(self.pre)
ret = func(*args, **kwargs)
print(self.pre)
print(f"this is after {func.__name__}")
print("=========================")
return ret
except Exception as e:
print(e)
return inner
@ExceptionHandler(pre="xxxx")
def func2(a):
print("this is func2")
print(1/a)
return 9
# 等价于
# func2 = ExceptionHandler(pre="xxxx")(add)
if __name__ == '__main__':
print(func2(1))
print(func2(0))
=========================
this is before func2
xxxx
this is func2
1.0
xxxx
this is after func2
=========================
9
=========================
this is before func2
xxxx
this is func2
division by zero
None
在类上添加装饰器
def add_str(string):
def __str__(self):
return str(self.__dict__)
string.__str__ = __str__
return string
@add_str
class MyClass:
def __init__(self, a):
self.a = a
# 等价于
# MyClass = add_str(MyClass)
if __name__ == '__main__':
o = MyClass(10)
print(o)
{'a': 10}
在类成员函数上添加装饰器
def excep(func):
def wrapper(*args, **kwargs):
try:
print("=========================")
print(f"this is before {func.__name__}")
print(func(*args, **kwargs))
print(f"this is after {func.__name__}")
print("=========================")
except Exception as e:
print(e)
return wrapper
class MyClass:
def __init__(self, a):
self.a = a
@excep
def test1(self, a):
print("test1")
print(1/a)
if __name__ == '__main__':
o = MyClass(10)
print(o)
o.test1(5)
o.test1(0)
<__main__.MyClass object at 0x000002EC6A9A7BE0>
=========================
this is before test1
test1
0.2
None
this is after test1
=========================
=========================
this is before test1
test1
division by zero
在类上和类成员函数上添加装饰器
def add_str(string):
def __str__(self):
return str(self.__dict__)
string.__str__ = __str__
return string
def excep(func):
def wrapper(*args, **kwargs):
try:
print("=========================")
print(f"this is before {func.__name__}")
print(func(*args, **kwargs))
print(f"this is after {func.__name__}")
print("=========================")
except Exception as e:
print(e)
return wrapper
@add_str
class MyClass:
def __init__(self, a):
self.a = a
@excep
def test1(self, a):
print("test1")
print(1/a)
return 10
# 等价于
# MyClass = add_str(MyClass)
if __name__ == '__main__':
o = MyClass(10)
print(o)
o.test1(5)
o.test1(0)
{'a': 10}
=========================
this is before test1
test1
0.2
10
this is after test1
=========================
=========================
this is before test1
test1
division by zero
在类成员函数上添加类中函数作为装饰器
class Decorators:
def log_function(func):
def wrapper(*args, **kwargs):
print("=========================")
print(f"this is before {func.__name__}")
print(f"args: {args}")
ret = func(*args, **kwargs)
print(ret)
print(f"this is after {func.__name__}")
print("=========================")
return ret
return wrapper
@log_function
def add(self, a, b):
return a + b
log_function = staticmethod(log_function)
d = Decorators()
print(d.add(3, 4))
=========================
this is before add
args: (<__main__.Decorators object at 0x000002DF473F8F70>, 3, 4)
7
this is after add
=========================
7
使用装饰器应用于类的所有函数/所有方法
def handle_exceptions(func):
def wrapper(*args, **kwargs):
try:
print("=========================")
print(f"this is before {func.__name__}")
ret = func(*args, **kwargs)
print(ret)
print(f"this is after {func.__name__}")
print("=========================")
return ret
except Exception as e:
# 在这里添加统一的异常处理逻辑
print(f"Exception caught: {str(e)}")
return wrapper
# 装饰器应用于类的所有方法
def apply_exception_handler(cls):
for name, method in cls.__dict__.items():
if callable(method):
setattr(cls, name, handle_exceptions(method))
return cls
# 示例:一个带有异常处理的类
@apply_exception_handler
class MyClass:
def method1(self):
print("Method 1")
raise ValueError("Error in method 1")
def method2(self):
print("Method 2")
# 无异常抛出的情况
# 创建类的实例
my_instance = MyClass()
# 调用类的方法
my_instance.method1()
my_instance.method2()
=========================
this is before method1
Method 1
Exception caught: Error in method 1
=========================
this is before method2
Method 2
None
this is after method2
=========================