Der pythonische Weg dafür ist:
x = [None] * numElements
oder welchen Standardwert Sie vorab bearbeiten möchten, z
bottles = [Beer()] * 99
sea = [Fish()] * many
vegetarianPizzas = [None] * peopleOrderingPizzaNotQuiche
[EDIT: Caveat Emptor Die [Beer()] * 99
Syntax erstellt eine Beer
und füllt dann ein Array mit 99 Verweisen auf dieselbe einzelne Instanz.]
Der Standardansatz von Python kann ziemlich effizient sein, obwohl diese Effizienz abnimmt, wenn Sie die Anzahl der Elemente erhöhen.
Vergleichen Sie
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)
mit
#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);
}
Auf meinem Windows 7 i7 gibt es 64-Bit-Python
Elements: 100000, Iterations: 144
doAppend: 3587.204933ms
doAllocate: 2701.154947ms
doGenerator: 1721.098185ms
Während C ++ bietet (erstellt mit MSVC, 64-Bit, Optimierungen aktiviert)
Elements: 100000, Iterations: 144
doAppend: 74.0042ms
doReserve: 27.0015ms
doAllocate: 5.0003ms
C ++ - Debugbuild erzeugt:
Elements: 100000, Iterations: 144
doAppend: 2166.12ms
doReserve: 2082.12ms
doAllocate: 273.016ms
Der Punkt hier ist, dass Sie mit Python eine Leistungsverbesserung von 7-8% erzielen können, und wenn Sie denken, dass Sie eine Hochleistungs-App schreiben (oder wenn Sie etwas schreiben, das in einem Webdienst oder etwas verwendet wird), dann Das ist nicht zu übersehen, aber Sie müssen möglicherweise Ihre Sprachwahl überdenken.
Außerdem ist der Python-Code hier nicht wirklich Python-Code. Wenn Sie hier zu wirklich pythoneskem Code wechseln, erhalten Sie eine bessere Leistung:
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)
Welches gibt
Elements: 100000, Iterations: 144
doAppend: 2153.122902ms
doAllocate: 1346.076965ms
doGenerator: 1614.092112ms
(In 32-Bit ist doGenerator besser als doAllocate).
Hier ist die Lücke zwischen doAppend und doAllocate deutlich größer.
Offensichtlich gelten die Unterschiede hier wirklich nur, wenn Sie dies mehr als ein paar Mal tun oder wenn Sie dies auf einem stark belasteten System tun, auf dem diese Zahlen um Größenordnungen skaliert werden, oder wenn Sie es zu tun haben erheblich größere Listen.
Der Punkt hier: Machen Sie es auf pythonische Weise für die beste Leistung.
Wenn Sie sich jedoch Sorgen um die allgemeine Leistung auf hohem Niveau machen, ist Python die falsche Sprache. Das grundlegendste Problem besteht darin, dass Python-Funktionsaufrufe aufgrund von Python-Funktionen wie Dekoratoren usw. ( https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ) traditionell bis zu 300-mal langsamer waren als andere Sprachen .