5

是否可以将导入模块中的代码应用于导入它的模块?例如,我有模块 Debug ,其中定义了一些用于调试的装饰器,例如:

def debug_func(f):
    def wrapper(*func_args, **func_kwargs):
        print(f(*func_args, **func_kwargs))
    return wrapper

想法是什么:如果我能做到这将是有用的

import Debug 

当前模块中的所有功能都将用装饰器包装。是否可以?

4

3 回答 3

3

在 Debug.py 中:

import functools
from types import FunctionType

def wrap_functions(module_dict):
    for k, f in module_dict.items():
        if not isinstance(f, FunctionType):
            continue
        def get_wrapper(f):
            def wrapper(*func_args, **func_kwargs):
                print(f(*func_args, **func_kwargs))
            return functools.wraps(f)(wrapper)
        module_dict[k] = get_wrapper(f)

在您希望调试的模块底部:

import Debug
Debug.wrap_functions(globals())

感谢 (+1) 所有提供建议的评论者。

于 2013-10-22T14:45:22.833 回答
3

如何Debug知道它是从哪个模块导入的?答:不能。如果它被导入到多个模块中,怎么会Debug知道运行不止一次?答:不会;模块只运行一次然后缓存。所以你想做的事情不能像你想做的那样简单。

但是,您可以通过debug在导入后调用模块中的函数来做到这一点。您可以__name__从调用模块传递以提供其名称,之后可以获得对模块本身的引用,然后是其中定义的顶级变量,其中一些可能是函数。然后可以装饰这些。

# debug.py
import types, sys, functools

# decorator to be applied to all top-level functions in a module
def debug(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        print "calling", fn.__name__, "with args", *args, **kwargs
        result = fn(*args, **kwargs)
        print "returning from", fn.__name__, "with return value", result
        return result

# decorate all top-level functions in named module with a given decorator
# (by default it is the above decorator but it could be a different one)
# This makes these functions behave as though they had been written with
# @debug above them.
def set_debug(modname, debug=debug):
    module = sys.modules[modname]
    for name in dir(module):
        if not name.startswith("_"):
            thing = getattr(module, name)
            if isinstance(thing, types.FunctionType):
                setattr(module, name, debug(thing))

现在在调用模块中:

# main.py
import debug

def main():
    print "in main module"

debug.set_debug(__name__)   # install debugging decorator

main()

Jim Garrison 显式传递命名空间(而不是模块名称)的方法也很好,实际上简化了一些事情;你可以用它来装饰模块以外的东西。我已经分解了我的,因此您可以根据需要传入不同的装饰器。

于 2013-10-22T15:02:52.233 回答
0

我认为这样做的pythonic方法是让您的Debug调用调试模块,作为标准工具(pdb,,unittest...),调用如下:

$ python -m Debug mymodule.py

随着您的调试使用您喜欢的任何装饰器导入/执行模块。以另一种方式(导入Debug)会混淆模块的评估顺序,因为您试图让您的Debug模块依赖于导入它的模块,这充其量是棘手的。

除了像 Jim Garrison 建议的那样将你的函数显式传递(通过globals()函数列表......)之外Debug.mark_as_debug,我认为组织你的代码更有意义,这样你就可以Debug调用你的模块而不是相反.

于 2013-10-22T15:02:22.577 回答