การฝึกสตริง Python


92

แม้ว่าคำถามนี้จะไม่มีการใช้งานจริงในทางปฏิบัติ แต่ฉันก็อยากรู้ว่า Python ใช้งานสตริงได้อย่างไร ฉันสังเกตเห็นสิ่งต่อไปนี้

>>> "string" is "string"
True

นี่เป็นไปตามที่ฉันคาดไว้

คุณยังสามารถทำได้

>>> "strin"+"g" is "string"
True

และนั่นก็ค่อนข้างฉลาด!

แต่คุณไม่สามารถทำได้

>>> s1 = "strin"
>>> s2 = "string"
>>> s1+"g" is s2
False

เหตุใด Python จึงไม่ประเมินs1+"g"และตระหนักว่ามันเหมือนกับs2และชี้ไปที่ที่อยู่เดียวกัน เกิดอะไรขึ้นในบล็อกสุดท้ายที่จะให้มันกลับมาFalse?

คำตอบ:


95

นี่เป็นเฉพาะการนำไปใช้งาน แต่ล่ามของคุณอาจกำลังอยู่ระหว่างค่าคงที่เวลาคอมไพล์ แต่ไม่ใช่ผลลัพธ์ของนิพจน์รันไทม์

ในสิ่งต่อไปนี้ฉันใช้ CPython 2.7.3

ในตัวอย่างที่สองการแสดงออกคือการประเมินที่รวบรวมเวลาและถูกแทนที่ด้วย"strin"+"g" "string"สิ่งนี้ทำให้สองตัวอย่างแรกมีพฤติกรรมเหมือนกัน

หากเราตรวจสอบ bytecodes เราจะเห็นว่าเหมือนกันทุกประการ:

  # s1 = "string"
  2           0 LOAD_CONST               1 ('string')
              3 STORE_FAST               0 (s1)

  # s2 = "strin" + "g"
  3           6 LOAD_CONST               4 ('string')
              9 STORE_FAST               1 (s2)

ตัวอย่างที่สามเกี่ยวข้องกับการต่อรันไทม์ซึ่งผลลัพธ์จะไม่ถูกควบคุมโดยอัตโนมัติ

  # s3a = "strin"
  # s3 = s3a + "g"
  4          12 LOAD_CONST               2 ('strin')
             15 STORE_FAST               2 (s3a)

  5          18 LOAD_FAST                2 (s3a)
             21 LOAD_CONST               3 ('g')
             24 BINARY_ADD          
             25 STORE_FAST               3 (s3)
             28 LOAD_CONST               0 (None)
             31 RETURN_VALUE        

หากคุณต้องการintern()ผลลัพธ์ของนิพจน์ที่สามด้วยตนเองคุณจะได้รับวัตถุเดิมเหมือนเดิม:

>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> intern(s3) is "string"
True

22
และสำหรับบันทึก: การเพิ่มประสิทธิภาพการมองลอดรู ธ จะคำนวณก่อนดำเนินการทางคณิตศาสตร์ในค่าคงที่ ( "string1" + "s2", 10 + 3*20ฯลฯ ) ที่รวบรวมเวลา แต่ข้อ จำกัด ที่เกิดวนเวียนอยู่เพียงแค่ 20 องค์ประกอบ (เพื่อป้องกัน [None] * 10**1000จากการขยายตัวมากเกินไป bytecode ของคุณ) มันคือการเพิ่มประสิทธิภาพที่ทรุด"strin" + "g"ลงไป"string"; ผลลัพธ์จะสั้นกว่า 20 อักขระ
Martijn Pieters

13
และเพื่อให้ชัดเจนเป็นทวีคูณ: ไม่มีการฝึกงานเกิดขึ้นที่นี่เลย ตัวอักษรที่ไม่เปลี่ยนรูปจะถูกเก็บเป็นค่าคงที่ด้วย bytecode แทน ฝึกงานไม่ใช้สถานที่สำหรับชื่อที่ใช้ในรหัส แต่ไม่ได้สำหรับค่าสตริงที่สร้างขึ้นโดยโปรแกรมเว้นแต่ฝึกงานโดยเฉพาะintern()ฟังก์ชั่น
Martijn Pieters

9
สำหรับผู้ที่พยายามค้นหาinternฟังก์ชันใน Python 3 - จะถูกย้ายไปที่sys.intern
Timofey Chernousov

1

กรณีที่ 1

>>> x = "123"  
>>> y = "123"  
>>> x == y  
True  
>>> x is y  
True  
>>> id(x)  
50986112  
>>> id(y)  
50986112  

กรณีที่ 2

>>> x = "12"
>>> y = "123"
>>> x = x + "3"
>>> x is y
False
>>> x == y
True

ตอนนี้คำถามของคุณคือเหตุผลที่ประชาชนได้เหมือนกันในกรณีที่ 1 และกรณีที่ไม่ได้อยู่ใน 2.
ในกรณีที่ 1 คุณได้กำหนดตัวอักษรสตริง"123"การและxy

เนื่องจากสตริงไม่เปลี่ยนรูปจึงเหมาะสมที่ล่ามจะเก็บสตริงลิเทอรัลเพียงครั้งเดียวและชี้ตัวแปรทั้งหมดไปที่อ็อบเจ็กต์เดียวกัน
ดังนั้นคุณจะเห็นว่า id เหมือนกัน

ในกรณีที่ 2 คุณกำลังแก้ไขxโดยใช้การเรียงต่อกัน ทั้งสองxและyมีค่าเหมือนกัน แต่ไม่มีเอกลักษณ์เหมือนกัน
ทั้งสองชี้ไปยังวัตถุที่แตกต่างกันในหน่วยความจำ ดังนั้นพวกเขาจึงแตกต่างกันidและisผู้ดำเนินการกลับFalse


เหตุใดเนื่องจากสตริงไม่เปลี่ยนรูปการกำหนด x + "3" (และการมองหาจุดใหม่เพื่อจัดเก็บสตริง) จึงไม่ได้กำหนดให้เป็นการอ้างอิงเดียวกับ y
nicecatch

เนื่องจากจำเป็นต้องเปรียบเทียบสตริงใหม่กับสตริงที่มีอยู่ทั้งหมด อาจเป็นการดำเนินการที่มีราคาแพงมาก มันสามารถทำได้ในพื้นหลังหลังจากมอบหมายงานที่ฉันคิดว่าเพื่อลดความจำ แต่แล้วคุณก็จะพบกับพฤติกรรมแปลก ๆid(x) != id(x)เช่นเนื่องจากสตริงถูกย้ายในกระบวนการประเมินผล
DylanYoung

1
@AndreaConte เนื่องจากการเชื่อมต่อสตริงไม่ได้ทำงานพิเศษในการค้นหาสตริงที่ใช้ทั้งหมดในแต่ละครั้งที่สร้างสตริงใหม่ ในทางกลับกันล่ามจะ "ปรับให้เหมาะสม" นิพจน์x = "12" + "3"เป็นx = "123"(การต่อกันของตัวอักษรสตริงสองตัวในนิพจน์เดียว) ดังนั้นการกำหนดจะทำการค้นหาและค้นหาสตริง "ภายใน" ที่เหมือนy = "123"กัน
derenio

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