【问题标题】:Python: Wrapping functions in the loopPython:在循环中包装函数
【发布时间】:2014-09-27 04:54:16
【问题描述】:

在 Python 中将多个函数包装在循环中的正确方法是什么? 我有通用包装器和函数列表。我需要将列表中的所有函数包装在一个循环中,但for f in funcs: 对我不起作用。 执行此操作的正确方法是什么?

def orig_func1(x, y):
    print "x=%i y=%i" % (x,y)

def orig_func2(a, b):
    print "a=%i b=%i" % (a,b)

def wrapper(func):
    f_name = func.__name__
    print 'adding hook for function [%s]' % f_name
    def inner(*args, **kwargs):
        print 'I am before original function'
        ret = func(*args, **kwargs)
        print 'I am after original function'
        return ret
    return inner

funcs = [orig_func1, orig_func2]
print funcs

for f in funcs:
    f =  wrapper(f)

print funcs

结果表明列表中的函数没有改变:

[<function orig_func1 at 0x022F78F0>, <function orig_func2 at 0x022F7930>]
adding hook for function [orig_func1]
adding hook for function [orig_func2]
[<function orig_func1 at 0x022F78F0>, <function orig_func2 at 0x022F7930>]
x=1 y=2
a=3 b=4

【问题讨论】:

  • 在该循环中,f 只不过是一个局部变量。除非您直接修改列表,否则您不会更改任何有意义的内容。
  • 你到底想完成什么?

标签: python function wrapper decorator


【解决方案1】:

在该循环中,f 只不过是一个局部变量。除非您直接修改列表,否则您不会更改任何有意义的内容。而不是:

for f in funcs:
    f =  wrapper(f)

你应该这样做:

for i, f in enumerate(funcs):
    funcs[i] = wrapper(f)

这会将列表中的函数更改为可以使用的新封装函数。但它仍然不会改变函数的最终定义。一旦定义完成,除了在函数定义的正上方使用一个完整的重新定义或包装器之外,什么都不会;直接调用orig_func1 将在for 循环前后得到相同的结果。如果您想在运行时修改函数,则必须继续引用您刚刚创建的函数的包装版本。

【讨论】:

  • 或者,funcs = map(wrapper, funcs)
【解决方案2】:

您应该使用Python Decorators,而不是循环尝试包装它们的函数。它们是修改函数行为的正确方法,而不是当前的循环方法。如果官方文档不够清楚,herehere 是一些对我有很大帮助的教程。

您现有的代码实际上看起来很像我的第一个教程链接中的一些代码 sn-ps。您应该用 @decorator 语法代替您的循环,而不是手动包装。

话虽如此,您可以通过理解来完成您最初想要的事情。用这个替换你的循环:

funcs = [wrapper(func) for func in funcs]

其他 cmets 和答案是正确的,您在循环中对 f 的修改不起作用,因为它具有该循环的本地范围并且没有修改您的列表。

【讨论】:

    【解决方案3】:

    我已经使用以下方法实现了所需的行为:

    import Module1, Module2
    
    funcs = ['Module1.func1','Module1.func2','Module2.func1','Module2.func2']
    hooks = {}
    
    def wrapper(func,f_name):
        if not hooks.has_key(f_name):
            hooks[f_name] = {'before':[],
                             'after':[]}
        def inner(*args, **kwargs):
            for f in hooks[f_name]['before']:
                f(*args, **kwargs)
            ret = func(*args, **kwargs)
            for f in hooks[f_name]['after']:
                f(*args, **kwargs)
            return ret
        return inner
    
    def implementHooks():
        for f in funcs:
            obj_name, func_name = f.rsplit('.',1)
            obj = globals()[obj_name]
            func = getattr(obj, func_name)
            setattr(obj, func_name, wrapper(func, f))
    
    implementHooks()
    
    def module1_func1_hook():
        print 'Before running module1.func1()'
    
    hooks['Module1.func1']['before'] += [module1_func1_hook]
    

    【讨论】:

      猜你喜欢
      • 2017-10-11
      • 1970-01-01
      • 2014-10-02
      • 2019-10-18
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多