"hashable" หมายถึงอะไรใน Python


194

ฉันพยายามค้นหาอินเทอร์เน็ต แต่ไม่สามารถค้นหาความหมายของการแฮชได้

เมื่อพวกเขาพูดว่าวัตถุคืออะไรhashableหรือhashable objectsมันหมายความว่าอย่างไร


1
ดูเอกสารบนhashableและวิธีการ__hash__()
ʇsәɹoɈ

5
ที่ค้นหาวัตถุหรือสิ่งที่มีได้ แต่ไม่มีลิงก์ใดที่อธิบายว่าจริง ๆ แล้ว
แฮช

ความเป็นไปได้ที่ซ้ำกันของHashable ไม่เปลี่ยนรูป
คนงานทุกคนมีความจำเป็น

คำตอบ:


181

จากอภิธานศัพท์ Python :

วัตถุนั้น hashable ถ้ามันมีค่าแฮซึ่งไม่เคยเปลี่ยนแปลงในช่วงชีวิตของมัน (มันต้องการ__hash__()วิธีการ) และสามารถนำมาเปรียบเทียบกับวัตถุอื่น ๆ (มันต้องมีวิธีการ__eq__()หรือ__cmp__()) วัตถุที่แฮชที่เปรียบเทียบได้จะต้องมีค่าแฮชเหมือนกัน

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

วัตถุในตัวที่ไม่เปลี่ยนรูปแบบของ Python ทั้งหมดนั้น hashable ในขณะที่ไม่มีคอนเทนเนอร์ที่ไม่แน่นอน (เช่นรายการหรือพจนานุกรม) วัตถุซึ่งเป็นอินสแตนซ์ของคลาสที่ผู้ใช้กำหนดจะแฮชตามค่าเริ่มต้น id()พวกเขาทั้งหมดเปรียบเทียบไม่เท่ากันและค่าแฮชของพวกเขาคือของพวกเขา


2
ถ้าhash valueตอนนี้มีค่าแฮช คุณสามารถยกตัวอย่าง
user1755071

2
@ user55711: ที่นี่, __hash__()ค่าแฮชเป็นผลมาจากการเรียก โดยทั่วไปแล้วโปรดดูen.wikipedia.org/wiki/Hash_function
NPE

16
@TorstenBronger: เนื่องจากวัตถุที่ไม่เท่ากันสองตัวสามารถแฮชไปที่ค่าเดียวกัน กล่าวอีกนัยหนึ่งคร่ำเครียดคือการสูญเสีย
NPE

1
ในหลาม-2.7.12, ผลมาจากการid(object)เป็น 16x object.__hash__()ผลมาจากการ ดังนั้นคำศัพท์ที่ตัดตอนมาไม่ถูกต้องสำหรับรุ่นนี้ - ค่าแฮชไม่ได้id()แต่มาจากมัน (ตามที่ระบุไว้ในเอกสารที่ปรับปรุงแล้วสำหรับ python 2.7.12)
davidA

2
ฉันรู้ว่านี่เป็นโพสต์เก่า แต่น่าจะกล่าวถึงว่ารายการอภิธานศัพท์ที่คัดลอกมาที่นี่ไม่ถูกต้องทั้งหมด คุณสามารถวางวัตถุที่ไม่แน่นอน (เช่นรายการ) ไว้ใน tuple tuple ยังคงไม่เปลี่ยนรูป แต่คุณสามารถเปลี่ยนรายการข้างในได้ดังนั้นจึงไม่แฮช พยายามที่hash((1, [2, 3]))จะเห็นมันในการดำเนินการ ฉันโพสต์คำขอเพื่อแก้ไขรายการคำศัพท์เพื่อแฮช
John Riehl

102

คำตอบทั้งหมดที่นี่มีคำอธิบายการทำงานที่ดีของวัตถุที่ลบได้ในหลาม แต่ฉันเชื่อว่าเราต้องเข้าใจคำว่า Hashing ก่อน

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

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

ดังนั้นคุณสามารถใช้อาร์เรย์ขนาด 100 แทนและใช้ฟังก์ชันแฮชเพื่อแมปชุดของค่ากับดัชนีเดียวกันและค่าเหล่านี้สามารถเก็บไว้ในรายการที่เชื่อมโยงได้ สิ่งนี้มีประสิทธิภาพคล้ายกับอาเรย์

ตอนนี้ฟังก์ชั่นแฮชสามารถทำได้ง่ายเพียงแค่หารจำนวนด้วยขนาดของอาเรย์และนำส่วนที่เหลือเป็นดัชนี

สำหรับรายละเอียดเพิ่มเติมโปรดดูที่https://en.wikipedia.org/wiki/Hash_function

นี่เป็นอีกหนึ่งแหล่งอ้างอิงที่ดี: http://interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html


1
นั่นเป็นมุมมองที่น่าสนใจเกี่ยวกับการคร่ำครวญ ฉันไม่ได้คิดอย่างนั้น
yuvgin

@yuvgin hash-tables มักใช้เพื่อสร้าง sparse-arrays (เช่นตัวอย่างที่ให้ไว้ที่นี่)
Eli Korvigo

@EliKorvigo ฉันชอบคิดว่าอาร์เรย์ปกติเป็นตารางแฮชที่ปรับให้เหมาะสมที่สุด
Mark Ransom

1
คุณสามารถสร้างรหัสง่ายๆเกี่ยวกับสถานการณ์หมายเลขโทรศัพท์เพื่ออธิบายแนวคิดของการแปลงแป้นพิมพ์ได้อย่างไร
Istiaque Ahmed

18

สิ่งใดที่ไม่สามารถเปลี่ยนแปลงได้ (หมายถึงไม่แน่นอนอาจมีการเปลี่ยนแปลง) สามารถถูกแฮช นอกจากฟังก์ชั่นแฮชที่จะมองหาแล้วหากคลาสมีมันด้วยเช่น dir(tuple)และมองหา__hash__วิธีการนี่คือตัวอย่างบางส่วน

#x = hash(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable

รายการประเภทไม่เปลี่ยนรูป:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

รายการประเภทที่ไม่แน่นอน:

list, dict, set, bytearray, user-defined classes

ฉันเพิ่งพบว่ายังเป็นประเภทที่ไม่เปลี่ยนรูปและสามารถใช้เป็นกุญแจสำคัญสำหรับการเป็นEllipsis dict
Gábor Fekete

แม้แต่คลาสที่ผู้ใช้กำหนดเองก็สามารถใช้ได้ เช่น:hash(MyClass)
Gábor Fekete

1
@ GáborFeketeกรณีของการเรียนที่ผู้ใช้กำหนดเป็น hashable ถ้าเรียนของพวกเขาดำเนินการและ__hash__ __eq__ยิ่งไปกว่านั้นคลาสที่ผู้ใช้กำหนดเองใช้เมธอดเหล่านี้ (และสามารถแฮชได้) เนื่องจากพวกมันสืบทอดเมธอดจากobject(คลาสฐานสากล)
Eli Korvigo

7

ในความเข้าใจของฉันตามอภิธานศัพท์ Python เมื่อคุณสร้างอินสแตนซ์ของวัตถุที่แฮชค่าที่ไม่สามารถเปลี่ยนแปลงได้จะถูกคำนวณตามสมาชิกหรือค่าของอินสแตนซ์ด้วย ตัวอย่างเช่นค่านั้นสามารถใช้เป็นคีย์ใน dict ดังต่อไปนี้:

>>> tuple_a = (1,2,3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2,3,4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1,2,3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(a) == id(c)  # a and c same object?
False
>>> a.__hash__() == c.__hash__()  # a and c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

เราสามารถพบว่าค่าแฮชของ tuple_a และ tuple_c เหมือนกันเนื่องจากมีสมาชิกเหมือนกัน เมื่อเราใช้ tuple_a เป็นกุญแจสำคัญใน dict_a เราจะพบว่าค่าสำหรับ dict_a [tuple_c] เหมือนกันซึ่งหมายความว่าเมื่อพวกเขาถูกใช้เป็นกุญแจสำคัญใน dict พวกเขากลับค่าเดียวกันเพราะค่าแฮช เหมือน. สำหรับวัตถุเหล่านั้นที่ไม่ได้แฮชวิธีแฮชจะถูกกำหนดเป็นไม่มี:

>>> type(dict.__hash__) 
<class 'NoneType'>

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


4

ผมขอยกตัวอย่างการทำงานให้คุณเข้าใจวัตถุที่แฮชใน python ฉันรับ 2 Tuples สำหรับตัวอย่างนี้ค่าแต่ละค่าใน tuple มีค่าแฮชที่ไม่ซ้ำกันซึ่งไม่เคยเปลี่ยนแปลงระหว่างอายุการใช้งาน ดังนั้นตามนี้จึงมีค่าการเปรียบเทียบระหว่างสองสิ่งอันดับจะทำ เราสามารถรับค่าแฮชขององค์ประกอบ tuple โดยใช้ Id ()

เปรียบเทียบระหว่าง 2 สิ่งอันดับความเท่าเทียมกันระหว่าง 2 tuples


26
สิ่งนี้จะมีประโยชน์มากขึ้นในรูปแบบข้อความแทนที่จะเป็นรูปภาพ
baxx

7
มันเป็นคำตอบที่ผิด id () แสดงที่อยู่ที่อ้างอิงในหน่วยความจำไม่ใช่ค่าแฮช เพื่อที่จะได้แฮใช้ฟังก์ชัน __hash __ () เช่น: t1 .__ hash __ ()
Vlad

@ascentman อย่าลังเลที่จะแก้ไขคำตอบที่คุณเชื่อว่าผิด การแก้ไขของคุณจะได้รับการตรวจสอบโดยเพื่อนและหากเป็นที่ยอมรับคุณจะได้รับรางวัลคะแนนเล็กน้อย
XavierStuvw

4

ในไพ ธ อนมันหมายความว่าวัตถุสามารถเป็นสมาชิกของชุดเพื่อส่งกลับดัชนี นั่นคือพวกเขามีเอกลักษณ์ / รหัสเฉพาะ

ตัวอย่างเช่นใน python 3.3:

รายการโครงสร้างข้อมูลไม่สามารถแฮชได้ แต่โครงสร้างข้อมูลทูเปิลนั้นจะแฮชได้


แฮชไม่เหมือนกับidที่อยู่ (โดยประมาณ) ที่อยู่ของวัตถุในหน่วยความจำ
poolie

3

Hashable = ความสามารถในการถูกแฮช

โอเคอะไรที่คร่ำครวญ? ฟังก์ชั่นการแฮชคือฟังก์ชั่นที่รับวัตถุพูดสตริงเช่น“ Python” และส่งคืนรหัสขนาดคงที่ เพื่อความง่ายสมมติว่าค่าส่งคืนเป็นจำนวนเต็ม

เมื่อฉันเรียกใช้แฮช ('Python') ใน Python 3 ฉันจะได้รับ 5952713340227947791 เป็นผลลัพธ์ งูหลามรุ่นต่าง ๆ มีอิสระในการเปลี่ยนฟังก์ชันแฮชพื้นฐานดังนั้นคุณน่าจะได้รับค่าที่แตกต่างกัน สิ่งสำคัญคือไม่ว่าตอนนี้หลายครั้งที่ฉันเรียกแฮ ('Python') ฉันจะได้ผลลัพธ์เดียวกันกับ Python รุ่นเดียวกันเสมอ

แต่แฮช ('Java') จะคืนค่า 1753925553814008565 ดังนั้นหากวัตถุที่ฉัน hashing มีการเปลี่ยนแปลงผลลัพธ์ก็จะได้เช่นกัน ในทางกลับกันหากวัตถุที่ฉัน hashing ไม่เปลี่ยนแปลงแล้วผลลัพธ์ยังคงเหมือนเดิม

เหตุใดเรื่องนี้

ยกตัวอย่างเช่นพจนานุกรมภาษาไพ ธ อนจำเป็นต้องใช้กุญแจในการเปลี่ยนรูปแบบ นั่นคือกุญแจต้องเป็นวัตถุที่ไม่เปลี่ยนแปลง สตริงไม่เปลี่ยนแปลงใน Python เช่นเดียวกับชนิดพื้นฐานอื่น ๆ (int, float, bool) Tuples และ frozensets ก็ไม่เปลี่ยนรูป ในทางกลับกันรายการไม่เปลี่ยนแปลง (กล่าวคือพวกมันไม่แน่นอน) เพราะคุณสามารถเปลี่ยนแปลงได้ ในทำนองเดียวกัน dicts สามารถเปลี่ยนแปลงได้

ดังนั้นเมื่อเราพูดบางสิ่งที่แฮชเราหมายความว่ามันไม่เปลี่ยน หากฉันพยายามส่งประเภทที่ไม่แน่นอนไปยังฟังก์ชัน hash () มันจะล้มเหลว:

>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656

1
โปรดทราบว่าหลามสุ่มเมล็ดอัลกอริทึมการแปลงแป้นพิมพ์ที่จุดเริ่มต้นของแต่ละกระบวนการ ดังนั้นคุณจะได้รับค่าแฮชที่แตกต่างกันหากคุณเรียกใช้แฮช ('Python') สองครั้งในกระบวนการที่ต่างกัน
D Hudson

2

ใน Python วัตถุใด ๆ ที่เปลี่ยนไม่ได้ (เช่นจำนวนเต็ม, บูลีน, สตริง, tuple) เป็น hashable ซึ่งหมายความว่าค่าของมันจะไม่เปลี่ยนแปลงในช่วงชีวิตของมัน วิธีนี้ช่วยให้ Python สร้างค่าแฮชที่ไม่ซ้ำกันเพื่อระบุค่าซึ่งพจนานุกรมสามารถใช้ในการติดตามคีย์ที่ไม่ซ้ำกันและตั้งค่าให้ติดตามค่าที่ไม่ซ้ำ

นี่คือเหตุผลที่ Python ต้องการให้เราใช้ประเภทข้อมูลที่ไม่เปลี่ยนรูปสำหรับคีย์ในพจนานุกรม


-1

สำหรับการสร้างตาราง hashing ตั้งแต่เริ่มต้นค่าทั้งหมดจะต้องตั้งค่าเป็น "ไม่มี" และแก้ไขเมื่อมีความต้องการเกิดขึ้น วัตถุที่ลบได้หมายถึงประเภทข้อมูลที่แก้ไขได้ (พจนานุกรมรายการ ฯลฯ ) ไม่สามารถกำหนดค่าเริ่มต้นอีกครั้งเมื่อตั้งค่าไว้ดังนั้นชุดจึงไม่สามารถแฮชได้ ในขณะที่ตัวแปรของ set () - frozenset () - สามารถแฮชได้

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