自动包装器,为函数添加输出

时间:2013-05-30 13:08:25

标签: python function wrapper output

[我正在使用python 2.7]

我想制作一个包装函数,为函数添加一个输出。类似的东西:

def add_output(fct, value):
    return lambda *args, **kargs: (fct(*args,**kargs),value)

使用示例:

def f(a): return a+1
g = add_output(f,42)
print g(12)            # print: (13,42)

这是预期的结果,但如果赋予add_ouput的函数返回多个输出(也不返回任何输出),则它不起作用。在这种情况下,包装函数将返回两个输出,一个包含初始函数的所有输出(如果没有输出则返回None),另一个包含添加的输出:

def f1(a): return a,a+1
def f2(a): pass
g1 = add_output(f1,42)
g2 = add_output(f2,42)
print g1(12)            # print: ((12,13),42)   instead of (12,13,42)
print g2(12)            # print: (None,42)      instead of 42

我可以看到这与区分元组类型的一个输出和几个输出的不可能性有关。但令人失望的是,不能用像python这样的动态语言做这么简单的事情......

有没有人知道如何自动实现这个目标足够,还是我处于死胡同?

注意: 如果这改变了什么,我的真正目的是做一些类(实例)方法的包装,看起来像函数(用于工作流的东西)。但是,需要在输出中添加self(如果其内容已更改):

class C(object):
    def f(self): return 'foo','bar'

def wrap(method):
    return lambda self, *args, **kargs: (self,method(self,*args,**kargs))

f = wrap(C.f)
c = C()
f(c)          # returns (c,('foo','bar')) instead of (c,'foo','bar')

我正在使用python 2.7,所以我想要这个版本的解决方案,否则我放弃了这个想法。我仍然对python 3的这个问题的评论感兴趣(也许是未来的读者)。

1 个答案:

答案 0 :(得分:1)

您的add_output()函数在Python中被称为decorator。无论如何,您可以使用collections模块的ABCs(抽象基类)之一来区分被包装函数的不同结果。例如:

import collections

def add_output(fct, value):
    def wrapped(*args, **kwargs):
        result = fct(*args, **kwargs)
        if isinstance(result, collections.Sequence):
            return tuple(result) + (value,)
        elif result is None:
            return value
        else: # non-None and non-sequence
            return (result, value)
    return wrapped

def f1(a): return a,a+1
def f2(a): pass
g1 = add_output(f1, 42)
g2 = add_output(f2, 42)
print g1(12)            # -> (12,13,42)
print g2(12)            # -> 42

根据您计划进行装饰的功能类型,您可能需要使用collections.Iterable ABC而不是collections.Sequence