Ответ 1
Вот itertools.chain.from_iterable. Это не трудно читать, даже если вы не знаете C, и вы можете сказать, что все происходит на уровне c (прежде чем использовать для создания списка в вашем коде).
Байт-код для понимания списков выглядит так:
def f(lsts):
return [x for y in lsts for x in y]
dis.dis(f.__code__.co_consts[1])
2 0 BUILD_LIST 0
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 18 (to 24)
6 STORE_FAST 1 (y)
8 LOAD_FAST 1 (y)
10 GET_ITER
>> 12 FOR_ITER 8 (to 22)
14 STORE_FAST 2 (x)
16 LOAD_FAST 2 (x)
18 LIST_APPEND 3
20 JUMP_ABSOLUTE 12
>> 22 JUMP_ABSOLUTE 4
>> 24 RETURN_VALUE
Это все операции интерпретатора python, связанные с созданием понимания списка. Просто наличие всех операций на уровне C (в chain
), а не нахождение интерпретатора над каждым шагом байтового кода (в понимании) - это то, что даст вам повышение производительности.
Тем не менее, этот импульс настолько мал, что я не стал бы беспокоиться об этом. Это питон, читаемость по скорости.
Редактировать:
Для просмотра списка завершенных генераторов
def g(lists):
return list(x for y in lsts for x in y)
# the comprehension
dis.dis(g.__code__.co_consts[1])
2 0 LOAD_FAST 0 (.0)
>> 2 FOR_ITER 20 (to 24)
4 STORE_FAST 1 (y)
6 LOAD_FAST 1 (y)
8 GET_ITER
>> 10 FOR_ITER 10 (to 22)
12 STORE_FAST 2 (x)
14 LOAD_FAST 2 (x)
16 YIELD_VALUE
18 POP_TOP
20 JUMP_ABSOLUTE 10
>> 22 JUMP_ABSOLUTE 2
>> 24 LOAD_CONST 0 (None)
26 RETURN_VALUE
Таким образом, у интерпретатора есть аналогичное количество шагов, которые нужно выполнить при запуске выражения генератора, который распаковывается списком, но, как и следовало ожидать, накладные расходы на уровне python из list
распаковки генератора (в отличие от команды C LIST_APPEND
) - это то, что замедляется это вниз.
dis.dis(f)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x000000000FB58B70, file "<ipython-input-33-1d46ced34d66>", line 2>)
2 LOAD_CONST 2 ('f.<locals>.<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_FAST 0 (lsts)
8 GET_ITER
10 CALL_FUNCTION 1
12 RETURN_VALUE
dis.dis(g)
2 0 LOAD_GLOBAL 0 (list)
2 LOAD_CONST 1 (<code object <genexpr> at 0x000000000FF6F420, file "<ipython-input-40-0334a7cdeb8f>", line 2>)
4 LOAD_CONST 2 ('g.<locals>.<genexpr>')
6 MAKE_FUNCTION 0
8 LOAD_GLOBAL 1 (lsts)
10 GET_ITER
12 CALL_FUNCTION 1
14 CALL_FUNCTION 1
16 RETURN_VALUE