4

我正在尝试实现我自己的版本itertools.compress,问题是我偶然发现了返回类型。我的意思是这两个函数都返回一个迭代器,但我认为第二个函数不被视为生成器函数,因为内部没有 yield 语句。所以我的问题是,这两种实现是否等效?

def compress (seq, selectors):
    from operator import itemgetter
    fst = itemgetter (0)
    snd = itemgetter (1)
    yield from map (fst, filter (snd, zip (seq, selectors)))

def compress (seq, selectors):
    from operator import itemgetter
    fst = itemgetter (0)
    snd = itemgetter (1)
    return map (fst, filter (snd, zip (seq, selectors)))
4

3 回答 3

5

不完全的。

yield from seq相当于for i in seq: yield i

这意味着您的第一个实现是一个生成器,它从 map() 的结果中生成每个项目,而您的第二个实现返回地图对象。

于 2017-08-10T18:14:57.190 回答
4

虽然它们可能看起来非常相似,甚至输出结果,但它们并不等价。

看看这些基本的代码示例,映射strrange(100)

def do_yield_from():
    yield from map(str, range(100))


def do_return():
    return map(str, range(100))

print(do_yield_from())
print(do_return())

>>> <class 'generator'>
>>> <class 'map'>

第一个函数是 a generator,产生的结果do_yield_from和缩短版本

for r in range(100): yield str(r)

第二个函数返回一个实例map,它是一个iterator而不是一个generator

由于第一个函数是 a generatoryield from因此性能比do_return

import timeit
print(timeit.timeit(do_yield_from))
>>> 0.53931242968009

print(timeit.timeit(do_return))
>>> 1.467075402143485
于 2017-08-10T18:23:04.843 回答
3

所以我的问题是,这两种实现是否等效?

一点也不。

yield from并且return是两种不同的、不同的句法结构。

yield fromPEP380中引入的语法。这称为生成器委托从文档中

PEP 380 添加了yield from表达式,允许生成器将其部分操作委托给另一个生成器。这允许将包含 yield 的一段代码分解出来并放置在另一个生成器中。此外,允许子生成器返回一个值,并且该值可供委托生成器使用。

return但是具有完全不同的行为。从文档中

return 只能在语法上嵌套在函数定义中,而不是在嵌套的类定义中。

如果存在表达式列表,则对其进行评估,否则将替换为无。

Nonereturn 以表达式列表(或)作为返回值离开当前函数调用。

基本上yield from <iter>相当于for element in <iter>: yield element, whilereturn只会返回一个值。在你的情况下,我相信yield from你正在寻找什么。您想要yield来自map迭代器的值,而不是return迭代器本身。

于 2017-08-10T18:30:17.667 回答