python廖雪峰-函数式编程 装饰器


装饰器

参考链接

优质参考

廖雪峰Python-装饰器

1
装饰器是在不改变原函数的源码和调用方式的情况下,为原函数增加功能
1
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

被装饰函数带参数-初级

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
def debug(fun):
def wrapper(*args, **kwargs):
print(fun.__name__)
return fun(*args, **kwargs)
return wrapper

@debug
def say_hello():
print("Hello")
@debug
def say_goodbye():
print("goodbye")
@debug
def say_parameter(para):
print(para)

if __name__ == '__main__':
''' # 不写@...可以这么用
say_hello = debug(say_hello)
say_hello()
say_goodbye = debug(say_goodbye)
say_goodbye()
say_parameter = debug(say_parameter)
say_parameter('Jack')

say_hello
Hello
say_goodbye
goodbye
say_parameter
Jack'''

有@...直接使用被装饰函数

装饰器带参数-高级

1
2
3
4
5
6
函数的闭包:
1、在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用【即外函数的返回值是内函数的内存地址】。这样就构成了一个闭包。

2、一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。

但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
1
2
装饰器的接口约定:
装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重载了__call__()方法,那么这个对象就是callable的。
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 logging(level):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print "[{level}]: enter function {func}()".format(
level=level,
func=func.__name__)
return func(*args, **kwargs)
return inner_wrapper
return wrapper

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

# 如果没有使用@语法,等同于
# say = logging(level='INFO')(say)

@logging(level='DEBUG')
def do(something):
print "do {}...".format(something)

if __name__ == '__main__':
say('hello')
do("my work")

[INFO]: enter function say()
say hello!
[DEBUG]: enter function do()
do my work...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator

@log('execute')
def now():
print('2015-3-25')

>>> now()
execute now():
2015-3-25
1
2
3
和两层嵌套的decorator相比,3层嵌套的效果是这样的:

>>> now = log('execute')(now)
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
以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

>>> now.__name__
'wrapper'
因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

import functools

def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
或者针对带参数的decorator:

import functools

def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
import functools是导入functools模块。模块的概念稍候讲解。现在,只需记住在定义wrapper()的前面加上@functools.wraps(func)即可。

基于类实现的装饰器

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
class logging(object):
def __init__(self, level):
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))

if __name__ == '__main__':
say('hello')

[INFO]: enter function say()
say hello!

内置装饰器

优质参考

参考链接

1
2



本文标题:python廖雪峰-函数式编程 装饰器

文章作者:TTYONG

发布时间:2022年04月16日 - 21:04

最后更新:2022年04月16日 - 22:04

原始链接:http://tianyong.fun/python%E5%BB%96%E9%9B%AA%E5%B3%B0-%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B-%E8%A3%85%E9%A5%B0%E5%99%A8.html

许可协议: 转载请保留原文链接及作者。

多少都是爱
0%