0

[我正在使用 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 的这个问题的评论感兴趣(也许是未来的读者)。

4

1 回答 1

1

你的add_output()函数就是Python 中的装饰器。无论如何,您可以使用collections模块的ABC(抽象基类)之一来区分来自被包装函数的不同结果。例如:

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.IterableABC 来代替collections.Sequence.

于 2013-05-30T15:40:31.700 回答