为完整模块定义Python装饰器
我有一个模块,里面有很多函数(超过25个)。我想给这些函数都加上一个共同的装饰器函数。通常的做法是在每个函数上方加一个 @decorator 的标记,但我在想有没有更好的方法?也许我可以在模块的顶部声明一个全局的装饰器,或者其他什么方法?
需要注意的是,因为我在使用别人的代码,所以我想尽量减少修改的行数,所以修改模块对我来说并不是理想的选择。
谢谢。
2 个回答
10
我觉得把装饰器大规模应用到函数上,这样就不容易找到函数的定义,通常是个坏主意。明确的比隐晦的要好,这个道理大家都懂。
如果你想给一些第三方模块的函数加装饰器,但又不想改动第三方的代码,我会这样做:
# my_wrapper_module.py
import some_module
import functools
def some_decorator(func):
@functools.wraps(func):
def wrapper(*args, **kwargs):
...
return wrapper
FUNCTION_NAMES = [
'some_func_1',
'some_func_2',
'some_func_3',
...
]
for name in FUNCTION_NAMES:
globals()[name] = some_decorator(getattr(some_module, name))
然后你可以通过 from my_wrapper_module import some_func_2
等方式在其他地方使用这些函数。
对我来说,这样做有以下几个好处:
- 不需要修改第三方的源文件
- 从调用的地方可以清楚地看到,我应该去查看
my_wrapper_module
来了解我在调用什么,而不是使用没有装饰器的函数 - 从
my_wrapper_module
中可以清楚地看到哪些函数被导出,它们最初来自some_module
,并且都应用了相同的装饰器 - 任何直接导入
some_module
的代码不会受到影响,这一点特别重要,尤其是当第三方代码有多个模块时
但是,如果你想要修改一个第三方库,让内部调用也受到影响,那这样做就不合适了。
20
如果你的装饰器叫做 my_decorator
### Decorate all the above functions
import types
for k,v in globals().items():
if isinstance(v, types.FunctionType):
globals()[k] = my_decorator(v)
你也可以在导入模块后将这个装饰器应用到模块上
import othermodule
import types
for k,v in vars(othermodule).items():
if isinstance(v, types.FunctionType):
vars(othermodule)[k] = my_decorator(v)