Python 中带属性的装饰器
刚刚完成 由 Python 的 Ellipsis 到 *, /, *args, **kwargs 函数参数,
又回想起在 熟悉和应用 Python 的装饰器,关于带属性的装饰器一直未交代,安心不下来,Python 中带属性的装饰器用得非常普遍,如 Flask 的
我们一看到 Python 的装饰器(Decorator) 会很直截的与 Java 的注解(Annotation) 联系起来,其实除了都用
在 Python 中被装饰的函数想要在执行期跳过装饰器函数的附加行为,能想到的一个比喻就是像踢开**闹**, 除非上面内部的通容才能做到。
回到 Python 的装饰器的话题上来,我们除了让装饰器可以传递函数参数,接受函数的返回值外,现在要给装饰器加上属性。在原来的装饰器实现上进行改进,在 熟悉和应用 Python 的装饰器 一文中有个例子是
如果我们想要的装饰器能写成
装饰器实现最外层的函数不再是直接面对函数(以函数为参数),而是将要的属性作为参数。执行上面的代码输出为
还有一个更巧妙的实现,可以利用 my_decorator 的一个参数,时为 function 时为 path, 见 Python 的 functools.py 中 https://github.com/python/cpython/blob/main/Lib/functools.py#L508
接下来还有更多的关于 Python 装饰器的内容,如用类代替函数作为装饰器等 永久链接 https://yanbin.blog/python-decorator-with-property/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
@app.route('/')。我们一看到 Python 的装饰器(Decorator) 会很直截的与 Java 的注解(Annotation) 联系起来,其实除了都用
@ 符号外是存在很大区别的。正如它们被翻译成的中文名那样,Java 的注解在一定程度上就是一个注释,只要没有注解处理器处理它们就可以被忽略,Java 要用反射来处理注解。而 Python 的装饰器更象是代理,函数一旦被装饰后,调用目标函数时是无法挣脱装饰器函数的控制的,是硬核的。在 Python 中被装饰的函数想要在执行期跳过装饰器函数的附加行为,能想到的一个比喻就是像踢开**闹**, 除非上面内部的通容才能做到。
回到 Python 的装饰器的话题上来,我们除了让装饰器可以传递函数参数,接受函数的返回值外,现在要给装饰器加上属性。在原来的装饰器实现上进行改进,在 熟悉和应用 Python 的装饰器 一文中有个例子是
1from functools import wraps
2
3def my_decorator(func):
4
5 @wraps(func)
6 def wrapper(*args, **kwargs):
7 print(f"before calling {func.__name__}")
8 func(*args, **kwargs)
9 print(f"after calling {func.__name__}")
10
11 return wrapper
12
13
14@my_decorator
15def say_hello(firstname, lastname, **kwargs):
16 print(f"Hello {firstname} {lastname}!", kwargs)
17
18
19say_hello("Steve", "Jobs", company="Apple", country="USA")如果我们想要的装饰器能写成
@my_decorator(path='/hello_world')那我们的 my_decorator 实现上还得加上一个层次
1from functools import wraps
2
3def my_decorator(path):
4 def inner_decorator(func):
5 @wraps(func)
6 def wrapper(*args, **kwargs):
7 print(f"input path {path}")
8 print(f"before calling {func.__name__}")
9 func(*args, **kwargs)
10 print(f"after calling {func.__name__}")
11
12 return wrapper
13
14 return inner_decorator
15
16
17@my_decorator(path="/hello_world")
18def say_hello(firstname, lastname, **kwargs):
19 print(f"Hello {firstname} {lastname}!", kwargs)
20
21
22say_hello("Steve", "Jobs", company="Apple", country="USA")装饰器实现最外层的函数不再是直接面对函数(以函数为参数),而是将要的属性作为参数。执行上面的代码输出为
input path /hello_world同样的,装饰器的机制是,得到原函数包装后的函数,再调用该 wrapper 函数,所以按照这机制不用 @my_decorator 的话,就是
before calling say_hello
Hello Steve Jobs! {'company': 'Apple', 'country': 'USA'}
after calling say_hello
1my_decorator(path="/hello_world")(say_hello)("Steve", "Jobs", company="Apple", country="USA")还有一个更巧妙的实现,可以利用 my_decorator 的一个参数,时为 function 时为 path, 见 Python 的 functools.py 中 https://github.com/python/cpython/blob/main/Lib/functools.py#L508
1def lru_cache(maxsize=128, typed=False):
2...
3
4 if isinstance(maxsize, int):
5 # Negative maxsize is treated as 0
6 if maxsize < 0:
7 maxsize = 0
8 elif callable(maxsize) and isinstance(typed, bool):
9 # The user_function was passed in directly via the maxsize argument
10 user_function, maxsize = maxsize, 128
11...接下来还有更多的关于 Python 装饰器的内容,如用类代替函数作为装饰器等 永久链接 https://yanbin.blog/python-decorator-with-property/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。