在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
更准确地说,作为单参数函数的函数是这种方法工作的必要但不充分的条件吗?而另一个必要条件是单个参数必须是单项(而不是序列)?
答案 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)
generate
是map
的生成器版本。
map(lambda x: x*2, range(5)) [0, 2, 4, 6, 8]
它取输入范围并将该函数应用于范围内的每个元素。
generate
也会这样做,但它不会返回列表。它产生了每次转换的结果。
现在看看你的例子。第一个结果是什么? sum(1)
。
但是sum
需要一个列表,而不是一个整数,因此是错误信息。