พจนานุกรมสั่งใน Python 3.6+ หรือไม่
พวกเขาจะแทรกสั่งซื้อ [1] ในฐานะที่เป็นของงูใหญ่ 3.6 สำหรับการดำเนินงานของงูใหญ่ CPython พจนานุกรมจำลำดับของรายการแทรก นี่คือการพิจารณารายละเอียดการดำเนินงานในหลาม 3.6 ; คุณจำเป็นต้องใช้OrderedDict
ถ้าคุณต้องการให้การสั่งซื้อแบบแทรกนั้นรับประกันได้กับการใช้งานอื่น ๆ ของ Python (และพฤติกรรมการสั่งซื้ออื่น ๆ[1] )
ในฐานะของ Python 3.7นี่ไม่ใช่รายละเอียดการใช้งานอีกต่อไปและจะกลายเป็นคุณสมบัติภาษาแทน จากข้อความ python-dev โดย GvR :
ทำให้เป็นเช่นนั้น "Dict เก็บคำสั่งแทรก" เป็นคำสั่ง ขอบคุณ!
นี้หมายความว่าคุณสามารถขึ้นอยู่กับมัน การใช้งานอื่น ๆ ของ Python จะต้องเสนอพจนานุกรมสั่งแทรกหากพวกเขาต้องการที่จะใช้งานที่สอดคล้องของ Python 3.7
การใช้3.6
พจนานุกรมPython ทำงานได้ดีกว่า[2]ที่เก่ากว่าในขณะที่รักษาลำดับองค์ประกอบ
เป็นหลักโดยการรักษาสองอาร์เรย์
อาร์เรย์แรกdk_entries
ถือรายการ ( จากประเภทPyDictKeyEntry
) สำหรับพจนานุกรมตามลำดับที่แทรก การรักษาคำสั่งซื้อทำได้โดยการต่อเติมเป็นอาร์เรย์ที่มีการแทรกรายการใหม่ที่ส่วนท้ายเสมอ (ลำดับการแทรก)
ประการที่สองdk_indices
ถือดัชนีสำหรับdk_entries
อาร์เรย์ (นั่นคือค่าที่ระบุตำแหน่งของรายการที่สอดคล้องกันdk_entries
) อาร์เรย์นี้ทำหน้าที่เป็นตารางแฮช เมื่อคีย์ถูกแฮชจะนำไปสู่หนึ่งในดัชนีที่จัดเก็บในและรายการที่สอดคล้องกันคือความจริงโดยการจัดทำดัชนีdk_indices
dk_entries
เนื่องจากดัชนีจะถูกเก็บไว้ชนิดของอาร์เรย์นี้จึงขึ้นอยู่กับขนาดโดยรวมของพจนานุกรม (ตั้งแต่ประเภทint8_t
( 1
ไบต์) ถึงint32_t
/ int64_t
( 4
/ 8
bytes) บน32
/ 64
สร้างบิต)
ในการใช้งานก่อนหน้านี้ต้องมีการจัดสรรประเภทPyDictKeyEntry
และขนาดของกระจัดกระจาย dk_size
โชคร้ายก็ยังส่งผลให้ในหลายพื้นที่ว่างตั้งแต่อาร์เรย์ที่ไม่ได้รับอนุญาตให้เป็นมากกว่า2/3 * dk_size
เต็มรูปแบบเพื่อเหตุผลด้านประสิทธิภาพ (และพื้นที่ว่างยังคงมีPyDictKeyEntry
ขนาด!)
กรณีนี้ไม่ได้ในขณะนี้ตั้งแต่เพียงต้องป้อนข้อมูลจะถูกเก็บไว้ (ผู้ที่ได้รับการแทรก) และอาร์เรย์เบาบางชนิดintX_t
( X
ขึ้นอยู่กับขนาด Dict) 2/3 * dk_size
เต็มจะถูกเก็บไว้ พื้นที่ว่างเปล่าเปลี่ยนจากประเภทการPyDictKeyEntry
intX_t
ดังนั้นการสร้างอาเรย์แบบเบาบางPyDictKeyEntry
จึงเป็นความต้องการของหน่วยความจำมากกว่าอาเรย์แบบเบาบางสำหรับการจัดเก็บint
s
คุณสามารถดูบทสนทนาเต็มรูปแบบใน Python-Devเกี่ยวกับคุณลักษณะนี้หากสนใจมันเป็นการอ่านที่ดี
ในข้อเสนอดั้งเดิมที่ทำโดย Raymond Hettingerการสร้างภาพข้อมูลของโครงสร้างข้อมูลที่ใช้สามารถเห็นได้ซึ่งรวบรวมส่วนสำคัญของความคิด
ตัวอย่างเช่นพจนานุกรม:
d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
ขณะนี้ถูกเก็บไว้เป็น [keyhash, key, value]:
entries = [['--', '--', '--'],
[-8522787127447073495, 'barry', 'green'],
['--', '--', '--'],
['--', '--', '--'],
['--', '--', '--'],
[-9092791511155847987, 'timmy', 'red'],
['--', '--', '--'],
[-6480567542315338377, 'guido', 'blue']]
แต่ควรจัดระเบียบข้อมูลดังต่อไปนี้:
indices = [None, 1, None, None, None, 0, None, 2]
entries = [[-9092791511155847987, 'timmy', 'red'],
[-8522787127447073495, 'barry', 'green'],
[-6480567542315338377, 'guido', 'blue']]
ดังที่คุณเห็นได้ในข้อเสนอเดิมพื้นที่ส่วนใหญ่ว่างเปล่าเพื่อลดการชนและทำให้การค้นหารวดเร็วขึ้น ด้วยวิธีการใหม่นี้คุณจะลดหน่วยความจำที่ต้องการโดยการย้ายความกระจัดกระจายตามที่จำเป็นในดัชนี
[1]: ฉันพูดว่า "การสั่งการแทรก" และไม่ใช่ "สั่ง" เนื่องจากมีการมีอยู่ของ OrderedDict "สั่ง" จะแนะนำพฤติกรรมเพิ่มเติมที่dict
วัตถุไม่ได้จัดเตรียมไว้ OrderedDicts ย้อนกลับให้การสั่งซื้อวิธีที่สำคัญและส่วนใหญ่ให้การทดสอบความเสมอภาคสั่งเซนซีฟ ( ==
, !=
) dict
s ไม่ได้เสนอพฤติกรรม / วิธีการใด ๆ
[2]: การปรับใช้พจนานุกรมใหม่จะทำให้หน่วยความจำดีขึ้นโดยการออกแบบให้กะทัดรัดยิ่งขึ้น นั่นคือประโยชน์หลักที่นี่ ความเร็วที่ชาญฉลาดความแตกต่างนั้นไม่รุนแรงนักมีสถานที่ที่ dict ใหม่อาจแนะนำการถดถอยเล็กน้อย ( เช่นการค้นหาคีย์เป็นต้น ) ในขณะที่ผู้อื่น
โดยรวมแล้วประสิทธิภาพของพจนานุกรมโดยเฉพาะอย่างยิ่งในสถานการณ์จริงได้รับการปรับปรุงให้ดีขึ้นเนื่องจากมีการใช้งานขนาดกะทัดรัด