Lớp chuỗi Python như StringBuilder trong C #?


121

Có một số lớp chuỗi trong Python giống như StringBuildertrong C # không?


6
Đây là bản sao của Python tương đương với Java StringBuffer . THẬN TRỌNG: Các câu trả lời ở đây đã lỗi thời và trên thực tế đã trở nên sai lệch. Xem câu hỏi khác để biết câu trả lời phù hợp hơn với các phiên bản Python hiện đại (chắc chắn là 2.7 trở lên).
Jean-François Corbett

Câu trả lời:


102

Không có mối tương quan 1-1. Để có một bài viết thực sự hay, vui lòng xem Kết nối chuỗi hiệu quả trong Python :

Việc xây dựng các chuỗi dài bằng ngôn ngữ lập trình Python đôi khi có thể dẫn đến mã chạy rất chậm. Trong bài viết này, tôi điều tra hiệu suất tính toán của các phương pháp nối chuỗi khác nhau.


27
Lưu ý rằng bài viết này được viết dựa trên Python 2.2. Các bài kiểm tra có thể sẽ xuất hiện hơi khác trong phiên bản Python hiện đại (CPython thường tối ưu hóa thành công việc nối, nhưng bạn không muốn phụ thuộc vào điều này trong mã quan trọng) và biểu thức trình tạo trong đó anh ta sử dụng khả năng hiểu danh sách sẽ đáng được xem xét .
Mike Graham

4
Sẽ rất tốt nếu bạn đưa ra một số điểm nổi bật trong bài viết đó, ít nhất là một vài cách triển khai (để tránh các vấn đề về mục đích liên kết).
jpmc 26

3
Phương pháp 1: resultString + = appendString là nhanh nhất theo các bài kiểm tra của @ Antoine-tran dưới đây
Justas

5
Trích dẫn của bạn hoàn toàn không trả lời câu hỏi. Vui lòng bao gồm các phần có liên quan trong chính câu trả lời của bạn, để tuân thủ các nguyên tắc mới.
Fund Monica's Kiện vào

27

Tôi đã sử dụng mã của Oliver Crow (liên kết do Andrew Hare cung cấp) và điều chỉnh nó một chút để điều chỉnh Python 2.7.3. (bằng cách sử dụng gói thời gian). Tôi đã chạy trên máy tính cá nhân của mình, Lenovo T61, RAM 6GB, Debian GNU / Linux 6.0.6 (vắt kiệt).

Đây là kết quả cho 10.000 lần lặp:

method1: 0.0538418292999 giây
quy trình kích thước 4800 kb
method2: 0,22602891922 giây
quy trình kích thước 4960 kb
method3: 0.0605459213257 giây
quy trình kích thước 4980 kb
method4: 0.0544030666351 giây
quy trình kích thước 5536 kb
method5: 0.0551080703735 giây
quy trình kích thước 5272 kb
method6: 0.0542731285095 giây
quy trình kích thước 5512 kb

và đối với 5.000.000 lần lặp (phương pháp 2 đã bị bỏ qua vì nó chạy quá chậm, giống như mãi mãi):

method1: 5.88603997231 giây
kích thước quy trình 37976 kb
method3: 8.40748500824 giây
quy trình kích thước 38024 kb
method4: 7.96380496025 giây
kích thước quy trình 321968 kb
method5: 8.03666186333 giây
quy trình kích thước 71720 kb
method6: 6.68192911148 giây
quy trình kích thước 38240 kb

Rõ ràng là những người dùng Python đã làm rất tốt việc tối ưu hóa việc nối chuỗi và như Hoare đã nói: "tối ưu hóa quá sớm là gốc rễ của mọi điều xấu xa" :-)


2
Rõ ràng Hoare không chấp nhận điều đó: hans.gerwitz.com/2004/08/12/…
Pimin Konstantin Kefaloukos

5
Nó không phải là tối ưu hóa quá sớm để tránh tối ưu hóa mỏng manh, phụ thuộc vào thông dịch viên. Nếu bạn muốn chuyển sang PyPy hoặc có nguy cơ gặp phải một trong nhiều trường hợp thất bại tinh vi để tối ưu hóa, hãy làm mọi thứ đúng cách.
Veedrac

1
Có vẻ như Phương pháp 1 dễ tối ưu hóa hơn cho trình biên dịch.
mbomb007

24

Việc dựa vào tối ưu hóa trình biên dịch là điều mong manh. Các điểm chuẩn được liên kết trong câu trả lời được chấp nhận và các con số do Antoine-tran đưa ra không đáng tin cậy. Andrew Hare đã mắc sai lầm khi bao gồm một cuộc gọi đến reprtrong các phương thức của mình. Điều đó làm chậm tất cả các phương thức như nhau nhưng che khuất hình phạt thực sự trong việc xây dựng chuỗi.

Sử dụng join. Nó rất nhanh và mạnh mẽ hơn.

$ ipython3
Python 3.5.1 (default, Mar  2 2016, 03:38:02) 
IPython 4.1.2 -- An enhanced Interactive Python.

In [1]: values = [str(num) for num in range(int(1e3))]

In [2]: %%timeit
   ...: ''.join(values)
   ...: 
100000 loops, best of 3: 7.37 µs per loop

In [3]: %%timeit
   ...: result = ''
   ...: for value in values:
   ...:     result += value
   ...: 
10000 loops, best of 3: 82.8 µs per loop

In [4]: import io

In [5]: %%timeit
   ...: writer = io.StringIO()
   ...: for value in values:
   ...:     writer.write(value)
   ...: writer.getvalue()
   ...: 
10000 loops, best of 3: 81.8 µs per loop

Có, reprcuộc gọi chiếm ưu thế trong thời gian chạy, nhưng không cần phải mắc lỗi cá nhân.
Alex Reinking

3
@AlexReinking xin lỗi, không có ý nghĩa cá nhân. Tôi không chắc điều gì khiến bạn nghĩ đó là chuyện cá nhân. Nhưng nếu đó là việc sử dụng tên của họ, tôi chỉ sử dụng chúng để tham khảo câu trả lời của người dùng (khớp với tên người dùng, không chắc có cách nào tốt hơn không).
GrantJ

1
tốt thời gian ví dụ mà tách dữ liệu khởi tạo và nối hoạt động
aiodintsov

19

Python có một số thứ đáp ứng các mục đích tương tự:

  • Một cách phổ biến để xây dựng các chuỗi lớn từ các phần là phát triển một danh sách các chuỗi và nối nó khi bạn hoàn thành. Đây là một thành ngữ Python được sử dụng thường xuyên.
    • Để tạo chuỗi kết hợp dữ liệu với định dạng, bạn sẽ thực hiện định dạng riêng biệt.
  • Để chèn và xóa ở cấp độ ký tự, bạn sẽ giữ một danh sách các chuỗi có độ dài một. (Để thực hiện điều này từ một chuỗi, bạn sẽ gọi list(your_string). Bạn cũng có thể sử dụng một UserString.MutableStringcho điều này.
  • (c)StringIO.StringIO hữu ích cho những thứ khác sẽ lấy một tệp, nhưng ít hơn đối với việc xây dựng chuỗi chung.

10

Sử dụng phương pháp 5 từ trên (Tập tin giả), chúng ta có thể có được hiệu suất rất tốt và tính linh hoạt

from cStringIO import StringIO

class StringBuilder:
     _file_str = None

     def __init__(self):
         self._file_str = StringIO()

     def Append(self, str):
         self._file_str.write(str)

     def __str__(self):
         return self._file_str.getvalue()

bây giờ đang sử dụng nó

sb = StringBuilder()

sb.Append("Hello\n")
sb.Append("World")

print sb


-1

Không có tương tự rõ ràng - tôi nghĩ bạn dự kiến ​​sẽ sử dụng nối chuỗi (có thể được tối ưu hóa như đã nói trước đây) hoặc lớp của bên thứ ba (tôi nghi ngờ rằng chúng hiệu quả hơn nhiều - danh sách trong python được nhập động nên không hoạt động nhanh char [] cho bộ đệm như tôi giả định). Các lớp giống như trình xây dựng chuỗi không phải là tối ưu hóa sớm vì tính năng bẩm sinh của chuỗi trong nhiều ngôn ngữ (tính bất biến) - cho phép nhiều tối ưu hóa (ví dụ, tham chiếu cùng một bộ đệm cho các lát / chuỗi con). Các lớp giống như Stringbuilder / stringbuffer / stringstream hoạt động nhanh hơn rất nhiều so với việc nối các chuỗi (tạo ra nhiều đối tượng tạm thời nhỏ vẫn cần phân bổ và thu gom rác) và thậm chí các công cụ giống như printf định dạng chuỗi, không cần thông dịch chi phí mẫu định dạng khá tốn rất nhiều cuộc gọi định dạng.


-4

Trong trường hợp bạn đang tìm kiếm một phương pháp nối chuỗi nhanh trong Python, thì bạn không cần một lớp StringBuilder đặc biệt. Việc nối đơn giản cũng hoạt động mà không bị phạt hiệu suất như trong C #.

resultString = ""

resultString += "Append 1"
resultString += "Append 2"

Xem câu trả lời của Antoine-tran để biết kết quả hoạt động

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.