Такой код часто бывает:
l = []
while foo:
#baz
l.append(bar)
#qux
Это очень медленно, если вы собираетесь добавить тысячи элементов в свой список, так как список должен будет постоянно изменяться, чтобы соответствовать новым элементам.
В Java вы можете создать ArrayList с начальной емкостью. Если у вас есть представление о том, насколько большим будет ваш список, это будет намного эффективнее.
Я понимаю, что подобный код часто может быть преобразован в понимание списка. Однако, если цикл for / while очень сложен, это невозможно. Есть ли какой-нибудь эквивалент для нас, программистов на Python?
python
list
dictionary
initialization
Клаудиу
источник
источник
Ответы:
Результаты . (оцените каждую функцию 144 раза и усредните продолжительность)
Заключение . Это едва имеет значение.
Преждевременная оптимизация - корень всего зла.
источник
Списки Python не имеют встроенного предварительного выделения. Если вам действительно нужно составить список, и вам нужно избежать дополнительных затрат на добавление (и вы должны убедиться, что вы это делаете), вы можете сделать это:
Возможно, вы могли бы избежать списка, используя вместо этого генератор:
Таким образом, список не хранится в памяти, а просто генерируется по мере необходимости.
источник
Короткая версия: использовать
предварительно выделить список (то есть, чтобы иметь возможность обращаться к элементам «размера» списка вместо постепенного формирования списка путем добавления). Эта операция очень быстрая, даже в больших списках. Выделение новых объектов, которые впоследствии будут назначены элементам списка, займет НАМНОГО больше времени и станет ВСЕЙ узким местом в вашей программе с точки зрения производительности.
Длинная версия:
Я думаю, что время инициализации должно быть принято во внимание. Поскольку в python все является ссылкой, не имеет значения, установлен ли каждый элемент в None или в какую-либо строку - в любом случае, это всего лишь ссылка. Хотя это займет больше времени, если вы хотите создать новый объект для каждого элемента для ссылки.
Для Python 3.2:
Оценка:
Как видите, создание большого списка ссылок на один и тот же объект None занимает очень мало времени.
Предварительное добавление или расширение занимает больше времени (я ничего не усреднял, но после нескольких попыток могу сказать, что расширение и добавление занимают примерно одно и то же время).
Выделение нового объекта для каждого элемента - это то, что занимает больше всего времени. И ответ С. Лотта делает это - каждый раз форматирует новую строку. Что не является строго обязательным - если вы хотите предварительно выделить некоторое пространство, просто составьте список None, а затем назначьте данные элементам списка по желанию. В любом случае для создания данных требуется больше времени, чем для добавления / расширения списка, независимо от того, генерируете ли вы его при создании списка или после него. Но если вы хотите малонаселенный список, то начинать со списка None определенно быстрее.
источник
[]*
подходPythonic путь для этого:
или любое другое значение по умолчанию, с которым вы хотите подготовиться, например
[EDIT: Caveat Emptor
[Beer()] * 99
синтаксис создает одинBeer
, а затем заполняет массив с 99 ссылками на тот же единственный экземпляр]Подход Python по умолчанию может быть довольно эффективным, хотя эта эффективность снижается по мере увеличения количества элементов.
сравнить
с участием
На моем Windows 7 i7 64-битный Python дает
В то время как C ++ дает (построен с MSVC, 64-битный, оптимизация включена)
Отладочная сборка C ++ производит:
Дело в том, что с Python вы можете добиться повышения производительности на 7-8%, и если вы думаете, что пишете высокопроизводительное приложение (или если вы пишете что-то, что используется в веб-сервисе или чем-то еще), то это не должно быть обнюхено, но вам, возможно, придется пересмотреть свой выбор языка.
Кроме того, код Python здесь не совсем код Python. Переход на действительно Pythonesque код здесь дает лучшую производительность:
Который дает
(в 32-битном doGenerator работает лучше, чем doAllocate).
Здесь разрыв между doAppend и doAllocate значительно больше.
Очевидно, что различия здесь действительно применимы, только если вы делаете это более чем несколько раз или если вы делаете это в сильно загруженной системе, где эти числа будут уменьшены на порядки или если вы имеете дело с значительно большие списки.
Суть здесь: сделать это питонским способом для лучшей производительности.
Но если вы беспокоитесь об общей производительности на высоком уровне, Python - не тот язык. Наиболее фундаментальная проблема заключается в том, что вызовы функций Python традиционно были в 300 раз медленнее, чем другие языки, из-за таких функций Python, как декораторы и т. Д. ( Https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ).
источник
timeit
timeit
, что вы должны использовать при синхронизации вашего кода Python; Я не говорю о C ++, очевидно.bottles = [Beer()] * 99
не создает 99 объектов пива. Вместо этого создается один объект Beer с 99 ссылками на него. Если вы измените его, все элементы в списке будут видоизменены, причина(bottles[i] is bootles[j]) == True
для каждогоi != j. 0<= i, j <= 99
.Как уже упоминалось, самый простой способ предварительно заполнить список
NoneType
объектами.При этом вы должны понять, как на самом деле работают списки Python, прежде чем решить, что это необходимо. В реализации списка в CPython базовый массив всегда создается с пространством служебных данных, с постепенно увеличивающимися размерами
( 4, 8, 16, 25, 35, 46, 58, 72, 88, 106, 126, 148, 173, 201, 233, 269, 309, 354, 405, 462, 526, 598, 679, 771, 874, 990, 1120, etc)
, так что изменение размера списка происходит не так часто.Из-за этого поведения большинство
list.append()
функций являютсяO(1)
сложностями для добавлений, только увеличивая сложность при пересечении одной из этих границ, и в этот момент сложность будетO(n)
. Именно такое поведение приводит к минимальному увеличению времени выполнения в ответе С. Лотта.Источник: http://www.laurentluce.com/posts/python-list-implementation/
источник
я запустил код @ s.lott и произвел такое же увеличение производительности на 10%, предварительно выделив. попробовал идею @ jeremy, используя генератор, и смог лучше увидеть характеристики генов, чем у doAllocate. Для моего проекта улучшение на 10% имеет значение, так что спасибо всем, так как это помогает куче.
источник
Озабоченность по поводу предварительного выделения в Python возникает, если вы работаете с numpy, который имеет больше C-подобных массивов. В этом случае проблемы перед выделением связаны с формой данных и значением по умолчанию.
Подумайте, если вы делаете числовые вычисления в больших списках и хотите повысить производительность.
источник
Для некоторых приложений словарь может быть тем, что вы ищете. Например, в методе find_totient мне было удобнее использовать словарь, поскольку у меня не было нулевого индекса.
Эта проблема также может быть решена с помощью предварительно выделенного списка:
Я чувствую, что это не так элегантно и подвержено ошибкам, потому что я храню None, который может вызвать исключение, если я их случайно использую неправильно, и потому что мне нужно подумать о крайних случаях, которых карта позволяет мне избежать.
Да, словарь не будет таким эффективным, но, как отмечали другие, небольшие различия в скорости не всегда стоят значительных рисков при обслуживании.
источник
Насколько я понимаю, списки Python уже очень похожи на ArrayLists. Но если вы хотите настроить эти параметры, я нашел этот пост в сети, который может быть интересным (в основном, просто создайте свой собственный
ScalableList
расширение):http://mail.python.org/pipermail/python-list/2000-May/035082.html
источник