Cách Pythonic cho việc này là:
x = [None] * numElements
hoặc bất kỳ giá trị mặc định nào bạn muốn chuẩn bị trước, vd
bottles = [Beer()] * 99
sea = [Fish()] * many
vegetarianPizzas = [None] * peopleOrderingPizzaNotQuiche
[EDIT: Caveat Emptor Các [Beer()] * 99
cú pháp tạo ra một Beer
và sau đó populates một mảng với sự tham khảo 99 đến trường hợp duy nhất cùng]
Cách tiếp cận mặc định của Python có thể khá hiệu quả, mặc dù hiệu quả đó giảm dần khi bạn tăng số lượng phần tử.
Đối chiếu
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)
với
#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);
}
Trên Windows 7 i7 của tôi, Python 64 bit cho
Elements: 100000, Iterations: 144
doAppend: 3587.204933ms
doAllocate: 2701.154947ms
doGenerator: 1721.098185ms
Trong khi C ++ cung cấp (được xây dựng với MSVC, 64 bit, bật Tối ưu hóa)
Elements: 100000, Iterations: 144
doAppend: 74.0042ms
doReserve: 27.0015ms
doAllocate: 5.0003ms
Bản dựng gỡ lỗi C ++ tạo ra:
Elements: 100000, Iterations: 144
doAppend: 2166.12ms
doReserve: 2082.12ms
doAllocate: 273.016ms
Vấn đề ở đây là với Python, bạn có thể đạt được cải thiện hiệu suất 7-8% và nếu bạn nghĩ rằng bạn đang viết một ứng dụng hiệu suất cao (hoặc nếu bạn đang viết một cái gì đó được sử dụng trong dịch vụ web hoặc một cái gì đó) thì điều đó không được đánh hơi, nhưng bạn có thể cần suy nghĩ lại về lựa chọn ngôn ngữ của mình.
Ngoài ra, mã Python ở đây không thực sự là mã Python. Chuyển sang mã Pythonesque thực sự ở đây cho hiệu suất tốt hơn:
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)
Mà cho
Elements: 100000, Iterations: 144
doAppend: 2153.122902ms
doAllocate: 1346.076965ms
doGenerator: 1614.092112ms
(trong 32-bit doGenerator làm tốt hơn do Allocate).
Ở đây, khoảng cách giữa doAppend và do Allocate lớn hơn đáng kể.
Rõ ràng, sự khác biệt ở đây thực sự chỉ áp dụng nếu bạn đang thực hiện việc này nhiều hơn một vài lần hoặc nếu bạn đang thực hiện việc này trên một hệ thống tải nặng, nơi những con số đó sẽ được thu nhỏ theo các đơn đặt hàng lớn hoặc nếu bạn đang xử lý danh sách lớn hơn đáng kể.
Vấn đề ở đây: Làm theo cách pythonic để có hiệu suất tốt nhất.
Nhưng nếu bạn lo lắng về hiệu suất chung, cấp cao, Python là ngôn ngữ sai. Vấn đề cơ bản nhất là các lệnh gọi hàm Python có truyền thống chậm hơn tới 300 lần so với các ngôn ngữ khác do các tính năng của Python như trang trí, v.v ( https://wiki.python.org/moin/PythonSpeed/PerformanceTips#Data_Aggregation#Data_Aggregation ).