Là một từ điển Python là một ví dụ về bảng băm?


186

Một trong những cấu trúc dữ liệu cơ bản trong Python là từ điển, cho phép một người ghi lại các "khóa" để tìm kiếm "giá trị" của bất kỳ loại nào. Điều này được thực hiện trong nội bộ như một bảng băm? Nếu không, nó là gì?


2
Nếu bạn quan tâm đến các chi tiết kỹ thuật, một bài viết trong Beautiful Code đề cập đến các phần bên trong dicttriển khai của Python .
Torsten Marek

Đó là một trong những chương yêu thích của tôi trong Beautiful Code.
DGentry

4
Dưới đây là bài nói chuyện của Brandon Craig Rhodes thảo luận về cách hoạt động của từ điển python, youtube.com/watch?v=C4Kc8xzcA68 .
chandola

Bây giờ tôi đã tìm một sơ đồ đại diện cho một dict, nó giải mã việc thực hiện trong bộ nhớ và CPython. Cảm ơn đã tham khảo cuốn sách!
Chen A.

Câu trả lời:


238

Vâng, nó là một ánh xạ băm hoặc bảng băm. Bạn có thể đọc một mô tả về việc thực hiện chính tả của python, như được viết bởi Tim Peters, tại đây .

Đó là lý do tại sao bạn không thể sử dụng thứ gì đó 'không thể băm' làm khóa chính tả, như danh sách:

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

Bạn có thể đọc thêm về bảng băm hoặc kiểm tra xem nó đã được thực hiện như thế nào trong pythontại sao nó được thực hiện theo cách đó .


1
Các đường nối liên kết Tim Peters bị phá vỡ, có một liên kết sạch ngoài đó không?
Matt Alcock

1
@MattAlcock: Tôi đã cập nhật liên kết. Đôi khi (thường là do ai đó muốn xóa địa chỉ email của họ ở đâu đó), kho lưu trữ danh sách python được xây dựng lại và id của email thay đổi, do đó phá vỡ các liên kết này. Các quản trị viên pydotorg thường cố gắng tránh điều đó trong những ngày này.
Martijn Pieters

Nhưng sử dụng .keys()có thể lấy một danh sách các khóa. Một bảng băm thực sự sẽ không lưu trữ khóa, chỉ cần băm để tiết kiệm không gian.
noɥʇʎԀʎzɐɹƆ

Mô tả đầy đủ hơn về việc thực hiện lệnh python tại đây: laurentluce.com/posts/python-dipedia-im THỰCation
Daniel Goldfarb

31

Phải có nhiều từ điển Python hơn là tra cứu bảng trên hàm băm (). Bằng thử nghiệm vũ phu tôi đã tìm thấy sự va chạm băm này :

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

Tuy nhiên, nó không phá vỡ từ điển:

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

Kiểm tra sự tỉnh táo:

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

Có thể có một mức tra cứu khác ngoài hàm băm () để tránh va chạm giữa các khóa từ điển. Hoặc có thể dict () sử dụng hàm băm khác.

(Nhân tiện, điều này trong Python 2.7.10. Câu chuyện tương tự trong Python 3.4.3 và 3.5.0 với sự va chạm tại hash(1.1) == hash(214748749.8).)


14
Vì vậy, va chạm là không thể tránh khỏi. Đặt S có thể chứa một số lượng lớn các mục và bạn muốn nó băm vào một số mà máy tính có thể lưu trữ. Mỗi triển khai có thể sử dụng của bảng băm đều giải quyết các xung đột, với hai trong số các phương thức thường gặp nhất là a) mở địa chỉ và b) xâu chuỗi. Chỉ vì nó không sử dụng hàm băm hoàn hảo không có nghĩa là nó không phải là bảng băm.
TurnipEntropy

1
Sự va chạm sẽ xảy ra nói chung, bởi vì có vô số giá trị có thể băm và mã băm hữu hạn. Ngay cả một bảng băm sẽ phải xử lý va chạm bằng cách nào đó.
Yanfeng Liu

3
@YanfengLiu Tôi tin rằng đó là chính xác những điểm mà TurnipEntropy đã thực hiện.
Bob Stein

1
Trong Python 3.7, có vẻ như có 2E20 trừ đi 1 giá trị băm có thể, trên thực tế. Từ -1E20 trừ 1 đến (+) 1E20 trừ 1. Hãy thử 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.')Điều này cho số thập phân 19 chữ số - -4037225020714749784nếu bạn đủ táo bạo để quan tâm. Tiếp tục bằng từ của riêng bạn, trẻ em và hàm băm vẫn là một số có 19 chữ số. Tôi giả sử có giới hạn về độ dài của chuỗi bạn có thể băm trong Python, nhưng an toàn để nói nhiều chuỗi có thể hơn các giá trị có thể. Và hash(False)= 0 bằng cách này.
Will Croxford

22

Đúng. Trong nội bộ, nó được thực hiện dưới dạng băm mở dựa trên đa thức nguyên thủy trên Z / 2 ( nguồn ).


7

Để mở rộng theo lời giải thích của nosklo:

a = {}
b = ['some', 'list']
a[b] = 'some' # this won't work
a[tuple(b)] = 'some' # this will, same as a['some', 'list']
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.