Hướng dẫn does python have hash tables? - python có bảng băm không?


Các bảng Hash là một loại cấu trúc dữ liệu trong đó địa chỉ hoặc giá trị chỉ mục của phần tử dữ liệu được tạo từ hàm băm. Điều đó làm cho việc truy cập dữ liệu nhanh hơn khi giá trị chỉ mục hoạt động như một khóa cho giá trị dữ liệu. Nói cách khác, bảng băm lưu trữ các cặp giá trị khóa nhưng khóa được tạo thông qua hàm băm.

Show

Vì vậy, chức năng tìm kiếm và chèn của một phần tử dữ liệu trở nên nhanh hơn nhiều khi chính các giá trị chính trở thành chỉ mục của mảng lưu trữ dữ liệu.

Trong Python, các loại dữ liệu từ điển đại diện cho việc thực hiện các bảng băm. Các khóa trong từ điển đáp ứng các yêu cầu sau.

  • Các khóa của từ điển có thể băm, tức là được tạo bằng hàm băm tạo ra kết quả duy nhất cho mỗi giá trị duy nhất được cung cấp cho hàm băm.

  • Thứ tự của các yếu tố dữ liệu trong từ điển không được sửa.

Vì vậy, chúng tôi thấy việc triển khai bảng băm bằng cách sử dụng các loại dữ liệu từ điển như dưới đây.

Truy cập các giá trị trong từ điển

Để truy cập các phần tử từ điển, bạn có thể sử dụng các dấu ngoặc vuông quen thuộc cùng với khóa để có được giá trị của nó.

Thí dụ

# Declare a dictionary 
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}

# Accessing the dictionary with its key
print "dict['Name']: ", dict['Name']
print "dict['Age']: ", dict['Age']

Đầu ra

Khi mã trên được thực thi, nó sẽ tạo ra kết quả sau -

dict['Name']:  Zara
dict['Age']:  7

Cập nhật từ điển

Bạn có thể cập nhật từ điển bằng cách thêm một mục nhập mới hoặc một cặp giá trị khóa, sửa đổi một mục nhập hiện có hoặc xóa một mục nhập hiện có như được hiển thị bên dưới trong ví dụ đơn giản-

Thí dụ

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']

Đầu ra

Khi mã trên được thực thi, nó sẽ tạo ra kết quả sau -

dict['Age']:  8
dict['School']:  DPS School

Cập nhật từ điển

Bạn có thể cập nhật từ điển bằng cách thêm một mục nhập mới hoặc một cặp giá trị khóa, sửa đổi một mục nhập hiện có hoặc xóa một mục nhập hiện có như được hiển thị bên dưới trong ví dụ đơn giản-

Thí dụ

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']

Đầu ra

Khi mã trên được thực thi, nó sẽ tạo ra kết quả sau -

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable

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

>>> hash(1.1)

>>> hash(4504.1)

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


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

.

.

Được phát minh hơn nửa thế kỷ trước, bảng băm là một cấu trúc dữ liệu cổ điển là nền tảng cho lập trình. Cho đến ngày nay, nó giúp giải quyết nhiều vấn đề thực tế, chẳng hạn như bảng cơ sở dữ liệu lập chỉ mục, bộ nhớ đệm giá trị tính toán hoặc thực hiện các bộ. Nó thường xuất hiện trong các cuộc phỏng vấn việc làm, và Python sử dụng các bảng băm ở khắp nơi để tra cứu tên gần như ngay lập tức.hash table is a classic data structure that has been fundamental to programming. To this day, it helps solve many real-life problems, such as indexing database tables, caching computed values, or implementing sets. It often comes up in job interviews, and Python uses hash tables all over the place to make name lookups almost instantaneous.

Mặc dù Python đi kèm với bảng băm của riêng nó được gọi là

dict['Name']:  Zara
dict['Age']:  7
70, nhưng có thể hữu ích để hiểu cách các bảng băm hoạt động đằng sau bức màn. Một đánh giá mã hóa thậm chí có thể giao nhiệm vụ cho bạn với việc xây dựng một. Hướng dẫn này sẽ hướng dẫn bạn qua các bước thực hiện bảng băm từ đầu như thể không có ai trong Python. Trên đường đi, bạn sẽ phải đối mặt với một vài thách thức màllll giới thiệu các khái niệm quan trọng và cung cấp cho bạn ý tưởng về lý do tại sao các bảng băm nhanh như vậy.

Ngoài ra, bạn sẽ có được một khóa học về sự cố thực hành trong phát triển theo hướng thử nghiệm (TDD) và sẽ chủ động thực hành nó trong khi xây dựng bảng băm của bạn theo kiểu từng bước. Bạn không bắt buộc phải có bất kỳ kinh nghiệm nào trước đó với TDD, nhưng đồng thời, bạn đã giành được sự chán nản ngay cả khi bạn làm thế!test-driven development (TDD) and will actively practice it while building your hash table in a step-by-step fashion. You’re not required to have any prior experience with TDD, but at the same time, you won’t get bored even if you do!

Trong hướng dẫn này, bạn sẽ học:

  • Làm thế nào một bảng băm khác với một từ điểnhash table differs from a dictionary
  • Cách bạn có thể thực hiện một bảng băm từ đầu trong Pythonimplement a hash table from scratch in Python
  • Làm thế nào bạn có thể đối phó với các vụ va chạm băm và các thách thức kháchash collisions and other challenges
  • Các thuộc tính mong muốn của hàm băm là gìhash function are
  • Làm thế nào Python từ
    dict['Name']:  Zara
    dict['Age']:  7
    
    71 hoạt động đằng sau hậu trườngPython’s
    dict['Name']:  Zara
    dict['Age']:  7
    
    71
    works behind the scenes

Nó sẽ giúp ích nếu bạn đã quen thuộc với từ điển Python và có kiến ​​thức cơ bản về các nguyên tắc lập trình hướng đối tượng. Để có được mã nguồn đầy đủ và các bước trung gian của bảng băm được thực hiện trong hướng dẫn này, hãy theo liên kết dưới đây:

Tìm hiểu cấu trúc dữ liệu bảng Hash

Trước khi lặn sâu hơn, bạn nên làm quen với thuật ngữ này vì nó có thể hơi khó hiểu. Thông thường, thuật ngữ bảng băm hoặc bản đồ băm thường được sử dụng thay thế cho nhau với từ điển từ. Tuy nhiên, có một sự khác biệt tinh tế giữa hai khái niệm như trước đây cụ thể hơn so với các khái niệm sau.hash table or hash map is often used interchangeably with the word dictionary. However, there’s a subtle difference between the two concepts as the former is more specific than the latter.

Bảng băm vs từ điển

Trong khoa học máy tính, một từ điển là một loại dữ liệu trừu tượng được tạo thành từ các khóa và giá trị được sắp xếp theo cặp. Hơn nữa, nó xác định các hoạt động sau cho các yếu tố đó:keys and values arranged in pairs. Moreover, it defines the following operations for those elements:

  • Thêm một cặp giá trị khóa
  • Xóa một cặp giá trị khóa
  • Cập nhật một cặp giá trị khóa
  • Tìm một giá trị được liên kết với khóa đã cho

Theo một nghĩa nào đó, loại dữ liệu trừu tượng này giống như một từ điển song ngữ, trong đó các khóa là từ nước ngoài và các giá trị là định nghĩa hoặc dịch thuật của chúng cho các ngôn ngữ khác. Nhưng không phải lúc nào cũng có cảm giác tương đương giữa các khóa và giá trị. Một danh bạ điện thoại là một ví dụ khác về từ điển, kết hợp các tên với các số điện thoại tương ứng.bilingual dictionary, where the keys are foreign words, and the values are their definitions or translations to other languages. But there doesn’t always have to be a sense of equivalence between keys and values. A phone book is another example of a dictionary, which combines names with the corresponding phone numbers.

Từ điển có một vài thuộc tính thú vị. Một trong số đó là bạn có thể nghĩ về một từ điển như một hàm toán học chiếu một hoặc nhiều đối số cho chính xác một giá trị. Hậu quả trực tiếp của thực tế đó là như sau:

  • Chỉ các cặp giá trị khóa: Bạn có thể có một khóa mà không có giá trị hoặc cách khác trong từ điển. Họ luôn đi cùng nhau. You can’t have a key without the value or the other way around in a dictionary. They always go together.
  • Các khóa và giá trị tùy ý: Các khóa và giá trị có thể thuộc về hai bộ phân tách cùng loại hoặc riêng biệt. Cả khóa và giá trị có thể là hầu hết mọi thứ, chẳng hạn như số, từ hoặc thậm chí hình ảnh. Keys and values can belong to two disjoint sets of the same or separate types. Both keys and values may be almost anything, such as numbers, words, or even pictures.
  • Các cặp giá trị khóa không có thứ tự: Vì điểm cuối cùng, từ điển don thường xác định bất kỳ thứ tự nào cho các cặp giá trị khóa của chúng. Tuy nhiên, đó có thể được thực hiện cụ thể. Because of the last point, dictionaries don’t generally define any order for their key-value pairs. However, that might be implementation-specific.
  • Các khóa duy nhất: Một từ điển có thể chứa các khóa trùng lặp, bởi vì điều đó sẽ vi phạm định nghĩa của một hàm. A dictionary can’t contain duplicate keys, because that would violate the definition of a function.
  • Các giá trị không duy nhất: cùng một giá trị có thể được liên kết với nhiều khóa, nhưng nó không phải. The same value can be associated with many keys, but it doesn’t have to.

Có những khái niệm liên quan mở rộng ý tưởng của một từ điển. Ví dụ: Multimap cho phép bạn có nhiều hơn một giá trị cho mỗi khóa, trong khi bản đồ hai chiều không chỉ ánh xạ các phím cho các giá trị mà còn cung cấp ánh xạ theo hướng ngược lại. Tuy nhiên, trong hướng dẫn này, bạn sẽ chỉ xem xét từ điển thông thường, bản đồ chính xác một giá trị cho mỗi khóa.

Ở đây, một mô tả đồ họa của một từ điển giả định, trong đó ánh xạ một số khái niệm trừu tượng cho các từ tiếng Anh tương ứng của chúng:

Hướng dẫn does python have hash tables? - python có bảng băm không?
Mô tả đồ họa của một loại dữ liệu trừu tượng từ điển

Nó có một bản đồ một chiều của các phím cho các giá trị, là hai bộ phần tử hoàn toàn khác nhau. Ngay lập tức, bạn có thể thấy ít giá trị hơn các phím vì từ Bow xảy ra là một từ đồng âm có nhiều nghĩa. Về mặt khái niệm, từ điển này vẫn chứa bốn cặp, mặc dù. Tùy thuộc vào cách bạn quyết định thực hiện nó, bạn có thể sử dụng lại các giá trị lặp lại để bảo tồn bộ nhớ hoặc nhân đôi chúng để đơn giản.

Bây giờ, làm thế nào để bạn mã hóa một từ điển như vậy bằng ngôn ngữ lập trình? Câu trả lời đúng là bạn don, bởi vì hầu hết các ngôn ngữ hiện đại đều đi kèm với từ điển như các loại dữ liệu nguyên thủy hoặc các lớp trong các thư viện tiêu chuẩn của chúng. Python vận chuyển với loại

dict['Name']:  Zara
dict['Age']:  7
70 tích hợp, đã kết thúc một cấu trúc dữ liệu được tối ưu hóa cao được viết bằng C để bạn không phải tự viết từ điển.

Python sườn

dict['Name']:  Zara
dict['Age']:  7
70 cho phép bạn thực hiện tất cả các hoạt động từ điển được liệt kê ở đầu phần này:

>>>

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}

Với cú pháp khung vuông (

dict['Name']:  Zara
dict['Age']:  7
74), bạn có thể thêm một cặp giá trị khóa mới vào từ điển. Bạn cũng có thể cập nhật giá trị hoặc xóa một cặp hiện có được xác định bởi một khóa. Cuối cùng, bạn có thể tra cứu giá trị liên quan đến khóa đã cho.square bracket syntax (
dict['Name']:  Zara
dict['Age']:  7
74), you can add a new key-value pair to a dictionary. You can also update the value of or delete an existing pair identified by a key. Finally, you can look up the value associated with the given key.

Điều đó nói rằng, bạn có thể hỏi một câu hỏi khác. Làm thế nào để từ điển tích hợp thực sự hoạt động? Làm thế nào để nó ánh xạ các khóa của các loại dữ liệu tùy ý và làm thế nào để nó làm nó nhanh như vậy?

Tìm kiếm một triển khai hiệu quả của loại dữ liệu trừu tượng này được gọi là vấn đề từ điển. Một trong những giải pháp nổi tiếng nhất tận dụng cấu trúc dữ liệu bảng Hash mà bạn sắp khám phá. Tuy nhiên, lưu ý rằng đó là cách duy nhất để thực hiện từ điển nói chung. Một triển khai phổ biến khác được xây dựng trên đỉnh của một cây màu đỏ đỏ.dictionary problem. One of the most well-known solutions takes advantage of the hash table data structure that you’re about to explore. However, note that it isn’t the only way to implement a dictionary in general. Another popular implementation builds on top of a red-black tree.

Bảng băm: một mảng có hàm băm

Bạn đã bao giờ tự hỏi tại sao việc truy cập các yếu tố trình tự trong Python hoạt động rất nhanh, bất kể bạn yêu cầu chỉ số nào? Nói rằng bạn đang làm việc với một chuỗi các ký tự rất dài, như thế này:

>>>

dict['Name']:  Zara
dict['Age']:  7
0

Với cú pháp khung vuông (

dict['Name']:  Zara
dict['Age']:  7
74), bạn có thể thêm một cặp giá trị khóa mới vào từ điển. Bạn cũng có thể cập nhật giá trị hoặc xóa một cặp hiện có được xác định bởi một khóa. Cuối cùng, bạn có thể tra cứu giá trị liên quan đến khóa đã cho.

>>>

dict['Name']:  Zara
dict['Age']:  7
1

Với cú pháp khung vuông (

dict['Name']:  Zara
dict['Age']:  7
74), bạn có thể thêm một cặp giá trị khóa mới vào từ điển. Bạn cũng có thể cập nhật giá trị hoặc xóa một cặp hiện có được xác định bởi một khóa. Cuối cùng, bạn có thể tra cứu giá trị liên quan đến khóa đã cho.

  1. Điều đó nói rằng, bạn có thể hỏi một câu hỏi khác. Làm thế nào để từ điển tích hợp thực sự hoạt động? Làm thế nào để nó ánh xạ các khóa của các loại dữ liệu tùy ý và làm thế nào để nó làm nó nhanh như vậy?contiguous block of memory.
  2. Tìm kiếm một triển khai hiệu quả của loại dữ liệu trừu tượng này được gọi là vấn đề từ điển. Một trong những giải pháp nổi tiếng nhất tận dụng cấu trúc dữ liệu bảng Hash mà bạn sắp khám phá. Tuy nhiên, lưu ý rằng đó là cách duy nhất để thực hiện từ điển nói chung. Một triển khai phổ biến khác được xây dựng trên đỉnh của một cây màu đỏ đỏ.fixed size known up front.

Bảng băm: một mảng có hàm bămoffset, then you can get to the desired element in the array instantly by calculating a fairly straightforward formula:

Hướng dẫn does python have hash tables? - python có bảng băm không?
Bạn đã bao giờ tự hỏi tại sao việc truy cập các yếu tố trình tự trong Python hoạt động rất nhanh, bất kể bạn yêu cầu chỉ số nào? Nói rằng bạn đang làm việc với một chuỗi các ký tự rất dài, như thế này:

Có 2,6 tỷ ký tự từ việc lặp lại các chữ cái ASCII trong biến

dict['Name']:  Zara
dict['Age']:  7
75 ở trên, mà bạn có thể đếm với chức năng Python tựa ____176. Tuy nhiên, nhận được phần đầu tiên, giữa, cuối cùng hoặc bất kỳ ký tự nào khác từ chuỗi này cũng nhanh như nhau:

Điều tương tự cũng đúng với tất cả các loại trình tự trong Python, chẳng hạn như danh sách và bộ dữ liệu. Làm thế nào mà? Bí quyết cho một tốc độ rực rỡ như vậy là các chuỗi trong Python được hỗ trợ bởi một mảng, đó là một cấu trúc dữ liệu truy cập ngẫu nhiên. Nó tuân theo hai nguyên tắc:

Mảng chiếm một khối bộ nhớ tiếp giáp.hashing, which lets them translate an arbitrary key into an integer number that can work as an index in a regular array. So, instead of searching a value by a numeric index, you’ll look it up by an arbitrary key without a noticeable performance loss. That’s neat!

Mỗi phần tử trong mảng có kích thước cố định được biết đến phía trước.

Khi bạn biết địa chỉ bộ nhớ của một mảng, được gọi là bù, thì bạn có thể truy cập phần tử mong muốn trong mảng ngay lập tức bằng cách tính toán một công thức khá đơn giản:

Công thức để tính toán địa chỉ bộ nhớ của phần tử trình tựhash value or the hash code. It’s a number that can act as a digital fingerprint or a digest, usually much smaller than the original data, which lets you verify its integrity. If you’ve ever fetched a large file from the Internet, such as a disk image of a Linux distribution, then you may have noticed an MD5 or SHA-2 checksum on the download page.

Bạn bắt đầu ở phần bù mảng, đây cũng là địa chỉ của phần tử đầu tiên của mảng, với số không. Tiếp theo, bạn tiến về phía trước bằng cách thêm số byte cần thiết mà bạn nhận được bằng cách nhân kích thước phần tử với chỉ mục phần tử đích. Nó luôn luôn mất cùng một lượng thời gian để nhân và thêm một vài số lại với nhau.security and cryptography. For example, you typically store hashed passwords in databases to mitigate the risk of data leaks. Digital signatures involve hashing to create a message digest before encryption. Blockchain transactions are another prime example of using a hash function for cryptographic purposes.

Được rồi, vì vậy bạn biết rằng việc tìm một phần tử trong một mảng là nhanh chóng, bất kể phần tử đó nằm ở đâu. Bạn có thể lấy cùng một ý tưởng và sử dụng lại nó trong một từ điển? Đúng!hashing algorithms, they all share a few common properties that you’re about to discover in this section. Implementing a good hash function correctly is a difficult task that may require the understanding of advanced math involving prime numbers. Fortunately, you don’t usually need to implement such an algorithm by hand.

Python đi kèm với một mô-đun Hashlib tích hợp, cung cấp nhiều hàm băm mật mã nổi tiếng, cũng như các thuật toán kiểm tra ít an toàn hơn. Ngôn ngữ cũng có chức năng toàn cầu

dict['Name']:  Zara
dict['Age']:  7
71, được sử dụng chủ yếu để tra cứu phần tử nhanh trong từ điển và bộ. Bạn có thể nghiên cứu cách nó hoạt động đầu tiên để tìm hiểu về các thuộc tính quan trọng nhất của các hàm băm.

Kiểm tra Python sườn tích hợp dict['Name']: Zara dict['Age']: 7 71

Trước khi đâm vào việc thực hiện chức năng băm từ đầu, hãy giữ một lúc và phân tích Python,

dict['Name']:  Zara
dict['Age']:  7
71 để chưng cất các thuộc tính của nó. Điều này sẽ giúp bạn hiểu những vấn đề nào liên quan khi thiết kế chức năng băm của riêng bạn.

Để bắt đầu, hãy thử gọi

dict['Name']:  Zara
dict['Age']:  7
71 trên một vài nghĩa đen kiểu dữ liệu được tích hợp vào Python, chẳng hạn như số và chuỗi, để xem chức năng hoạt động như thế nào:

>>>

dict['Name']:  Zara
dict['Age']:  7
2

Đã có một số quan sát mà bạn có thể thực hiện bằng cách nhìn vào kết quả. Đầu tiên, hàm băm tích hợp có thể trả về các giá trị khác nhau ở đầu của bạn cho một số đầu vào được hiển thị ở trên. Mặc dù đầu vào số dường như luôn tạo ra một giá trị băm giống hệt nhau, nhưng chuỗi rất có thể không có. Tại sao vậy? Có vẻ như

dict['Name']:  Zara
dict['Age']:  7
71 là một chức năng không xác định, nhưng điều đó không thể là sự thật!

Khi bạn gọi

dict['Name']:  Zara
dict['Age']:  7
71 với cùng một đối số trong phiên phiên dịch hiện tại của bạn, thì bạn sẽ tiếp tục nhận được kết quả tương tự:

>>>

dict['Name']:  Zara
dict['Age']:  7
3

Đã có một số quan sát mà bạn có thể thực hiện bằng cách nhìn vào kết quả. Đầu tiên, hàm băm tích hợp có thể trả về các giá trị khác nhau ở đầu của bạn cho một số đầu vào được hiển thị ở trên. Mặc dù đầu vào số dường như luôn tạo ra một giá trị băm giống hệt nhau, nhưng chuỗi rất có thể không có. Tại sao vậy? Có vẻ như

dict['Name']:  Zara
dict['Age']:  7
71 là một chức năng không xác định, nhưng điều đó không thể là sự thật!immutable and don’t change throughout an object’s lifetime. However, as soon as you exit Python and start it again, then you’ll almost certainly see different hash values across Python invocations. You can test this by trying the
dict['Name']:  Zara
dict['Age']:  7
83 option to run a one-liner script in your terminal:

  • Khi bạn gọi
    dict['Name']:  Zara
    dict['Age']:  7
    
    71 với cùng một đối số trong phiên phiên dịch hiện tại của bạn, thì bạn sẽ tiếp tục nhận được kết quả tương tự:
  • Điều đó bởi vì các giá trị băm là bất biến và không thay đổi trong suốt vòng đời của một đối tượng. Tuy nhiên, ngay khi bạn thoát Python và bắt đầu lại, thì bạn sẽ gần như chắc chắn thấy các giá trị băm khác nhau trên các lời mời của Python. Bạn có thể kiểm tra điều này bằng cách thử tùy chọn
    dict['Name']:  Zara
    dict['Age']:  7
    
    83 để chạy tập lệnh một lớp trong thiết bị đầu cuối của bạn:

dict['Name']:  Zara
dict['Age']:  7
4

dict['Name']:  Zara
dict['Age']:  7
5

các cửa sổ

Linux + MacOShash randomization by default for some inputs, such as strings, to make the hash values less predictable. This makes

dict['Name']:  Zara
dict['Age']:  7
71 a bit more secure and the attack more difficult. You can disable randomization, though, by setting a fixed seed value through the
dict['Name']:  Zara
dict['Age']:  7
85 environment variable, for example:

  • Khi bạn gọi
    dict['Name']:  Zara
    dict['Age']:  7
    
    71 với cùng một đối số trong phiên phiên dịch hiện tại của bạn, thì bạn sẽ tiếp tục nhận được kết quả tương tự:
  • Điều đó bởi vì các giá trị băm là bất biến và không thay đổi trong suốt vòng đời của một đối tượng. Tuy nhiên, ngay khi bạn thoát Python và bắt đầu lại, thì bạn sẽ gần như chắc chắn thấy các giá trị băm khác nhau trên các lời mời của Python. Bạn có thể kiểm tra điều này bằng cách thử tùy chọn
    dict['Name']:  Zara
    dict['Age']:  7
    
    83 để chạy tập lệnh một lớp trong thiết bị đầu cuối của bạn:

dict['Name']:  Zara
dict['Age']:  7
6

dict['Name']:  Zara
dict['Age']:  7
7

các cửa sổdeterministic function, which is one of the most fundamental features of the hash function.

Linux + MacOSuniversal as it takes arbitrary inputs. In other words, it takes values of various types and sizes. The function accepts strings and floating-point numbers regardless of their length or magnitude without complaining. In fact, you can calculate a hash value of more exotic types too:

>>>

Đã có một số quan sát mà bạn có thể thực hiện bằng cách nhìn vào kết quả. Đầu tiên, hàm băm tích hợp có thể trả về các giá trị khác nhau ở đầu của bạn cho một số đầu vào được hiển thị ở trên. Mặc dù đầu vào số dường như luôn tạo ra một giá trị băm giống hệt nhau, nhưng chuỗi rất có thể không có. Tại sao vậy? Có vẻ như
dict['Name']:  Zara
dict['Age']:  7
71 là một chức năng không xác định, nhưng điều đó không thể là sự thật!

Khi bạn gọi

dict['Name']:  Zara
dict['Age']:  7
71 với cùng một đối số trong phiên phiên dịch hiện tại của bạn, thì bạn sẽ tiếp tục nhận được kết quả tương tự:

>>>

dict['Name']:  Zara
dict['Age']:  7
9

Đã có một số quan sát mà bạn có thể thực hiện bằng cách nhìn vào kết quả. Đầu tiên, hàm băm tích hợp có thể trả về các giá trị khác nhau ở đầu của bạn cho một số đầu vào được hiển thị ở trên. Mặc dù đầu vào số dường như luôn tạo ra một giá trị băm giống hệt nhau, nhưng chuỗi rất có thể không có. Tại sao vậy? Có vẻ như

dict['Name']:  Zara
dict['Age']:  7
71 là một chức năng không xác định, nhưng điều đó không thể là sự thật!

Khi bạn gọi dict['Name']: Zara dict['Age']: 7 71 với cùng một đối số trong phiên phiên dịch hiện tại của bạn, thì bạn sẽ tiếp tục nhận được kết quả tương tự:

Điều đó bởi vì các giá trị băm là bất biến và không thay đổi trong suốt vòng đời của một đối tượng. Tuy nhiên, ngay khi bạn thoát Python và bắt đầu lại, thì bạn sẽ gần như chắc chắn thấy các giá trị băm khác nhau trên các lời mời của Python. Bạn có thể kiểm tra điều này bằng cách thử tùy chọn

dict['Name']:  Zara
dict['Age']:  7
83 để chạy tập lệnh một lớp trong thiết bị đầu cuối của bạn:fixed-size output no matter how big the input was. In Python, the hash value is an integer with a moderate magnitude. Occasionally, it may come out as a negative number, so take that into account if you plan to rely on hash values in one way or another:

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
0

Đã có một số quan sát mà bạn có thể thực hiện bằng cách nhìn vào kết quả. Đầu tiên, hàm băm tích hợp có thể trả về các giá trị khác nhau ở đầu của bạn cho một số đầu vào được hiển thị ở trên. Mặc dù đầu vào số dường như luôn tạo ra một giá trị băm giống hệt nhau, nhưng chuỗi rất có thể không có. Tại sao vậy? Có vẻ như

dict['Name']:  Zara
dict['Age']:  7
71 là một chức năng không xác định, nhưng điều đó không thể là sự thật!hash collision when two different inputs produce the same hash value.

Va chạm băm là một khái niệm thiết yếu trong các bảng băm, mà bạn sẽ xem xét lại sau nhiều hơn khi thực hiện bảng băm tùy chỉnh của mình. Hiện tại, bạn có thể nghĩ về chúng là rất không mong muốn. Bạn nên tránh va chạm băm càng nhiều càng tốt vì chúng có thể dẫn đến tra cứu rất không hiệu quả và có thể bị tin tặc khai thác. Do đó, chức năng băm tốt phải giảm thiểu khả năng va chạm băm cho cả bảo mật và hiệu quả.

Trong thực tế, điều này thường có nghĩa là hàm băm phải gán các giá trị phân phối đồng đều trên không gian có sẵn. Bạn có thể trực quan hóa việc phân phối các giá trị băm được tạo bởi Python từ

dict['Name']:  Zara
dict['Age']:  7
71 bằng cách vẽ một biểu đồ văn bản trong thiết bị đầu cuối của bạn. Sao chép khối mã sau và lưu nó trong một tệp có tên
dict['Name']:  Zara
dict['Age']:  7
95:uniformly distributed values over the available space. You can visualize the distribution of hash values produced by Python’s
dict['Name']:  Zara
dict['Age']:  7
71 by plotting a textual histogram in your terminal. Copy the following block of code and save it in a file named
dict['Name']:  Zara
dict['Age']:  7
95:

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
1

Nó sử dụng một thể hiện

dict['Name']:  Zara
dict['Age']:  7
96 để biểu diễn thuận tiện biểu đồ của các giá trị băm của các mục được cung cấp. Các giá trị băm được trải đều trên số lượng container được chỉ định bằng cách gói chúng bằng toán tử modulo. Bây giờ, bạn có thể lấy một trăm ký tự ASCII có thể in, sau đó tính toán các giá trị băm của chúng và hiển thị phân phối của chúng:

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
2

Khi chỉ có hai container, bạn nên mong đợi khoảng năm mươi năm mươi phân phối. Thêm nhiều container nên dẫn đến việc lấp đầy chúng ít nhiều. Như bạn có thể thấy, hàm

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp khá tốt nhưng không hoàn hảo trong việc phân phối các giá trị băm đồng đều.

Liên quan đến điều đó, phân phối đồng đều của các giá trị băm thường là giả ngẫu nhiên, điều này đặc biệt quan trọng đối với các hàm băm mật mã. Điều này ngăn chặn những kẻ tấn công tiềm năng sử dụng phân tích thống kê để thử và dự đoán mối tương quan giữa đầu vào và đầu ra của hàm băm. Cân nhắc thay đổi một chữ cái trong một chuỗi và kiểm tra xem điều đó ảnh hưởng đến giá trị băm kết quả như thế nào trong Python:pseudo-random, which is especially important for cryptographic hash functions. This prevents potential attackers from using statistical analysis to try and predict the correlation between input and output of the hash function. Consider altering a single letter in a string, and check how that affects the resulting hash value in Python:

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
3

Khi chỉ có hai container, bạn nên mong đợi khoảng năm mươi năm mươi phân phối. Thêm nhiều container nên dẫn đến việc lấp đầy chúng ít nhiều. Như bạn có thể thấy, hàm

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp khá tốt nhưng không hoàn hảo trong việc phân phối các giá trị băm đồng đều.

Liên quan đến điều đó, phân phối đồng đều của các giá trị băm thường là giả ngẫu nhiên, điều này đặc biệt quan trọng đối với các hàm băm mật mã. Điều này ngăn chặn những kẻ tấn công tiềm năng sử dụng phân tích thống kê để thử và dự đoán mối tương quan giữa đầu vào và đầu ra của hàm băm. Cân nhắc thay đổi một chữ cái trong một chuỗi và kiểm tra xem điều đó ảnh hưởng đến giá trị băm kết quả như thế nào trong Python:

Bây giờ, nó có một giá trị băm hoàn toàn khác, mặc dù chỉ có một chữ cái khác nhau. Các giá trị băm thường phải chịu hiệu ứng tuyết lở, vì ngay cả sự thay đổi đầu vào nhỏ nhất cũng được khuếch đại. Tuy nhiên, tính năng này của hàm băm không cần thiết vì mục đích thực hiện cấu trúc dữ liệu bảng băm.

Trong hầu hết các trường hợp, Python sườn

dict['Name']:  Zara
dict['Age']:  7
71 thể hiện một đặc điểm không cần thiết khác của các hàm băm mật mã, bắt nguồn từ nguyên tắc pigeonhole được đề cập trước đó. Nó hoạt động giống như một chức năng một chiều bởi vì việc tìm kiếm nghịch đảo của nó là không thể trong phần lớn các trường hợp. Tuy nhiên, có những ngoại lệ đáng chú ý:fast, even for very big inputs. On a modern computer, calling
dict['Name']:  Zara
dict['Age']:  7
71 with a string of 100 million characters as the argument returns instantaneously. If it weren’t so fast, then the additional overhead of the hash value computation would offset the benefits of hashing in the first place.

Giá trị băm của các số nguyên nhỏ bằng với chính chúng, đây là một chi tiết triển khai mà CPython sử dụng cho sự đơn giản và hiệu quả. Hãy nhớ rằng các giá trị băm thực tế không có vấn đề gì miễn là bạn có thể tính toán chúng theo cách xác định.

Cuối cùng nhưng không kém phần quan trọng, việc tính toán giá trị băm trong Python là nhanh, ngay cả đối với các đầu vào rất lớn. Trên một máy tính hiện đại, gọi

dict['Name']:  Zara
dict['Age']:  7
71 với chuỗi 100 triệu ký tự khi đối số quay trở lại ngay lập tức. Nếu nó không quá nhanh, thì chi phí bổ sung của tính toán giá trị băm sẽ bù đắp lợi ích của việc băm ngay từ đầu.

Xác định các thuộc tính hàm bămDựa trên những gì bạn đã học được cho đến nay về Python từ
dict['Name']:  Zara
dict['Age']:  7
71, giờ đây bạn có thể đưa ra kết luận về các thuộc tính mong muốn của hàm băm nói chung. Ở đây, một bản tóm tắt các tính năng đó, so sánh chức năng băm thường với hương vị mật mã của nó:
Tính năng
Hàm bămChức năng băm mật mãChức năng băm mật mã
Xác địnhChức năng băm mật mãChức năng băm mật mã
Xác địnhChức năng băm mật mãChức năng băm mật mã
Xác địnhChức năng băm mật mãChức năng băm mật mã
Xác địnhChức năng băm mật mãChức năng băm mật mã
Xác định Chức năng băm mật mã
Xác định Chức năng băm mật mã
Xác định Chức năng băm mật mã
Xác định Chức năng băm mật mã

Xác định

Đầu vào phổ quát

Đầu ra có kích thước cố định

>>>

Nhanh chóng để tính toán

Phân bố đồng đều

Vì vậy, tại sao Python nhấn mạnh vào việc sử dụng một chức năng khác để băm sau đó?

Trước hết, mục đích của

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
01 khác với
dict['Name']:  Zara
dict['Age']:  7
71, vì vậy các bản phân phối Python khác có thể thực hiện bản sắc theo những cách khác. Thứ hai, địa chỉ bộ nhớ có thể dự đoán được mà không có phân phối đồng đều, điều này vừa không an toàn và không hiệu quả nghiêm trọng đối với băm. Cuối cùng, các đối tượng bằng nhau thường nên tạo ra cùng một mã băm ngay cả khi chúng có danh tính riêng biệt.

Với cách đó, cuối cùng bạn cũng có thể nghĩ đến việc làm cho chức năng băm của riêng bạn.

Làm chức năng băm của riêng bạn

Thiết kế chức năng băm đáp ứng tất cả các yêu cầu từ đầu là khó. Như đã đề cập trước đây, bạn sẽ sử dụng hàm

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp để tạo nguyên mẫu bảng băm của bạn trong phần tiếp theo. Tuy nhiên, cố gắng xây dựng chức năng băm từ đầu là một cách tuyệt vời để học cách nó hoạt động. Đến cuối phần này, bạn sẽ chỉ có một hàm băm thô sơ mà khác xa với sự hoàn hảo, nhưng bạn sẽ có được những hiểu biết có giá trị.

Trong bài tập này, bạn có thể giới hạn bản thân chỉ một loại dữ liệu lúc đầu và thực hiện chức năng băm thô xung quanh nó. Ví dụ: bạn có thể xem xét các chuỗi và tổng hợp các giá trị thứ tự của các ký tự riêng lẻ trong đó:ordinal values of the individual characters in them:

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
5

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
6

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

Ngay lập tức, bạn sẽ nhận thấy một vài vấn đề với chức năng này. Không chỉ là chuỗi cụ thể mà còn phải chịu sự phân phối mã băm kém, có xu hướng hình thành các cụm ở các giá trị đầu vào tương tự. Một thay đổi nhỏ trong đầu vào có ít ảnh hưởng đến đầu ra quan sát được. Thậm chí tệ hơn, chức năng vẫn không nhạy cảm với thứ tự ký tự trong văn bản, có nghĩa là các phương pháp của cùng một từ, chẳng hạn như Loren và Loner, dẫn đến va chạm mã băm.

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
7

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

Ngay lập tức, bạn sẽ nhận thấy một vài vấn đề với chức năng này. Không chỉ là chuỗi cụ thể mà còn phải chịu sự phân phối mã băm kém, có xu hướng hình thành các cụm ở các giá trị đầu vào tương tự. Một thay đổi nhỏ trong đầu vào có ít ảnh hưởng đến đầu ra quan sát được. Thậm chí tệ hơn, chức năng vẫn không nhạy cảm với thứ tự ký tự trong văn bản, có nghĩa là các phương pháp của cùng một từ, chẳng hạn như Loren và Loner, dẫn đến va chạm mã băm.

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
8

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

>>>

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
9

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

>>>

dict['Age']:  8
dict['School']:  DPS School
0

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

>>>

dict['Age']:  8
dict['School']:  DPS School
1

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

Ngay lập tức, bạn sẽ nhận thấy một vài vấn đề với chức năng này. Không chỉ là chuỗi cụ thể mà còn phải chịu sự phân phối mã băm kém, có xu hướng hình thành các cụm ở các giá trị đầu vào tương tự. Một thay đổi nhỏ trong đầu vào có ít ảnh hưởng đến đầu ra quan sát được. Thậm chí tệ hơn, chức năng vẫn không nhạy cảm với thứ tự ký tự trong văn bản, có nghĩa là các phương pháp của cùng một từ, chẳng hạn như Loren và Loner, dẫn đến va chạm mã băm.

>>>

dict['Age']:  8
dict['School']:  DPS School
2

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

>>>

dict['Age']:  8
dict['School']:  DPS School
3

Bạn lặp lại văn bản bằng cách sử dụng biểu thức trình tạo, sau đó biến mỗi ký tự riêng lẻ thành điểm mã unicode tương ứng với hàm

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
06 tích hợp và cuối cùng tổng hợp các giá trị thứ tự với nhau. Điều này sẽ loại bỏ một số duy nhất cho bất kỳ văn bản nào được cung cấp dưới dạng đối số:

Ngay lập tức, bạn sẽ nhận thấy một vài vấn đề với chức năng này. Không chỉ là chuỗi cụ thể mà còn phải chịu sự phân phối mã băm kém, có xu hướng hình thành các cụm ở các giá trị đầu vào tương tự. Một thay đổi nhỏ trong đầu vào có ít ảnh hưởng đến đầu ra quan sát được. Thậm chí tệ hơn, chức năng vẫn không nhạy cảm với thứ tự ký tự trong văn bản, có nghĩa là các phương pháp của cùng một từ, chẳng hạn như Loren và Loner, dẫn đến va chạm mã băm.

>>>

dict['Age']:  8
dict['School']:  DPS School
4

Việc phân phối là không đồng đều. Hơn nữa, có sáu container có sẵn, nhưng một container bị thiếu trong biểu đồ. Vấn đề này bắt nguồn từ thực tế là hai dấu nháy đơn được thêm vào

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
14 gây ra hầu như tất cả các khóa trong ví dụ này để dẫn đến một số băm chẵn. Bạn có thể tránh điều này bằng cách loại bỏ dấu nháy đơn bên trái nếu nó tồn tại:

>>>

dict['Age']:  8
dict['School']:  DPS School
5

Cuộc gọi đến

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
19 sẽ chỉ ảnh hưởng đến một chuỗi nếu nó bắt đầu với tiền tố được chỉ định để dải.

Đương nhiên, bạn có thể tiếp tục cải thiện chức năng băm của mình hơn nữa. Nếu bạn tò mò về việc triển khai

dict['Name']:  Zara
dict['Age']:  7
71 cho các chuỗi và chuỗi byte trong Python, thì hiện tại nó sẽ sử dụng thuật toán Siphash, có thể trở lại phiên bản FNV được sửa đổi nếu trước đây không có sẵn. Để tìm ra thuật toán băm nào mà trình thông dịch Python của bạn đang sử dụng, hãy tiếp cận với mô -đun
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
21:

>>>

dict['Age']:  8
dict['School']:  DPS School
6

Tại thời điểm này, bạn có một nắm bắt khá tốt về chức năng băm, cách thức hoạt động của nó và những thách thức mà bạn có thể phải đối mặt trong việc thực hiện nó. Trong các phần sắp tới, bạn sẽ sử dụng hàm băm để xây dựng bảng băm. Việc lựa chọn một thuật toán băm cụ thể sẽ ảnh hưởng đến hiệu suất của bảng băm. Với kiến ​​thức đó là nền tảng của bạn, bạn có thể thoải mái gắn bó với

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp từ bây giờ.

Xây dựng nguyên mẫu bảng băm trong Python với TDD

Trong phần này, bạn sẽ tạo ra một lớp tùy chỉnh đại diện cho cấu trúc dữ liệu bảng Hash. Nó đã thắng được hỗ trợ bởi một từ điển Python, vì vậy bạn có thể xây dựng một bảng băm từ đầu và thực hành những gì bạn đã học được cho đến nay. Đồng thời, bạn sẽ mô hình hóa việc triển khai của mình sau từ điển tích hợp bằng cách bắt chước các tính năng thiết yếu nhất của nó.

Dưới đây là danh sách các yêu cầu cấp cao cho bảng băm của bạn, mà bạn sẽ thực hiện ngay bây giờ. Đến cuối phần này, bảng băm của bạn sẽ thể hiện các tính năng cốt lõi sau. Nó sẽ cho phép bạn:core features. It’ll let you:

  • Tạo một bảng băm trống
  • Chèn một cặp giá trị khóa vào bảng băm
  • Xóa một cặp giá trị khóa khỏi bảng băm
  • Tìm một giá trị theo phím trong bảng băm
  • Cập nhật giá trị được liên kết với khóa hiện có
  • Kiểm tra xem bảng băm có khóa nhất định không

Ngoài ra, bạn sẽ thực hiện một vài tính năng không cần thiết nhưng vẫn hữu ích. Cụ thể, bạn sẽ có thể:nonessential but still useful features. Specifically, you should be able to:

  • Tạo một bảng băm từ một từ điển Python
  • Tạo một bản sao nông của bảng băm hiện có
  • Trả về giá trị mặc định nếu không tìm thấy khóa tương ứng
  • Báo cáo số lượng cặp giá trị khóa được lưu trữ trong bảng băm
  • Trả về các khóa, giá trị và cặp giá trị khóa
  • Làm cho bảng băm có thể đi được
  • Làm cho bảng băm có thể so sánh bằng cách sử dụng toán tử kiểm tra bình đẳng
  • Hiển thị biểu diễn văn bản của bảng băm

Trong khi thực hiện các tính năng này, bạn sẽ tích cực thực hiện phát triển theo hướng thử nghiệm bằng cách dần dần thêm nhiều tính năng vào bảng băm của bạn. Lưu ý rằng nguyên mẫu của bạn sẽ chỉ bao gồm những điều cơ bản. Bạn sẽ học cách đối phó với một số trường hợp góc nâng cao hơn một chút sau đó trong hướng dẫn này. Cụ thể, phần này đã giành được bao gồm cách làm thế nào:test-driven development by gradually adding more features to your hash table. Note that your prototype will only cover the basics. You’ll learn how to cope with some more advanced corner cases a bit later in this tutorial. In particular, this section won’t cover how to:

  • Giải quyết va chạm mã băm
  • Giữ lại thứ tự chèn
  • Thay đổi kích thước bảng băm một cách linh hoạt
  • Tính hệ số tải

Hãy sử dụng các tài liệu bổ sung làm điểm kiểm soát kiểm soát nếu bạn bị kẹt hoặc nếu bạn muốn bỏ qua một số bước tái cấu trúc trung gian. Mỗi tiểu mục kết thúc với một giai đoạn thực hiện hoàn chỉnh và các thử nghiệm tương ứng mà bạn có thể bắt đầu. Lấy liên kết sau và tải xuống các tài liệu hỗ trợ với mã nguồn đầy đủ và các bước trung gian được sử dụng trong hướng dẫn này:control checkpoints if you get stuck or if you’d like to skip some of the intermediate refactoring steps. Each subsection ends with a complete implementation stage and the corresponding tests that you can start from. Grab the following link and download the supporting materials with the complete source code and the intermediate steps used in this tutorial:

Tham gia một khóa học về sự phát triển theo hướng thử nghiệm

Bây giờ bạn đã biết các thuộc tính cấp cao của hàm băm và mục đích của nó, bạn có thể thực hiện phương pháp phát triển theo hướng thử nghiệm để xây dựng bảng băm. Nếu bạn chưa bao giờ thử kỹ thuật lập trình này trước đây, thì nó sẽ giảm xuống còn ba bước mà bạn có xu hướng lặp lại trong một chu kỳ:

  1. Red Red: Hãy nghĩ về một trường hợp thử nghiệm duy nhất và tự động hóa nó bằng cách sử dụng khung kiểm tra đơn vị mà bạn chọn. Bài kiểm tra của bạn sẽ thất bại vào thời điểm này, nhưng điều đó ổn. Người chạy thử thường chỉ ra một thử nghiệm thất bại với màu đỏ, do đó tên của giai đoạn chu kỳ này. Think of a single test case and automate it using a unit testing framework of your choice. Your test will fail at this point, but that’s okay. Test runners typically indicate a failing test with the red color, hence the name of this cycle phase.
  2. Màu xanh lá cây: Thực hiện tối thiểu để làm cho bài kiểm tra của bạn vượt qua, nhưng không còn nữa! Điều này sẽ đảm bảo bảo hiểm mã cao hơn và giúp bạn viết mã dự phòng. Báo cáo thử nghiệm sẽ làm sáng lên một màu xanh lá cây thỏa mãn sau đó. Implement the bare minimum to make your test pass, but no more! This will ensure higher code coverage and spare you from writing redundant code. The test report will light up to a satisfying green color afterward.
  3. Tùy chọn: Tùy chọn, sửa đổi mã của bạn mà không thay đổi hành vi của nó miễn là tất cả các trường hợp kiểm tra vẫn vượt qua. Bạn có thể sử dụng điều này như một cơ hội để loại bỏ sự trùng lặp và cải thiện khả năng đọc mã của bạn. Optionally, modify your code without changing its behavior as long as all test cases still pass. You can use this as an opportunity to remove duplication and improve the readability of your code.

Python đi kèm với gói nhất quán ra khỏi hộp, nhưng thư viện pytest của bên thứ ba có đường cong học tập nông hơn được cho là, vì vậy bạn sẽ sử dụng nó trong hướng dẫn này. Đi trước và cài đặt

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
23 trong môi trường ảo của bạn ngay bây giờ:

  • các cửa sổ
  • Linux + MacOS

dict['Age']:  8
dict['School']:  DPS School
7

dict['Age']:  8
dict['School']:  DPS School
8

Hãy nhớ rằng bạn có thể xác minh từng giai đoạn thực hiện đối với một số điểm kiểm soát kiểm soát. Tiếp theo, hãy tạo một tệp có tên

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
24 và xác định chức năng kiểm tra giả trong đó để kiểm tra xem pytest có chọn nó không:

dict['Age']:  8
dict['School']:  DPS School
9

Khung tận dụng câu lệnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
25 tích hợp để chạy các bài kiểm tra của bạn và báo cáo kết quả của họ. Điều đó có nghĩa là bạn chỉ có thể sử dụng cú pháp Python thông thường, mà không cần nhập bất kỳ API cụ thể nào cho đến khi hoàn toàn cần thiết. Nó cũng phát hiện các tệp kiểm tra và chức năng kiểm tra miễn là tên của chúng bắt đầu bằng tiền tố
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
26.

Câu lệnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
25 lấy biểu thức boolean làm đối số, theo sau là thông báo lỗi tùy chọn. Khi điều kiện đánh giá thành
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
28, thì không có gì xảy ra, như thể không có khẳng định nào cả. Mặt khác, Python sẽ tăng
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
29 và hiển thị thông báo trên luồng lỗi tiêu chuẩn (STDERR). Trong khi đó, pytest chặn các lỗi khẳng định và xây dựng một báo cáo xung quanh chúng.

Bây giờ, hãy mở thiết bị đầu cuối, thay đổi thư mục làm việc của bạn thành bất cứ nơi nào bạn đã lưu tệp kiểm tra đó và chạy lệnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
23 mà không có bất kỳ đối số nào. Đầu ra của nó sẽ trông giống như thế này:

  • các cửa sổ
  • Linux + MacOS

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
0

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
1

Hãy nhớ rằng bạn có thể xác minh từng giai đoạn thực hiện đối với một số điểm kiểm soát kiểm soát. Tiếp theo, hãy tạo một tệp có tên

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
24 và xác định chức năng kiểm tra giả trong đó để kiểm tra xem pytest có chọn nó không:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
2

Khung tận dụng câu lệnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
25 tích hợp để chạy các bài kiểm tra của bạn và báo cáo kết quả của họ. Điều đó có nghĩa là bạn chỉ có thể sử dụng cú pháp Python thông thường, mà không cần nhập bất kỳ API cụ thể nào cho đến khi hoàn toàn cần thiết. Nó cũng phát hiện các tệp kiểm tra và chức năng kiểm tra miễn là tên của chúng bắt đầu bằng tiền tố
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
26.actual and expected values were for the failed assertion. In this case, adding two plus two results in four rather than twenty-two. You can fix the code by correcting the expected value:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
3

Câu lệnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
25 lấy biểu thức boolean làm đối số, theo sau là thông báo lỗi tùy chọn. Khi điều kiện đánh giá thành
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
28, thì không có gì xảy ra, như thể không có khẳng định nào cả. Mặt khác, Python sẽ tăng
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
29 và hiển thị thông báo trên luồng lỗi tiêu chuẩn (STDERR). Trong khi đó, pytest chặn các lỗi khẳng định và xây dựng một báo cáo xung quanh chúng.

  • các cửa sổ
  • Linux + MacOS

Hãy nhớ rằng bạn có thể xác minh từng giai đoạn thực hiện đối với một số điểm kiểm soát kiểm soát. Tiếp theo, hãy tạo một tệp có tên

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
24 và xác định chức năng kiểm tra giả trong đó để kiểm tra xem pytest có chọn nó không:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
5

Khung tận dụng câu lệnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
25 tích hợp để chạy các bài kiểm tra của bạn và báo cáo kết quả của họ. Điều đó có nghĩa là bạn chỉ có thể sử dụng cú pháp Python thông thường, mà không cần nhập bất kỳ API cụ thể nào cho đến khi hoàn toàn cần thiết. Nó cũng phát hiện các tệp kiểm tra và chức năng kiểm tra miễn là tên của chúng bắt đầu bằng tiền tố
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
26.

Câu lệnh # Declare a dictionary dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} dict['Age'] = 8; # update existing entry dict['School'] = "DPS School"; # Add new entry print "dict['Age']: ", dict['Age'] print "dict['School']: ", dict['School'] 25 lấy biểu thức boolean làm đối số, theo sau là thông báo lỗi tùy chọn. Khi điều kiện đánh giá thành # Declare a dictionary dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} dict['Age'] = 8; # update existing entry dict['School'] = "DPS School"; # Add new entry print "dict['Age']: ", dict['Age'] print "dict['School']: ", dict['School'] 28, thì không có gì xảy ra, như thể không có khẳng định nào cả. Mặt khác, Python sẽ tăng # Declare a dictionary dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} dict['Age'] = 8; # update existing entry dict['School'] = "DPS School"; # Add new entry print "dict['Age']: ", dict['Age'] print "dict['School']: ", dict['School'] 29 và hiển thị thông báo trên luồng lỗi tiêu chuẩn (STDERR). Trong khi đó, pytest chặn các lỗi khẳng định và xây dựng một báo cáo xung quanh chúng.

Bây giờ, hãy mở thiết bị đầu cuối, thay đổi thư mục làm việc của bạn thành bất cứ nơi nào bạn đã lưu tệp kiểm tra đó và chạy lệnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
23 mà không có bất kỳ đối số nào. Đầu ra của nó sẽ trông giống như thế này:red-green-refactor cycle described earlier. Therefore, you must start by identifying your first test case. For example, you should be able to instantiate a new hash table by calling the hypothetical
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 class imported from the
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
34 module. This call should return a non-empty object:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
6

Uh-oh. Có một thất bại trong bài kiểm tra của bạn. Để tìm ra nguyên nhân gốc, hãy tăng độ merbosity của đầu ra pytest bằng cách nối lại cờ

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
31 vào lệnh. Bây giờ bạn có thể xác định chính xác vấn đề nằm ở đâu:red phase, after all. The red phase is the only time when you’re allowed to add new features, so go on and create another module named
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
35 and put the
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 class definition in it:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
7

Đầu ra cho thấy những gì các giá trị thực tế và dự kiến ​​là cho khẳng định thất bại. Trong trường hợp này, thêm hai kết quả cộng với bốn kết quả thay vì hai mươi hai. Bạn có thể sửa mã bằng cách sửa giá trị dự kiến:

Hướng dẫn does python have hash tables? - python có bảng băm không?
Khi bạn chạy lại pytest, sẽ không còn thất bại kiểm tra nữa:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
4

Đó là nó! Bạn chỉ học các bước thiết yếu trong việc tự động hóa các trường hợp kiểm tra cho việc triển khai bảng băm của bạn. Đương nhiên, bạn có thể sử dụng IDE như Pycharm hoặc trình soạn thảo như mã VS tích hợp với các khung kiểm tra nếu điều đó thuận tiện hơn cho bạn. Tiếp theo, bạn sẽ đưa kiến ​​thức mới này vào thực tế.fixed size established at the hash table’s creation time. Modify your existing test case accordingly:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
8

Xác định một lớp tùy chỉnh ____232

Hãy nhớ theo chu kỳ Red-Green-Refactor được mô tả trước đó. Do đó, bạn phải bắt đầu bằng cách xác định trường hợp thử nghiệm đầu tiên của bạn. Ví dụ: bạn sẽ có thể khởi tạo một bảng băm mới bằng cách gọi lớp giả thuyết

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 được nhập từ mô -đun
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
34. Cuộc gọi này sẽ trả về một đối tượng không trống:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
9

Tại thời điểm này, bài kiểm tra của bạn sẽ từ chối chạy vì một tuyên bố nhập không thỏa mãn ở đầu tệp. Rốt cuộc, bạn trong giai đoạn đỏ. Pha màu đỏ là lần duy nhất khi bạn được phép thêm các tính năng mới, vì vậy hãy tiếp tục và tạo một mô -đun khác có tên

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
35 và đặt định nghĩa lớp
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 trong đó:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
0

Như bạn có thể nói, chu trình màu xanh lá cây màu đỏ bao gồm các giai đoạn ngắn, thường kéo dài không quá vài giây mỗi giai đoạn. Vì vậy, tại sao bạn không tiếp tục bằng cách thêm nhiều trường hợp kiểm tra? Sẽ thật tuyệt nếu cấu trúc dữ liệu của bạn có thể báo cáo lại dung lượng của bảng Hash bằng cách sử dụng chức năng

dict['Name']:  Zara
dict['Age']:  7
76 tích hợp của Python. Thêm một trường hợp kiểm tra khác và quan sát cách nó thất bại thảm hại:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
1

Để xử lý chính xác

dict['Name']:  Zara
dict['Age']:  7
76, bạn phải triển khai phương pháp đặc biệt
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
44 trong lớp của bạn và ghi nhớ dung lượng được cung cấp thông qua trình khởi tạo lớp:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
2

Bạn có thể nghĩ rằng TDD không phải là người di chuyển bạn đi đúng hướng. Đó không phải là cách mà bạn có thể đã hình dung việc thực hiện bảng băm. Nơi mà chuỗi các giá trị mà bạn bắt đầu ngay từ đầu? Thật không may, thực hiện các bước của em bé và thực hiện nhiều điều chỉnh khóa học trên đường đi là điều mà sự phát triển theo hướng thử nghiệm nhận được rất nhiều lời chỉ trích. Do đó, nó có thể không phù hợp cho các dự án liên quan đến nhiều thử nghiệm.baby steps and making many course corrections along the way is something that test-driven development gets a lot of criticism for. Therefore, it may not be appropriate for projects involving lots of experimentation.

Mặt khác, việc triển khai cấu trúc dữ liệu nổi tiếng như bảng băm là một ứng dụng hoàn hảo của phương pháp phát triển phần mềm này. Bạn có những kỳ vọng rõ ràng đơn giản để mã hóa như các trường hợp kiểm tra. Chẳng mấy chốc, bạn sẽ thấy rằng thực hiện bước tiếp theo sẽ dẫn đến một sự thay đổi nhỏ trong việc thực hiện. Mặc dù vậy, đừng lo lắng về điều đó, vì việc hoàn thiện mã ít quan trọng hơn so với việc làm cho các trường hợp thử nghiệm của bạn vượt qua.

Khi bạn tiếp tục thêm nhiều ràng buộc thông qua các trường hợp thử nghiệm, bạn thường phải suy nghĩ lại về việc thực hiện của mình. Ví dụ, một bảng băm mới có thể nên bắt đầu với các khe trống cho các giá trị được lưu trữ:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
3

Nói cách khác, một bảng băm mới sẽ hiển thị thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 có độ dài được yêu cầu và được lấp đầy với các yếu tố
dict['Name']:  Zara
dict['Age']:  7
88. Nhân tiện, nó phổ biến để sử dụng tên hàm dài dòng như vậy vì chúng sẽ xuất hiện trong báo cáo thử nghiệm của bạn. Các bài kiểm tra của bạn càng dễ đọc và mô tả, bạn càng nhanh chóng tìm ra phần nào cần sửa chữa.

Đây là một trong nhiều cách có thể để đáp ứng các bài kiểm tra hiện tại của bạn:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
4

Bạn thay thế thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
47 bằng danh sách độ dài được yêu cầu chỉ chứa các phần tử
dict['Name']:  Zara
dict['Age']:  7
88. Nhân số một số với một danh sách hoặc cách khác là một cách nhanh chóng để điền vào danh sách đó với giá trị hoặc giá trị đã cho. Ngoài ra, bạn cập nhật phương pháp đặc biệt
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
44 để tất cả các thử nghiệm sẽ vượt qua.

Bây giờ bạn đã làm quen với TDD, đã đến lúc đi sâu hơn và thêm các tính năng còn lại vào bảng băm của bạn.

Chèn một cặp giá trị khóa

Bây giờ bạn có thể tạo một bảng băm, đã đến lúc cung cấp cho nó một số khả năng lưu trữ. Bảng băm truyền thống được hỗ trợ bởi một mảng có khả năng chỉ lưu trữ một loại dữ liệu. Bởi vì điều này, việc triển khai bảng băm bằng nhiều ngôn ngữ, chẳng hạn như Java, yêu cầu bạn phải khai báo loại cho các khóa và giá trị của chúng lên phía trước:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
5

Ví dụ, bảng băm đặc biệt này cho các số nguyên. Tuy nhiên, vì các mảng không có nguồn gốc từ Python, bạn sẽ tiếp tục sử dụng một danh sách. Là một tác dụng phụ, bảng băm của bạn sẽ có thể chấp nhận các loại dữ liệu tùy ý cho cả các khóa và giá trị, giống như Python tựa

dict['Name']:  Zara
dict['Age']:  7
70.

Bây giờ thêm một trường hợp kiểm tra khác để chèn các cặp giá trị khóa vào bảng băm của bạn bằng cú pháp khung vuông quen thuộc:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
6

Đầu tiên, bạn tạo một bảng băm với một trăm khe trống và sau đó đặt nó với ba cặp khóa và giá trị của nhiều loại, bao gồm chuỗi, số điểm nổi và booleans. Cuối cùng, bạn khẳng định rằng bảng băm chứa các giá trị dự kiến ​​theo bất kỳ thứ tự nào. Lưu ý rằng bảng băm của bạn chỉ nhớ các giá trị nhưng không phải là các khóa liên quan tại thời điểm này!

Việc thực hiện đơn giản nhất và có lẽ hơi ngây thơ sẽ thỏa mãn bài kiểm tra này như sau:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
7

Nó hoàn toàn bỏ qua khóa và chỉ nối giá trị vào đầu bên phải của danh sách, tăng độ dài của nó. Bạn rất có thể nghĩ ngay lập tức về một trường hợp thử nghiệm khác. Chèn các yếu tố vào bảng băm nên không phát triển kích thước của nó. Tương tự, việc loại bỏ một phần tử không nên thu hẹp bảng băm, nhưng bạn chỉ ghi chú tinh thần về điều đó, bởi vì không có khả năng loại bỏ các cặp giá trị khóa.

Trong thế giới thực, bạn muốn tạo các trường hợp thử nghiệm riêng biệt với các tên mô tả dành riêng để kiểm tra các hành vi này. Tuy nhiên, vì đây chỉ là một hướng dẫn, bạn sẽ thêm một khẳng định mới cho chức năng hiện có cho sự ngắn gọn:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
8

Bạn có thể ở giai đoạn đỏ bây giờ, vì vậy hãy viết lại phương pháp đặc biệt của mình để giữ cho công suất cố định mọi lúc:

dict['Age']:
Traceback (most recent call last):
   File "test.py", line 8, in <module>
      print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
9

Bạn biến một khóa tùy ý thành giá trị băm số và sử dụng toán tử modulo để hạn chế chỉ số kết quả trong không gian địa chỉ có sẵn. Tuyệt quá! Báo cáo thử nghiệm của bạn sáng lên màu xanh lá cây một lần nữa.

Nhưng bạn có thể nghĩ về một số trường hợp cạnh, có thể? Điều gì về việc chèn

dict['Name']:  Zara
dict['Age']:  7
88 vào bảng băm của bạn? Nó sẽ tạo ra một cuộc xung đột giữa một giá trị hợp pháp và giá trị sentinel được chỉ định mà bạn đã chọn để biểu thị khoảng trống trong bảng băm của bạn. Bạn sẽ muốn tránh điều đó.

Như mọi khi, bắt đầu bằng cách viết một trường hợp kiểm tra để thể hiện hành vi mong muốn:

>>> hash(1.1)

>>> hash(4504.1)

0

Một cách để làm việc xung quanh điều này là thay thế

dict['Name']:  Zara
dict['Age']:  7
88 trong phương thức
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
38 của bạn bằng một giá trị duy nhất khác mà người dùng khó có thể chèn. Ví dụ: bạn có thể xác định một hằng số đặc biệt bằng cách tạo một đối tượng hoàn toàn mới để thể hiện khoảng trống trong bảng băm của bạn:

>>> hash(1.1)

>>> hash(4504.1)

1

Bạn chỉ cần một phiên bản trống duy nhất để đánh dấu các vị trí là trống. Đương nhiên, bạn sẽ cần cập nhật một trường hợp thử nghiệm cũ hơn để quay lại giai đoạn xanh:

>>> hash(1.1)

>>> hash(4504.1)

2

Sau đó, viết một trường hợp kiểm tra tích cực thực hiện đường dẫn hạnh phúc để xử lý việc chèn giá trị

dict['Name']:  Zara
dict['Age']:  7
88:

>>> hash(1.1)

>>> hash(4504.1)

3

Bạn tạo một bảng băm trống với một trăm khe và chèn

dict['Name']:  Zara
dict['Age']:  7
88 được liên kết với một số khóa tùy ý. Nó sẽ hoạt động như một sự quyến rũ nếu bạn đã theo sát các bước cho đến nay. Nếu không, sau đó nhìn vào các thông báo lỗi vì chúng thường chứa manh mối về những gì đã sai. Ngoài ra, hãy kiểm tra mã mẫu có sẵn để tải xuống tại liên kết này:

Trong tiểu mục tiếp theo, bạn sẽ thêm khả năng truy xuất các giá trị bằng các khóa liên quan của chúng.

Tìm một giá trị theo khóa

Để lấy một giá trị từ bảng băm, bạn sẽ muốn tận dụng cú pháp khung vuông giống như trước đây, chỉ mà không sử dụng câu lệnh gán. Bạn cũng cần một bảng băm mẫu. Để tránh sao chép cùng một mã thiết lập trên các trường hợp thử nghiệm riêng lẻ trong bộ thử nghiệm của bạn, bạn có thể bọc nó trong một vật cố thử nghiệm được phơi bày bởi pytest:

>>> hash(1.1)

>>> hash(4504.1)

4

Một vật cố thử là một chức năng được chú thích với bộ trang trí

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
56. Nó trả về dữ liệu mẫu cho các trường hợp thử nghiệm của bạn, chẳng hạn như bảng băm có các khóa và giá trị đã biết. Pytest của bạn sẽ tự động gọi chức năng đó cho bạn và đưa kết quả của nó vào bất kỳ chức năng kiểm tra nào tuyên bố một đối số có cùng tên với trận đấu của bạn. Trong trường hợp này, chức năng kiểm tra mong đợi một đối số
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
57, tương ứng với tên trận đấu của bạn.test fixture is a function annotated with the
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
56 decorator. It returns sample data for your test cases, such as a hash table populated with known keys and values. Your pytest will automatically call that function for you and inject its result into any test function that declares an argument with the same name as your fixture. In this case, the test function expects a
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
57 argument, which corresponds to your fixture name.

Để có thể tìm thấy các giá trị theo khóa, bạn có thể thực hiện tra cứu phần tử thông qua một phương thức đặc biệt khác gọi là

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
58 trong lớp
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn:

>>> hash(1.1)

>>> hash(4504.1)

5

Bạn tính toán chỉ mục của một phần tử dựa trên mã băm của khóa được cung cấp và trả về bất cứ điều gì nằm trong chỉ số đó. Nhưng những gì về các phím thiếu? Đến bây giờ, bạn có thể trả lại một trường hợp trống khi một khóa nhất định đã được sử dụng trước đó, một kết quả không phải là tất cả những gì hữu ích. Để tái tạo cách một Python

dict['Name']:  Zara
dict['Age']:  7
70 sẽ hoạt động trong trường hợp như vậy, bạn nên tăng ngoại lệ
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
61 thay thế: thay vào đó:

>>> hash(1.1)

>>> hash(4504.1)

6

Bạn tạo một bảng băm trống và thử truy cập một trong các giá trị của nó thông qua một khóa bị thiếu. Khung pytest bao gồm một cấu trúc đặc biệt để kiểm tra các ngoại lệ. Ở trên, bạn sử dụng Trình quản lý bối cảnh

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
62 để mong đợi một loại ngoại lệ cụ thể trong khối mã sau. Xử lý trường hợp này là vấn đề thêm một câu lệnh có điều kiện vào phương thức excessor của bạn:

>>> hash(1.1)

>>> hash(4504.1)

7

Nếu giá trị tại chỉ mục đã cho là trống, thì bạn sẽ tăng ngoại lệ. Nhân tiện, bạn sử dụng toán tử

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
63 thay vì toán tử kiểm tra bình đẳng (
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
64) để đảm bảo rằng bạn có thể so sánh các danh tính hơn là các giá trị. Mặc dù việc triển khai mặc định của bài kiểm tra bình đẳng trong các lớp tùy chỉnh rơi trở lại để so sánh danh tính của các trường hợp của họ, hầu hết các loại dữ liệu tích hợp phân biệt giữa hai toán tử và thực hiện chúng khác nhau.

Vì bây giờ bạn có thể xác định xem một khóa nhất định có giá trị liên quan trong bảng băm của bạn hay không, bạn cũng có thể triển khai toán tử

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
65 để bắt chước từ điển Python. Hãy nhớ viết và bao gồm các trường hợp thử nghiệm này để tôn trọng các nguyên tắc phát triển theo hướng thử nghiệm:

>>> hash(1.1)

>>> hash(4504.1)

8

Cả hai trường hợp thử nghiệm đều tận dụng lợi thế của vật cố thử nghiệm mà bạn đã chuẩn bị trước đó và xác minh phương pháp đặc biệt

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
66 mà bạn có thể thực hiện theo cách sau:

>>> hash(1.1)

>>> hash(4504.1)

9

Khi truy cập khóa đã cho tăng

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
61, bạn sẽ chặn ngoại lệ đó và trả về
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
68 để chỉ ra một khóa bị thiếu. Mặt khác, bạn kết hợp khối
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
69 ____ ____270 với mệnh đề
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
71 và trả về
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
28. Xử lý ngoại lệ là tuyệt vời nhưng đôi khi có thể bất tiện, đó là lý do tại sao
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
73 cho phép bạn chỉ định một giá trị mặc định tùy chọn. Bạn có thể sao chép cùng một hành vi trong bảng băm tùy chỉnh của mình:default value. You can replicate the same behavior in your custom hash table:

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

Mã của

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
74 trông tương tự như phương pháp đặc biệt mà bạn đã thực hiện:

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

Bạn cố gắng trả về giá trị tương ứng với khóa được cung cấp. Trong trường hợp ngoại lệ, bạn trả về giá trị mặc định, đó là một đối số tùy chọn. Khi người dùng rời khỏi nó không xác định, thì nó bằng

dict['Name']:  Zara
dict['Age']:  7
88.

Để hoàn thiện, bạn sẽ thêm khả năng xóa một cặp giá trị khóa khỏi bảng băm của bạn trong tiểu mục sắp tới.

Xóa một cặp giá trị khóa

Từ điển Python cho phép bạn xóa các cặp giá trị khóa được chèn trước đó bằng cách sử dụng từ khóa

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
76 tích hợp, loại bỏ thông tin về cả khóa và giá trị. Ở đây, cách làm thế nào điều này có thể hoạt động với bảng băm của bạn:

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

Đầu tiên, bạn xác minh nếu bảng băm mẫu có khóa và giá trị mong muốn. Sau đó, bạn xóa cả hai bằng cách chỉ biểu thị khóa và lặp lại các xác nhận nhưng với những kỳ vọng đảo ngược. Bạn có thể thực hiện vượt qua bài kiểm tra này như sau:

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

Bạn tính toán chỉ mục được liên kết với một khóa và xóa giá trị tương ứng khỏi danh sách vô điều kiện. Tuy nhiên, bạn ngay lập tức nhớ ghi chú tinh thần của bạn từ trước đó về việc khẳng định rằng bảng băm của bạn không nên co lại khi bạn xóa các yếu tố khỏi nó. Vì vậy, bạn thêm hai xác nhận nữa:

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

Những điều này sẽ đảm bảo rằng kích thước của bảng băm của bạn trong danh sách cơ bản của bạn vẫn không bị ảnh hưởng. Bây giờ, bạn cần cập nhật mã của mình để nó đánh dấu một khe trống thay vì vứt nó đi hoàn toàn:

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

Xem xét rằng bạn đã ở giai đoạn xanh một lần nữa, bạn có thể tận dụng cơ hội này để dành thời gian tái cấu trúc. Công thức chỉ số giống nhau xuất hiện ba lần ở những nơi khác nhau. Bạn có thể trích xuất nó và đơn giản hóa mã:

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

Đột nhiên, sau khi chỉ áp dụng sửa đổi nhẹ này, một mô hình xuất hiện. Xóa một mục tương đương với việc chèn một đối tượng trống. Vì vậy, bạn có thể viết lại thói quen xóa của mình để tận dụng phương thức đột biến:

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

Gán một giá trị thông qua các phép cú pháp của dấu ngoặc vuông cho phương thức

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
77. Được rồi, bây giờ đủ tái cấu trúc. Nó rất quan trọng để nghĩ về các trường hợp thử nghiệm khác tại thời điểm này. Ví dụ: điều gì xảy ra khi bạn yêu cầu xóa khóa bị thiếu? Python sườn
dict['Name']:  Zara
dict['Age']:  7
70 làm tăng ngoại lệ
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
61 trong trường hợp như vậy, vì vậy bạn có thể làm như vậy:

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

Bao gồm trường hợp kiểm tra này tương đối đơn giản vì bạn có thể dựa vào mã mà bạn đã viết khi thực hiện toán tử

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
65:

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

Nếu bạn tìm thấy khóa trong bảng băm của bạn, thì bạn sẽ ghi đè lên giá trị liên quan bằng giá trị sentinel để xóa cặp đó. Nếu không, bạn nêu ra một ngoại lệ. Được rồi, có một hoạt động bảng băm cơ bản hơn để che, điều mà bạn sẽ làm tiếp theo.

Cập nhật giá trị của một cặp hiện có

Phương pháp chèn nên đã chăm sóc cập nhật một cặp giá trị khóa, vì vậy bạn chỉ sẽ thêm một trường hợp kiểm tra có liên quan và kiểm tra xem nó có hoạt động như mong đợi không:

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


0

Sau khi sửa đổi giá trị, xin chào, của một khóa hiện có và thay đổi nó thành Hallo, bạn cũng kiểm tra xem các cặp giá trị khóa khác, cũng như độ dài bảng băm, vẫn chưa được xử lý. Đó là nó. Bạn đã có một triển khai bảng băm cơ bản, nhưng một vài tính năng bổ sung tương đối rẻ để thực hiện vẫn còn thiếu.

Nhận các cặp giá trị khóa

Nó thời gian để giải quyết con voi trong phòng. Từ điển Python cho phép bạn lặp lại các khóa, giá trị hoặc cặp giá trị khóa được gọi là các mục. Tuy nhiên, bảng băm của bạn thực sự chỉ là một danh sách các giá trị có lập chỉ mục ưa thích trên đầu của nó. Nếu bạn từng muốn truy xuất các khóa ban đầu được đặt vào bảng băm của bạn, thì bạn sẽ không gặp may vì việc triển khai bảng băm hiện tại đã giành chiến thắng.keys, values, or key-value pairs called items. However, your hash table is really only a list of values with fancy indexing on top of it. If you ever wanted to retrieve the original keys put into your hash table, then you’d be out of luck because the current hash table implementation won’t ever remember them.

Trong tiểu mục này, bạn sẽ tái cấu trúc bảng băm của mình để thêm khả năng giữ lại các khóa và giá trị. Hãy nhớ rằng sẽ có một số bước liên quan và nhiều bài kiểm tra sẽ bắt đầu thất bại do điều đó. Nếu bạn muốn bỏ qua các bước trung gian đó và xem hiệu ứng, thì hãy nhảy về phía trước để sao chép phòng thủ.

Đợi tí. Bạn tiếp tục đọc về các cặp giá trị khóa trong hướng dẫn này, vậy tại sao không thay thế các giá trị bằng bộ dữ liệu? Rốt cuộc, bộ dữ liệu rất đơn giản trong Python. Thậm chí tốt hơn, bạn có thể sử dụng các bộ dữ liệu được đặt tên để tận dụng việc tra cứu phần tử được đặt tên của chúng. Nhưng trước tiên, bạn cần phải nghĩ về một bài kiểm tra.key-value pairs in this tutorial, so why not replace values with tuples? After all, tuples are straightforward in Python. Even better, you could use named tuples to take advantage of their named element lookup. But first, you need to think of a test.

Trước hết, bạn sẽ cần một thuộc tính khác trong lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của mình để giữ các cặp giá trị khóa:

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


1

Thứ tự của các cặp giá trị khóa là không quan trọng vào thời điểm này, vì vậy bạn có thể cho rằng chúng có thể đi ra theo bất kỳ thứ tự nào mỗi khi bạn yêu cầu chúng. Tuy nhiên, thay vì giới thiệu một lĩnh vực khác cho lớp, bạn có thể sử dụng lại

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 bằng cách đổi tên nó thành
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 và thực hiện các điều chỉnh cần thiết khác. Có một vài. Chỉ cần lưu ý rằng điều này sẽ tạm thời làm cho một số thử nghiệm thất bại cho đến khi bạn sửa chữa việc thực hiện.

Khi bạn đổi tên

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 thành
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 trong
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
35 và
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
24, thì bạn cũng sẽ cần cập nhật phương thức đặc biệt
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
77. Cụ thể, nó nên lưu trữ các bộ dữ liệu của khóa và giá trị liên quan ngay bây giờ:

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


2

Chèn một phần tử vào bảng băm của bạn bao bọc khóa và giá trị trong một bộ và sau đó đặt bộ điều đó vào chỉ mục mong muốn trong danh sách các cặp của bạn. Lưu ý rằng danh sách của bạn ban đầu sẽ chỉ chứa các đối tượng trống thay vì các bộ dữ liệu, do đó, bạn sẽ sử dụng hai loại dữ liệu khác nhau trong danh sách các cặp của mình. Một là một tuple, trong khi cái còn lại có thể là bất cứ thứ gì ngoại trừ một tuple để biểu thị một khe trống.

Do đó, bạn không cần bất kỳ hằng số Sentinel đặc biệt nào nữa để đánh dấu một khe trống. Bạn có thể loại bỏ hằng số

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
89 của mình một cách an toàn và thay thế nó bằng đơn giản
dict['Name']:  Zara
dict['Age']:  7
88 một lần nữa khi cần thiết, vì vậy hãy tiếp tục và làm điều đó ngay bây giờ.

Bạn có thể quay lại một bước nữa để lấy lại quyền kiểm soát việc xóa một mục:

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


3

Thật không may, phương pháp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
91 của bạn không còn có thể tận dụng cú pháp của dấu ngoặc vuông vì điều này sẽ dẫn đến việc gói bất kỳ giá trị sentinel nào bạn chọn trong một bộ không cần thiết. Bạn phải sử dụng một tuyên bố chuyển nhượng rõ ràng ở đây để tránh logic phức tạp không cần thiết xuống đường.

Phần quan trọng cuối cùng của câu đố là cập nhật phương pháp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
58:

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


4

Bạn nhìn trộm ở một chỉ mục, mong đợi tìm được một cặp giá trị khóa. Nếu bạn không nhận được gì cả, thì bạn sẽ tăng một ngoại lệ. Mặt khác, nếu bạn thấy một cái gì đó thú vị, thì bạn sẽ lấy phần tử thứ hai của Tuple tại Index One, tương ứng với giá trị được ánh xạ. Tuy nhiên, bạn có thể viết điều này một cách thanh lịch hơn bằng cách sử dụng một tuple có tên, như đã đề xuất trước đó:

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


5

Lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
93 bao gồm các thuộc tính
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
94 và
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
95, miễn phí để lấy các giá trị của bất kỳ loại dữ liệu nào. Đồng thời, lớp của bạn kế thừa tất cả các hành vi tuple thông thường vì nó mở rộng cha mẹ ____296. Lưu ý rằng bạn phải gọi rõ ràng
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
97 trên khóa và giá trị của mình trong phương thức
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
77 để tận dụng quyền truy cập thuộc tính được đặt tên trong
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
58.

Đương nhiên, bạn có một vài trường hợp thử nghiệm để cập nhật tại thời điểm này trước khi báo cáo có thể chuyển sang màu xanh lá cây. Hãy dành thời gian của bạn và xem xét cẩn thận bộ thử nghiệm của bạn. Ngoài ra, hãy nhìn vào mã từ các tài liệu hỗ trợ nếu bạn cảm thấy bị mắc kẹt hoặc xem qua đây:

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


6

Sẽ có một trường hợp thử nghiệm khác cần được chăm sóc đặc biệt. Cụ thể, nó về việc xác minh rằng một bảng băm trống không có giá trị

dict['Name']:  Zara
dict['Age']:  7
88 khi được tạo. Bạn chỉ thay thế một danh sách các giá trị bằng một danh sách các cặp. Để câu được các giá trị một lần nữa, bạn có thể sử dụng danh sách hiểu như thế này:

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


7

Nếu bạn lo lắng về việc nhồi quá nhiều logic vào trường hợp thử nghiệm, thì bạn sẽ hoàn toàn đúng. Rốt cuộc, bạn muốn kiểm tra hành vi của bảng băm. Nhưng đừng lo lắng về điều đó. Bạn sẽ xem lại trường hợp thử nghiệm này trong thời gian ngắn.

Sử dụng sao chép phòng thủ

Khi bạn trở lại giai đoạn xanh, hãy cố gắng tìm ra các trường hợp góc có thể. Ví dụ,

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 được phơi bày như một thuộc tính công khai mà bất kỳ ai cũng có thể cố ý hoặc vô ý giả mạo. Trong thực tế, các phương thức Accessor không bao giờ nên rò rỉ triển khai nội bộ của bạn mà nên tạo các bản sao phòng thủ để bảo vệ các thuộc tính có thể thay đổi khỏi các sửa đổi bên ngoài:defensive copies to protect mutable attributes from external modifications:

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


8

Bất cứ khi nào bạn yêu cầu các cặp giá trị khóa từ bảng băm, bạn mong đợi có được một đối tượng hoàn toàn mới với một danh tính duy nhất. Bạn có thể ẩn một trường riêng phía sau thuộc tính Python, vì vậy hãy tạo một trường và thay thế mọi tham chiếu đến

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 bằng
dict['Age']:  8
dict['School']:  DPS School
03 trong lớp
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn. Dấu gạch dưới hàng đầu là một quy ước đặt tên tiêu chuẩn trong Python cho thấy việc thực hiện nội bộ:

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


9

Khi bạn yêu cầu một danh sách các cặp giá trị khóa được lưu trữ trong bảng băm của bạn, bạn sẽ nhận được bản sao nông của chúng mỗi lần. Bởi vì bạn đã giành được một tài liệu tham khảo về trạng thái nội bộ của bàn băm của bạn, nên nó sẽ không bị ảnh hưởng bởi những thay đổi tiềm năng đối với bản sao của nó.

Để bắt chước

dict['Age']:  8
dict['School']:  DPS School
05 trong tài sản của bạn, danh sách kết quả của các cặp nên không bao gồm các khe trống. Nói cách khác, không nên có bất kỳ giá trị
dict['Name']:  Zara
dict['Age']:  7
88 nào trong danh sách đó:

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
0

Để đáp ứng thử nghiệm này, bạn có thể lọc ra các giá trị trống bằng cách thêm một điều kiện vào danh sách hiểu trong thuộc tính của bạn:

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
1

Bạn không cần một cuộc gọi rõ ràng đến

dict['Age']:  8
dict['School']:  DPS School
07 vì danh sách hiểu được tạo ra một danh sách mới. Đối với mỗi cặp trong danh sách ban đầu của các cặp giá trị khóa, bạn kiểm tra xem cặp cụ thể đó có phải là sự thật không và giữ nó trong danh sách kết quả. Tuy nhiên, điều này sẽ phá vỡ hai thử nghiệm khác mà bạn cần cập nhật ngay bây giờ:

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
2

Điều đó không lý tưởng vì một trong những thử nghiệm của bạn đạt được để triển khai nội bộ thay vì tập trung vào các giao diện công cộng. Tuy nhiên, thử nghiệm như vậy được gọi là thử nghiệm hộp trắng, có vị trí của nó.

Nhận các phím và giá trị

Bạn có nhớ trường hợp kiểm tra mà bạn đã sửa đổi bằng cách thêm danh sách hiểu để truy xuất các giá trị từ các cặp giá trị khóa của bạn không? Chà, đây là một lần nữa nếu bạn cần làm mới bộ nhớ của mình:

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


7

Dòng được tô sáng trông giống như những gì bạn cần để thực hiện thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 mà bạn đã thay thế bằng
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 trước đó. Bạn có thể cập nhật chức năng kiểm tra để tận dụng
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 một lần nữa:

>>> hash(1.1)

>>> hash(4504.1)

0

Nó có thể cảm thấy như thể đó là một nỗ lực lãng phí. Nhưng, các giá trị này hiện được đánh giá linh hoạt thông qua một thuộc tính getter, trong khi chúng được lưu trữ trong một danh sách kích thước cố định trước đó. Để đáp ứng bài kiểm tra này, bạn có thể sử dụng lại một phần của triển khai cũ, sử dụng danh sách hiểu biết:

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
5

Lưu ý rằng bạn không còn phải chỉ định điều kiện lọc tùy chọn ở đây, bởi vì đã có một người ẩn giấu phía sau thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83.

Những người theo chủ nghĩa thuần túy có thể nghĩ đến việc sử dụng một sự hiểu biết đã thiết lập thay vì một danh sách hiểu để truyền đạt sự thiếu bảo đảm cho thứ tự các giá trị. Tuy nhiên, điều đó sẽ dẫn đến việc mất thông tin về các giá trị trùng lặp trong bảng băm. Bảo vệ bản thân khỏi khả năng như vậy lên phía trước bằng cách viết một trường hợp kiểm tra khác:

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
6

Ví dụ, nếu bạn có một bảng băm có tên và tuổi, và nhiều hơn một người có cùng tuổi, thì

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 sẽ giữ tất cả các giá trị tuổi lặp đi lặp lại. Bạn có thể sắp xếp các độ tuổi để đảm bảo chạy thử nghiệm lặp lại. Mặc dù trường hợp kiểm tra này không yêu cầu viết mã mới, nhưng nó sẽ bảo vệ chống lại hồi quy.

Nó có giá trị để kiểm tra các giá trị dự kiến, loại của chúng và số lượng của chúng. Tuy nhiên, bạn có thể so sánh hai danh sách trực tiếp vì các giá trị thực tế trong bảng băm có thể xuất hiện theo thứ tự không thể đoán trước. Để coi thường thứ tự trong bài kiểm tra của bạn, bạn có thể chuyển đổi cả hai danh sách thành đặt hoặc sắp xếp chúng như trước. Thật không may, các bộ loại bỏ các bản sao tiềm năng, trong khi việc sắp xếp không thể khi các danh sách chứa các loại không tương thích.

Để kiểm tra một cách đáng tin cậy xem hai danh sách có chính xác các yếu tố của các loại tùy ý với các bản sao tiềm năng trong khi bỏ qua thứ tự của chúng không, bạn có thể sử dụng thành ngữ Python sau:

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
7

Nó tận dụng chức năng

dict['Age']:  8
dict['School']:  DPS School
13 tích hợp, nhưng nó khá dài dòng. Bạn có thể tốt hơn khi sử dụng plugin
dict['Age']:  8
dict['School']:  DPS School
14. Đừng quên cài đặt nó vào môi trường ảo của bạn trước:

  • các cửa sổ
  • Linux + MacOS

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
8

>>> glossary = {"BDFL": "Benevolent Dictator For Life"}
>>> glossary["GIL"] = "Global Interpreter Lock"  # Add
>>> glossary["BDFL"] = "Guido van Rossum"  # Update
>>> del glossary["GIL"]  # Delete
>>> glossary["BDFL"]  # Search
'Guido van Rossum'
>>> glossary
{'BDFL': 'Guido van Rossum'}
9

Tiếp theo, nhập chức năng

dict['Age']:  8
dict['School']:  DPS School
15 vào bộ thử nghiệm của bạn và sử dụng nó để bọc các giá trị bảng băm:

dict['Name']:  Zara
dict['Age']:  7
00

Làm như vậy chuyển đổi các giá trị thành một danh sách không có thứ tự, trong đó xác định lại toán tử kiểm tra bình đẳng để nó không có thứ tự khi so sánh các yếu tố danh sách. Ngoài ra, các giá trị của bảng băm trống phải là một danh sách trống, trong khi thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 phải luôn trả về một bản sao danh sách mới:

dict['Name']:  Zara
dict['Age']:  7
01

Mặt khác, các phím bàn băm phải là duy nhất, vì vậy thật hợp lý khi nhấn mạnh rằng bằng cách trả lại một bộ thay vì một danh sách các khóa. Rốt cuộc, các bộ theo định nghĩa các bộ sưu tập các mục không có thứ tự không có bản sao:

dict['Name']:  Zara
dict['Age']:  7
02

Ở đó, không có tập hợp nào theo nghĩa đen trong Python, vì vậy bạn phải gọi chức năng

dict['Age']:  8
dict['School']:  DPS School
17 tích hợp trực tiếp trong trường hợp này. Việc triển khai chức năng Getter tương ứng sẽ trông quen thuộc:

dict['Name']:  Zara
dict['Age']:  7
03

Nó giống với thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45. Sự khác biệt là bạn sử dụng dấu ngoặc xoăn thay vì dấu ngoặc vuông và tham khảo thuộc tính
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
94 thay vì
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
95 trong tuple có tên của bạn. Ngoài ra, bạn có thể sử dụng
dict['Age']:  8
dict['School']:  DPS School
21 nếu bạn muốn, nhưng nó có vẻ không thể đọc được.

Điều này cũng nhắc nhở bạn về sự cần thiết của một trường hợp thử nghiệm tương tự mà bạn đã bỏ lỡ khi bao gồm thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83. Thật hợp lý khi trả lại một tập hợp các cặp vì sự nhất quán:

dict['Name']:  Zara
dict['Age']:  7
04

Vì vậy, thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 cũng sẽ sử dụng một thiết lập hiểu từ bây giờ:

dict['Name']:  Zara
dict['Age']:  7
05

Bạn không cần phải lo lắng về việc mất bất kỳ thông tin nào, bởi vì mỗi cặp giá trị khóa là duy nhất. Tại thời điểm này, bạn nên ở trong giai đoạn xanh một lần nữa.

Lưu ý rằng bạn có thể tận dụng thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 để chuyển đổi bảng băm của bạn thành một từ điển cũ đơn giản và sử dụng
dict['Age']:  8
dict['School']:  DPS School
25 và
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 để kiểm tra rằng:

dict['Name']:  Zara
dict['Age']:  7
06

Để coi thường thứ tự của các yếu tố, hãy nhớ quấn các khóa từ điển và các cặp giá trị khóa với các bộ trước khi thực hiện so sánh. Ngược lại, các giá trị bảng băm của bạn xuất hiện dưới dạng danh sách, vì vậy hãy chắc chắn sử dụng hàm

dict['Age']:  8
dict['School']:  DPS School
15 để so sánh các danh sách trong khi bỏ qua thứ tự phần tử.

Được rồi, bảng băm của bạn thực sự bắt đầu hình thành ngay bây giờ!

Báo cáo độ dài bảng băm

Có một chi tiết nhỏ mà bạn cố tình bị phá vỡ vì sự đơn giản cho đến bây giờ. Nó có độ dài của bảng băm của bạn, hiện đang báo cáo công suất tối đa của nó ngay cả khi chỉ có các khe trống. May mắn thay, nó không cần nhiều nỗ lực để khắc phục điều này. Tìm chức năng của bạn có tên

dict['Age']:  8
dict['School']:  DPS School
28, đổi tên như hình bên dưới và kiểm tra xem độ dài của bảng băm trống có bằng 0 thay vì một trăm không:

dict['Name']:  Zara
dict['Age']:  7
07

Để làm cho công suất độc lập với độ dài, hãy sửa đổi phương pháp đặc biệt của bạn

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
44 để đề cập đến tài sản công cộng với các cặp được lọc thay vì danh sách riêng của tất cả các vị trí:

dict['Name']:  Zara
dict['Age']:  7
08

Bạn vừa loại bỏ dấu gạch dưới hàng đầu khỏi tên biến. Nhưng sự thay đổi nhỏ đó hiện đang khiến cả một loạt các bài kiểm tra kết thúc đột ngột với một lỗi và một số ít thất bại.

Có vẻ như hầu hết các trường hợp thử nghiệm phải chịu cùng một ngoại lệ chưa được xử lý do phân chia theo 0 khi ánh xạ khóa thành một chỉ mục. Điều đó có ý nghĩa bởi vì

dict['Age']:  8
dict['School']:  DPS School
30 sử dụng độ dài bảng băm để tìm phần còn lại từ việc chia khóa băm cho số lượng khe cắm có sẵn. Tuy nhiên, độ dài của bảng băm có một ý nghĩa khác. Thay vào đó, bạn cần phải có độ dài của danh sách nội bộ:

dict['Name']:  Zara
dict['Age']:  7
09

Điều đó tốt hơn nhiều bây giờ. Ba trường hợp thử nghiệm vẫn không sử dụng các giả định sai về độ dài của bảng băm. Thay đổi các giả định đó để thực hiện các bài kiểm tra vượt qua:

dict['Name']:  Zara
dict['Age']:  7
10

Bạn đã trở lại trong trò chơi, nhưng

dict['Age']:  8
dict['School']:  DPS School
31 là một lá cờ đỏ sẽ ngay lập tức khiến bạn muốn thêm các trường hợp thử nghiệm bổ sung:

dict['Name']:  Zara
dict['Age']:  7
11

Tạo ra một

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 với khả năng không tích cực không có ý nghĩa gì. Làm thế nào bạn có thể có một thùng chứa có chiều dài âm? Vì vậy, bạn nên nêu ra một ngoại lệ nếu ai đó cố gắng điều đó, có mục đích hoặc tình cờ. Cách tiêu chuẩn để chỉ ra các đối số đầu vào không chính xác như vậy trong Python là bằng cách tăng ngoại lệ
dict['Age']:  8
dict['School']:  DPS School
33:

dict['Name']:  Zara
dict['Age']:  7
12

Nếu bạn siêng năng, thì có lẽ bạn cũng nên kiểm tra các loại đối số không hợp lệ, nhưng điều đó vượt quá phạm vi của hướng dẫn này. Bạn có thể coi nó như một bài tập tự nguyện.

Tiếp theo, thêm một kịch bản khác để kiểm tra độ dài của bảng băm không trống được cung cấp dưới dạng vật cố của pytest:

dict['Name']:  Zara
dict['Age']:  7
13

Có ba cặp giá trị khóa, vì vậy độ dài của bảng băm cũng phải là ba. Bài kiểm tra này không nên yêu cầu bất kỳ mã bổ sung. Cuối cùng, vì bạn đang trong giai đoạn tái cấu trúc bây giờ, bạn có thể thêm một chút đường cú pháp bằng cách giới thiệu thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
47 và sử dụng nó nếu có thể:

dict['Name']:  Zara
dict['Age']:  7
14

Công suất là không đổi và được xác định tại thời gian sáng tạo của bàn băm. Bạn có thể lấy nó từ độ dài của danh sách các cặp cơ bản:

dict['Name']:  Zara
dict['Age']:  7
15

Khi bạn giới thiệu từ vựng mới cho miền vấn đề của bạn, nó giúp bạn khám phá các cơ hội mới để đặt tên chính xác, không rõ ràng hơn. Ví dụ, bạn đã thấy các cặp từ được sử dụng thay thế cho nhau để chỉ cả hai cặp giá trị khóa thực tế được lưu trữ trong bảng băm của bạn và danh sách các khe cắm bên trong cho các cặp. Nó có thể là một cơ hội tốt để tái cấu trúc mã của bạn bằng cách thay đổi

dict['Age']:  8
dict['School']:  DPS School
03 thành
dict['Age']:  8
dict['School']:  DPS School
36 ở khắp mọi nơi.

Sau đó, một trong những trường hợp thử nghiệm trước đó của bạn sẽ truyền đạt ý định của nó rõ ràng hơn:

dict['Name']:  Zara
dict['Age']:  7
16

Có lẽ sẽ có ý nghĩa hơn nữa để đổi tên bài kiểm tra này bằng cách thay thế giá trị từ bằng cặp trong đó:

dict['Name']:  Zara
dict['Age']:  7
17

Bạn có thể nghĩ rằng những suy nghĩ triết học như vậy không cần thiết. Tuy nhiên, tên của bạn càng mô tả, mã của bạn sẽ dễ đọc hơn nếu không dành cho người khác, thì chắc chắn cho bạn trong tương lai. Thậm chí có những cuốn sách và trò đùa về nó. Các bài kiểm tra của bạn là một hình thức tài liệu, vì vậy nó được đền đáp để duy trì mức độ chú ý tương tự đến chi tiết cho chúng như đối với mã của bạn được kiểm tra.

Làm cho bảng băm có thể đi được

Python cho phép bạn lặp lại một từ điển thông qua các khóa, giá trị hoặc các cặp giá trị khóa được gọi là các mục. Bạn muốn hành vi tương tự trong bảng băm tùy chỉnh của mình, vì vậy bạn bắt đầu bằng cách phác thảo một vài trường hợp kiểm tra:

dict['Name']:  Zara
dict['Age']:  7
18

Lặp lại bởi các khóa, giá trị hoặc các cặp giá trị khóa hoạt động ngoài hộp với việc triển khai hiện tại vì các bộ và danh sách cơ bản có thể đã xử lý điều đó. Mặt khác, để thực hiện các trường hợp của lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn, bạn phải xác định một phương pháp đặc biệt khác, điều này sẽ cho phép bạn hợp tác trực tiếp với các vòng lặp
dict['Age']:  8
dict['School']:  DPS School
38:

dict['Name']:  Zara
dict['Age']:  7
19

Không giống như trước đây, bạn bàn giao một tham chiếu đến ví dụ

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 ở đây, nhưng hành vi này giống như khi bạn đang lặp lại thuộc tính
dict['Age']:  8
dict['School']:  DPS School
25. Hành vi này tương thích với
dict['Name']:  Zara
dict['Age']:  7
70 tích hợp trong Python.

Phương pháp đặc biệt mà bạn cần,

dict['Age']:  8
dict['School']:  DPS School
42, phải trả về một đối tượng Iterator, mà vòng lặp sử dụng nội bộ:

dict['Name']:  Zara
dict['Age']:  7
20

Đây là một ví dụ về trình lặp máy phát điện, tận dụng từ khóa năng suất trong Python.

Từ khóa

dict['Age']:  8
dict['School']:  DPS School
43 cho phép bạn xác định trình lặp tại chỗ bằng cách sử dụng kiểu chức năng mà không tạo ra một lớp khác. Phương pháp đặc biệt có tên
dict['Age']:  8
dict['School']:  DPS School
42 được gọi bởi vòng lặp
dict['Age']:  8
dict['School']:  DPS School
38 khi nó bắt đầu.

Được rồi, chỉ thiếu một vài tính năng không cần thiết từ bảng băm của bạn tại thời điểm này.

Đại diện cho bảng băm trong văn bản

Bit tiếp theo mà bạn sẽ thực hiện trong phần này sẽ làm cho bảng băm của bạn trông dễ chịu khi được in vào đầu ra tiêu chuẩn. Biểu diễn văn bản của bảng băm của bạn sẽ trông giống như một con trăn

dict['Name']:  Zara
dict['Age']:  7
70 theo nghĩa đen:

dict['Name']:  Zara
dict['Age']:  7
21

Theo nghĩa đen sử dụng niềng răng xoăn, dấu phẩy và đại phân, trong khi các khóa và giá trị có các biểu diễn tương ứng của chúng. Ví dụ, các chuỗi được đặt trong các dấu nháy đơn. Như bạn không biết thứ tự chính xác của các cặp giá trị khóa, bạn kiểm tra xem biểu diễn chuỗi của bảng băm của bạn có phù hợp với một trong các hoán vị cặp có thể không.

Để làm cho lớp của bạn hoạt động với chức năng

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
07 tích hợp, bạn phải triển khai phương thức đặc biệt tương ứng trong
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32:

dict['Name']:  Zara
dict['Age']:  7
22

Bạn lặp lại các khóa và giá trị thông qua thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 và sử dụng các chuỗi F để định dạng các cặp riêng lẻ. Lưu ý cờ chuyển đổi
dict['Age']:  8
dict['School']:  DPS School
50 trong chuỗi mẫu, thực thi gọi
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
14 thay vì mặc định
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
07 trên các khóa và giá trị. Điều này đảm bảo biểu diễn rõ ràng hơn, thay đổi giữa các loại dữ liệu. Ví dụ, nó kết thúc chuỗi trong các dấu nháy đơn.

Sự khác biệt giữa

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
07 và
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
14 là tinh vi hơn. Nói chung, cả hai đều có nghĩa là để chuyển đổi các đối tượng thành chuỗi. Tuy nhiên, trong khi bạn có thể mong đợi
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
07 trả về văn bản thân thiện với con người,
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
14 thường trả về một đoạn mã python hợp lệ mà bạn có thể đánh giá để tạo lại đối tượng gốc:

>>>

dict['Name']:  Zara
dict['Age']:  7
23

Trong ví dụ này, biểu diễn chuỗi của phân số python là

dict['Age']:  8
dict['School']:  DPS School
57, nhưng biểu diễn chuỗi chính tắc của cùng một đối tượng đại diện cho một cuộc gọi đến lớp
dict['Age']:  8
dict['School']:  DPS School
58.

Bạn có thể đạt được hiệu ứng tương tự trong lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn. Thật không may, trình khởi tạo lớp của bạn không cho phép tạo các phiên bản mới ra khỏi các giá trị tại thời điểm này. Bạn sẽ giải quyết vấn đề này bằng cách giới thiệu một phương thức lớp mà cho phép bạn tạo các trường hợp ____232 từ từ điển Python:

dict['Name']:  Zara
dict['Age']:  7
24

Điều này chơi độc đáo với chuyển đổi trước đó của bạn, theo hướng ngược lại. Tuy nhiên, bạn sẽ cần phải giả định một công suất đủ lớn cho bảng băm để giữ tất cả các cặp giá trị khóa từ từ điển ban đầu. Một ước tính hợp lý dường như gấp mười lần số cặp. Bạn có thể mã hóa nó ngay bây giờ:

dict['Name']:  Zara
dict['Age']:  7
25

Bạn tạo một bảng băm mới và đặt công suất của nó bằng một yếu tố tùy ý. Sau đó, bạn chèn các cặp giá trị khóa bằng cách sao chép chúng từ từ điển được truyền như một đối số cho phương thức. Bạn có thể cho phép ghi đè dung lượng mặc định nếu bạn muốn, vì vậy hãy thêm một trường hợp kiểm tra tương tự:

dict['Name']:  Zara
dict['Age']:  7
26

Để làm cho năng lực tùy chọn, bạn có thể tận dụng đánh giá ngắn mạch của các biểu thức Boolean:

dict['Name']:  Zara
dict['Age']:  7
27

Nếu

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
41 được chỉ định, thì bạn sẽ quay trở lại hành vi mặc định, nhân có độ dài từ điển từ từ điển. Với điều này, cuối cùng bạn cũng có thể cung cấp một biểu diễn chuỗi chính tắc cho các phiên bản
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn:

dict['Name']:  Zara
dict['Age']:  7
28

Như trước đây, bạn kiểm tra tất cả các hoán vị thứ tự thuộc tính có thể có trong biểu diễn kết quả. Biểu diễn chuỗi chính tắc của bảng băm trông chủ yếu giống như với

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
07, nhưng nó cũng kết thúc theo nghĩa đen trong một cuộc gọi đến phương thức lớp
dict['Age']:  8
dict['School']:  DPS School
64 mới của bạn. Các đại biểu triển khai tương ứng cho phương thức đặc biệt
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
09 bằng cách gọi hàm
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
07 tích hợp:

dict['Name']:  Zara
dict['Age']:  7
29

Lưu ý rằng bạn không mã hóa tên lớp, để tránh các vấn đề nếu bạn chọn đổi tên lớp của mình sau đó.

Nguyên mẫu bảng băm của bạn gần như đã sẵn sàng, vì bạn đã triển khai gần như tất cả các tính năng cốt lõi và không cần thiết từ danh sách được đề cập trong phần giới thiệu về phần này. Bạn chỉ cần thêm khả năng tạo bảng băm từ Python

dict['Name']:  Zara
dict['Age']:  7
70 và cung cấp các biểu diễn chuỗi cho các trường hợp của nó. Bit cuối cùng và cuối cùng là đảm bảo rằng các phiên bản bảng băm có thể được so sánh theo giá trị.

Kiểm tra sự bình đẳng của các bảng băm

Các bảng băm giống như các bộ theo nghĩa là chúng không áp đặt bất kỳ thứ tự cụ thể nào cho nội dung của chúng. Trên thực tế, các bảng và bộ băm có nhiều điểm chung hơn bạn nghĩ, vì cả hai đều được hỗ trợ bởi một hàm băm. Nó có chức năng băm làm cho các cặp giá trị khóa trong bảng băm không được đặt hàng. Tuy nhiên, hãy nhớ rằng bắt đầu từ Python 3.6,

dict['Name']:  Zara
dict['Age']:  7
70 thực sự giữ lại thứ tự chèn như một chi tiết thực hiện.

Hai bảng băm nên so sánh bằng nhau khi và chỉ khi chúng có cùng một tập hợp các cặp giá trị khóa. Tuy nhiên, Python so sánh danh tính đối tượng theo mặc định vì nó không biết cách diễn giải các giá trị của các loại dữ liệu tùy chỉnh. Vì vậy, hai trường hợp của bảng băm của bạn sẽ luôn so sánh không đồng đều ngay cả khi họ chia sẻ cùng một bộ các cặp giá trị khóa.identities by default because it doesn’t know how to interpret values of custom data types. So, two instances of your hash table would always compare unequal even if they shared the same set of key-value pairs.

Để khắc phục điều này, bạn có thể triển khai toán tử kiểm tra bình đẳng (

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
64) bằng cách cung cấp phương thức
dict['Age']:  8
dict['School']:  DPS School
70 đặc biệt trong lớp
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn. Ngoài ra, Python sẽ gọi phương pháp này để bạn đánh giá toán tử không bằng nhau (
dict['Age']:  8
dict['School']:  DPS School
72) trừ khi bạn cũng thực hiện rõ ràng
dict['Age']:  8
dict['School']:  DPS School
73.

Bạn muốn bảng băm bằng chính nó, bản sao của nó hoặc một trường hợp khác với cùng một cặp giá trị khóa bất kể thứ tự của chúng. Ngược lại, bảng băm không nên bằng một thể hiện với một tập hợp các cặp giá trị khóa khác hoặc một loại dữ liệu hoàn toàn khác:

dict['Name']:  Zara
dict['Age']:  7
30

Bạn sử dụng

dict['Age']:  8
dict['School']:  DPS School
64, được giới thiệu trong tiểu mục trước, để nhanh chóng điền vào các bảng băm mới với các giá trị. Bạn có thể tận dụng cùng một phương thức lớp để tạo một bản sao mới của thể hiện bảng băm. Ở đây, mã thỏa mãn các trường hợp thử nghiệm này:

dict['Name']:  Zara
dict['Age']:  7
31

Phương pháp đặc biệt

dict['Age']:  8
dict['School']:  DPS School
70 cần một số đối tượng để so sánh như một đối số. Nếu đối tượng đó là thể hiện hiện tại của
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32, thì bạn sẽ trả về
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
28 vì cùng một danh tính ngụ ý bình đẳng giá trị. Mặt khác, bạn tiến hành bằng cách so sánh các loại và bộ của các cặp giá trị khóa. Việc chuyển đổi sang các bộ giúp làm cho việc đặt hàng không liên quan ngay cả khi bạn quyết định biến
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 thành một danh sách được đặt hàng khác trong tương lai.

Nhân tiện, bản sao kết quả không chỉ có cùng các cặp giá trị khóa mà còn cùng dung lượng với bảng băm nguồn. Đồng thời, hai bảng băm có khả năng khác nhau vẫn sẽ so sánh bằng nhau:

dict['Name']:  Zara
dict['Age']:  7
32

Hai thử nghiệm này sẽ hoạt động với triển khai

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 hiện tại của bạn, vì vậy bạn không cần phải viết thêm bất cứ điều gì.

Nguyên mẫu bảng Hash tùy chỉnh của bạn vẫn còn thiếu một vài tính năng không cần thiết mà từ điển tích hợp cung cấp. Bạn có thể cố gắng tự thêm chúng như một bài tập. Ví dụ: bạn có thể sao chép các phương thức khác từ từ điển Python, chẳng hạn như

dict['Age']:  8
dict['School']:  DPS School
80 hoặc
dict['Age']:  8
dict['School']:  DPS School
81. Ngoài ra, bạn có thể triển khai một trong các toán tử bitwise được hỗ trợ bởi
dict['Name']:  Zara
dict['Age']:  7
70 kể từ Python 3.9, cho phép hoạt động của công đoàn.

Làm tốt! Đây là bộ thử nghiệm đã hoàn thành cho hướng dẫn và bảng băm của bạn đã vượt qua tất cả các bài kiểm tra đơn vị. Hãy cho mình một cái vỗ nhẹ xứng đáng ở phía sau bởi vì đó là một công việc tuyệt vời. Hay là nó?

Giả sử bạn giảm công suất của bảng băm của bạn để chỉ tính đến các cặp được chèn. Bảng băm sau đây sẽ chứa cả ba cặp giá trị khóa được lưu trữ trong từ điển nguồn:

>>>

dict['Name']:  Zara
dict['Age']:  7
33

Tuy nhiên, khi bạn tiết lộ các khóa và giá trị của bảng băm kết quả, đôi khi bạn sẽ thấy rằng có ít mục hơn. Để làm cho đoạn mã này có thể lặp lại, hãy chạy nó với ngẫu nhiên băm bị vô hiệu hóa bằng cách đặt biến môi trường

dict['Name']:  Zara
dict['Age']:  7
85 thành
dict['Age']:  8
dict['School']:  DPS School
84.

Thường xuyên hơn không, cuối cùng bạn sẽ mất thông tin mặc dù có đủ không gian có sẵn trong bảng băm. Điều đó bởi vì hầu hết các chức năng băm đều không hoàn hảo, gây ra sự va chạm băm, mà bạn sẽ học cách giải quyết tiếp theo.

Giải quyết va chạm mã băm

Trong phần này, bạn sẽ khám phá hai chiến lược phổ biến nhất để xử lý các va chạm mã băm và bạn sẽ thực hiện chúng trong lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn. Nếu bạn muốn làm theo các ví dụ dưới đây, thì đừng quên đặt biến
dict['Name']:  Zara
dict['Age']:  7
85 thành
dict['Age']:  8
dict['School']:  DPS School
84 để vô hiệu hóa ngẫu nhiên băm Python.

Đến bây giờ, bạn nên có một ý tưởng tốt về va chạm băm là gì. Nó có thể khi hai khóa tạo ra mã băm giống hệt nhau, dẫn các giá trị riêng biệt va chạm với nhau ở cùng một chỉ số trong bảng băm. Ví dụ: trong bảng băm có một trăm khe, các phím

dict['Age']:  8
dict['School']:  DPS School
88 và
dict['Age']:  8
dict['School']:  DPS School
89 xảy ra để chia sẻ cùng một chỉ mục khi ngẫu nhiên băm bị vô hiệu hóa:

>>>

dict['Name']:  Zara
dict['Age']:  7
34

Tuy nhiên, khi bạn tiết lộ các khóa và giá trị của bảng băm kết quả, đôi khi bạn sẽ thấy rằng có ít mục hơn. Để làm cho đoạn mã này có thể lặp lại, hãy chạy nó với ngẫu nhiên băm bị vô hiệu hóa bằng cách đặt biến môi trường

dict['Name']:  Zara
dict['Age']:  7
85 thành
dict['Age']:  8
dict['School']:  DPS School
84.

>>>

dict['Name']:  Zara
dict['Age']:  7
35

Tuy nhiên, khi bạn tiết lộ các khóa và giá trị của bảng băm kết quả, đôi khi bạn sẽ thấy rằng có ít mục hơn. Để làm cho đoạn mã này có thể lặp lại, hãy chạy nó với ngẫu nhiên băm bị vô hiệu hóa bằng cách đặt biến môi trường

dict['Name']:  Zara
dict['Age']:  7
85 thành
dict['Age']:  8
dict['School']:  DPS School
84.

Thường xuyên hơn không, cuối cùng bạn sẽ mất thông tin mặc dù có đủ không gian có sẵn trong bảng băm. Điều đó bởi vì hầu hết các chức năng băm đều không hoàn hảo, gây ra sự va chạm băm, mà bạn sẽ học cách giải quyết tiếp theo.

Giải quyết va chạm mã bămTrong phần này, bạn sẽ khám phá hai chiến lược phổ biến nhất để xử lý các va chạm mã băm và bạn sẽ thực hiện chúng trong lớp
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn. Nếu bạn muốn làm theo các ví dụ dưới đây, thì đừng quên đặt biến
dict['Name']:  Zara
dict['Age']:  7
85 thành
dict['Age']:  8
dict['School']:  DPS School
84 để vô hiệu hóa ngẫu nhiên băm Python.
Đến bây giờ, bạn nên có một ý tưởng tốt về va chạm băm là gì. Nó có thể khi hai khóa tạo ra mã băm giống hệt nhau, dẫn các giá trị riêng biệt va chạm với nhau ở cùng một chỉ số trong bảng băm. Ví dụ: trong bảng băm có một trăm khe, các phím
dict['Age']:  8
dict['School']:  DPS School
88 và
dict['Age']:  8
dict['School']:  DPS School
89 xảy ra để chia sẻ cùng một chỉ mục khi ngẫu nhiên băm bị vô hiệu hóa:
Đến bây giờ, bảng băm của bạn có thể phát hiện các nỗ lực lưu trữ các giá trị khác nhau trong cùng một vị trí:
Bạn không chỉ kết thúc việc ghi đè lên cặp được xác định bởi khóa
dict['Age']:  8
dict['School']:  DPS School
88, mà còn tệ hơn nữa, việc truy xuất giá trị của khóa hiện không có khả năng này cho bạn một câu trả lời không chính xác!
Có ba chiến lược có sẵn cho bạn để giải quyết các vụ va chạm băm:
Địa chỉ đóngGiữ các giá trị va chạm trong một cấu trúc dữ liệu riêng biệt để tìm kiếm thông qua.

Mặc dù băm hoàn hảo chỉ có thể khi bạn biết tất cả các giá trị ở phía trước, hai phương pháp độ phân giải va chạm băm khác là thực tế hơn, vì vậy bạn sẽ xem xét kỹ hơn về chúng trong hướng dẫn này. Lưu ý rằng địa chỉ mở có thể được biểu diễn bằng một số thuật toán cụ thể, bao gồm:open addressing can be represented by several specific algorithms, including:

  • Cuckoo băm
  • Gấp đôi băm
  • Hopscotch băm
  • Thăm dò tuyến tính
  • Thăm dò bậc hai
  • Robin Hood băm

Ngược lại, địa chỉ đóng được biết đến nhiều nhất với chuỗi riêng biệt. Ngoài ra, còn có Băm cũng kết hợp, kết hợp các ý tưởng đằng sau cả địa chỉ mở và đóng thành một thuật toán.closed addressing is best known for separate chaining. Additionally, there’s also coalesced hashing, which combines the ideas behind both open and closed addressing into one algorithm.

Để theo dõi sự phát triển theo hướng thử nghiệm, bạn sẽ cần thiết kế một trường hợp thử nghiệm trước. Nhưng làm thế nào để bạn kiểm tra va chạm băm? Theo mặc định, chức năng tích hợp của Python, sử dụng ngẫu nhiên cho một số loại dữ liệu của nó, điều này khiến việc dự đoán hành vi của nó trở nên vô cùng khó khăn. Việc chọn hạt băm theo cách thủ công với biến môi trường

dict['Name']:  Zara
dict['Age']:  7
85 sẽ không thực tế và làm cho các trường hợp thử nghiệm của bạn mong manh.

Cách tốt nhất để làm việc xung quanh việc này là sử dụng thư viện chế giễu, chẳng hạn như Python,

dict['Age']:  8
dict['School']:  DPS School
92:

dict['Name']:  Zara
dict['Age']:  7
36

Vá tạm thời thay thế một đối tượng bằng một đối tượng khác. Ví dụ: bạn có thể thay thế hàm

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp bằng một chức năng giả luôn trả về cùng một giá trị dự kiến, làm cho các bài kiểm tra của bạn lặp lại. Sự thay thế này chỉ có một hiệu ứng trong cuộc gọi chức năng, sau đó
dict['Name']:  Zara
dict['Age']:  7
71 ban đầu được đưa trở lại.

Bạn có thể áp dụng trình trang trí

dict['Age']:  8
dict['School']:  DPS School
95 đối với toàn bộ chức năng kiểm tra của bạn hoặc giới hạn phạm vi đối tượng giả với một trình quản lý bối cảnh:

dict['Name']:  Zara
dict['Age']:  7
37

Với trình quản lý bối cảnh, bạn có thể truy cập chức năng

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp cũng như phiên bản bị chế giễu của nó trong cùng một trường hợp thử nghiệm. Bạn thậm chí có thể có nhiều hương vị của chức năng bị chế giễu nếu bạn muốn. Tham số
dict['Age']:  8
dict['School']:  DPS School
97 cho phép bạn chỉ định một ngoại lệ để nâng cao hoặc một chuỗi các giá trị mà đối tượng giả của bạn sẽ trở lại khi gọi liên tiếp.

Trong phần còn lại của hướng dẫn này, bạn sẽ tiếp tục thêm nhiều tính năng vào lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của mình mà không cần phát triển theo định hướng thử nghiệm. Các bài kiểm tra mới sẽ được bỏ qua cho sự ngắn gọn, trong khi sửa đổi lớp sẽ khiến một số bài kiểm tra hiện tại không thành công. Tuy nhiên, bạn sẽ tìm thấy một bộ thử nghiệm làm việc trong các tài liệu đi kèm có sẵn để tải xuống.

Tìm các phím va chạm thông qua thăm dò tuyến tính

Dừng lại một lúc để hiểu lý thuyết đằng sau va chạm mã băm. Khi nói đến việc xử lý chúng, thăm dò tuyến tính là một trong những kỹ thuật lâu đời nhất, đơn giản nhất và hiệu quả nhất, tất cả cùng một lúc. Nó đòi hỏi một vài bước bổ sung để các hoạt động chèn, tra cứu, xóa và cập nhật, mà bạn sẽ học.linear probing is one of the oldest, most straightforward, and most effective techniques, all at the same time. It requires a few extra steps for the insert, lookup, delete, and update operations, which you’re about to learn.

Hãy xem xét một bảng băm mẫu đại diện cho bảng chú giải Python với các từ viết tắt phổ biến. Nó có tổng công suất mười khe cắm, nhưng bốn trong số chúng đã được thực hiện bởi các cặp giá trị khóa sau:

Mục lụcChìa khóaGiá trị
0
1 BDFLNhà độc tài nhân từ cho cuộc sống
2
3 Thay thếĐọc Vòng lặp in dấu in
4
5
6
7
8 PepĐề xuất tăng cường Python
9 WSGIGiao diện cổng máy chủ web

Bây giờ bạn muốn đặt một thuật ngữ khác vào thuật ngữ của mình để xác định từ viết tắt MRO, viết tắt của thứ tự phân giải phương thức. Bạn tính toán mã băm của khóa và cắt nó với toán tử modulo để có một chỉ mục giữa 0 và chín:MRO acronym, which stands for method resolution order. You calculate the hash code of the key and truncate it with the modulo operator to get an index between zero and nine:

>>>

dict['Name']:  Zara
dict['Age']:  7
38

Thay vì sử dụng toán tử modulo, bạn có thể cắt ngắn mã băm bằng một bitmask thích hợp, đó là cách Python tựa

dict['Name']:  Zara
dict['Age']:  7
70 hoạt động trong nội bộ.

Tuyệt quá! Có một khe cắm miễn phí trong bảng băm của bạn tại Index Five, nơi bạn có thể chèn một cặp giá trị khóa mới:

Mục lụcChìa khóaGiá trị
0
1 BDFLNhà độc tài nhân từ cho cuộc sống
2
3 Thay thếĐọc Vòng lặp in dấu in
4
5 PepĐề xuất tăng cường Python
6
7
8 PepĐề xuất tăng cường Python
9 WSGIGiao diện cổng máy chủ web

Bây giờ bạn muốn đặt một thuật ngữ khác vào thuật ngữ của mình để xác định từ viết tắt MRO, viết tắt của thứ tự phân giải phương thức. Bạn tính toán mã băm của khóa và cắt nó với toán tử modulo để có một chỉ mục giữa 0 và chín:

>>>

dict['Name']:  Zara
dict['Age']:  7
39

Thay vì sử dụng toán tử modulo, bạn có thể cắt ngắn mã băm bằng một bitmask thích hợp, đó là cách Python tựa

dict['Name']:  Zara
dict['Age']:  7
70 hoạt động trong nội bộ.

Mục lụcChìa khóaGiá trị
0
1 BDFLNhà độc tài nhân từ cho cuộc sống
2 Thay thếĐọc Vòng lặp in dấu in
3 Thay thếĐọc Vòng lặp in dấu in
4
5 MROThứ tự phân giải phương pháp
6
7
8 PepĐề xuất tăng cường Python
9 WSGIGiao diện cổng máy chủ web

Mặc dù các phím BDFL và EAFP cung cấp cùng một chỉ số bằng một, chỉ có cặp giá trị khóa được chèn đầu tiên kết thúc việc lấy nó. Bất cứ cặp nào đứng thứ hai sẽ được đặt bên cạnh chỉ số chiếm đóng. Do đó, thăm dò tuyến tính làm cho bảng băm nhạy cảm với thứ tự chèn.

Cân nhắc thêm một từ viết tắt khác, ABC, cho các lớp cơ sở trừu tượng, có mã băm cắt ngắn để lập chỉ mục tám. Bạn có thể chèn nó ở vị trí sau đây vì nó đã được WSGI thực hiện. Trong các trường hợp bình thường, bạn đã tiếp tục tìm kiếm một khe miễn phí ở xa hơn, nhưng vì bạn đã đạt được chỉ số cuối cùng, bạn phải bao quanh và chèn từ viết tắt mới tại Index Zero:ABC, for abstract base classes, whose hash code truncates to index eight. You can’t insert it in the following position this time because it’s already taken by WSGI. Under normal circumstances, you’d continue looking for a free slot further down, but because you reached the last index, you must wrap around and insert the new acronym at index zero:

Mục lụcChìa khóaGiá trị
0 ABCLớp cơ sở trừu tượng
1 BDFLNhà độc tài nhân từ cho cuộc sống
2 EAFPDễ dàng nhận được sự tha thứ hơn là sự cho phép
3 Thay thếĐọc Vòng lặp in dấu in
4
5 MROThứ tự phân giải phương pháp
6
7
8 PepĐề xuất tăng cường Python
9 WSGIGiao diện cổng máy chủ web

Mặc dù các phím BDFL và EAFP cung cấp cùng một chỉ số bằng một, chỉ có cặp giá trị khóa được chèn đầu tiên kết thúc việc lấy nó. Bất cứ cặp nào đứng thứ hai sẽ được đặt bên cạnh chỉ số chiếm đóng. Do đó, thăm dò tuyến tính làm cho bảng băm nhạy cảm với thứ tự chèn.search for key-value pairs stuffed into the hash table like this, follow a similar algorithm. Start by looking at the expected index first. For example, to find the value associated with the ABC key, calculate its hash code and map it to an index:

Cân nhắc thêm một từ viết tắt khác, ABC, cho các lớp cơ sở trừu tượng, có mã băm cắt ngắn để lập chỉ mục tám. Bạn có thể chèn nó ở vị trí sau đây vì nó đã được WSGI thực hiện. Trong các trường hợp bình thường, bạn đã tiếp tục tìm kiếm một khe miễn phí ở xa hơn, nhưng vì bạn đã đạt được chỉ số cuối cùng, bạn phải bao quanh và chèn từ viết tắt mới tại Index Zero:

dict['Name']:  Zara
dict['Age']:  7
40

Mục lục

Chìa khóa

  1. Giá trị
  2. ABC
  3. Lớp cơ sở trừu tượng

BDFLdeleting an existing key-value pair more tricky. If you just removed an entry from the hash table, then you’d introduce a blank slot, which would stop the lookup there regardless of any previous collisions. To make the collided key-value pairs reachable again, you’d have to either rehash them or use a lazy deletion strategy.

Nhà độc tài nhân từ cho cuộc sống

Mục lụcChìa khóaGiá trị
0 ABCLớp cơ sở trừu tượng
1 BDFL
2 EAFPDễ dàng nhận được sự tha thứ hơn là sự cho phép
3 Thay thếĐọc Vòng lặp in dấu in
4
5 MROThứ tự phân giải phương pháp
6
7
8 BDFL
9 WSGIGiao diện cổng máy chủ web

Mặc dù các phím BDFL và EAFP cung cấp cùng một chỉ số bằng một, chỉ có cặp giá trị khóa được chèn đầu tiên kết thúc việc lấy nó. Bất cứ cặp nào đứng thứ hai sẽ được đặt bên cạnh chỉ số chiếm đóng. Do đó, thăm dò tuyến tính làm cho bảng băm nhạy cảm với thứ tự chèn.

Cân nhắc thêm một từ viết tắt khác, ABC, cho các lớp cơ sở trừu tượng, có mã băm cắt ngắn để lập chỉ mục tám. Bạn có thể chèn nó ở vị trí sau đây vì nó đã được WSGI thực hiện. Trong các trường hợp bình thường, bạn đã tiếp tục tìm kiếm một khe miễn phí ở xa hơn, nhưng vì bạn đã đạt được chỉ số cuối cùng, bạn phải bao quanh và chèn từ viết tắt mới tại Index Zero:updating the value of an existing entry in a hash table with linear probing. When searching for a pair to update, you should only skip the slot if it’s occupied by another pair with a different key or if it contains a sentinel value. On the other hand, if the slot is empty or has a matching key, then you should set the new value.

Mục lục

Chìa khóa

Giá trị

dict['Name']:  Zara
dict['Age']:  7
41

ABC

Lớp cơ sở trừu tượng

dict['Name']:  Zara
dict['Age']:  7
42

Nếu khe trống hoặc chứa một cặp với phím khớp, thì bạn sẽ gán lại một cặp giá trị khóa mới ở chỉ mục hiện tại và dừng đầu dò tuyến tính. Mặt khác, nếu một cặp khác chiếm vị trí đó và có một phím khác, hoặc khe được đánh dấu là bị xóa, thì bạn tiến về phía trước cho đến khi bạn tìm thấy một khe miễn phí hoặc xả tất cả các khe cắm có sẵn. Nếu bạn hết các vị trí có sẵn, bạn sẽ tăng ngoại lệ

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
03 để chỉ ra khả năng không đủ của bảng băm.

Nhận và xóa các cặp giá trị khóa khỏi bảng băm bằng cách sử dụng thăm dò tuyến tính hoạt động gần như theo cùng một cách:

dict['Name']:  Zara
dict['Age']:  7
43

Sự khác biệt duy nhất là trong các dòng nổi bật. Để xóa một cặp, bạn phải biết nơi nó nằm trong bảng băm để thay thế nó bằng giá trị sentinel. Mặt khác, bạn chỉ quan tâm đến giá trị tương ứng khi tìm kiếm theo khóa. Nếu sao chép mã này làm phiền bạn, thì bạn có thể thử tái cấu trúc nó như một bài tập. Tuy nhiên, có nó bằng văn bản rõ ràng giúp đưa ra quan điểm.

Có một chi tiết quan trọng khác cần lưu ý. Các khe cắm bàn băm không còn có thể ở một trong hai trạng thái duy nhất, đó là trống hoặc chiếm. Chèn giá trị sentinel vào bảng băm để đánh dấu một khe khi đã xóa làm hỏng bảng băm từ ____ ____283,

dict['Age']:  8
dict['School']:  DPS School
25 và
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 thuộc tính và báo cáo độ dài không chính xác. Để khắc phục điều này, bạn phải lọc cả hai giá trị
dict['Name']:  Zara
dict['Age']:  7
88 và
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
08 khi trả về các cặp giá trị khóa:

dict['Name']:  Zara
dict['Age']:  7
44

Với bản cập nhật nhỏ đó, bảng băm của bạn bây giờ có thể đối phó với các va chạm băm bằng cách lan truyền các cặp va chạm và tìm kiếm chúng theo kiểu tuyến tính:

>>>

dict['Name']:  Zara
dict['Age']:  7
45

Mặc dù có cùng một mã băm bằng hai mươi bốn, cả hai khóa va chạm,

dict['Age']:  8
dict['School']:  DPS School
88 và
dict['Age']:  8
dict['School']:  DPS School
89, xuất hiện cạnh nhau trong danh sách
dict['Age']:  8
dict['School']:  DPS School
36. Lưu ý rằng họ được liệt kê theo cùng một thứ tự mà bạn đã thêm chúng vào bảng băm. Hãy thử hoán đổi thứ tự chèn hoặc thay đổi khả năng của bảng băm và quan sát cách thức ảnh hưởng đến các vị trí.

Đến bây giờ, công suất của bảng băm vẫn được cố định. Trước khi thực hiện thăm dò tuyến tính, bạn vẫn không biết gì và tiếp tục ghi đè lên các giá trị va chạm. Bây giờ, bạn có thể phát hiện khi có thêm không gian trong bảng băm của bạn và nêu ra một ngoại lệ tương ứng. Tuy nhiên, sẽ tốt hơn nếu để bảng băm tự động mở rộng công suất của nó khi cần thiết?

Đặt bảng băm tự động thay đổi kích thước

Có hai chiến lược khác nhau khi nói đến việc thay đổi kích thước một bảng băm. Bạn có thể đợi cho đến giây phút cuối cùng và chỉ thay đổi kích thước bảng băm khi nó đầy, hoặc bạn có thể làm rất háo hức sau khi đạt đến một ngưỡng nhất định. Cả hai cách đều có ưu và nhược điểm của họ. Chiến lược lười biếng được cho là đơn giản hơn để thực hiện, vì vậy bạn sẽ xem xét kỹ hơn về nó trước. Tuy nhiên, nó có thể dẫn đến nhiều va chạm và hiệu suất tồi tệ hơn.lazy strategy is arguably more straightforward to implement, so you’ll take a closer look at it first. However, it can lead to more collisions and worse performance.

Lần duy nhất bạn hoàn toàn phải tăng số lượng vị trí trong bảng băm của bạn là khi việc chèn một cặp mới thất bại, nâng ngoại lệ

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
03. Đi trước và thay thế câu lệnh
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
13 bằng một cuộc gọi đến một phương thức trợ giúp khác mà bạn sẽ tạo, theo sau là một cuộc gọi đệ quy tới
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
77 thông qua cú pháp khung vuông:

dict['Name']:  Zara
dict['Age']:  7
46

Khi bạn xác định rằng tất cả các vị trí bị chiếm, bởi một cặp hợp pháp hoặc giá trị sentinel, bạn phải phân bổ nhiều bộ nhớ hơn, sao chép các cặp hiện có và thử chèn cặp giá trị khóa mới đó.

Bây giờ, thực hiện thay đổi kích thước và thử lại theo cách sau:

dict['Name']:  Zara
dict['Age']:  7
47

Tạo một bản sao cục bộ của bảng băm. Bởi vì nó rất khó để dự đoán bạn có thể cần thêm bao nhiêu khe cắm, hãy phỏng đoán hoang dã và tăng gấp đôi kích thước công suất. Sau đó, lặp lại bộ các cặp giá trị khóa hiện có của bạn và chèn chúng vào bản sao. Cuối cùng, gán lại thuộc tính

dict['Age']:  8
dict['School']:  DPS School
36 trong trường hợp của bạn để nó trỏ đến danh sách các vị trí mở rộng.

Bảng băm của bạn bây giờ có thể tự động tăng kích thước của nó khi cần thiết, vì vậy hãy cung cấp cho nó một vòng quay. Tạo một bảng băm trống với công suất của một và thử chèn một số cặp giá trị khóa vào đó:

  • các cửa sổ
  • Linux + MacOS

>>>

dict['Name']:  Zara
dict['Age']:  7
48

>>>

dict['Name']:  Zara
dict['Age']:  7
49

Mặc dù có cùng một mã băm bằng hai mươi bốn, cả hai khóa va chạm,

dict['Age']:  8
dict['School']:  DPS School
88 và
dict['Age']:  8
dict['School']:  DPS School
89, xuất hiện cạnh nhau trong danh sách
dict['Age']:  8
dict['School']:  DPS School
36. Lưu ý rằng họ được liệt kê theo cùng một thứ tự mà bạn đã thêm chúng vào bảng băm. Hãy thử hoán đổi thứ tự chèn hoặc thay đổi khả năng của bảng băm và quan sát cách thức ảnh hưởng đến các vị trí.

Đến bây giờ, công suất của bảng băm vẫn được cố định. Trước khi thực hiện thăm dò tuyến tính, bạn vẫn không biết gì và tiếp tục ghi đè lên các giá trị va chạm. Bây giờ, bạn có thể phát hiện khi có thêm không gian trong bảng băm của bạn và nêu ra một ngoại lệ tương ứng. Tuy nhiên, sẽ tốt hơn nếu để bảng băm tự động mở rộng công suất của nó khi cần thiết?default capacity for new hash tables. This way, creating an instance of the

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 class will no longer require specifying the initial capacity, although doing so could improve performance. A common choice for the initial capacity is a small power of two, such as eight:

dict['Name']:  Zara
dict['Age']:  7
50

Điều đó làm cho nó có thể tạo các bảng băm với một cuộc gọi đến trình khởi tạo không tham số

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
17. Lưu ý rằng bạn cũng có thể cập nhật phương thức lớp
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
18 của mình để sử dụng độ dài từ điển từ dung lượng ban đầu. Trước đây, bạn đã nhân chiều dài từ điển của một yếu tố tùy ý, điều này là cần thiết để làm cho các bài kiểm tra của bạn vượt qua, do các va chạm băm chưa được xử lý.

Như đã nói trước đây, có một vấn đề với chiến lược thay đổi kích thước lười biếng, và đó là khả năng va chạm tăng lên. Bạn sẽ giải quyết vấn đề tiếp theo.

Tính hệ số tải

Chờ đợi cho đến khi bảng băm của bạn trở nên bão hòa là tối ưu. Bạn có thể thử một chiến lược háo hức để thay đổi kích thước bảng băm trước khi đạt được tổng công suất của nó, giữ cho các va chạm không xảy ra ngay từ đầu. Làm thế nào để bạn quyết định thời điểm tốt nhất để thay đổi kích thước và thử lại? Sử dụng hệ số tải!eager strategy to resize the hash table before reaching its total capacity, keeping the collisions from happening in the first place. How do you decide on the best moment to resize and rehash? Use the load factor!

Hệ số tải là tỷ lệ của số lượng các khe hiện đang bị chiếm, bao gồm cả các khe bị xóa, so với tất cả các vị trí trong bảng băm. Hệ số tải càng cao, cơ hội va chạm băm càng lớn, dẫn đến hiệu suất tra cứu tồi tệ hơn. Do đó, bạn muốn hệ số tải luôn giữ được tương đối nhỏ. Đang tăng kích thước bảng băm là do bất cứ khi nào hệ số tải đạt đến một ngưỡng nhất định.load factor is the ratio of the number of currently occupied slots, including the deleted ones, to all slots in the hash table. The higher the load factor, the bigger the chance of a hash collision, which results in worse lookup performance. Therefore, you want the load factor to remain relatively small at all times. Bumping up the hash table’s size is due whenever the load factor reaches a certain threshold.

Sự lựa chọn của một ngưỡng cụ thể là một ví dụ kinh điển về sự đánh đổi thời gian không gian trong khoa học máy tính. Thay đổi kích thước bảng băm thường xuyên hơn là rẻ hơn và dẫn đến hiệu suất tốt hơn với chi phí tiêu thụ bộ nhớ nhiều hơn. Ngược lại, chờ đợi lâu hơn có thể tiết kiệm cho bạn một số bộ nhớ, nhưng tra cứu chính sẽ chậm hơn. Biểu đồ dưới đây mô tả mối quan hệ giữa lượng bộ nhớ được phân bổ và số lượng va chạm trung bình:

Hướng dẫn does python have hash tables? - python có bảng băm không?

Dữ liệu đằng sau biểu đồ này đo số lượng va chạm trung bình gây ra bằng cách chèn một trăm yếu tố vào bảng băm trống với công suất ban đầu là một. Việc đo lường được lặp lại nhiều lần cho các ngưỡng hệ số tải khác nhau, tại đó bảng băm tự thay đổi kích thước trong các bước nhảy rời rạc bằng cách nhân đôi dung lượng của nó.

Giao điểm của cả hai lô, xuất hiện ở khoảng 0,75, cho thấy điểm ngọt ngào của ngưỡng, với lượng bộ nhớ và số lần va chạm thấp nhất. Sử dụng ngưỡng hệ số tải cao hơn không cung cấp tiết kiệm bộ nhớ đáng kể, nhưng nó làm tăng số lượng va chạm theo cấp số nhân. Một ngưỡng nhỏ hơn cải thiện hiệu suất nhưng với giá cao của bộ nhớ bị lãng phí cao. Hãy nhớ rằng tất cả những gì bạn thực sự cần là một trăm khe!sweet spot, with the lowest amount of memory and number of collisions. Using a higher load factor threshold doesn’t provide significant memory savings, but it increases the number of collisions exponentially. A smaller threshold improves the performance but for a high price of mostly wasted memory. Remember that all you really need is one hundred slots!

Bạn có thể thử nghiệm các ngưỡng hệ số tải khác nhau, nhưng thay đổi kích thước bảng băm khi 60 phần trăm các khe của nó được thực hiện có thể là một điểm khởi đầu tốt. Tại đây, cách bạn có thể thực hiện tính toán hệ số tải trong lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn:

dict['Name']:  Zara
dict['Age']:  7
51

Bạn bắt đầu bằng cách lọc các vị trí là sự thật, đó sẽ là bất cứ điều gì ngoại trừ

dict['Name']:  Zara
dict['Age']:  7
88, và sau đó lấy tỷ lệ theo định nghĩa của yếu tố tải. Lưu ý rằng nếu bạn quyết định sử dụng biểu thức hiểu, thì đó phải là một danh sách hiểu để đếm tất cả các lần xuất hiện giá trị sentinel. Trong trường hợp này, sử dụng một cách hiểu được thiết lập sẽ lọc ra các dấu hiệu lặp lại của các cặp bị xóa, chỉ để lại một trường hợp và dẫn đến một hệ số tải sai.

Tiếp theo, sửa đổi lớp của bạn để chấp nhận ngưỡng hệ số tải tùy chọn và sử dụng nó để háo hức thay đổi kích thước và thử lại các vị trí:load factor threshold and use it to eagerly resize and rehash the slots:

dict['Name']:  Zara
dict['Age']:  7
52

Ngưỡng hệ số tải mặc định là 0,6, có nghĩa là 60 phần trăm của tất cả các vị trí bị chiếm. Bạn sử dụng bất bình đẳng yếu (

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
21) thay vì nghiêm ngặt (
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
22) để tính đến ngưỡng hệ số tải ở giá trị tối đa của nó, không bao giờ có thể lớn hơn một. Nếu hệ số tải bằng một, thì bạn cũng phải thay đổi kích thước bảng băm trước khi chèn một cặp giá trị khóa khác.

Rực rỡ! Bảng băm của bạn đã trở nên nhanh hơn một chút. Điều đó kết thúc ví dụ địa chỉ mở trong hướng dẫn này. Tiếp theo, bạn sẽ giải quyết các va chạm băm bằng một trong những kỹ thuật địa chỉ đóng phổ biến nhất.

Cô lập các phím va chạm với chuỗi riêng biệt

Chuỗi riêng là một phương pháp độ phân giải va chạm băm cực kỳ phổ biến khác, thậm chí có thể phổ biến hơn so với thăm dò tuyến tính. Ý tưởng là nhóm các mục tương tự theo một tính năng chung thành cái gọi là xô để thu hẹp không gian tìm kiếm. Ví dụ, bạn có thể tưởng tượng việc thu hoạch trái cây và thu thập chúng vào các giỏ được mã hóa màu: is another extremely popular hash collision resolution method, perhaps even more widespread than linear probing. The idea is to group similar items by a common feature into so-called buckets to narrow down the search space. For example, you could imagine harvesting fruits and collecting them into color-coded baskets:

Hướng dẫn does python have hash tables? - python có bảng băm không?
Trái cây được nhóm theo màu trong mỗi giỏ

Mỗi giỏ chứa trái cây gần như cùng một màu. Vì vậy, khi bạn thèm một quả táo, chẳng hạn, bạn chỉ cần tìm kiếm qua giỏ được dán nhãn màu đỏ. Trong một thế giới lý tưởng, mỗi giỏ không nên chứa nhiều hơn một yếu tố, làm cho tìm kiếm ngay lập tức. Bạn có thể nghĩ về các nhãn như mã băm và các loại trái cây có cùng màu với các cặp giá trị khóa va chạm.

Bảng băm dựa trên chuỗi riêng biệt là danh sách các tham chiếu đến xô, thường được triển khai dưới dạng danh sách được liên kết hình thành chuỗi các yếu tố:

Hướng dẫn does python have hash tables? - python có bảng băm không?
Chuỗi các cặp khóa-giá trị va chạm

Mỗi danh sách được liên kết chứa các cặp giá trị khóa có các khóa chia sẻ cùng mã băm do va chạm. Khi tìm kiếm một giá trị theo khóa, bạn cần xác định vị trí nhóm bên phải trước, sau đó đi qua nó bằng tìm kiếm tuyến tính để tìm khóa khớp và cuối cùng trả về giá trị tương ứng. Tìm kiếm tuyến tính chỉ có nghĩa là đi qua từng mục trong xô, từng cái một, cho đến khi bạn tìm đúng phím.linear search to find the matching key, and finally return the corresponding value. Linear search just means going through each item in the bucket, one by one, until you find the right key.

Để điều chỉnh lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 của bạn để sử dụng chuỗi riêng, hãy bắt đầu bằng cách loại bỏ phương pháp
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
24 và thay thế các khe bằng xô. Bây giờ, thay vì có giá trị
dict['Name']:  Zara
dict['Age']:  7
88 hoặc một cặp ở mỗi chỉ mục, bạn sẽ làm cho mỗi chỉ mục giữ một thùng có thể trống hoặc không. Mỗi thùng sẽ là một danh sách được liên kết:

dict['Name']:  Zara
dict['Age']:  7
53

Thay vì thực hiện một danh sách được liên kết từ đầu, bạn có thể tận dụng hàng đợi hai kết thúc của Python, hoặc Deque, có sẵn trong mô-đun

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
26, sử dụng danh sách liên kết gấp đôi dưới mui xe. Nó cho phép bạn nối và loại bỏ các yếu tố hiệu quả hơn một danh sách đơn giản.

Don Tiết quên cập nhật các thuộc tính

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83,
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
47 và
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
29 để chúng đề cập đến xô thay vì các khe:

dict['Name']:  Zara
dict['Age']:  7
54

Bạn không còn cần giá trị sentinel để đánh dấu các phần tử là bị xóa, vì vậy hãy tiếp tục và loại bỏ hằng số

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
08. Điều này làm cho các cặp giá trị khóa và các yếu tố tải định nghĩa đơn giản hơn. Công suất đồng nghĩa với số lượng thùng vì bạn muốn giữ nhiều nhất một cặp giá trị khóa trong mỗi thùng, giảm thiểu số lượng va chạm mã băm.

Với chuỗi riêng biệt, tất cả các hoạt động của bảng băm cơ bản sôi sục để tìm đúng xô và tìm kiếm thông qua nó, điều này làm cho các phương thức tương ứng trông giống nhau:

dict['Name']:  Zara
dict['Age']:  7
55

Các trường hợp Deque chăm sóc cập nhật các tài liệu tham khảo nội bộ của họ khi bạn xóa một mục theo chỉ mục. Nếu bạn đã sử dụng một danh sách liên kết tùy chỉnh, bạn sẽ phải tua lại các cặp giá trị khóa va chạm bằng tay sau mỗi lần sửa đổi. Như trước đây, việc cập nhật một cặp giá trị khóa hiện có yêu cầu thay thế cái cũ bằng một cặp hoàn toàn mới vì các cặp giá trị khóa là bất biến.

Nếu bạn muốn tránh lặp lại bản thân, thì hãy thử tái cấu trúc ba phương pháp ở trên bằng cách sử dụng kết hợp mô hình cấu trúc, được giới thiệu trong Python 3.10. Bạn sẽ tìm thấy một giải pháp khả thi trong các tài liệu đi kèm.

Được rồi, bạn biết cách đối phó với các va chạm mã băm và bây giờ bạn đã sẵn sàng để tiếp tục. Tiếp theo, bạn sẽ làm cho bảng băm của bạn trả về các khóa và giá trị theo thứ tự chèn của họ.

Giữ lại thứ tự chèn vào bảng băm

Bởi vì cấu trúc dữ liệu bảng băm cổ điển sử dụng băm để truyền các khóa đồng đều và đôi khi giả ngẫu nhiên, nên nó có thể đảm bảo thứ tự của họ. Theo nguyên tắc thông thường, bạn không bao giờ nên cho rằng các yếu tố bảng băm sẽ đến theo thứ tự nhất quán khi bạn yêu cầu chúng. Nhưng đôi khi nó có thể hữu ích hoặc thậm chí cần thiết để áp đặt một thứ tự cụ thể đối với các yếu tố của bạn.hashing to spread the keys uniformly and sometimes pseudo-randomly, it can’t guarantee their order. As a rule of thumb, you should never assume that hash table elements will come in a consistent order when you request them. But it may sometimes be useful or even necessary to impose a specific order on your elements.

Cho đến Python 3.6, cách duy nhất để thực thi thứ tự đối với các yếu tố từ điển là sử dụng trình bao bọc

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
31 từ thư viện tiêu chuẩn. Sau đó, loại dữ liệu
dict['Name']:  Zara
dict['Age']:  7
70 tích hợp bắt đầu bảo tồn thứ tự chèn của các cặp giá trị khóa. Bất kể, vẫn có thể khôn ngoan khi cho rằng thiếu thứ tự phần tử để làm cho mã của bạn tương thích với các phiên bản Python cũ hơn hoặc thay thế.insertion order of the key-value pairs. Regardless, it may still be wise to assume a lack of element order to make your code compatible with older or alternative Python versions.

Làm thế nào bạn có thể sao chép một bảo quản thứ tự chèn tương tự trong lớp

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
32 tùy chỉnh của bạn? Một cách có thể là nhớ chuỗi các khóa khi bạn chèn chúng và lặp lại chuỗi đó để trả về các khóa, giá trị và cặp. Bắt đầu bằng cách khai báo một trường nội bộ khác trong lớp của bạn:

dict['Name']:  Zara
dict['Age']:  7
56

Nó có một danh sách trống của các khóa màllll phát triển và co lại khi bạn sửa đổi nội dung của bảng băm:

dict['Name']:  Zara
dict['Age']:  7
57

Bạn xóa phím khi có một cặp giá trị khóa liên quan trong bảng băm. Mặt khác, bạn chỉ thêm một khóa khi bạn chèn một cặp giá trị khóa hoàn toàn mới vào bảng băm lần đầu tiên. Bạn không muốn chèn một khóa khi bạn thực hiện một bản cập nhật, bởi vì điều đó sẽ dẫn đến nhiều bản sao của cùng một khóa.

Tiếp theo, bạn có thể thay đổi ba thuộc tính

dict['Age']:  8
dict['School']:  DPS School
25,
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
45 và
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
83 để chúng tuân theo cùng một thứ tự của các khóa được chèn:

dict['Name']:  Zara
dict['Age']:  7
58

Đảm bảo trả về một bản sao của các khóa của bạn để tránh rò rỉ việc thực hiện nội bộ. Ngoài ra, lưu ý rằng tất cả ba thuộc tính này hiện trả về danh sách thay vì các bộ vì bạn muốn chúng giữ đúng thứ tự. Đổi lại, điều này cho phép bạn khóa các khóa và giá trị để tạo các cặp:

>>>

dict['Name']:  Zara
dict['Age']:  7
59

Các khóa và giá trị luôn được trả về theo cùng một thứ tự để, ví dụ, khóa đầu tiên và bản đồ giá trị đầu tiên cho nhau. Điều này có nghĩa là bạn có thể zip chúng như trong ví dụ trên.

Bây giờ bạn đã biết cách giữ thứ tự chèn của các cặp giá trị khóa trong bảng băm của bạn. Mặt khác, nếu bạn muốn sắp xếp chúng theo các tiêu chí nâng cao hơn, thì bạn có thể làm theo các kỹ thuật tương tự như với việc sắp xếp một từ điển tích hợp. Không có mã bổ sung nào để viết vào thời điểm này.

Sử dụng các phím băm

Bảng băm của bạn đã hoàn thành và đầy đủ chức năng bây giờ. Nó có thể ánh xạ các khóa tùy ý cho các giá trị bằng cách sử dụng hàm

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp. Nó có thể phát hiện và giải quyết các va chạm mã băm và thậm chí giữ lại thứ tự chèn của các cặp giá trị khóa. Về mặt lý thuyết, bạn có thể sử dụng nó trên Python
dict['Name']:  Zara
dict['Age']:  7
70 nếu bạn muốn, mà không nhận thấy nhiều sự khác biệt ngoài hiệu suất kém và đôi khi có nhiều cú pháp dài dòng hơn.

Cho đến bây giờ, bạn đã cho rằng hầu hết các loại tích hợp trong Python có thể hoạt động như các phím bảng băm. Tuy nhiên, để sử dụng bất kỳ việc thực hiện bảng băm nào trong thực tế, bạn sẽ phải hạn chế các khóa ở các loại có thể băm và hiểu được ý nghĩa của việc làm như vậy. Điều đó sẽ đặc biệt hữu ích khi bạn quyết định đưa các loại dữ liệu tùy chỉnh vào phương trình.

Khả năng băm vs bất biến

Bạn đã học được trước đó rằng một số loại dữ liệu, bao gồm hầu hết các loại dữ liệu nguyên thủy trong Python, có thể băm, trong khi những loại khác. Đặc điểm chính của khả năng băm là khả năng tính toán mã băm của một đối tượng đã cho:hashable, while others aren’t. The primary trait of hashability is the ability to calculate the hash code of a given object:

>>>

dict['Name']:  Zara
dict['Age']:  7
60

Ví dụ: các trường hợp của loại dữ liệu

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
39 trong Python có thể băm, trong khi các bộ thông thường không thực hiện băm. Khả năng băm ảnh hưởng trực tiếp đến việc các đối tượng thuộc một số loại có thể trở thành khóa từ điển hoặc đặt thành viên, vì cả hai cấu trúc dữ liệu này sử dụng hàm
dict['Name']:  Zara
dict['Age']:  7
71 trong nội bộ:dictionary keys or set members, as both of these data structures use the
dict['Name']:  Zara
dict['Age']:  7
71 function internally:

>>>

dict['Name']:  Zara
dict['Age']:  7
61

Mặc dù một thể hiện của

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
39 có thể băm, tập hợp tương ứng với chính xác các giá trị tương tự thì không. Xin lưu ý rằng bạn vẫn có thể sử dụng một loại dữ liệu không thể chối cãi cho các giá trị từ điển. Nó có các khóa từ điển phải có khả năng tính toán mã băm tương ứng của chúng.

Khả năng băm có liên quan chặt chẽ đến khả năng đột biến hoặc khả năng thay đổi trạng thái bên trong của một đối tượng trong suốt cuộc đời của nó. Mối quan hệ giữa hai người giống như thay đổi một địa chỉ. Khi bạn chuyển đến một nơi khác, bạn vẫn là cùng một người, nhưng những người bạn cũ của bạn có thể có một thời gian khó khăn để cố gắng tìm thấy bạn.mutability, or the ability to change the internal state of an object during its lifetime. The relationship between the two is a bit like changing an address. When you move to another place, you’re still the same person, but your old friends might have a hard time trying to find you.

Các loại không thể đo lường được trong Python, chẳng hạn như danh sách, bộ hoặc từ điển, tình cờ là các thùng chứa có thể thay đổi, vì bạn có thể sửa đổi các giá trị của chúng bằng cách thêm hoặc loại bỏ các yếu tố. Mặt khác, hầu hết các loại băm tích hợp trong Python là bất biến. Điều này có nghĩa là các loại có thể thay đổi có thể được băm?mutable containers, as you can modify their values by adding or removing elements. On the other hand, most built-in hashable types in Python are immutable. Does this mean mutable types can’t be hashable?

Câu trả lời đúng là chúng có thể vừa thay đổi vừa có thể băm, nhưng chúng hiếm khi nên như vậy! Đột biến một khóa sẽ dẫn đến việc thay đổi địa chỉ bộ nhớ của nó trong bảng băm. Coi lớp tùy chỉnh này là một ví dụ:

>>>

dict['Name']:  Zara
dict['Age']:  7
62

Lớp này đại diện cho một người có tên. Python cung cấp một triển khai mặc định cho phương pháp đặc biệt

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
42 trong các lớp của bạn, chỉ sử dụng danh tính đối tượng để lấy mã băm của nó:

>>>

dict['Name']:  Zara
dict['Age']:  7
63

Mỗi cá thể

dict['Name']:  Zara
dict['Age']:  7
90 có mã băm duy nhất ngay cả khi nó có mặt bằng nhau bằng các trường hợp khác. Để làm cho giá trị đối tượng xác định mã băm của nó, bạn có thể ghi đè lên việc triển khai mặc định của
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
42 như vậy:

>>>

dict['Name']:  Zara
dict['Age']:  7
64

Bạn gọi

dict['Name']:  Zara
dict['Age']:  7
71 trên thuộc tính
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
46 để các phiên bản của lớp
dict['Name']:  Zara
dict['Age']:  7
90 có tên bằng nhau luôn có cùng mã băm. Điều này là thuận tiện cho việc tìm kiếm chúng trong một từ điển chẳng hạn.

Một đặc điểm khác của các loại băm là khả năng so sánh các trường hợp của chúng theo giá trị. Hãy nhớ lại rằng bảng băm so sánh các khóa với toán tử kiểm tra bình đẳng (

# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
64), do đó bạn phải thực hiện một phương pháp đặc biệt khác,
dict['Age']:  8
dict['School']:  DPS School
70, trong lớp của bạn để cho phép điều đó:

>>>

dict['Name']:  Zara
dict['Age']:  7
65

Đoạn mã này sẽ trông quen thuộc nếu bạn đã trải qua bài kiểm tra bình đẳng của các bảng băm trước đó. Tóm lại, bạn kiểm tra xem đối tượng khác có phải là cùng một thể hiện chính xác không, một thể hiện của loại khác hoặc một thể hiện khác của cùng loại và giá trị bằng với thuộc tính

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
46.

Đã triển khai

dict['Age']:  8
dict['School']:  DPS School
70 và
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
42, bạn có thể sử dụng các phiên bản lớp
dict['Name']:  Zara
dict['Age']:  7
90 làm khóa từ điển:

>>>

dict['Name']:  Zara
dict['Age']:  7
66

Hoàn hảo! Không có vấn đề gì nếu bạn tìm thấy một nhân viên bằng tài liệu tham khảo

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
54 mà bạn đã tạo trước đó hoặc một ví dụ
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
55 hoàn toàn mới. Thật không may, mọi thứ trở nên phức tạp khi Bob đột nhiên quyết định thay đổi tên của mình và thay vào đó là Bobby:

>>>

dict['Name']:  Zara
dict['Age']:  7
67

Bạn không còn cách lấy giá trị tương ứng mặc dù bạn vẫn sử dụng đối tượng khóa ban đầu mà bạn đã chèn trước đó. Mặc dù vậy, điều đáng ngạc nhiên hơn là bạn có thể truy cập giá trị thông qua một đối tượng chính mới với tên người được cập nhật hoặc với tên cũ. Bạn có thể biết tại sao?

Mã băm của khóa ban đầu được xác định là thùng nào giá trị liên quan được lưu trữ. Đột biến trạng thái khóa của bạn đã tạo ra mã băm của nó cho thấy một nhóm hoặc khe hoàn toàn khác, không chứa giá trị dự kiến. Nhưng sử dụng một chìa khóa với tên cũ cũng không giúp ích gì. Mặc dù nó chỉ vào thùng bên phải, khóa được lưu trữ đã bị đột biến, làm cho so sánh bình đẳng giữa

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
56 và
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
57 đánh giá thành
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School"; # Add new entry
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
68 thay vì khớp.

Do đó, mã băm phải là bất biến để băm hoạt động như mong đợi. Vì các mã băm thường có nguồn gốc từ các thuộc tính của đối tượng, nên trạng thái của chúng nên được sửa và không bao giờ thay đổi theo thời gian. Trong thực tế, điều này cũng có nghĩa là các đối tượng dự định như các phím bảng băm nên tự mình là bất biến.immutable for the hashing to work as expected. Since hash codes are typically derived from an object’s attributes, their state should be fixed and never change over time. In practice, this also means that objects intended as hash table keys should be immutable themselves.

Tóm lại, một loại dữ liệu có thể băm có các đặc điểm sau:

  1. Có phương thức
    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    del dict['Name']; # remove entry with key 'Name'
    dict.clear();     # remove all entries in dict
    del dict ;        # delete entire dictionary
    
    print "dict['Age']: ", dict['Age']
    print "dict['School']: ", dict['School']
    
    42 để tính toán mã băm phiên bảnhash code
  2. Có phương thức
    dict['Age']:  8
    dict['School']:  DPS School
    
    70 để so sánh các trường hợp theo giá trịcompare instances by value
  3. Có mã băm bất biến, không thay đổi trong thời gian tồn tạiimmutable hash codes, which don’t change during instances’ lifetimes
  4. Phù hợp với hợp đồng bămhash-equal contract

Đặc điểm thứ tư và cuối cùng của các loại băm là chúng phải tuân thủ hợp đồng băm, mà bạn sẽ tìm hiểu thêm về tiểu mục sau. Nói tóm lại, các đối tượng có giá trị bằng nhau phải có mã băm giống hệt nhau.hash-equal contract, which you’ll learn more about in the following subsection. In short, objects with equal values must have identical hash codes.

Hợp đồng băm nhỏ

Để tránh các vấn đề khi sử dụng các lớp tùy chỉnh làm khóa bảng băm, chúng nên tuân thủ hợp đồng băm. Nếu có một điều cần nhớ về hợp đồng đó, thì đó là khi bạn thực hiện

dict['Age']:  8
dict['School']:  DPS School
70, bạn phải luôn thực hiện một
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
42 tương ứng. Lần duy nhất bạn không phải thực hiện cả hai phương pháp là khi bạn sử dụng một trình bao bọc như lớp dữ liệu hoặc một loại tuple có tên bất biến đã làm điều này cho bạn.data class or an immutable named tuple that already does this for you.

Ngoài ra, việc không thực hiện cả hai phương thức có thể ổn, miễn là bạn hoàn toàn chắc chắn rằng bạn đã giành được các đối tượng thuộc loại dữ liệu của mình làm khóa từ điển hoặc đặt thành viên. Nhưng bạn có thể chắc chắn như vậy?

Mặc dù bạn có thể thực hiện cả hai phương thức theo cách bạn thích, nhưng chúng phải đáp ứng hợp đồng bằng băm, trong đó nêu rõ rằng hai đối tượng bằng nhau phải băm với mã băm bằng nhau. Điều này làm cho nó có thể tìm đúng xô dựa trên một khóa được cung cấp. Tuy nhiên, điều ngược lại là đúng, bởi vì các va chạm đôi khi có thể khiến cùng một mã băm được chia sẻ bởi các giá trị không đồng đều. Bạn có thể thể hiện điều này chính thức hơn bằng cách sử dụng hai hàm ý này:bucket based on a provided key. However, the reverse isn’t true, because collisions may occasionally cause the same hash code to be shared by unequal values. You can express this more formally by using these two implications:

  1. dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    del dict['Name']; # remove entry with key 'Name'
    dict.clear();     # remove all entries in dict
    del dict ;        # delete entire dictionary
    
    print "dict['Age']: ", dict['Age']
    print "dict['School']: ", dict['School']
    
    63
    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    del dict['Name']; # remove entry with key 'Name'
    dict.clear();     # remove all entries in dict
    del dict ;        # delete entire dictionary
    
    print "dict['Age']: ", dict['Age']
    print "dict['School']: ", dict['School']
    
    64
  2. dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    del dict['Name']; # remove entry with key 'Name'
    dict.clear();     # remove all entries in dict
    del dict ;        # delete entire dictionary
    
    print "dict['Age']: ", dict['Age']
    print "dict['School']: ", dict['School']
    
    64
    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    del dict['Name']; # remove entry with key 'Name'
    dict.clear();     # remove all entries in dict
    del dict ;        # delete entire dictionary
    
    print "dict['Age']: ", dict['Age']
    print "dict['School']: ", dict['School']
    
    63

Hợp đồng băm là một hợp đồng một chiều. Nếu hai khóa bằng nhau bằng logic, thì mã băm của chúng cũng phải bằng nhau. Mặt khác, nếu hai khóa chia sẻ cùng một mã băm, thì có khả năng chúng có cùng một khóa, nhưng nó cũng có thể là các phím khác nhau. Bạn cần so sánh chúng để chắc chắn nếu chúng thực sự phù hợp. Theo luật đối lập, bạn có thể lấy được một hàm ý khác từ cái đầu tiên:one-way contract. If two keys are logically equal, then their hash codes must also be equal. On the other hand, if two keys share the same hash code, it’s likely they’re the same key, but it’s also possible that they’re different keys. You need to compare them to be sure if they really match. By the law of contraposition, you can derive another implication from the first one:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
67
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
68

Nếu bạn biết rằng hai khóa có mã băm khác nhau, thì không có điểm nào trong việc so sánh chúng. Điều đó có thể giúp cải thiện hiệu suất, vì bài kiểm tra bình đẳng có xu hướng tốn kém.

Một số IDE cung cấp để tự động tạo các phương thức

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict['Name']; # remove entry with key 'Name'
dict.clear();     # remove all entries in dict
del dict ;        # delete entire dictionary

print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
42 và
dict['Age']:  8
dict['School']:  DPS School
70 cho bạn, nhưng bạn cần nhớ tái tạo chúng mỗi khi bạn sửa đổi các thuộc tính lớp của mình. Do đó, hãy gắn bó với các lớp dữ liệu Python, hoặc các bộ dữ liệu được đặt tên bất cứ khi nào bạn có thể để đảm bảo việc thực hiện đúng các loại băm.

Sự kết luận

Tại thời điểm này, bạn có thể thực hiện một bảng băm từ đầu trong Python, sử dụng các chiến lược khác nhau để giải quyết các va chạm băm. Bạn biết cách làm cho bảng băm của bạn thay đổi kích thước và thử lại một cách linh hoạt để chứa nhiều dữ liệu hơn và cách bảo quản thứ tự chèn của các cặp giá trị khóa. Trên đường đi, bạn đã thực hành phát triển theo hướng thử nghiệm (TDD) bằng cách thêm các tính năng vào bảng băm của bạn từng bước.implement a hash table from scratch in Python, using different strategies to resolve hash collisions. You know how to make your hash table resize and rehash dynamically to accommodate more data and how to preserve the insertion order of key-value pairs. Along the way, you practiced test-driven development (TDD) by adding features to your hash table step by step.

Ngoài ra, bạn có một sự hiểu biết sâu sắc về chức năng

dict['Name']:  Zara
dict['Age']:  7
71 tích hợp của Python và có thể tạo ra một chức năng của riêng bạn. Bạn hiểu hợp đồng bằng băm, sự khác biệt giữa các loại dữ liệu có thể băm và không thể không và mối quan hệ của chúng với các loại bất biến. Bạn biết cách tạo các lớp Hashable tùy chỉnh bằng các công cụ khác nhau trong Python.hash-equal contract, the difference between hashable and unhashable data types, and their relationship with immutable types. You know how to create custom hashable classes using various tools in Python.

Trong hướng dẫn này, bạn đã học được:

  • Làm thế nào một bảng băm khác với một từ điểnhash table differs from a dictionary
  • Cách bạn có thể thực hiện một bảng băm từ đầu trong Pythonimplement a hash table from scratch in Python
  • Làm thế nào bạn có thể đối phó với các vụ va chạm băm và các thách thức kháchash collisions and other challenges
  • Các thuộc tính mong muốn của hàm băm là gìhash function are
  • Làm thế nào Python từ
    dict['Name']:  Zara
    dict['Age']:  7
    
    71 hoạt động đằng sau hậu trườngPython’s
    dict['Name']:  Zara
    dict['Age']:  7
    
    71
    works behind the scenes

Với kiến ​​thức này, bạn đã chuẩn bị để trả lời hầu hết các câu hỏi mà bạn có thể nhận được một cuộc phỏng vấn xin việc liên quan đến cấu trúc dữ liệu bảng Hash.job interview related to the hash table data structure.

Bạn có thể tải xuống mã nguồn đầy đủ và các bước trung gian được sử dụng trong suốt hướng dẫn này bằng cách nhấp vào liên kết bên dưới:

Có một cái bàn băm trong Python?

Một bảng băm trong Python sử dụng một mảng làm phương tiện lưu trữ và sử dụng phương pháp băm để tạo một chỉ mục trong đó một phần tử sẽ được tìm kiếm từ hoặc cần được chèn. Nói cách khác, bảng băm trong Python là cấu trúc dữ liệu lưu trữ dữ liệu bằng cách sử dụng một cặp giá trị và khóa.. In other words, a Hash Table in Python is a data structure which stores data by using a pair of values and keys.

Python sử dụng băm cái gì?

Vì vậy, ở đó bạn có nó: Python sử dụng Siphash vì đó là chức năng băm mật mã đáng tin cậy sẽ ngăn chặn các cuộc tấn công va chạm.SipHash because it's a trusted, cryptographic hash function that should prevent collision attacks.

Sự khác biệt giữa bảng băm và python từ điển là gì?

Trong Hashtable, bạn có thể lưu trữ các cặp khóa/giá trị cùng loại hoặc loại từ điển khác nhau, bạn có thể lưu trữ các cặp khóa/giá trị cùng loại.Trong Hashtable, không cần chỉ định loại khóa và giá trị.Trong từ điển, bạn phải chỉ định loại khóa và giá trị. In Dictionary, you can store key/value pairs of same type. In Hashtable, there is no need to specify the type of the key and value. In Dictionary, you must specify the type of key and value.

Từ điển có phải là bảng băm không?

Từ điển là một cấu trúc dữ liệu ánh xạ các khóa cho các giá trị.Bảng băm là một cấu trúc dữ liệu ánh xạ các phím lên các giá trị bằng cách lấy giá trị băm của khóa (bằng cách áp dụng một số hàm băm cho nó) và ánh xạ nó vào một thùng nơi lưu trữ một hoặc nhiều giá trị.