2010-02-24 28 views
5

Có một thành ngữ phổ biến để tránh vô nghĩa sao chép lát đối với trường hợp như thế này:Tránh sao chép lát không cần thiết trong Python

>>> a = bytearray(b'hello') 
>>> b = bytearray(b'goodbye, cruel world.') 
>>> a.extend(b[14:20]) 
>>> a 
bytearray(b'hello world') 

Dường như với tôi rằng có một bản sao không cần thiết xảy ra khi lát b[14:20] được tạo ra. Thay vì tạo một lát mới trong bộ nhớ để cung cấp cho extend Tôi muốn nói "chỉ sử dụng phạm vi này của đối tượng hiện tại".

Một số phương pháp này sẽ giúp bạn ra ngoài với các thông số lát, ví dụ count:

>>> a = bytearray(1000000)  # a million zero bytes 
>>> a[0:900000].count(b'\x00') # expensive temporary slice 
900000 
>>> a.count(b'\x00', 0, 900000) # helpful start and end parameters 
900000 

nhưng với nhiều người, như extend trong ví dụ đầu tiên của tôi, không có tính năng này.

Tôi nhận ra rằng đối với nhiều ứng dụng tôi đang nói đến sẽ là tối ưu hóa vi mô, vì vậy trước khi có ai đó hỏi - vâng, tôi đã lược tả đơn đăng ký của mình và điều đáng lo ngại cho trường hợp của tôi.

Tôi có một 'giải pháp' bên dưới, nhưng mọi ý tưởng hay hơn đều được chào đón nhiều nhất.

Trả lời

5

Tạo một đối tượng buffer tránh sao chép lát, nhưng đối với những lát ngắn nó hiệu quả hơn để chỉ cần thực hiện sao chép:

>>> a.extend(buffer(b, 14, 6)) 
>>> a 
bytearray(b'hello world') 

Ở đây chỉ có một bản sao làm bằng ký ức, nhưng chi phí của việc tạo ra các buffer đối tượng nhiều hơn xóa bỏ việc tiết kiệm. Nó nên được tốt hơn cho lát lớn hơn mặc dù. Tôi không chắc chắn về độ lớn của slice để phương pháp này hiệu quả hơn.

Lưu ý rằng cho Python 3 (và tùy chọn bằng Python 2.7) bạn cần một đối tượng memoryview thay vì:

>>> a.extend(memoryview(b)[14:20]) 
+0

bộ đệm là lựa chọn tốt cho các đối tượng hỗ trợ giao diện đệm. Thông thường nó không có giá trị vỏ đặc biệt cho các trường hợp nhỏ (trừ khi hầu hết các trường hợp sử dụng của bạn là nhỏ) vì 50% nhiều hơn một số lượng nhỏ vẫn là một số lượng nhỏ –

2

itertoolsislice. islice không có phương thức đếm vì vậy nó rất hữu ích trong các trường hợp khác mà bạn muốn tránh sao chép slice. Như bạn đã chỉ ra - số liệu có cơ chế cho điều đó anyway

>>> from itertools import islice 
>>> a = bytearray(1000000) 
>>> sum(1 for x in islice(a,0,900000) if x==0) 
900000 
>>> len(filter(b'\x00'.__eq__,islice(a,0,900000))) 
900000 

>>> a=bytearray(b"hello") 
>>> b = bytearray(b'goodbye, cruel world.') 
>>> a.extend(islice(b,14,20)) 
>>> a 
bytearray(b'hello world') 
+0

'islice' là một lựa chọn tốt đẹp. Tôi đã thực hiện một số bài kiểm tra nhanh và có vẻ nhanh như 'buffer' khi được sử dụng với' extend', tuy nhiên chúng chậm hơn * nhiều * so với chỉ sử dụng một slice, thậm chí với nửa triệu phần tử ... –

Các vấn đề liên quan