Các đối tượng Python có thể băm được không?

Một bài đăng gần đây trên Reddit đã gây ra một số bình luận, vì vậy tôi muốn làm rõ. Trong Python, các đối tượng có thể băm phải là bất biến và các đối tượng có thể thay đổi không thể băm được. [Với một ngoại lệ. ]

Trước khi thu thập đuốc và chĩa ba, hãy để tôi giải thích một số thông tin cơ bản

Nếu bạn muốn làm cho các lớp của mình có thể băm được, bạn phải tuân theo hai quy tắc được nêu trong

Một đối tượng có thể băm nếu [1] nó có giá trị băm không bao giờ thay đổi trong suốt thời gian tồn tại của nó [nó cần một phương thức _______________4] và có thể được so sánh với các đối tượng khác [nó cần một phương thức _______________5]. [2] Các đối tượng có thể băm so sánh bằng nhau phải có cùng giá trị băm

Trong Python, số nguyên, số float và bool đều là bất biến. Và bởi vì

>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
6, nên
>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
7

Hãy tạo một lớp Point bất biến, lớp này có các thuộc tính chỉ đọc

>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
8 và
>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
9 và nó sử dụng lại các giá trị băm cho các bộ dữ liệu

_______________

Chúng ta có thể tạo _______________0 đối tượng và chúng là bất biến. chúng tôi không thể thay đổi thuộc tính

>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
8 hoặc
>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
9 của chúng

_______________

Vì chúng có thể băm được nên chúng ta cũng có thể sử dụng các đối tượng này làm khóa trong từ điển

_______________

Bây giờ, vì giá trị băm dựa trên giá trị của đối tượng và giá trị băm của đối tượng không bao giờ thay đổi [theo quy tắc từ Thuật ngữ Python], điều này nhất thiết có nghĩa là chỉ các đối tượng bất biến mới có thể được băm. Lưu ý rằng bạn không thể sử dụng danh sách hoặc từ điển có thể thay đổi làm khóa trong từ điển, chúng cũng không trả về bất kỳ thứ gì từ

>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
3

_______________

Nhưng tại sao nó lại như thế?

Lý do liên quan đến cách băm được sử dụng trong từ điển. Điều này sẽ yêu cầu một số nền tảng CS về cách hoạt động của từ điển/bản đồ băm [nhưng bạn có thể xem bài nói chuyện về PyCon 2010 của Brandon Rhode, The Mighty Dictionary]. Nhưng câu trả lời ngắn gọn là nếu giá trị của đối tượng thay đổi, thì hàm băm cũng phải thay đổi vì hàm băm dựa trên các giá trị. Tuy nhiên, nếu giá trị của đối tượng thay đổi sau khi nó được sử dụng làm khóa trong từ điển, hàm băm sẽ không còn tham chiếu đến nhóm chính xác trong từ điển cho khóa đó. Hãy sử dụng một ví dụ

Đây là một lớp con của kiểu dữ liệu danh sách tích hợp sẵn của Python [có thể thay đổi] mà chúng tôi đã thêm hàm

>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
4 vào

_______________

Chúng ta có thể tạo một đối tượng danh sách có thể băm và đặt nó vào từ điển

_______________

Nó dường như được làm việc. Chúng tôi thậm chí còn tạo một danh sách có thể băm khác có cùng giá trị và dường như nó cũng hoạt động

_______________

Bây giờ chúng ta thay đổi

>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
6. Đúng như dự đoán, nó tạo ra một
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
7 vì
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
8 không phải là từ khóa trong từ điển, chỉ có
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
9 là [điều này hóa ra là sai, nhưng tạm thời hãy bỏ qua điều đó]

_______________2

Nhưng đây là điều.

>>> {[1, 2, 3]: 'hello'}
Traceback [most recent call last]:
  File "stdin", line 1, in module
TypeError: unhashable type: 'list'

>>> hash[[1, 2, 3]]
Traceback [most recent call last]:
  File "stdin", line 1, in module
TypeError: unhashable type: 'list'

>>> hash[{1:2, 3:4}]
Traceback [most recent call last]:
  File "stdin", line 1, in module
TypeError: unhashable type: 'dict'
0 không còn hoạt động như một khóa, mặc dù nó là
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
9

_______________

Tại sao lại thế này? . Khi chúng tôi thay đổi

>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
6, chúng tôi cũng thay đổi khóa từ điển

_______________

Vì vậy, điều này có nghĩa là chìa khóa bây giờ là

>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
8, nhưng nó nằm trong thùng/khe dành cho
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
9. Nhưng
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
9 của
>>> {[1, 2, 3]: 'hello'}
Traceback [most recent call last]:
  File "stdin", line 1, in module
TypeError: unhashable type: 'list'

>>> hash[[1, 2, 3]]
Traceback [most recent call last]:
  File "stdin", line 1, in module
TypeError: unhashable type: 'list'

>>> hash[{1:2, 3:4}]
Traceback [most recent call last]:
  File "stdin", line 1, in module
TypeError: unhashable type: 'dict'
0 sẽ không hoạt động vì giá trị của khóa bây giờ là
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
8 và Python chỉ cho rằng đó là một xung đột hàm băm

Để làm cho mọi thứ trở nên tồi tệ hơn, hãy thử đặt

>>> import collections

>>> class HashableList[collections.UserList]:
..     def __hash__[self]:
..         return hash[tuple[self]]
0 thành
>>> import collections

>>> class HashableList[collections.UserList]:
..     def __hash__[self]:
..         return hash[tuple[self]]
1. Hoàn toàn trùng hợp,
>>> import collections

>>> class HashableList[collections.UserList]:
..     def __hash__[self]:
..         return hash[tuple[self]]
2 băm vào cùng một thùng/khe như
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
9. Và các giá trị đều giống nhau [vì key cũng đã thay đổi thành
>>> import collections

>>> class HashableList[collections.UserList]:
..     def __hash__[self]:
..         return hash[tuple[self]]
2] nên nó hoạt động hoàn toàn ổn mặc dù nó sẽ gây ra lỗi
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
7

_______________0

Vì vậy, đây là lý do tại sao việc các mục có thể thay đổi có thể được băm là một Điều Xấu. thay đổi chúng cũng thay đổi khóa trong từ điển. Đôi khi điều này hoạt động mặc dù nó sẽ gây ra

>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
7 [khi có xung đột hàm băm do trùng hợp ngẫu nhiên] và những lần khác, nó sẽ gây ra
>>> d = {ip: 'hello'}

>>> d[ip]
'hello'

>>> d[ip2]
'hello'
7 khi nó hoạt động [vì khóa từ điển đã thay đổi khi đối tượng có thể thay đổi đã thay đổi].

NHƯNG HÃY CHỜ, MỘT NGOẠI LỆ LÀ GÌ? . Nghĩa là, nó phải có các triển khai

>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
5 và
>>> ip = ImmutablePoint[10, 20]

>>> ip.x, ip.y
[10, 20]

>>> ip.x = 'changed' # x and y are read-only
Traceback [most recent call last]:
  File "stdin", line 1, in module
AttributeError: can't set attribute

>>> ip2 = ImmutablePoint[10, 20]

>>> ip == ip2
True
4 sau đây

_______________1

Đây cũng là những triển khai mặc định cho các lớp Python, vì vậy chúng ta có thể rút ngắn lớp của mình thành như sau

_______________2

Trong trường hợp này, chúng tôi duy trì hai quy tắc cho khả năng băm. Nhưng chúng tôi không thực sự có một lớp hữu ích, bởi vì mọi đối tượng thuộc loại

>>> h = HashableList[[1, 2, 3]]

>>> d = {h: 'hello'}

>>> d
{[1, 2, 3]: 'hello'}
0 chỉ bằng chính nó và sẽ luôn là
>>> h = HashableList[[1, 2, 3]]

>>> d = {h: 'hello'}

>>> d
{[1, 2, 3]: 'hello'}
1 khi so sánh với bất kỳ đối tượng nào khác, bất kể giá trị của nó là bao nhiêu

_______________3

Vì vậy, bạn có thể tuân theo hai quy tắc khả năng băm của Python cho lớp của mình hoặc bạn có thể tạo các đối tượng có thể băm, có thể thay đổi mà không thực sự hoạt động trong từ điển. Ngoại lệ duy nhất khi bạn có thể có một lớp có thể băm, có thể thay đổi là khi hàm băm dựa trên danh tính chứ không phải giá trị, điều này hạn chế nghiêm trọng tính hữu dụng của nó như một khóa từ điển. Điều đó có nghĩa là, một cách hiệu quả, chỉ các đối tượng bất biến mới có thể được băm và các đối tượng có thể thay đổi không thể được băm

Điều đó có nghĩa là gì đối với một đối tượng có thể băm Python?

Một đối tượng Python có thể băm là bất kỳ đối tượng nào có giá trị băm — một mã định danh số nguyên của đối tượng đó và không bao giờ thay đổi trong suốt thời gian tồn tại của nó. Để kiểm tra xem một đối tượng có thể băm hay không và tìm ra giá trị băm của nó [nếu có thể băm], chúng ta sử dụng hàm hash[] trên đối tượng này. in [ băm [ 3 ]. 14]]Đầu ra. 322818021289917443.

Python có thể băm được không?

dict , list , set vốn dĩ có thể thay đổi và do đó không thể băm được . str, bytes, freezeset và tuple là bất biến và do đó có thể băm.

Các đặc điểm của các đối tượng không thay đổi và có thể băm trong Python là gì?

0. 00 Đối tượng bất biến là loại đối tượng không thể sửa đổi sau khi đã tạo. Hash[] là một loại đối tượng mà bạn có thể gọi hash[] trên .

Tại sao các đối tượng có thể thay đổi không thể băm được?

Giá trị băm của một đối tượng sẽ không bao giờ thay đổi . Đây là lý do tại sao hầu hết các đối tượng có thể thay đổi không thể băm được. the hash value of an object should never change over the lifetime of that object. This is the reason that most mutable objects aren't hashable.

Chủ Đề