2012-01-21 23 views
12

我有一个包含很多函数(超过25个)的模块。我想为这些函数中的每一个添加一个通用的装饰器函数。正常的做法是在每个函数上添加一个@decorator行,但我想知道是否有更好的方法来做到这一点?也许我可以在模块的顶部或其他地方声明一个全局装饰器?为完整模块定义Python装饰器

请注意,由于我正在使用别人的代码,因此我想尽量减少更改的行数,因此修改模块对我来说并不理想。

谢谢。

回答

12

如果你的装饰被称为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) 
+0

这是非常安全的 - 我真的在一个真实的项目中使用这样的东西。 – jsbueno

+0

感谢您的回答!这对我有用,但有一个小问题,它还添加了我导入的函数(如“从复制导入deepcopy”)...是否有一种方法可以跳过这些函数,只添加I我自己定义在模块的顶层? ... 谢谢! – Rajat

+0

为了避免可能的''dictproxy'对象不支持项目分配'替换“vars(othermodule)[k] = my_decorator(v)”“setattr(othermodule,k,my_decorator(v))” – user2426679

7

我想申请一个装饰后应用到模块EN-集体这样,这不是很明显,你将去查找有关函数(在其定义)通常是一个坏主意。显式优于隐式,以及所有这些。

如果你想装饰适用于某些第三方模块的功能,而无需修改第三方代码,这里是我会怎么做:

# 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并不能直接默默莫名其妙地影响任何代码;如果第三方代码的多个模块

这可能是特别重要的,但如果你正在试图做的是破解一个第三方库,这样内部呼叫影响,那么这是不是你想要的。

+0

就像你创建'wrapper_module'的想法一样。顺便说一下,我删除了我的答案(因为@ gnibbler的更完整,并且对函数类型有正确的判断)。 – reclosedev

+0

感谢您的回答。我做了以下 – Rajat

+0

@reclosedev干杯,我已经删除了对你的答案的参考。 – Ben