装饰器详解

装饰器是什么

  • 装饰器本质上是一种函数构造方法,其构造的是一种可变函数;我们知道在python中一切皆对象,函数即对象,由于对象是灵活不受约束的,因此我们在构造函数时,可将函数对象作为参数传递或者返回,可将函数对象进行随意嵌套,基于这些特性,我们可在在不变更代码的情况下,灵活的扩展函数/模块的功能;

装饰器的作用

  • 为已存在的对象添加额外功能

装饰器的实现

  • 原则:
    • 装饰器必须接受一个callable对象
    • 其实它并不关心你返回什么,可以是另外一个callable对象(大部分情况),也可以是其他类对象,比如property
1
2
3
4
5
6
7
8
9
10
11
12
13
#装饰器的基本语法如下
def father(funs):
def b(funs):
funs
pass
return b
#@这种称为语法糖,实际等同father(son)
@father()
def son():
pass

#使用,执行子函数,基于结构,会将子函数作为参数传递给父函数,实际执行的是父函数
son()
  • 由上可知,将子函数作为参数传递给父函数,父函数,会谁传递的函数的对象的变化而执行不同的操作,从而实现可变函数的构造。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #上方的结构,不支持复合结构如下,这是由于执行son时已经是复合结构了,在复用一层,就会报错,但是python针对这种场景,也有处理的方法
    father(son())

    #处理方法

    ```bash
    #装饰器的基本语法如下
    def father(funs):
    @wraps(funs)
    def b(funs):
    funs
    pass
    return b

    @father()
    def son():
    pass

    #此时即可支持复合结构
  • 除上诉以外,装饰器还能被进一步封装
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
def logged(level, name=None, message=None):
"""
Add logging to a function. level is the logging
level, name is the logger name, and message is the
log message. If name and message aren't specified,
they default to the function's module and name.
"""
def decorate(func):
logname = name if name else func.__module__
log = logging.getLogger(logname)
logmsg = message if message else func.__name__

@wraps(func)
def wrapper(*args, **kwargs):
log.log(level, logmsg)
return func(*args, **kwargs)
return wrapper
return decorate

# Example use
@logged(logging.DEBUG)
def add(x, y):
return x + y

@logged(logging.CRITICAL, 'example')
def spam():
print('Spam!')


  • 同样一个函数,也可以有多个装饰器
1
2
3
4
5
6
7
#a/b/c都是装饰器,执行的优先顺序是先内后外即a(son)>b(son)>c(son)
@c
@b
@a
def son():
pass

  • 装饰器不仅仅只能是函数,也可以是类,利用的是类的内置方法(__call__)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class logging(object):
def __init__(self, level='INFO'):
self.level = level

def __call__(self, func): # 接受函数
def wrapper(*args, **kwargs):
print "[{level}]: enter function {func}()".format(
level=self.level,
func=func.__name__)
func(*args, **kwargs)
return wrapper #返回函数

@logging(level='INFO')
def say(something):
print "say {}!".format(something)

参考:装饰器详解

欢迎关注我的其它发布渠道