Python: понимание итераторов и `join()` лучше
Функция join()
принимает итеративный параметр. Однако мне было интересно, почему:
text = 'asdfqwer'
Это:
''.join([c for c in text])
Значительно быстрее:
''.join(c for c in text)
То же самое происходит с длинными строками (т.е. text * 10000000
).
Наблюдая за объемом памяти обоих исполнений с длинными строками, я думаю, что оба они создают один и только один список символов в памяти, а затем присоединяют их к строке. Поэтому я предполагаю, что разница заключается только в том, как join()
создает этот список из генератора и как интерпретатор Python делает то же самое, когда видит [c for c in text]
. Но, опять же, я просто догадываюсь, поэтому я хотел бы, чтобы кто-то подтвердил/отклонил мои догадки.
Ответы
Ответ 1
Метод join
читает свой ввод дважды; один раз, чтобы определить, сколько памяти выделяется для результирующего строкового объекта, затем снова выполнить фактическое соединение. Передача списка происходит быстрее, чем передача объекта-генератора, что ему нужно сделать копию, чтобы она могла перебирать ее дважды.
Понимание списка - это не просто объект-генератор, завернутый в список, поэтому построение списка извне происходит быстрее, чем join
создать его из объекта-генератора. Объекты генератора оптимизированы для эффективности памяти, а не скорости.
Конечно, строка уже является итерируемым объектом, поэтому вы можете просто написать ''.join(text)
. (Кроме того, это не так быстро, как создание списка явно из строки.)