คลาสสตริง Python เช่น StringBuilder ใน C #?


121

มีคลาสสตริงใน Python เหมือนStringBuilderใน C # หรือไม่?


6
นี่คือที่ซ้ำกันของงูหลามเทียบเท่า Java StringBuffer ข้อควรระวัง: คำตอบในที่นี้ล้าสมัยและในความเป็นจริงแล้วอาจทำให้เข้าใจผิดได้ ดูคำถามอื่นสำหรับคำตอบที่เกี่ยวข้องกับ Python เวอร์ชันใหม่ ๆ (แน่นอนว่า 2.7 ขึ้นไป)
Jean-François Corbett

คำตอบ:


102

ไม่มีความสัมพันธ์แบบหนึ่งต่อหนึ่ง สำหรับบทความที่ดีจริงๆโปรดดูการต่อสตริงที่มีประสิทธิภาพใน Python :

การสร้างสตริงที่ยาวในภาษา Python progamming บางครั้งอาจส่งผลให้โค้ดทำงานช้ามาก ในบทความนี้ฉันตรวจสอบประสิทธิภาพการคำนวณของวิธีการต่อสายอักขระต่างๆ


27
โปรดทราบว่าบทความนี้เขียนโดยใช้ Python 2.2 การทดสอบน่าจะออกมาแตกต่างกันบ้างใน Python เวอร์ชันใหม่ (โดยปกติแล้ว CPython จะเพิ่มประสิทธิภาพการเรียงต่อกันได้สำเร็จ แต่คุณไม่ต้องการขึ้นอยู่กับสิ่งนี้ในรหัสที่สำคัญ) และนิพจน์ตัวสร้างที่เขาใช้ความเข้าใจในรายการจะเป็นสิ่งที่ควรค่าแก่การพิจารณา .
Mike Graham

4
จะเป็นการดีที่จะดึงเอาจุดเด่นบางอย่างในบทความนั้นมาใช้อย่างน้อยสองอย่าง (เพื่อหลีกเลี่ยงปัญหาลิงค์เน่า)
jpmc26

3
วิธีที่ 1: resultString + = appendString เร็วที่สุดตามการทดสอบโดย @ Antoine-tran ด้านล่าง
Justas

5
คำพูดของคุณไม่สามารถตอบคำถามได้เลย โปรดระบุส่วนที่เกี่ยวข้องในคำตอบของคุณเองเพื่อให้เป็นไปตามหลักเกณฑ์ใหม่
คดีของ Fund Monica

27

ฉันใช้รหัสของ Oliver Crow (ลิงก์ที่ให้โดย Andrew Hare) และปรับแต่งเล็กน้อยเพื่อปรับแต่ง Python 2.7.3 (โดยใช้แพ็คเกจ timeit) ฉันใช้คอมพิวเตอร์ส่วนบุคคล Lenovo T61, RAM 6GB, Debian GNU / Linux 6.0.6 (บีบ)

นี่คือผลลัพธ์สำหรับการทำซ้ำ 10,000 ครั้ง:

method1: 0.0538418292999 วินาที
ขนาดกระบวนการ 4800 kb
method2: 0.22602891922 วินาที
ขนาดกระบวนการ 4960 kb
วิธีที่ 3: 0.0605459213257 วินาที
ขนาดกระบวนการ 4980 kb
method4: 0.0544030666351 วินาที
ขนาดกระบวนการ 5536 kb
method5: 0.0551080703735 วินาที
ขนาดกระบวนการ 5272 kb
method6: 0.0542731285095 วินาที
ขนาดกระบวนการ 5512 kb

และสำหรับการทำซ้ำ 5,000,000 ครั้ง (วิธีที่ 2 ถูกละเว้นเพราะมันทำงานช้าเกินไปเช่นตลอดไป):

method1: 5.88603997231 วินาที
ขนาดกระบวนการ 37976 kb
method3: 8.40748500824 วินาที
ขนาดกระบวนการ 38024 kb
วิธี 4: 7.96380496025 วินาที
ขนาดกระบวนการ 321968 kb
method5: 8.03666186333 วินาที
ขนาดกระบวนการ 71720 kb
method6: 6.68192911148 วินาที
ขนาดกระบวนการ 38240 kb

ค่อนข้างชัดเจนว่าพวก Python ทำงานได้ดีมากในการเพิ่มประสิทธิภาพการต่อสายอักขระและอย่างที่ Hoare กล่าวว่า: "การเพิ่มประสิทธิภาพก่อนกำหนดเป็นรากเหง้าของความชั่วร้ายทั้งหมด" :-)


2
เห็นได้ชัดว่า Hoare ไม่ยอมรับว่า: hans.gerwitz.com/2004/08/12/…
Pimin Konstantin Kefaloukos

5
ไม่ใช่การปรับให้เหมาะสมก่อนกำหนดเพื่อหลีกเลี่ยงการเพิ่มประสิทธิภาพที่เปราะบางขึ้นอยู่กับล่าม หากคุณต้องการพอร์ตไปยัง PyPy หรือเสี่ยงต่อการกดปุ่มหนึ่งในหลาย ๆ กรณีความล้มเหลวที่ละเอียดอ่อนสำหรับการเพิ่มประสิทธิภาพให้ทำสิ่งต่างๆให้ถูกต้อง
Veedrac

1
ดูเหมือนว่าวิธีที่ 1 จะง่ายกว่าสำหรับคอมไพลเลอร์ในการปรับให้เหมาะสม
mbomb007

25

การอาศัยการปรับแต่งคอมไพลเลอร์นั้นเปราะบาง เกณฑ์มาตรฐานที่เชื่อมโยงในคำตอบที่ยอมรับและตัวเลขที่ Antoine-tran ให้ไว้ไม่น่าเชื่อถือ แอนดรูแฮร์ทำผิดพลาดในการรวมการเรียกร้องreprในวิธีการของเขา นั่นทำให้วิธีการทั้งหมดช้าลงเท่า ๆ กัน แต่บดบังโทษที่แท้จริงในการสร้างสตริง

ใช้join. มันเร็วมากและแข็งแกร่งมากขึ้น

$ 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

ใช่การreprโทรเข้าครอบงำรันไทม์ แต่ไม่จำเป็นต้องทำให้ความผิดพลาดเป็นเรื่องส่วนตัว
Alex Reinking

3
@AlexReinking ขอโทษไม่มีความหมายส่วนตัว ฉันไม่แน่ใจว่าอะไรทำให้คุณคิดว่ามันเป็นเรื่องส่วนตัว แต่ถ้าเป็นการใช้ชื่อของพวกเขาฉันจะใช้ชื่อเหล่านั้นเพื่ออ้างถึงคำตอบของผู้ใช้เท่านั้น (ตรงกับชื่อผู้ใช้ไม่แน่ใจว่ามีวิธีที่ดีกว่านี้หรือไม่)
GrantJ

1
ตัวอย่างเวลาที่ดีที่แยกการเริ่มต้นข้อมูลและการดำเนินการต่อ
aiodintsov

19

Python มีหลายสิ่งที่ตอบสนองวัตถุประสงค์ที่คล้ายกัน:

  • วิธีหนึ่งทั่วไปในการสร้างสตริงขนาดใหญ่จากชิ้นส่วนคือการเพิ่มรายชื่อสตริงและเข้าร่วมเมื่อคุณทำเสร็จแล้ว นี่คือสำนวน Python ที่ใช้บ่อย
    • ในการสร้างสตริงที่รวมข้อมูลเข้ากับการจัดรูปแบบคุณจะต้องจัดรูปแบบแยกกัน
  • สำหรับการแทรกและการลบในระดับอักขระคุณจะต้องเก็บรายการสตริงที่มีความยาว 1 บรรทัด (หากต้องการสร้างสิ่งนี้จากสตริงคุณจะโทรหาlist(your_string)คุณยังสามารถใช้ a UserString.MutableStringสำหรับสิ่งนี้
  • (c)StringIO.StringIO มีประโยชน์สำหรับสิ่งที่อาจใช้ไฟล์ แต่น้อยกว่านั้นสำหรับการสร้างสตริงทั่วไป

10

ใช้วิธีที่ 5 จากด้านบน (ไฟล์ Pseudo) เราจะได้รับความสมบูรณ์แบบและความยืดหยุ่นที่ดีมาก

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()

ตอนนี้ใช้มัน

sb = StringBuilder()

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

print sb


-1

ไม่มีอะนาล็อกที่ชัดเจน - ฉันคิดว่าคุณคาดว่าจะใช้การต่อสตริง (น่าจะได้รับการปรับให้เหมาะสมตามที่กล่าวไว้ก่อนหน้านี้) หรือคลาสของบุคคลที่สาม (ฉันสงสัยว่ามันมีประสิทธิภาพมากกว่ามาก - รายการใน python เป็นแบบไดนามิกจึงไม่ทำงานอย่างรวดเร็ว ถ่าน [] สำหรับบัฟเฟอร์ตามที่ฉันคิด) คลาสที่เหมือน Stringbuilder ไม่ใช่การปรับให้เหมาะสมก่อนเวลาอันควรเนื่องจากคุณลักษณะโดยกำเนิดของสตริงในหลายภาษา (ไม่เปลี่ยนรูปแบบ) ซึ่งอนุญาตให้มีการปรับให้เหมาะสมได้หลายแบบ (ตัวอย่างเช่นการอ้างอิงบัฟเฟอร์เดียวกันสำหรับชิ้นส่วน / สตริงย่อย) Stringbuilder / stringbuffer / stringstream-like คลาสทำงานได้เร็วกว่าการต่อสตริง (สร้างอ็อบเจ็กต์ชั่วคราวขนาดเล็กจำนวนมากที่ยังต้องการการจัดสรรและการรวบรวมขยะ) และแม้แต่การจัดรูปแบบสตริงเครื่องมือที่เหมือน printf โดยไม่จำเป็นต้องตีความค่าใช้จ่ายในการจัดรูปแบบรูปแบบที่ค่อนข้างใช้เวลานาน มีรูปแบบการโทรมากมาย


-4

ในกรณีที่คุณกำลังมองหาวิธีการต่อสายอักขระที่รวดเร็วใน Python คุณไม่จำเป็นต้องมีคลาส StringBuilder พิเศษ การเชื่อมต่อแบบง่ายก็ใช้ได้เช่นกันโดยไม่มีการลงโทษด้านประสิทธิภาพที่เห็นใน C #

resultString = ""

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

ดูคำตอบของ Antoine-tranสำหรับผลลัพธ์ด้านประสิทธิภาพ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.