2016-08-14 5 views
3

Я иду через документы Python 3.X, я сомневаюсь в скорости выполнения расписания List и том, как он работает.Каким образом List Comprehension работает на Python?

Давайте рассмотрим следующий пример:

Листинг 1

... 
L = range(0,10) 
L = [x ** 2 for x in L] 
... 

Теперь в моем знании это возвращает новый список, и это эквивалент записать:

каталог 2

... 
res = [] 
for x in L: 
    res.append(x ** 2) 
... 

Главное отличие - скорость выполнения, если я прав. Листинг 1 предполагается выполнять на скорости языка C внутри интерпретатора, а листинг 2 - нет.

Но Листинг 2 является то, что список понимание делает внутренне (не уверен), так почему Листинг 1 выполняется на C Скорость внутри интерпретатора & листинге 2 не? Оба они преобразуются в байтовый код перед обработкой, или я что-то упускаю?

+2

_both преобразуются в байтовый код перед обработкой. Да, конечно, ну и что? Они не преобразуются в один и тот же байтовый код, так почему они должны принимать такое же количество времени? –

+1

@ ŁukaszRogalski не перечисляет 2, какое понимание списка делает внутренне? Если это так, нужно преобразовать в один и тот же код байта. Я думаю, – Sid

+1

Основная цель понимания списков - упростить создание сложных списков и улучшить читаемость для однострочного. Вы можете сравнить, если есть разница в скомпилированном байт-кодеке 'pyc'.Исходный код Python открыт, поэтому, если вы читаете C, вы можете прочитать алгоритмы, соответствующие пониманию списка. – noumenal

ответ

3

Посмотрите на фактический байт-код, который производится. Я поместил два фрагмента кода в fuctions, называемые f1 и f2.

Понимание делает это:

3   15 LOAD_CONST    3 (<code object <listcomp> at 0x7fbf6c1b59c0, file "<stdin>", line 3>) 
      18 LOAD_CONST    4 ('f1.<locals>.<listcomp>') 
      21 MAKE_FUNCTION   0 
      24 LOAD_FAST    0 (L) 
      27 GET_ITER 
      28 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      31 STORE_FAST    0 (L) 

Уведомление нет петли в байткод. Цикл происходит в С.

Теперь цикл делает это:

4   21 SETUP_LOOP    31 (to 55) 
      24 LOAD_FAST    0 (L) 
      27 GET_ITER 
     >> 28 FOR_ITER    23 (to 54) 
      31 STORE_FAST    2 (x) 
      34 LOAD_FAST    1 (res) 
      37 LOAD_ATTR    1 (append) 
      40 LOAD_FAST    2 (x) 
      43 LOAD_CONST    3 (2) 
      46 BINARY_POWER 
      47 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      50 POP_TOP 
      51 JUMP_ABSOLUTE   28 
     >> 54 POP_BLOCK 

В отличие от понимания, петля явно здесь в байткод. Таким образом, цикл встречается в python.

Байткоды разные, и первое должно быть быстрее.

+0

Да, это все! Я только что проверил байтовый код, как это было предложено вами и Лукашем, и получил тот же результат. На самом деле да, два листинга одинаковы, а переосмысление списка делает то же самое, что и L2, но в C, очевидно, быстрее, примерно в два раза. Еще раз спасибо! – Sid

3

Ответ на самом деле в вашем вопросе.

Когда вы запускаете любую встроенную функцию python, вы запускаете что-то, что было написано на C и скомпилировано в машинный код.

Когда вы пишете свою собственную версию, этот код должен быть преобразован в объекты CPython, которые обрабатываются интерпретатором.

В результате встроенный подход или функция всегда быстрее (или занимает меньше места) на Python, чем написание собственной функции.

Смежные вопросы