Вы ошибаетесь в своем мышлении. Ваше выражение генератора делает точно то же самое, что и функция генератора, только с одной разницей: вы поместили print()
в неправильное место. В evens2
вы печатаете до выполнено выражение генератора, создающее объект генератора, а в evens
вы печатаете внутри самой функции генератора.
Если это Python 3 (или вы использовали from __future__ import print_function
), вы можете использовать функцию print()
внутри выражения генератора тоже:
def evens2(stream):
return (print('inside evens2') or n for n in stream if n % 2 == 0)
Это является эквивалентом:
def evens(stream):
for n in stream:
if n % 2 == 0:
yield print("Inside evens") or n
print()
всегда возвращается None
, поэтому print(..) or n
вернет n
. Итерация либо будет печататься, либо выводить все значения n
.
Демо:
>>> def evens2(stream):
... return (print('inside evens2') or n for n in stream if n % 2 == 0)
...
>>> def evens(stream):
... for n in stream:
... if n % 2 == 0:
... yield print("Inside evens") or n
...
>>> g1 = evens([1, 2, 3, 4, 5])
>>> g2 = evens2([1, 2, 3, 4, 5])
>>> g1
<generator object evens at 0x10bbf5938>
>>> g2
<generator object evens2.<locals>.<genexpr> at 0x10bbf5570>
>>> next(g1)
Inside evens
2
>>> next(g2)
inside evens2
2
>>> next(g1)
Inside evens
4
>>> next(g2)
inside evens2
4
Оба вызова производит объект генератора, и как генератор объектов печати дополнительной информации каждый раз, когда вы заранее их один шаг с next()
.
Что касается Python, то, что два объекта генератора производят более или менее такой же байт-код:
>>> import dis
>>> dis.dis(compile('(n for n in stream if n % 2 == 0)', '', 'exec').co_consts[0])
1 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 27 (to 33)
6 STORE_FAST 1 (n)
9 LOAD_FAST 1 (n)
12 LOAD_CONST 0 (2)
15 BINARY_MODULO
16 LOAD_CONST 1 (0)
19 COMPARE_OP 2 (==)
22 POP_JUMP_IF_FALSE 3
25 LOAD_FAST 1 (n)
28 YIELD_VALUE
29 POP_TOP
30 JUMP_ABSOLUTE 3
>> 33 LOAD_CONST 2 (None)
36 RETURN_VALUE
>>> dis.dis(compile('''\
... def evens(stream):
... for n in stream:
... if n % 2 == 0:
... yield n
... ''', '', 'exec').co_consts[0])
2 0 SETUP_LOOP 35 (to 38)
3 LOAD_FAST 0 (stream)
6 GET_ITER
>> 7 FOR_ITER 27 (to 37)
10 STORE_FAST 1 (n)
3 13 LOAD_FAST 1 (n)
16 LOAD_CONST 1 (2)
19 BINARY_MODULO
20 LOAD_CONST 2 (0)
23 COMPARE_OP 2 (==)
26 POP_JUMP_IF_FALSE 7
4 29 LOAD_FAST 1 (n)
32 YIELD_VALUE
33 POP_TOP
34 JUMP_ABSOLUTE 7
>> 37 POP_BLOCK
>> 38 LOAD_CONST 0 (None)
41 RETURN_VALUE
Оба используют FOR_ITER
в цикле, COMPARE_OP
, чтобы увидеть, если выход BINARY_MODULO
равно 0 и оба используют YIELD_VALUE
, чтобы получить значение n
.
Ваш оператор 'print()' находится в неправильном месте в 'evens'. Он должен быть в начале, а не в цикле. –
Ваше выражение генератора и функция генератора ведут себя точно так же * в противном случае. Оба дают 'n' только при итерации. –