พจนานุกรม Python เป็นตัวอย่างของตารางแฮชหรือไม่


187

หนึ่งในโครงสร้างข้อมูลพื้นฐานใน Python คือพจนานุกรมซึ่งอนุญาตให้บันทึก "คีย์" เพื่อค้นหา "ค่า" ทุกประเภท สิ่งนี้ถูกนำไปใช้ภายในเป็นตารางแฮชหรือไม่ ถ้าไม่มันคืออะไร


2
หากคุณกำลังสนใจในรายละเอียดทางเทคนิคหนึ่งบทความในรหัสที่สวยงามข้อตกลงกับ internals ของงูใหญ่ของdictการดำเนินงาน
Torsten Marek

นั่นเป็นหนึ่งในบทที่ฉันชอบในรหัสที่สวยงาม
DGentry

4
นี่คือการพูดคุยโดยแบรนดอนเครกโรดส์พูดถึงวิธีหลามพจนานุกรมงานyoutube.com/watch?v=C4Kc8xzcA68
chandola

ฉันค้นหาไดอะแกรมที่แสดงถึงพจน์ในขณะนี้ซึ่งถอดรหัสการนำไปใช้ในหน่วยความจำและ CPython ขอบคุณสำหรับการอ้างอิงหนังสือ!
เฉินเอ.

คำตอบ:


239

ใช่มันคือการแมปแฮชหรือตารางแฮช คุณสามารถอ่านรายละเอียดของการดำเนินการ Dict หลามเป็นหนังสือที่เขียนโดยทิมปีเตอร์สที่นี่

นั่นเป็นเหตุผลที่คุณไม่สามารถใช้บางสิ่งบางอย่างที่ 'ไม่แฮช' เป็นคีย์ dict เช่นรายการ:

>>> a = {}
>>> b = ['some', 'list']
>>> hash(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable
>>> a[b] = 'some'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับตารางแฮชหรือตรวจสอบวิธีการนำไปใช้ในไพ ธ อนและทำไมมันจึงถูกนำไปใช้ในวิธีนั้น


1
การเชื่อมโยงของ Tim Peters จะถูกทำลายมีลิงก์ที่สะอาดอยู่ที่นั่นหรือไม่?
Matt Alcock

1
@MattAlcock: ฉันได้อัพเดทลิงค์แล้ว บางครั้ง (โดยปกติแล้วเนื่องจากมีคนต้องการลบที่อยู่อีเมลของพวกเขา) คลังรายการหลามนั้นถูกสร้างขึ้นมาใหม่และรหัสของอีเมลก็เปลี่ยนไปดังนั้นการทำลายลิงก์เหล่านี้ ผู้ดูแลระบบ pydotorg โดยทั่วไปพยายามที่จะหลีกเลี่ยงในวันนี้
Martijn Pieters

แต่การใช้.keys()สามารถดึงรายการคีย์ได้ ตารางแฮชจริงจะไม่เก็บคีย์เพียงแฮชเพื่อประหยัดพื้นที่
noɥʇʎԀʎzɐɹƆ

คำอธิบายที่สมบูรณ์มากขึ้นเกี่ยวกับการใช้งานpict dython
Daniel Goldfarb

32

จะต้องมีพจนานุกรม Python มากกว่าการค้นหาตารางบนแฮช () จากการทดลองที่ดุร้ายฉันพบการชนกันของแฮชนี้:

>>> hash(1.1)
2040142438
>>> hash(4504.1)
2040142438

แต่มันก็ไม่ได้ทำลายพจนานุกรม:

>>> d = { 1.1: 'a', 4504.1: 'b' }
>>> d[1.1]
'a'
>>> d[4504.1]
'b'

ตรวจสอบสติ:

>>> for k,v in d.items(): print(hash(k))
2040142438
2040142438

อาจมีระดับการค้นหาอื่นนอกเหนือจากแฮช () ที่หลีกเลี่ยงการชนระหว่างคีย์พจนานุกรม หรืออาจ dict () ใช้แฮชอื่น

(โดยวิธีการนี้ใน Python 2.7.10 เรื่องเดียวกันใน Python 3.4.3 และ 3.5.0 ที่มีการปะทะกันที่hash(1.1) == hash(214748749.8))


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

1
การชนจะเกิดขึ้นโดยทั่วไปเนื่องจากมีค่าแฮชที่เป็นไปไม่ได้และรหัสแฮช จำกัด แม้ตารางแฮชจะต้องจัดการกับการปะทะกันอย่างใด
Yanfeng Liu

3
@ YanfengLiu ฉันเชื่อว่าสิ่งเหล่านี้เป็นจุดเดียวกัน TurnipEntropy
Bob Stein

1
ใน Python 3.7 ดูเหมือนว่ามีค่าแฮช 2E20 ลบ 1 ที่เป็นไปได้ จาก -1E20 ลบ 1 ถึง (+) 1E20 ลบ 1 ลองhash('I wandered lonely as a cloud, that drifts on high o\'er vales and hills, when all at once, I saw a crowd, a host of golden daffodils.')นี่ให้ทศนิยม 19 หลัก - -4037225020714749784ถ้าคุณ geeky พอที่จะสนใจ ดำเนินการต่อในคำพูดของคุณเองเด็ก ๆ และแฮชยังคงเป็นตัวเลข 19 หลัก ฉันคิดว่ามีข้อ จำกัด เกี่ยวกับความยาวของสายอักขระที่คุณสามารถแฮชใน Python ได้ แต่ปลอดภัยที่จะพูดถึงสตริงที่เป็นไปได้มากกว่าค่าที่เป็นไปได้ และhash(False)= 0 โดยวิธีการ
Will Croxford


7

หากต้องการขยายคำอธิบายของ nosklo:

a = {}
b = ['some', 'list']
a[b] = 'some' # this won't work
a[tuple(b)] = 'some' # this will, same as a['some', 'list']
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.