Python ผนวก () กับ + ตัวดำเนินการในรายการทำไมสิ่งเหล่านี้จึงให้ผลลัพธ์ที่แตกต่างกัน?


113

ทำไมทั้งสองการดำเนินงาน ( append()resp. +) ให้ผลลัพธ์ที่แตกต่างกันอย่างไร

>>> c = [1, 2, 3]
>>> c
[1, 2, 3]
>>> c += c
>>> c
[1, 2, 3, 1, 2, 3]
>>> c = [1, 2, 3]
>>> c.append(c)
>>> c
[1, 2, 3, [...]]
>>> 

ในกรณีสุดท้ายมีการเรียกซ้ำไม่สิ้นสุด c[-1]และcเหมือนกัน ทำไมจึงแตกต่างกับการ+ดำเนินการ?


1
ด้วยเหตุผลทั้งหมดสำหรับคำถามใหม่ที่เป็นไปได้: ฉันย้อนกลับไปที่คำถามเดิมเพื่อรักษาความสะอาด (1 คำถามต่อเธรดดู SO FAQ) โปรดถามคำถามใหม่หรือถามคำถามติดตามในเธรดความคิดเห็นด้านล่างคำตอบแต่ละข้อ หมายเหตุ: การแก้ไขของคุณจะไม่สูญหายคลิกประวัติและคุณสามารถคัดลอก / วางลงในคำถามใหม่ได้
Abel


ดูเหมือนว่ามันจะให้ ans ต่างกัน แต่ไม่ใช่อย่างนั้น หากคุณต้องการเพิ่มค่าโดยใช้ + โอเปอเรเตอร์คุณมีเครื่องหมาย o ใช้ [] c + = [c] จะให้ผลลัพธ์เช่นเดียวกับการผนวก
Sharif Chowdhury

@SharifChowdhury ฉันเชื่อว่าคุณจะได้รับผลลัพธ์เดียวกัน
trustory

คำตอบ:


143

เพื่ออธิบายว่า "ทำไม":

การ+ดำเนินการจะเพิ่มองค์ประกอบอาร์เรย์ให้กับอาร์เรย์เดิม การarray.appendดำเนินการจะแทรกอาร์เรย์ (หรือวัตถุใด ๆ ) ลงในส่วนท้ายของอาร์เรย์เดิมซึ่งส่งผลให้มีการอ้างอิงถึงตัวเองในจุดนั้น (ดังนั้นการเรียกซ้ำไม่สิ้นสุด)

ความแตกต่างที่นี่คือการดำเนินการ + จะทำหน้าที่เฉพาะเมื่อคุณเพิ่มอาร์เรย์ (มันโอเวอร์โหลดเหมือนคนอื่น ๆ ดูบทนี้เกี่ยวกับลำดับ) โดยการต่อองค์ประกอบ อย่างไรก็ตาม append-method ทำในสิ่งที่คุณถามอย่างแท้จริง: ต่อท้ายวัตถุทางด้านขวามือที่คุณให้ (อาร์เรย์หรือวัตถุอื่น ๆ ) แทนที่จะใช้องค์ประกอบของมัน

ทางเลือก

ใช้extend()ถ้าคุณต้องการใช้ฟังก์ชันที่คล้ายกับตัวดำเนินการ + (ตามที่คนอื่น ๆ แสดงไว้ที่นี่เช่นกัน) ไม่ฉลาดที่จะทำในทางตรงกันข้าม: พยายามเลียนแบบการต่อท้ายด้วยตัวดำเนินการ + สำหรับรายการ (ดูลิงก์ก่อนหน้าของฉันเกี่ยวกับสาเหตุ)

ประวัติศาสตร์เล็กน้อย

เพื่อความสนุกสนานประวัติเล็ก ๆ น้อย ๆ : การกำเนิดของโมดูลอาร์เรย์ใน Pythonในเดือนกุมภาพันธ์ 1993 อาจทำให้คุณประหลาดใจ แต่อาร์เรย์ถูกเพิ่มเข้ามาหลังจากลำดับและรายการเริ่มมีอยู่จริง


2
+1 เพราะฉันให้คะแนนข้อมูลที่ถูกต้องเสมอ ลิงก์ไปยังเอกสารอย่างเป็นทางการเป็นข้อดีเสมอ!
jathanism

10
อีกส่วนหนึ่งของ "ทำไม": คนมีสติคาดหวังว่า+จะสมมาตร: รายการต่อเนื่องกับรายการ
Beni Cherniavsky-Paskin

1
+1, จุดดี Beni (ในขณะที่ฉันสามารถพิจารณาได้ว่า "มีเหตุผล" ที่จะพูดว่า "วัตถุที่อยู่ด้าน rh ถูกต่อท้ายอาร์เรย์ที่ด้าน lh" แต่โดยส่วนตัวแล้วพบว่าพฤติกรรมปัจจุบันเหมาะสมกว่า)
Abel

ถ้าองค์ประกอบเป็นสตริงเดียวเช่น s = 'word', l = ['this', 'is'] จากนั้น l.append (s) และ l + s ควรเหมือนกัน ฉันถูกไหม?
user3512680

23

ตัวดำเนินการเรียงต่อกัน+เป็นตัวดำเนินการอินฟิกซ์ไบนารีซึ่งเมื่อนำไปใช้กับรายการจะส่งคืนรายการใหม่ที่มีองค์ประกอบทั้งหมดของตัวถูกดำเนินการสองตัว list.append()วิธีการเป็นmutatorบนlistซึ่งผนวกเดียวobjectอาร์กิวเมนต์ (ในตัวอย่างของคุณโดยเฉพาะรายการc) listกับเรื่อง ในตัวอย่างของคุณผลลัพธ์นี้จะcเป็นการต่อท้ายการอ้างอิงถึงตัวมันเอง (ดังนั้นการเรียกซ้ำแบบไม่มีที่สิ้นสุด)

อีกทางเลือกหนึ่งสำหรับการเชื่อมต่อ '+'

list.extend()วิธีนี้ยังเป็นวิธี Mutator ซึ่งเชื่อมตนทะเลาะกับเรื่องsequence listโดยเฉพาะจะผนวกแต่ละองค์ประกอบของsequenceลำดับการวนซ้ำ

กัน

การเป็นตัวดำเนินการ+จะส่งคืนผลลัพธ์ของนิพจน์เป็นค่าใหม่ ในฐานะที่เป็นวิธีการที่ไม่ผูกมัดmutatorให้list.extend()แก้ไขรายการหัวเรื่องในสถานที่และไม่ส่งคืนอะไรเลย

อาร์เรย์

ฉันได้เพิ่มสิ่งนี้เนื่องจากความสับสนที่อาจเกิดขึ้นซึ่งคำตอบของ Abel ข้างต้นอาจเกิดจากการผสมผสานการอภิปรายของรายการลำดับและอาร์เรย์ Arraysถูกเพิ่มลงใน Python หลังจากลำดับและรายการซึ่งเป็นวิธีที่มีประสิทธิภาพมากขึ้นในการจัดเก็บอาร์เรย์ของชนิดข้อมูลอินทิกรัล อย่าสับสนกับarrays listsพวกเขาไม่เหมือนกัน

จากเอกสารอาร์เรย์ :

อาร์เรย์เป็นประเภทลำดับและทำงานคล้ายกับรายการมากยกเว้นว่าประเภทของวัตถุที่จัดเก็บอยู่ในนั้นมีข้อ จำกัด ชนิดถูกระบุในเวลาสร้างออบเจ็กต์โดยใช้รหัสชนิดซึ่งเป็นอักขระเดี่ยว


18

appendกำลังต่อท้ายองค์ประกอบในรายการ extendถ้าคุณต้องการที่จะขยายรายการที่มีรายการใหม่ที่คุณต้องใช้

>>> c = [1, 2, 3]
>>> c.extend(c)
>>> c
[1, 2, 3, 1, 2, 3]

4
ฉันคิดว่ามันค่อนข้างชัดเจนว่าทำไมผลลัพธ์ถึงแตกต่างกันเพราะการดำเนินการไม่เหมือนกัน! หากสิ่งนั้นปรากฏขึ้น+และextendให้ผลลัพธ์ที่แตกต่างออกไปซึ่งเรามีบางอย่างที่ต้องคิด
SilentGhost

1
+1: ทำไมฉันถึงไม่ชอบคำถาม "ทำไม": appendและ+แตกต่างกัน นั่นเป็นเหตุผลว่าทำไม ฉันชอบคำตอบนี้เพราะเสนอสิ่งที่ทำที่เหมาะสมกว่า
ล็อต

ไซต์นี้ไม่เกี่ยวกับการตอบคำถามที่ถามใช่หรือไม่ มีคนถามว่าทำไม PHP ถึงเรียกว่า PHP และทำไม__lt__ไม่สามารถโอเวอร์โหลดใน Python ได้ (ปัจจุบันทำได้) ทำไมคำถามเป็นคำถามที่สำคัญที่สุด แต่มักจะเป็นคำถามที่ยากที่สุดในการตอบ: พวกเขาถามหาสาระสำคัญไม่ใช่เพื่อชี้ไปที่คู่มือ และแน่นอน: ถ้าคุณไม่ชอบคำถาม (ฉันไม่ชอบมากที่สุด) ก็อย่าตอบ ;-)
Abel

สำหรับการสาธิตเพิ่มเติมอาจแสดงc += [c]และc.append(c[:])เกินไป
ephemient

2
@ อเบล: ทำไมa+b != a*bล่ะ? การดำเนินการต่างกัน นั่นคือคำตอบ "ทำไม" จึงไม่มีประโยชน์เท่ากับคำถามอื่น ๆ เช่น "ฉันจะต่อท้ายอย่างถูกต้องได้อย่างไร" หรือ "มีอะไรผิดปกติกับการต่อท้ายนี้ที่ทำให้เกิดการเรียกซ้ำไม่สิ้นสุด" คำถามเกี่ยวกับแบบฟอร์ม "ฉันทำอะไรกับ X" หรือ "เกิดอะไรขึ้นเมื่อฉันทำ X" หรือ "ฉันควรทำอย่างไรแทน X" จะช่วยให้ผู้อื่นเรียนรู้ แต่จะให้คำตอบที่เน้นใช้งานได้และนำไปปฏิบัติได้
ล็อตต์

8

รายการ Python มีความแตกต่างกันซึ่งองค์ประกอบในรายการเดียวกันอาจเป็นวัตถุประเภทใดก็ได้ นิพจน์: ต่อc.append(c)ท้ายวัตถุcสิ่งที่เคยเป็นในรายการ ในกรณีที่ทำให้รายการเป็นสมาชิกของรายการ

การแสดงออกเพิ่มสองรายการด้วยกันและกำหนดผลให้กับตัวแปรc += c cตัว+ดำเนินการที่โอเวอร์โหลดถูกกำหนดไว้ในรายการเพื่อสร้างรายการใหม่ซึ่งมีเนื้อหาเป็นองค์ประกอบในรายการแรกและองค์ประกอบในรายการที่สอง

ดังนั้นนี่จึงเป็นเพียงการแสดงออกที่แตกต่างกันที่ใช้ในการออกแบบสิ่งต่างๆ


7

extend()วิธีการที่คุณกำลังมองหาอยู่ จากเอกสาร Python :

list.append(x)
    Add an item to the end of the list; equivalent to a[len(a):] = [x].

list.extend(L)
    Extend the list by appending all the items in the given list; equivalent to a[len(a):] = L.

list.insert(i, x)
    Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).


2

ดูเอกสารประกอบ :

list.append (x)

  • เพิ่มรายการที่ท้ายรายการ เทียบเท่ากับ [len (a):] = [x]

list.extend (L) - ขยายรายการโดยต่อท้ายรายการทั้งหมดในรายการที่กำหนด เทียบเท่ากับ [len (a):] = L.

c.append(c)"ผนวก" C ตัวเองเป็นองค์ประกอบ เนื่องจากรายการเป็นประเภทการอ้างอิงจึงสร้างโครงสร้างข้อมูลแบบวนซ้ำ

c += cเทียบเท่ากับextend(c)ซึ่งต่อท้ายองค์ประกอบของ cถึง c

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