Khóa python có thể là danh sách không?

Bạn có thể sử dụng danh sách Python làm giá trị từ điển. Trên thực tế, bạn có thể sử dụng các đối tượng Python tùy ý làm giá trị từ điển và tất cả các đối tượng có thể băm làm khóa từ điển. Bạn có thể xác định danh sách [1, 2] dưới dạng giá trị chính tả với dict[key] = [1, 2] hoặc với

friends = dict()
friends['Alice'] = ['Bob', 'Carl']
friends['Bob'] = ['Alice']
friends['Carl'] = []


print('Alice friends: ', friends['Alice'])
# Alice friends:  ['Bob', 'Carl']

print('Bob friends: ', friends['Bob'])
# Bob friends:  ['Alice']

print('Carl friends: ', friends['Carl'])
# Carl friends:  []
0

Đây là một ví dụ cụ thể cho thấy cách tạo một từ điển

friends = dict()
friends['Alice'] = ['Bob', 'Carl']
friends['Bob'] = ['Alice']
friends['Carl'] = []


print('Alice friends: ', friends['Alice'])
# Alice friends:  ['Bob', 'Carl']

print('Bob friends: ', friends['Bob'])
# Bob friends:  ['Alice']

print('Carl friends: ', friends['Carl'])
# Carl friends:  []
1 trong đó mỗi giá trị từ điển thực tế là một danh sách bạn bè

friends = {'Alice': ['Bob', 'Carl'],
           'Bob': ['Alice'],
           'Carl': []}


print('Alice friends: ', friends['Alice'])
# Alice friends:  ['Bob', 'Carl']

print('Bob friends: ', friends['Bob'])
# Bob friends:  ['Alice']

print('Carl friends: ', friends['Carl'])
# Carl friends:  []

Lưu ý rằng bạn cũng có thể gán danh sách làm giá trị của các khóa cụ thể bằng cách sử dụng thao tác gán từ điển như vậy

friends = dict()
friends['Alice'] = ['Bob', 'Carl']
friends['Bob'] = ['Alice']
friends['Carl'] = []


print('Alice friends: ', friends['Alice'])
# Alice friends:  ['Bob', 'Carl']

print('Bob friends: ', friends['Bob'])
# Bob friends:  ['Alice']

print('Carl friends: ', friends['Carl'])
# Carl friends:  []

Tôi có thể sử dụng Danh sách làm Khóa chính tả không?

Bạn không thể sử dụng danh sách làm khóa từ điển vì danh sách có thể thay đổi và do đó không thể băm được. Vì từ điển được xây dựng trên bảng băm, tất cả các khóa phải có thể băm được nếu không Python sẽ đưa ra thông báo lỗi

Đây là một ví dụ

d = dict()
my_list = [1, 2, 3]
d[my_list] = 'abc'

Điều này dẫn đến thông báo lỗi sau

Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\code.py", line 3, in 
    d[my_list] = 'abc'
TypeError: unhashable type: 'list'

Để khắc phục điều này, hãy chuyển đổi danh sách thành bộ dữ liệu Python và sử dụng bộ dữ liệu Python làm khóa từ điển. Các bộ dữ liệu trong Python là bất biến và có thể băm được, do đó, có thể được sử dụng làm phần tử tập hợp hoặc khóa từ điển

Đây là ví dụ tương tự sau khi chuyển đổi danh sách thành một bộ—nó hoạt động. 🎉

d = dict()
my_list = [1, 2, 3]
my_tuple = tuple(my_list)
d[my_tuple] = 'abc'

Trước khi đi, có thể bạn muốn tham gia học viện email miễn phí của chúng tôi gồm những người học đầy tham vọng như bạn? . Chúng tôi cũng có cheat sheet. 👇

Khóa python có thể là danh sách không?

Chris

Trong khi làm việc với tư cách là một nhà nghiên cứu trong các hệ thống phân tán, Dr. Christian Mayer tìm thấy tình yêu của mình với việc dạy sinh viên khoa học máy tính

Để giúp sinh viên đạt được mức độ thành công Python cao hơn, anh ấy đã thành lập trang web giáo dục lập trình Finxter. com. Ông là tác giả của cuốn sách lập trình nổi tiếng Python One-Liners (NoStarch 2020), đồng tác giả của loạt sách tự xuất bản Coffee Break Python, người đam mê khoa học máy tính, cộng tác viên tự do và chủ sở hữu của một trong 10 blog Python lớn nhất thế giới

Niềm đam mê của anh ấy là viết, đọc và mã hóa. Nhưng niềm đam mê lớn nhất của anh ấy là phục vụ các lập trình viên đầy tham vọng thông qua Finxter và giúp họ nâng cao kỹ năng của mình. Bạn có thể tham gia học viện email miễn phí của anh ấy tại đây

Yêu cầu duy nhất đối với khóa từ điển là khóa đó có thể băm được. Các loại có thể thay đổi như danh sách, từ điển và bộ sẽ không hoạt động và dẫn đến lỗi như TypeError. loại không thể băm. 'dict'.

Những người mới sử dụng Python thường thắc mắc tại sao, trong khi ngôn ngữ này bao gồm cả bộ dữ liệu và loại danh sách, bộ dữ liệu có thể được sử dụng làm khóa từ điển, trong khi danh sách thì không. Đây là một quyết định thiết kế có chủ ý và có thể được giải thích tốt nhất bằng cách hiểu cách thức hoạt động của từ điển Python

Từ điển hoạt động như thế nào

Từ điển, trong Python, còn được gọi là "ánh xạ", bởi vì chúng "ánh xạ" hoặc "liên kết" các đối tượng chính với các đối tượng giá trị

Do đó, ánh xạ Python phải có khả năng, với một đối tượng khóa cụ thể, xác định đối tượng giá trị nào (nếu có) được liên kết với một khóa đã cho. Một cách tiếp cận đơn giản là lưu trữ danh sách các cặp (khóa, giá trị), sau đó tìm kiếm danh sách một cách tuần tự mỗi khi một giá trị được yêu cầu. Tuy nhiên, cách tiếp cận này sẽ rất chậm với số lượng lớn các mục - về độ phức tạp, thuật toán này sẽ là O(n), trong đó n là số lượng mục trong ánh xạ

Việc triển khai từ điển của Python giảm độ phức tạp trung bình của việc tra cứu từ điển xuống O(1) bằng cách yêu cầu các đối tượng chính đó cung cấp hàm "băm". Hàm băm như vậy lấy thông tin trong một đối tượng chính và sử dụng nó để tạo ra một số nguyên, được gọi là giá trị băm. Giá trị băm này sau đó được sử dụng để xác định cặp "nhóm" (khóa, giá trị) này sẽ được đặt vào. Mã giả cho chức năng tra cứu này có thể trông giống như

Để thuật toán tra cứu như vậy hoạt động chính xác, các hàm băm được cung cấp phải đảm bảo rằng nếu hai khóa tạo ra các giá trị băm khác nhau thì hai đối tượng khóa không tương đương, nghĩa là,

for all i1, i2, if hash(i1) != hash(i2), then i1 != i2

Mặt khác, việc kiểm tra giá trị băm của một đối tượng chính có thể khiến chúng ta tìm sai nhóm và do đó không bao giờ tìm thấy giá trị liên quan

Để thuật toán tra cứu như vậy hoạt động hiệu quả, hầu hết các nhóm chỉ nên có một số lượng nhỏ các mục (tốt nhất là chỉ có một mục). Xem xét điều gì sẽ xảy ra với hàm băm sau

Lưu ý rằng hàm này đáp ứng các yêu cầu của hàm băm - mỗi khi hai khóa có giá trị băm khác nhau, chúng sẽ đại diện cho các đối tượng khác nhau. (Điều này đúng một cách tầm thường vì không có khóa nào có giá trị băm khác nhau - tất cả chúng đều có giá trị 1. ) Nhưng đây là một hàm băm tồi vì nó có nghĩa là tất cả các cặp (khóa, giá trị) sẽ được đặt trong một danh sách duy nhất và do đó, mỗi lần tra cứu sẽ yêu cầu tìm kiếm toàn bộ danh sách này. Do đó, một thuộc tính mong muốn (rất) của hàm băm là nếu hai khóa tạo ra các giá trị băm giống nhau, thì các đối tượng khóa là tương đương, nghĩa là,

for all i1, i2, if hash(i1) == hash(i2), then i1 == i2

Các hàm băm có thể ước lượng tốt thuộc tính này sẽ phân phối đồng đều các cặp (khóa, giá trị) trên các nhóm và giảm thời gian tra cứu

Các loại có thể sử dụng làm khóa từ điển

Cuộc thảo luận ở trên sẽ giải thích tại sao Python yêu cầu điều đó

Để được sử dụng làm khóa từ điển, một đối tượng phải hỗ trợ hàm băm (e. g. đến __hash__), so sánh bình đẳng (e. g. thông qua __eq__ hoặc __cmp__) và phải thỏa mãn điều kiện đúng ở trên

Danh sách dưới dạng khóa từ điển

Điều đó nói rằng, câu trả lời đơn giản cho lý do tại sao danh sách không thể được sử dụng làm khóa từ điển là danh sách không cung cấp phương thức __hash__ hợp lệ. Tất nhiên, câu hỏi rõ ràng là, "Tại sao không?"

Xem xét những loại hàm băm nào có thể được cung cấp cho danh sách

Nếu các danh sách được băm theo id, thì điều này chắc chắn sẽ hợp lệ theo định nghĩa của hàm băm của Python - các danh sách có giá trị băm khác nhau sẽ có các id khác nhau. Nhưng danh sách là vùng chứa và hầu hết các hoạt động khác trên chúng đều xử lý chúng như vậy. Vì vậy, danh sách băm theo id của chúng thay vào đó sẽ tạo ra hành vi không mong muốn, chẳng hạn như

  • Tra cứu các danh sách khác nhau có cùng nội dung sẽ tạo ra các kết quả khác nhau, mặc dù so sánh các danh sách có cùng nội dung sẽ chỉ ra chúng là tương đương

  • Sử dụng một danh sách theo nghĩa đen trong tra cứu từ điển sẽ là vô nghĩa -- nó sẽ luôn tạo ra KeyError

Nếu các danh sách được băm theo nội dung của chúng (như các bộ dữ liệu), thì đây cũng sẽ là một hàm băm hợp lệ - các danh sách có giá trị băm khác nhau sẽ có nội dung khác nhau. Vì vậy, một lần nữa, vấn đề không nằm ở định nghĩa của hàm băm. Nhưng điều gì sẽ xảy ra khi một danh sách, được sử dụng làm khóa từ điển, bị sửa đổi? . Điều này có thể dẫn đến các lỗi không mong muốn như

   1 >>> l = [1, 2]
   2 >>> d = {}
   3 >>> d[l] = 42
   4 >>> l.append(3)
   5 >>> d[l]
   6 Traceback (most recent call last):
   7   File "", line 1, in ?
   8 KeyError: [1, 2, 3]
   9 >>> d[[1, 2]]
  10 Traceback (most recent call last):
  11   File "", line 1, in ?
  12 KeyError: [1, 2]

trong đó giá trị 42 không còn nữa vì danh sách băm thành cùng một giá trị, [1, 2], không tương đương với danh sách đã sửa đổi và giá trị tương đương với danh sách đã sửa đổi, [1, 2, 3] . Vì từ điển không biết khi nào một đối tượng khóa được sửa đổi, nên các lỗi như vậy chỉ có thể được tạo ra khi tra cứu khóa chứ không phải tại thời điểm sửa đổi đối tượng, điều này có thể khiến các lỗi như vậy khá khó gỡ lỗi

Nhận thấy rằng cả hai cách băm danh sách đều có một số tác dụng phụ không mong muốn, rõ ràng hơn là tại sao Python có lập trường rằng

Không nên sử dụng loại danh sách tích hợp làm khóa từ điển

Lưu ý rằng vì các bộ dữ liệu là bất biến, nên chúng không gặp rắc rối với danh sách - chúng có thể được băm theo nội dung của chúng mà không phải lo lắng về việc sửa đổi. Do đó, trong Python, chúng cung cấp phương thức __hash__ hợp lệ và do đó có thể sử dụng làm khóa từ điển

Các loại do người dùng xác định làm khóa từ điển

Còn các trường hợp của các loại do người dùng xác định thì sao?

Theo mặc định, tất cả các loại do người dùng xác định đều có thể sử dụng làm khóa từ điển với hash(object) mặc định là id(object) và cmp(object1, object2) mặc định là cmp(id(object1), id(object2)). Đề xuất tương tự này đã được thảo luận ở trên cho các danh sách và thấy không đạt yêu cầu. Tại sao các loại do người dùng xác định lại khác nhau?

  1. Trong trường hợp một đối tượng phải được đặt trong ánh xạ, nhận dạng đối tượng thường quan trọng hơn nhiều so với nội dung đối tượng
  2. Trong trường hợp nội dung đối tượng thực sự quan trọng, cài đặt mặc định có thể được xác định lại bằng cách ghi đè __hash__ và __cmp__ hoặc __eq__

Lưu ý rằng cách thực hành tốt hơn thường là khi một đối tượng được liên kết với một giá trị, chỉ cần gán giá trị đó làm một trong các thuộc tính của đối tượng

Một giá trị quan trọng có thể là một danh sách?

Bạn không thể sử dụng danh sách làm khóa , vì danh sách có thể được sửa đổi tại chỗ bằng cách sử dụng phép gán chỉ mục, phép gán lát cắt hoặc các phương thức như append() và expand(). Tốt nhất là coi từ điển như một bộ chìa khóa. các cặp giá trị, với yêu cầu các khóa là duy nhất (trong một từ điển).

Khóa từ điển có thể là một danh sách không?

Danh sách dưới dạng khóa từ điển

Tại sao không thể sử dụng danh sách làm khóa?

Bạn không thể sử dụng danh sách làm khóa vì danh sách có thể thay đổi . Tương tự, bạn không thể sử dụng một bộ làm khóa nếu bất kỳ phần tử nào của nó là danh sách. (Bạn chỉ có thể sử dụng một bộ làm khóa nếu tất cả các phần tử của nó là bất biến. )

Những loại khóa nào có thể là Python?

Khóa phải là bất biến . Chúng ta cũng có thể sử dụng các bộ dữ liệu làm khóa nhưng chúng chỉ được chứa các chuỗi, số nguyên hoặc các bộ dữ liệu khác. Strings and numbers are the two most commonly used data types as dictionary keys. We can also use tuples as keys but they must contain only strings, integers, or other tuples.