装饰器

什么是装饰器

在不修改原有类或者方法的情况下,给类或者方法添加新的内容。

怎么实现

简单包裹方法

通过得到原有方法的实例,由一个新的方法对其进行包裹,例如:

1
2
3
4
5
6
7
8

def source_func():
print("这里是原来方法")

def wrapper_func():
print("wrapper方法执行新的内容")
source_func();

参数包裹方法

由于python可以将方法当作参数进行传递,如果碰到很多需要添加某个功能的函数就可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
def wrapper_func(func):
print("例如这是一个日志功能,其他的函数都需要新增这样的一段功能")
func()

def func1():
print("func1")
def func2():
print("func2")

# 使用的时候可以这样
func1 = wrapper_func(func1)
func2 = wrapper_func(func2)

语法糖

由于在pyhon中这样的需求很多,python语言将这类的包裹方法按照特定语法可以使用 @ 符号的语法糖,具体使用例子如下:

1
2
3
4
5
6
7
8
9
10
def wrapper_func(func):
def wrapper():
print("这里是wrapper方法")
return func()
return wrapper

@wrapper_func
def my_func():
print("这里是自定义方法")

额外

带参数的方法如何进行包裹

可以使用 *args、**kwargs 关键字即可
对于单个已知参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def func1(name):
print("i am %s" % name)

# 可以在定义wrapper方法的时候传入参数
def wrapper(name):
print("wrapper 方法")
return func(name)

# 对于不知道有几个参数的情况
def wrapper(*args):
print("wrapper方法")
return func(*args)
# 对于有默认参数的情况
def foo(name, age=None, height=None):
print("I am %s, age %s, height %s" % (name, age, height))

#
def wrapper(*args, **kwargs):
# args是一个数组,kwargs一个字典
logging.warn("%s is running" % func.__name__)
return func(*args, **kwargs)

带参数的装饰器

装饰器带参数,需要装饰器函数外部在包裹一层。具体如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
logging.warn("%s is running" % func.__name__)
elif level == "info":
logging.info("%s is running" % func.__name__)
return func(*args)
return wrapper

return decorator

@use_logging(level="warn")
def foo(name='foo'):
print("i am %s" % name)

foo()

装饰器类

没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

class Foo(object):
def __init__(self, func):
self._func = func

def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')

@Foo
def bar():
print ('bar')

bar()

Python自带的有用的装饰器

@property

该装饰器可以将类方法变成属性的调用方式。类似于getter setter方法,具体实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class People:

def __init__(self, name, age):
self.__name = name
self.__age = age

@property
def age(self):
return self.__age

@age.setter
def age(self, age):
if isinstance(age, int):
self.__age = age
else:
raise ValueError

@age.deleter
def age(self):
print("删除年龄数据!")

obj = People("jack", 18)
print(obj.age)
obj.age = 19
print("obj.age: ", obj.age)
del obj.age

---------------------------
打印结果:
18
obj.age: 19
删除年龄数据!


装饰器
https://chenhongjun.top/2022/12/22/装饰器/
作者
Delightening
发布于
2022年12月22日
许可协议