Пітонічний шлях для цього:
x = [None] * numElements
або будь-яке значення за замовчуванням, яке ви хочете доповнити, наприклад
bottles = [Beer()] * 99
sea = [Fish()] * many
vegetarianPizzas = [None] * peopleOrderingPizzaNotQuiche
[EDIT: Caveat Emptor[Beer()] * 99
синтаксис створює один Beer
, а потім заповнює масив з 99 посиланнями на той же єдиний екземпляр]
Підхід Python за замовчуванням може бути досить ефективним, хоча ця ефективність зменшується у міру збільшення кількості елементів.
Порівняйте
import time
class Timer(object):
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
end = time.time()
secs = end - self.start
msecs = secs * 1000 # millisecs
print('%fms' % msecs)
Elements = 100000
Iterations = 144
print('Elements: %d, Iterations: %d' % (Elements, Iterations))
def doAppend():
result = []
i = 0
while i < Elements:
result.append(i)
i += 1
def doAllocate():
result = [None] * Elements
i = 0
while i < Elements:
result[i] = i
i += 1
def doGenerator():
return list(i for i in range(Elements))
def test(name, fn):
print("%s: " % name, end="")
with Timer() as t:
x = 0
while x < Iterations:
fn()
x += 1
test('doAppend', doAppend)
test('doAllocate', doAllocate)
test('doGenerator', doGenerator)
з
#include <vector>
typedef std::vector<unsigned int> Vec;
static const unsigned int Elements = 100000;
static const unsigned int Iterations = 144;
void doAppend()
{
Vec v;
for (unsigned int i = 0; i < Elements; ++i) {
v.push_back(i);
}
}
void doReserve()
{
Vec v;
v.reserve(Elements);
for (unsigned int i = 0; i < Elements; ++i) {
v.push_back(i);
}
}
void doAllocate()
{
Vec v;
v.resize(Elements);
for (unsigned int i = 0; i < Elements; ++i) {
v[i] = i;
}
}
#include <iostream>
#include <chrono>
using namespace std;
void test(const char* name, void(*fn)(void))
{
cout << name << ": ";
auto start = chrono::high_resolution_clock::now();
for (unsigned int i = 0; i < Iterations; ++i) {
fn();
}
auto end = chrono::high_resolution_clock::now();
auto elapsed = end - start;
cout << chrono::duration<double, milli>(elapsed).count() << "ms\n";
}
int main()
{
cout << "Elements: " << Elements << ", Iterations: " << Iterations << '\n';
test("doAppend", doAppend);
test("doReserve", doReserve);
test("doAllocate", doAllocate);
}
У моєму Windows 7 i7 64-розрядний Python дає
Elements: 100000, Iterations: 144
doAppend: 3587.204933ms
doAllocate: 2701.154947ms
doGenerator: 1721.098185ms
У той час як C ++ дає (побудований з MSVC, 64-розрядні, увімкнено оптимізацію)
Elements: 100000, Iterations: 144
doAppend: 74.0042ms
doReserve: 27.0015ms
doAllocate: 5.0003ms
Збірка налагодження C ++ виробляє:
Elements: 100000, Iterations: 144
doAppend: 2166.12ms
doReserve: 2082.12ms
doAllocate: 273.016ms
Сенс у тому, що за допомогою Python ви можете досягти 7-8% підвищення продуктивності, і якщо ви думаєте, що пишете високоефективний додаток (або якщо ви пишете те, що використовується у веб-службі чи щось), то це не слід нюхати, але вам може знадобитися переосмислити свій вибір мови.
Також код Python тут насправді не є кодом Python. Перехід на справді пітонський код дає кращі показники:
import time
class Timer(object):
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
end = time.time()
secs = end - self.start
msecs = secs * 1000 # millisecs
print('%fms' % msecs)
Elements = 100000
Iterations = 144
print('Elements: %d, Iterations: %d' % (Elements, Iterations))
def doAppend():
for x in range(Iterations):
result = []
for i in range(Elements):
result.append(i)
def doAllocate():
for x in range(Iterations):
result = [None] * Elements
for i in range(Elements):
result[i] = i
def doGenerator():
for x in range(Iterations):
result = list(i for i in range(Elements))
def test(name, fn):
print("%s: " % name, end="")
with Timer() as t:
fn()
test('doAppend', doAppend)
test('doAllocate', doAllocate)
test('doGenerator', doGenerator)
Що дає
Elements: 100000, Iterations: 144
doAppend: 2153.122902ms
doAllocate: 1346.076965ms
doGenerator: 1614.092112ms
(у 32-бітному doGenerator краще, ніж у doAllocate).
Тут розрив між doAppend і doAllocate значно більший.
Очевидно, що різниці тут дійсно застосовуються лише в тому випадку, якщо ви робите це більше кількох разів, або якщо ви робите це в сильно завантаженій системі, де ці цифри будуть зменшені на порядок, або якщо ви маєте справу з значно більші списки.
Суть у цьому: Зробіть це пітонічним шляхом для найкращого виконання.
Але якщо ви турбуєтесь про загальну продуктивність на високому рівні, Python - це неправильна мова. Найбільш фундаментальною проблемою є те, що виклики функції Python традиційно піднімаються на 300 разів повільніше, ніж інші мови через функції Python, такі як декоратори тощо ( https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ).