将任何单参数函数转换为生成函数?

时间:2016-01-22 21:38:30

标签: python function generator yield

David Beazley's talk on generators中,他展示了如何从任何单参数函数创建生成器函数:

def generate(func):
    def gen_func(s):
        for item in s:
            yield func(item)
    return gen_func

并用math.sqrt

说明
gen_sqrt = generate(math.sqrt)
for x in gen_sqrt(xrange(100)):
    print x

为什么:

gen_sum = generate(sum)
for x in gen_sum([1,2,3,4,5]):
    print x

产生

TypeError                                 Traceback (most recent call last)
<ipython-input-73-ef521f2bbfc8> in <module>()
      1 gen_sum = generate(sum)
----> 2 for x in gen_sum(1):
      3     print x

<ipython-input-50-3c0ba12c2429> in gen_func(s)
      1 def generate(func):
      2     def gen_func(s): # closure
----> 3         for item in s:
      4             yield func(item)
      5     return gen_func

TypeError: 'int' object is not iterable

更准确地说,作为单参数函数的函数是这种方法工作的必要但不充分的条件吗?而另一个必要条件是单个参数必须是单项(而不是序列)?

3 个答案:

答案 0 :(得分:3)

您正在传递其元素类型错误的列表。当然它不会起作用,原因与gen_sqrt(['a', 's', 'd', 'f'])不起作用的原因相同。

您需要传递gen_sum一个有意义的内容列表,以便打开sum,例如其他列表:

for x in gen_sum([[1, 2], [3, 4]]):
    print x

输出:

3
7

答案 1 :(得分:2)

你是对的,两者都是必要的要求:

def generate(func):
    def gen_func(s):
        for item in s:          # <--- requires s to be interable
            yield func(item)    # <--- requires func to accept a single argument
    return gen_func

所以在

gen_sum = generate(func)
for x in gen_sum(s):
    print x

func必须接受一个参数,s必须是可迭代的。

答案 2 :(得分:1)

generatemap的生成器版本。

map(lambda x: x*2, range(5))   [0, 2, 4, 6, 8]

它取输入范围并将该函数应用于范围内的每个元素。

generate也会这样做,但它不会返回列表。它产生了每次转换的结果。

现在看看你的例子。第一个结果是什么? sum(1)

但是sum需要一个列表,而不是一个整数,因此是错误信息。