Không có nghĩa là hash hashable có nghĩa gì trong Python?


193

Tôi đã thử tìm kiếm trên internet nhưng không thể tìm thấy ý nghĩa của hashable.

Khi họ nói các đối tượng là gì hashablehoặc hashable objectsnó có nghĩa là gì?


1
Xem tài liệu về hashable__hash__()phương pháp .
ʇsәɹoɈ

5
tìm kiếm các đối tượng có thể có hoặc một cái gì đó, nhưng không có liên kết nào giải thích ý nghĩa thực sự có thể
băm

Câu trả lời:


181

Từ bảng chú giải Python :

Một đối tượng có thể băm nếu nó có giá trị băm không bao giờ thay đổi trong suốt vòng đời của nó (nó cần một __hash__()phương thức) và có thể so sánh với các đối tượng khác (nó cần một phương thức __eq__()hoặc __cmp__()phương thức). Các đối tượng có thể băm so sánh bằng nhau phải có cùng giá trị băm.

Hashability làm cho một đối tượng có thể sử dụng như một khóa từ điển và một thành viên được thiết lập, bởi vì các cấu trúc dữ liệu này sử dụng giá trị băm bên trong.

Tất cả các đối tượng tích hợp bất biến của Python đều có thể băm được, trong khi không có thùng chứa có thể thay đổi nào (như danh sách hoặc từ điển). Các đối tượng là các thể hiện của các lớp do người dùng định nghĩa có thể được băm theo mặc định; tất cả đều so sánh không bằng nhau và giá trị băm của chúng là của chúng id().


2
nếu hash valuebây giờ nó có giá trị băm là gì. bạn có thể đưa ra một số ví dụ
user1755071

2
@ user55711: Ở đây, giá trị băm là kết quả của cuộc gọi __hash__(). Tổng quát hơn, xem en.wikipedia.org/wiki/Hash_feft
NPE

16
@TorstenBronger: Bởi vì hai đối tượng không bằng nhau có thể băm đến cùng một giá trị. Nói cách khác, băm là mất mát.
NPE

1
Trong python-2.7.12, kết quả id(object)là 16 lần kết quả của object.__hash__(). Vì vậy, đoạn trích chú giải không chính xác cho phiên bản này - giá trị băm thì không id(), nhưng nó được lấy từ nó (như thực sự được ghi chú trong các tài liệu cập nhật cho python 2.7.12).
davidA

2
Tôi biết đây là một bài viết cũ, nhưng điều đáng nói là mục chú giải được sao chép ở đây không hoàn toàn chính xác. Bạn có thể đặt một đối tượng có thể thay đổi (như danh sách) bên trong một tuple. Bộ dữ liệu vẫn không thay đổi, nhưng bạn có thể thay đổi danh sách bên trong nó, vì vậy nó không thể băm được. Hãy thử hash((1, [2, 3]))nhìn nó trong hành động. Tôi đã đăng một yêu cầu để sửa mục chú giải cho hashable.
John Riehl

102

Tất cả các câu trả lời ở đây đều có giải thích hoạt động tốt về các đối tượng có thể băm trong python, nhưng tôi tin rằng người ta cần hiểu thuật ngữ Hashing trước tiên.

Băm là một khái niệm trong khoa học máy tính được sử dụng để tạo ra các cấu trúc dữ liệu truy cập ngẫu nhiên, giả ngẫu nhiên, trong đó một lượng lớn dữ liệu sẽ được lưu trữ và truy cập nhanh chóng.

Ví dụ: nếu bạn có 10.000 số điện thoại và bạn muốn lưu trữ chúng trong một mảng (là cấu trúc dữ liệu tuần tự lưu trữ dữ liệu ở các vị trí bộ nhớ liền kề và cung cấp quyền truy cập ngẫu nhiên), nhưng bạn có thể không có lượng tiếp giáp cần thiết vị trí bộ nhớ.

Vì vậy, thay vào đó, bạn có thể sử dụng một mảng có kích thước 100 và sử dụng hàm băm để ánh xạ một tập hợp các giá trị vào cùng các chỉ mục và các giá trị này có thể được lưu trữ trong danh sách được liên kết. Điều này cung cấp một hiệu suất tương tự như một mảng.

Bây giờ, một hàm băm có thể đơn giản như chia số với kích thước của mảng và lấy phần còn lại làm chỉ mục.

Để biết thêm chi tiết, tham khảo https://en.wikipedia.org/wiki/Hash_feft

Dưới đây là một tài liệu tham khảo tốt khác: http://interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html


1
Đó là một quan điểm thú vị về băm. Tôi đã không nghĩ về nó theo cách đó.
yuvgin

Các bảng băm @yuvgin thường được sử dụng để triển khai các mảng thưa thớt (ví dụ: ví dụ được đưa ra ở đây).
Eli Korvigo

@EliKorvigo Tôi thích nghĩ về các mảng thông thường như các phiên bản được tối ưu hóa cao của bảng băm.
Đánh dấu tiền chuộc

1
bạn có thể tạo một số mã đơn giản liên quan đến kịch bản mảng số điện thoại để làm rõ khái niệm băm không?
Istiaque Ahmed

18

Bất cứ điều gì không thể thay đổi (phương tiện có thể thay đổi, có khả năng thay đổi) đều có thể được băm. Ngoài hàm băm cần tìm, nếu một lớp có nó, ví dụ. dir(tuple)và tìm kiếm __hash__phương pháp, đây là một số ví dụ

#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

Danh sách các loại bất biến:

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

Danh sách các loại đột biến:

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

Gần đây tôi phát hiện ra rằng đó Ellipsiscũng là một loại không thay đổi và có thể được sử dụng làm chìa khóa cho a dict.
Gábor Fekete

Ngay cả các lớp do người dùng định nghĩa có thể được sử dụng nhưng chỉ tên của họ không phải là thể hiện. Ví dụ:hash(MyClass)
Gábor Fekete

1
Các phiên bản @ GáborFekete của các lớp do người dùng định nghĩa có thể băm nếu các lớp của chúng triển khai __hash____eq__. Hơn nữa, tất cả các lớp do người dùng định nghĩa đều thực hiện các phương thức này (và do đó có thể băm được), bởi vì chúng kế thừa các phương thức từ object(lớp cơ sở phổ quát).
Eli Korvigo

6

Theo cách hiểu của tôi theo thuật ngữ Python, khi bạn tạo một thể hiện của các đối tượng có thể băm, một giá trị không thể thay đổi cũng được tính theo các thành viên hoặc giá trị của thể hiện. Ví dụ: giá trị đó sau đó có thể được sử dụng làm khóa trong một lệnh như sau:

>>> 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'

chúng ta có thể thấy rằng giá trị băm của tuple_a và tuple_c là như nhau vì chúng có cùng các thành viên. Khi chúng ta sử dụng tuple_a làm khóa trong dict_a, chúng ta có thể thấy rằng giá trị của dict_a [tuple_c] là như nhau, có nghĩa là, khi chúng được sử dụng làm khóa trong một dict, chúng trả về cùng một giá trị vì các giá trị băm là giống nhau. Đối với những đối tượng không thể băm, hàm băm phương thức được định nghĩa là Không có:

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

Tôi đoán giá trị băm này được tính dựa trên việc khởi tạo thể hiện, không phải theo cách động, đó là lý do tại sao chỉ các đối tượng bất biến là có thể băm. Hi vọng điêu nay co ich.


4

Hãy để tôi cho bạn một ví dụ hoạt động để hiểu các đối tượng có thể băm trong python. Tôi đang lấy 2 Tuples cho ví dụ này. Mỗi giá trị trong một tuple có Giá trị Hash duy nhất không bao giờ thay đổi trong suốt vòng đời của nó. Vì vậy, dựa trên điều này có giá trị, việc so sánh giữa hai bộ dữ liệu được thực hiện. Chúng ta có thể nhận giá trị băm của một phần tử tuple bằng cách sử dụng Id ().

So sánh giữa 2 bộSự tương đương giữa 2 bộ


26
điều này sẽ hữu ích hơn dưới dạng văn bản chứ không phải là hình ảnh
baxx

6
đó là một câu trả lời sai id () hiển thị địa chỉ được tham chiếu trong bộ nhớ, nó không phải là giá trị băm. Để có được hàm băm, hãy sử dụng hàm __hash __ (). ví dụ: t1 .__ băm __ ()
Vlad

@ascentman Đừng ngần ngại chỉnh sửa một câu trả lời mà bạn cho là sai. Chỉnh sửa của bạn sẽ được đánh giá ngang hàng và, nếu được chấp nhận, bạn sẽ nhận được một phần thưởng nhỏ cho nó.
XavierStuvw

4

Trong python, điều đó có nghĩa là đối tượng có thể là thành viên của các tập hợp để trả về một chỉ mục. Đó là, họ có danh tính / id duy nhất.

ví dụ: trong python 3.3:

cấu trúc dữ liệu Danh sách không thể băm được nhưng cấu trúc dữ liệu Tuples có thể băm được.


Hàm băm không giống với id, đó là (xấp xỉ) địa chỉ của đối tượng trong bộ nhớ.
poolie

3

Hashable = có khả năng được băm.

Ok, băm là gì? Hàm băm là một hàm lấy một đối tượng, giả sử một chuỗi như Python Python, 'và trả về mã có kích thước cố định. Để đơn giản, giả sử giá trị trả về là một số nguyên.

Khi tôi chạy hàm băm ('Python') trong Python 3, tôi nhận được 5952713340227947791. Các phiên bản khác nhau của Python được tự do thay đổi hàm băm cơ bản, do đó bạn có thể sẽ nhận được một giá trị khác. Điều quan trọng là cho dù bây giờ nhiều lần tôi chạy hàm băm ('Python'), tôi sẽ luôn nhận được kết quả tương tự với cùng một phiên bản Python.

Nhưng hàm băm ('Java') trả về 1753925553814008565. Vì vậy, nếu đối tượng tôi đang băm thay đổi, kết quả cũng vậy. Mặt khác, nếu đối tượng tôi đang băm không thay đổi, thì kết quả vẫn giữ nguyên.

Vì sao vấn đề này?

Vâng, ví dụ, từ điển Python yêu cầu các khóa là bất biến. Đó là, các khóa phải là các đối tượng không thay đổi. Chuỗi là bất biến trong Python, cũng như các loại cơ bản khác (int, float, bool). Tuples và fro chục cũng là bất biến. Danh sách, mặt khác, không phải là bất biến (nghĩa là chúng có thể thay đổi) bởi vì bạn có thể thay đổi chúng. Tương tự, dicts là đột biến.

Vì vậy, khi chúng tôi nói một cái gì đó có thể băm, chúng tôi có nghĩa là nó là bất biến. Nếu tôi cố gắng chuyển một loại có thể thay đổi cho hàm hash (), nó sẽ thất bại:

>>> 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
Lưu ý rằng python ngẫu nhiên gieo hạt thuật toán băm vào đầu mỗi quá trình. Do đó, bạn thực sự sẽ nhận được các giá trị băm khác nhau nếu bạn chạy hàm băm ('Python') hai lần trong các quy trình khác nhau.
D Hudson

2

Trong Python, bất kỳ đối tượng bất biến nào (như số nguyên, boolean, chuỗi, tuple) đều có thể băm, có nghĩa là giá trị của nó không thay đổi trong suốt vòng đời của nó. Điều này cho phép Python tạo một giá trị băm duy nhất để xác định nó, có thể được sử dụng bởi các từ điển để theo dõi các khóa và bộ duy nhất để theo dõi các giá trị duy nhất.

Đây là lý do tại sao Python yêu cầu chúng ta sử dụng các kiểu dữ liệu bất biến cho các khóa trong từ điển.


-1

Để tạo bảng băm từ đầu, tất cả các giá trị phải được đặt thành "Không" và được sửa đổi khi có yêu cầu. Các đối tượng có thể băm tham chiếu đến các kiểu dữ liệu có thể sửa đổi (Từ điển, danh sách, v.v.). Mặt khác, các bộ không thể được khởi tạo lại sau khi được gán, vì vậy các bộ không thể băm được. Trong khi đó, biến thể của tập hợp () - froundredet () - có thể băm được.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.