问题
I'm trying to implement my own version of itertools.compress, the problem is that i stumbled upon the return type. I mean both of these functions return an iterator, but i think the second one is not considered a generator function because there is no yield statement inside. So my question is, are these two implementations equivalent ?
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)))
回答1:
Not quite.
yield from seq is equivalent to for i in seq: yield i
This means your first implementation is a generator that yields each item from the result of map(), while your second implementation returns the map object.
回答2:
While they may look like very similar, even outputted with results, they are not equivalent.
Look at these basic code examples, mapping str to range(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'>
The first function is a generator, yielding the results from do_yield_from and a shortened version of
for r in range(100): yield str(r)
The second function returns an instance of map, which is an iterator and not a generator.
Due to the first function being a generator, yield from has better performance than do_return
import timeit
print(timeit.timeit(do_yield_from))
>>> 0.53931242968009
print(timeit.timeit(do_return))
>>> 1.467075402143485
回答3:
So my question is, are these two implementations equivalent ?
Not at all.
yield from and return are two different, distinct syntactic constructs.
yield from is syntax that was introduced in PEP380. It's called generator delegation. From the documentation:
PEP 380 adds the
yield fromexpression, allowing a generator to delegate part of its operations to another generator. This allows a section of code containing yield to be factored out and placed in another generator. Additionally, the subgenerator is allowed to return with a value, and the value is made available to the delegating generator.
return however has completely different behavior. From the documentation:
return may only occur syntactically nested in a function definition, not within a nested class definition.
If an expression list is present, it is evaluated, else None is substituted.
return leaves the current function call with the expression list (or
None) as return value.
Basically yield from <iter> is equivlent to for element in <iter>: yield element, while return will simply return a single value.
In your case, I believe yield from is what you're looking for. You want to yield the values from the map iterator, not return the iterator itself.
来源:https://stackoverflow.com/questions/45620608/difference-between-return-iterator-and-yield-from-iterator