【问题标题】:Defining Python decorators for a complete module为完整的模块定义 Python 装饰器
【发布时间】:2012-02-15 15:08:42
【问题描述】:

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

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

谢谢。

【问题讨论】:

    标签: python decorator


    【解决方案1】:

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

    【讨论】:

    • 这是非常安全的——我实际上在一个真实的项目中使用了这样的东西。
    • 感谢您的回答!这确实对我有用,但是有一个小问题,它还添加了我已导入的功能(例如“从复制导入深度复制”)...有没有办法可以跳过这些功能而只添加我的功能我自己在模块的顶层定义? ...谢谢!
    • 替换 "vars(othermodule)[k] = my_decorator(v)" 为 "setattr(othermodule, k, my_decorator(v))" 以避免可能的 "'dictproxy' 对象不支持项目分配”
    • 但请注意,这会使读者更难意识到函数是经过修饰的。我同意有时这是一种很好的方法,但它有点违背“显式优于隐式”的准则。
    【解决方案2】:

    我认为整体应用装饰器,这样你会去哪里寻找函数(在其定义中)并不明显,这通常是一个坏主意。显式优于隐式,等等。

    如果你想在不修改第三方代码的情况下将装饰器应用于某些第三方模块的功能,我会这样做:

    # 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 的代码都不会受到静默和莫名其妙的影响;如果第三方代码不止一个模块,这一点尤其重要

    但是,如果您尝试破解第三方库以影响内部调用,那么这不是您想要的。

    【讨论】:

    • 喜欢你创建wrapper_module的想法。顺便说一句,我已经删除了我的答案(因为@gnibbler's 更完整并且对函数类型有正确的检查)。
    • 感谢您的回答。我做了以下
    • @reclosedev 干杯,我现在删除了对您答案的引用。
    猜你喜欢
    • 1970-01-01
    • 2012-04-11
    • 1970-01-01
    • 2015-05-15
    • 2013-08-09
    • 1970-01-01
    • 2012-12-04
    • 2013-02-06
    • 1970-01-01
    相关资源
    最近更新 更多