Сейчас я использую список и ожидаю что-то вроде:
verts = list (1000)
Должен ли я использовать массив вместо?
Сейчас я использую список и ожидаю что-то вроде:
verts = list (1000)
Должен ли я использовать массив вместо?
Первое, что приходит мне на ум, это:
verts = [None]*1000
Но вам действительно нужно предварительно инициализировать его?
Не совсем уверен, почему каждый человек испытывает трудности с желанием сделать это - есть несколько сценариев, в которых вы хотите получить список с фиксированным размером. И вы правильно определили, что массивы разумны в этих случаях.
import array
verts=array.array('i',(0,)*1000)
Для не-pythonistas термин (0,)*1000
создает кортеж, содержащий 1000 нулей. Запятая заставляет python распознавать (0)
как кортеж, иначе он будет оцениваться как 0.
Я использовал кортеж вместо списка, потому что они обычно имеют более низкие служебные данные.
Один очевидный и, вероятно, не эффективный способ -
verts = [0 for x in range(1000)]
Обратите внимание, что это можно легко расширить до 2-мерного. Например, чтобы получить массив 10x100, вы можете сделать
verts = [[0 for x in range(100)] for y in range(10)]
Желание инициализировать массив фиксированного размера - вполне приемлемая вещь для любого языка программирования; это не похоже на то, что программист хочет поставить оператор break в течение некоторого (истинного) цикла. Поверьте мне, особенно если элементы просто будут перезаписаны, а не просто добавлены/вычтены, как в случае многих алгоритмов динамического программирования, вы не хотите обходиться с операторами append и проверять, не был ли этот элемент инициализирован еще "на лету" (что много кодовых символов).
object = [0 for x in range(1000)]
Это будет работать для того, чего пытается достичь программист.
@Steve уже дал хороший ответ на ваш вопрос:
verts = [None] * 1000
Предупреждение: Как указал @Joachim Wuttke, список должен быть инициализирован неизменным элементом. [[]] * 1000
работает не так, как ожидалось, потому что вы получите список из 1000 идентичных списков (аналогично списку из 1000 пунктов в тот же список на C). Неизменяемые объекты, такие как int, str или кортеж, будут работать нормально.
Изменение размеров списков происходит медленно. Следующие результаты не очень удивляют:
>>> N = 10**6
>>> %timeit a = [None] * N
100 loops, best of 3: 7.41 ms per loop
>>> %timeit a = [None for x in xrange(N)]
10 loops, best of 3: 30 ms per loop
>>> %timeit a = [None for x in range(N)]
10 loops, best of 3: 67.7 ms per loop
>>> a = []
>>> %timeit for x in xrange(N): a.append(None)
10 loops, best of 3: 85.6 ms per loop
Но изменение размера не очень медленно, если у вас нет очень больших списков. Вместо инициализации списка одним элементом (например, None
) и фиксированной длиной, чтобы избежать изменения размера списка, вам следует рассмотреть возможность использования списков и непосредственно заполнить список правильными значениями. Например:
>>> %timeit a = [x**2 for x in xrange(N)]
10 loops, best of 3: 109 ms per loop
>>> def fill_list1():
"""Not too bad, but complicated code"""
a = [None] * N
for x in xrange(N):
a[x] = x**2
>>> %timeit fill_list1()
10 loops, best of 3: 126 ms per loop
>>> def fill_list2():
"""This is slow, use only for small lists"""
a = []
for x in xrange(N):
a.append(x**2)
>>> %timeit fill_list2()
10 loops, best of 3: 177 ms per loop
Для огромного набора данных numpy или других оптимизированных библиотек выполняется намного быстрее:
from numpy import ndarray, zeros
%timeit empty((N,))
1000000 loops, best of 3: 788 ns per loop
%timeit zeros((N,))
100 loops, best of 3: 3.56 ms per loop
Вы можете сделать это:
verts = list(xrange(1000))
Это даст вам список из 1000 элементов в размере и который будет инициализирован со значениями от 0 до 999. Поскольку list
делает a __len__
первым, чтобы изменить размер нового списка, он должен быть достаточно эффективным.
Вам следует использовать тип dict
вместо предварительно инициализированного списка. Стоимость поиска в словарях мала и сопоставима со стоимостью доступа к произвольному элементу списка.
И при использовании сопоставления вы можете написать:
aDict = {}
aDict[100] = fetchElement()
putElement(fetchElement(), fetchPosition(), aDict)
И функция putElement
может хранить элемент в любой заданной позиции. И если вам нужно проверить, содержит ли ваша коллекция элемент по заданному индексу, более питонов написать:
if anIndex in aDict:
print "cool!"
Чем:
if not myList[anIndex] is None:
print "cool!"
Поскольку последний предполагает, что никакой реальный элемент в вашей коллекции не может быть None
. И если это произойдет - ваш код неправильно.
И если вам отчаянно нужна производительность и почему вы пытаетесь предварительно инициализировать свои переменные и записываете самый быстрый код - измените свой язык. Самый быстрый код не может быть написан на Python. Вы должны попробовать C вместо этого и реализовать оболочки для вызова вашего предварительно инициализированного и предварительно скомпилированного кода из Python.
Это:
list = [8 for i in range(9)]
создает список, элементы инициализируются 8
но это:
list = [0] * 7
создаст 7 списков, у которых есть один элемент
Не зная больше о проблемной области, трудно ответить на ваш вопрос. Если вы не уверены, что вам нужно сделать что-то еще, питонический способ инициализации списка:
verts = []
Вы действительно видите проблему с производительностью? Если да, то каково узкое место в производительности? Не пытайтесь решить проблему, которой у вас нет. Вероятно, что производительность для динамического заполнения массива до 1000 элементов полностью неактуальна для программы, которую вы действительно пытаетесь написать.
Класс массива полезен, если вещи в вашем списке всегда будут конкретным примитивным типом фиксированной длины (например, char, int, float). Но это также не требует предварительной инициализации.