เหตุใดพจนานุกรมของงูหลามจึงไม่สามารถย้อนกลับได้สำหรับ python3.7


11

เริ่มจาก 3.7 พจนานุกรม python มาตรฐานรับประกันว่าจะรักษาคำสั่งแทรก (*)

d = {'b': 1, 'a': 2}
for k in d: 
    print(k)
# Prints always 'b' before 'a'.

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

# TypeError: 'dict' object is not reversible
for k in reversed(d): 
    print(k)

# TypeError: 'dict_keys' object is not reversible
for k in reversed(d.keys()): 
    print(k)

คำถาม:อะไรคือเหตุผลที่อยู่เบื้องหลังพฤติกรรมนี้ ทำไม dicts จึงไม่สามารถย้อนกลับได้? มีแผนการที่จะเปลี่ยนแปลงพฤติกรรมนี้ในอนาคตหรือไม่?

วิธีแก้ปัญหาของหลักสูตรใช้งานได้:

for k in reversed(list(d.keys())): 
    print(k)

(*) เป็นเรื่องของความเป็นจริงเป็นกรณีนี้แล้วสำหรับการติดตั้งทั่วไปของงูหลาม 3.6 ตามที่กล่าวไว้ในโพสต์นี้


อัปเดต : เริ่มต้นด้วยpython 3.8 dicts จริง ๆ แล้วย้อนกลับได้ คำตอบที่ได้รับการยอมรับหมายถึงการสนทนาระหว่างกุยโดและนักพัฒนาหลักอื่น ๆ ที่นำไปสู่การตัดสินใจนี้ สั้นพวกเขาถ่วงน้ำหนักภาษาสอดคล้องกับความพยายามในการใช้งานและผลประโยชน์ที่แท้จริงสำหรับผู้ใช้

คำตอบ:


5

จากเอกสาร :

กลับรายการ ( seq )

iteratorกลับย้อนกลับ seq ต้องเป็นวัตถุที่มี__reversed__()วิธีการหรือสนับสนุนโปรโตคอลลำดับ ( __len__()วิธีการและ__getitem__()วิธีการที่มีอาร์กิวเมนต์จำนวนเต็มเริ่มต้นที่ 0)

วัตถุไม่ใช้dict __reversed__มันใช้ทั้งสองวิธีหลัง อย่างไรก็ตาม__getitem__รับคีย์เป็นอาร์กิวเมนต์แทนที่จะเป็นจำนวนเต็ม (เริ่มต้นที่ 0)

ว่าทำไมนี้ได้รับการแนะนำและพูดคุยกันที่นี่

แก้ไข:

เครื่องหมายคำพูดเหล่านี้มาจากรายชื่อผู้รับจดหมายของ Python-Dev (เธรด "เพิ่ม __reversed__ method for dict", เริ่มต้นที่ 25. 05. 18. ), ฉันจะเริ่มด้วยอาร์กิวเมนต์ "conceptual" อันแรกมาจาก Antoine Pitrou:

ไม่มีอะไรที่คุ้มค่าที่ OrderedDict รองรับการกลับรายการแล้ว () อาร์กิวเมนต์สามารถไปได้ทั้งสองวิธี:

  1. dict คล้ายกับ OrderedDict ทุกวันนี้ดังนั้นจึงควรสนับสนุน reverse () ด้วย;

  2. คุณสามารถใช้ OrderedDict เพื่อส่งสัญญาณอย่างชัดเจนว่าคุณสนใจสั่งซื้อ ไม่จำเป็นต้องเพิ่มอะไรลงไป

ความคิดของฉันคือการรับประกันการแทรกสำหรับ dicts ปกติเป็นแบรนด์ใหม่ดังนั้นจึงต้องใช้เวลาสักครู่สำหรับความคิดที่จะเข้ามาและกลายเป็นส่วนหนึ่งของการคิดทุกวันเกี่ยวกับ dicts เมื่อเกิดเหตุการณ์นี้ขึ้นก็อาจจะหลีกเลี่ยงไม่ได้ที่กรณีการใช้งานจะปรากฏขึ้นและ __ กลับมาจะได้รับการเพิ่มในบางจุด การนำไปปฏิบัติดูเหมือนจะตรงไปตรงมาและการก้าวกระโดดทางแนวคิดไม่มากนักเพื่อคาดหวังว่าคอลเลกชันที่มีคำสั่ง จำกัด จะสามารถย้อนกลับได้

ตามมาด้วยคำตอบของ Raymond Hettinger:

เนื่องจาก dicts ในขณะนี้ติดตามคำสั่งแทรกดูเหมือนว่าเหมาะสมที่จะต้องการทราบการแทรกล่าสุด (เช่นวนลูปมากกว่างานที่เพิ่มล่าสุดในงานเขียนตามคำบอก) กรณีการใช้งานที่เป็นไปได้อื่น ๆ น่าจะสอดคล้องกับวิธีที่เราใช้คำสั่ง Unix tail

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

ความกังวลหลักที่แสดงอยู่ในรายชื่อที่ส่งเป็นที่ว่านี้จะเพิ่มการขยายตัวมากเกินไปหรือลดประสิทธิภาพหน่วยความจำ (ต้องมีรายการที่เชื่อมโยงเป็นทวีคูณแทนคนที่เชื่อมโยงเดี่ยว) ในอย่างน้อยบางส่วนการใช้งานที่นี่เป็นคำพูด Inada Naoki จากงูหลามบั๊ก ( ปัญหา 33462 ):

"มีคำสั่งซื้อ" ไม่ได้แปลว่า "ย้อนกลับได้" ตัวอย่างเช่นมีการเรียงลำดับรายการเชื่อมโยงเดียว แต่ไม่สามารถย้อนกลับได้

ในขณะที่การใช้งาน CPython สามารถให้บริการที่มีประสิทธิภาพ__reverse__การเพิ่ม__reverse__หมายถึงการใช้งาน Python ทั้งหมดคาดว่าจะให้มัน ตัวอย่างเช่นการใช้งาน Python บางอย่างอาจใช้ dict ด้วย hashmap + รายการที่ลิงก์เดียว หาก__reverse__มีการเพิ่มจะไม่สามารถทำได้อีกต่อไป

กลับไปที่รายชื่อผู้รับจดหมายนี่เป็นข้อความสุดท้ายสองข้อความ (ทั้งสองโพสต์เมื่อ 08.06.2018) ที่แรกมาจาก Michael Selik:

ฉันถูกต้องหรือไม่ที่บอกว่าฉันทามติคือ +1 สำหรับรวมไว้ใน v3.8?

จุดสุดท้ายของเธรดคือ INADA Naoki ทำการวิจัยการใช้งานต่าง ๆ และตัดสินใจว่ามันใช้ได้ที่จะรวมคุณสมบัตินี้ไว้ใน 3.8 เมื่อฉันเข้าใจแล้ว Guido ก็เห็นด้วยกับคำแนะนำของ INADA เพื่อรอการใช้งาน v3.7 ของ MicroPython เนื่องจาก INADA เปลี่ยนใจฉันจึงเดาว่าทั้งหมดนี้เป็นของกำนัล?

สรุปข้อความของ Guido van Rossum:

นั่นฟังดูเหมาะสมสำหรับฉัน จากนั้นเราจะมีสองเวอร์ชันซึ่งเป็นกรณีนี้:

  • 3.6 มีการใช้งานการรักษาคำสั่งซื้อใน CPython แต่ในข้อกำหนดภาษา

  • 3.7 มันถูกเพิ่มเข้าไปในสเป็คภาษาด้วย

ตามที่ระบุไว้ในคำตอบและความคิดเห็นอื่น ๆreversed()รองรับทั้ง dicts และ dictviews ตั้งแต่รุ่น 3.8 (14.10.2018)


5
ข้อความที่สองของคุณดูเหมือนจะเป็นการเลือกแบบอคติจากชุดข้อความนั้น ฉันทามติดูเหมือนว่าจะมีการเพิ่มฟังก์ชันการทำงานใน 3.8 ก่อนหน้านี้กับไพ ธ อน 3.7 ก็ไม่มีการสั่งซื้อdictวัตถุปกติ(อย่างน้อยก็ไม่รับประกันจากภาษา) ดังนั้นจึงreversedไม่มีเหตุผล
FlyingTeller

ฉันไม่มีสุนัขในการต่อสู้ฉันแค่ยกคำตอบแรกของเขา แต่คุณพูดถูกเอาดีชี้ไปที่ - ฉันลบคำพูด
gst

1
ขอบคุณ กระทู้การสนทนาของ python-dev ถูกเปิดเผย ตามความเป็นจริงแล้วฟีเจอร์นี้ได้ถูกนำไปใช้งานใน python 3.8 ซึ่งเปิดตัวเมื่อสองวันก่อน (14 ตุลาคม 2019)
normanius


การอ้างอิงเอกสารไม่เป็นประโยชน์ แต่จะเกิดคำถามต่อไปเท่านั้น "ดังนั้นทำไมจึงไม่ใช้ประเภท dict __reversed__" ลิงค์ python-dev มีเนื้อหาที่มีประโยชน์ แต่ส่วนที่เกี่ยวข้องควรทำซ้ำในคำตอบโดยตรง (เนื่องจากลิงก์นอกไซต์ดังกล่าวมีแนวโน้มที่จะเน่า)
wim


1

อัพเดทสำหรับ python 3.8

Dict และ dictviews ขณะนี้สามารถใช้คำสั่งแทรกได้โดยใช้ reverse ()

>>> dict = {1: "1", 2: "2", 3: "3"}
>>> reversed(dict)
<dict_reversekeyiterator object at 0x7f72ca795130>

คำตอบนี้มีส่วนช่วยอะไรใหม่ ๆ ที่ไม่ได้ครอบคลุมอยู่ในคำตอบความคิดเห็นหรือคำถามอื่น ๆ หรือไม่?
normanius

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