为完整模块定义Python装饰器

17 投票
2 回答
6190 浏览
提问于 2025-04-17 10:45

我有一个模块,里面有很多函数(超过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 等方式在其他地方使用这些函数。

对我来说,这样做有以下几个好处:

  1. 不需要修改第三方的源文件
  2. 从调用的地方可以清楚地看到,我应该去查看 my_wrapper_module 来了解我在调用什么,而不是使用没有装饰器的函数
  3. my_wrapper_module 中可以清楚地看到哪些函数被导出,它们最初来自 some_module,并且都应用了相同的装饰器
  4. 任何直接导入 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)

撰写回答