Скорость понимания списка и генератора с функцией соединения

Итак, я получил эти примеры из официальной документации. https://docs.python.org/2/library/timeit.html

Что именно делает первый пример (выражение генератора) медленнее, чем второй (понимание списка)?

>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.7288308143615723

1 ответ

Решение

str.join Метод преобразует свой итеративный параметр в список, если он уже не является списком или кортежем. Это позволяет логике объединения выполнять итерации по элементам несколько раз (выполняется один проход для вычисления размера строки результата, а затем второй проход для фактического копирования данных).

Вы можете увидеть это в исходном коде CPython:

PyObject *
PyUnicode_Join(PyObject *separator, PyObject *seq)
{
    /* lots of variable declarations at the start of the function omitted */

    fseq = PySequence_Fast(seq, "can only join an iterable");

    /* ... */
}

PySequence_Fast Функция в C API делает именно то, что я описал. Он преобразует произвольную итерацию в список (по сути, вызывая list на нем), если это уже не список или кортеж.

Преобразование выражения генератора в список означает, что обычные преимущества генераторов (меньший объем памяти и возможность короткого замыкания) не применяются к str.joinи поэтому (небольшие) дополнительные накладные расходы, которые имеет генератор, ухудшают его производительность.

Другие вопросы по тегам