Cara Pythonic untuk ini adalah:
x = [None] * numElements
atau nilai default apa pun yang ingin Anda siapkan, mis
bottles = [Beer()] * 99
sea = [Fish()] * many
vegetarianPizzas = [None] * peopleOrderingPizzaNotQuiche
[EDIT: Caveat Emptor The [Beer()] * 99
sintaks menciptakan satu Beer
dan kemudian Mempopulai sebuah array dengan referensi 99 untuk satu contoh yang sama]
Pendekatan default Python bisa sangat efisien, meskipun efisiensi itu meluruh ketika Anda meningkatkan jumlah elemen.
Membandingkan
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)
dengan
#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);
}
Pada Windows 7 i7 saya, Python 64-bit memberi
Elements: 100000, Iterations: 144
doAppend: 3587.204933ms
doAllocate: 2701.154947ms
doGenerator: 1721.098185ms
Sementara C ++ memberi (dibangun dengan MSVC, 64-bit, Pengoptimalan diaktifkan)
Elements: 100000, Iterations: 144
doAppend: 74.0042ms
doReserve: 27.0015ms
doAllocate: 5.0003ms
C ++ debug build menghasilkan:
Elements: 100000, Iterations: 144
doAppend: 2166.12ms
doReserve: 2082.12ms
doAllocate: 273.016ms
Intinya di sini adalah bahwa dengan Python Anda dapat mencapai peningkatan kinerja 7-8%, dan jika Anda berpikir Anda sedang menulis aplikasi berkinerja tinggi (atau jika Anda sedang menulis sesuatu yang digunakan dalam layanan web atau sesuatu) maka itu tidak bisa diendus, tetapi Anda mungkin perlu memikirkan kembali pilihan bahasa Anda.
Juga, kode Python di sini bukan kode Python. Beralih ke kode Pythonesque yang sesungguhnya di sini memberikan kinerja yang lebih baik:
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)
Pemberian yang mana
Elements: 100000, Iterations: 144
doAppend: 2153.122902ms
doAllocate: 1346.076965ms
doGenerator: 1614.092112ms
(dalam doGenerator 32-bit lebih baik daripada doAllocate).
Di sini kesenjangan antara doAppend dan doAllocate secara signifikan lebih besar.
Jelas, perbedaan di sini benar-benar hanya berlaku jika Anda melakukan ini lebih dari beberapa kali atau jika Anda melakukan ini pada sistem yang sarat dengan beban di mana angka-angka itu akan diperkecil oleh urutan besarnya, atau jika Anda berurusan dengan daftar jauh lebih besar.
Intinya di sini: Lakukan dengan cara pythonic untuk kinerja terbaik.
Tetapi jika Anda khawatir tentang kinerja tingkat tinggi yang umum, Python adalah bahasa yang salah. Masalah yang paling mendasar adalah bahwa panggilan fungsi Python secara tradisional lebih lambat hingga 300x daripada bahasa lain karena fitur Python seperti dekorator dll ( https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ).