2011-08-31 37 views
61

Tôi là một chút bối rối về những gì có thể/không thể được sử dụng như một chìa khóa cho một dict python.Tại sao tôi không thể sử dụng danh sách dưới dạng khóa dict trong python?

dicked = {} 
dicked[None] = 'foo'  # None ok 
dicked[(1,3)] = 'baz' # tuple ok 
import sys 
dicked[sys] = 'bar'  # wow, even a module is ok ! 
dicked[(1,[3])] = 'qux' # oops, not allowed 

Vì vậy, bộ túp là một loại không thay đổi nhưng nếu tôi ẩn danh sách bên trong, thì nó không thể là chìa khóa .. tôi có thể dễ dàng ẩn danh sách bên trong mô-đun không?

Tôi đã có một số ý tưởng mơ hồ rằng khóa phải là "băm" nhưng tôi sẽ thừa nhận sự thiếu hiểu biết của riêng tôi về các chi tiết kỹ thuật; Tôi không biết điều gì đang diễn ra ở đây. Điều gì sẽ xảy ra nếu bạn cố sử dụng danh sách dưới dạng khóa, với băm như vị trí bộ nhớ của chúng?

+1

Đây là một cuộc thảo luận tốt: http://stackoverflow.com/questions/2671211/create-a-dictionary-in-python-which-is-indexed-by-lists – Hernan

+25

Got a cười ra khỏi tên biến của bạn. – kindall

Trả lời

21

Có một bài viết hay về chủ đề trong wiki Python: Why Lists Can't Be Dictionary Keys. Như được giải thích ở đó:

Điều gì sẽ xảy ra nếu bạn cố gắng sử dụng danh sách dưới dạng khóa, với vị trí bộ nhớ của chúng?

Nó có thể được thực hiện mà không thực sự vi phạm bất kỳ yêu cầu nào, nhưng dẫn đến hành vi không mong muốn. Danh sách thường được coi như là giá trị của chúng được lấy từ giá trị nội dung của chúng, ví dụ khi kiểm tra (in-) bình đẳng. Nhiều người sẽ - dễ hiểu - hy vọng rằng bạn có thể sử dụng bất kỳ danh sách [1, 2] để có được cùng một khóa, nơi bạn sẽ phải giữ xung quanh chính xác cùng một đối tượng danh sách. Nhưng tra cứu bằng cách chia nhỏ giá trị ngay khi danh sách được sử dụng làm khóa được sửa đổi và tìm kiếm theo danh tính yêu cầu bạn giữ chính xác danh sách tương tự - không yêu cầu bất kỳ hoạt động danh sách chung nào khác (ít nhất là tôi không thể nghĩ đến).

đối tượng khác như mô-đun và object làm cho một thỏa thuận lớn hơn nhiều trong số nhận dạng đối tượng của họ anyway (khi là lần cuối cùng bạn có hai đối tượng mô-đun riêng biệt gọi là sys?), Và được so sánh bởi đó anyway.Do đó, nó ít đáng ngạc nhiên hơn - hoặc thậm chí được mong đợi - rằng chúng, khi được sử dụng như các khóa dict, so sánh với bản sắc trong trường hợp đó.

7

Dưới đây là một câu trả lời http://wiki.python.org/moin/DictionaryKeys

Điều gì sẽ đi sai nếu bạn cố gắng sử dụng danh sách như chìa khóa, với băm như, nói, vị trí bộ nhớ của họ?

Tìm kiếm 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 danh sách có cùng nội dung sẽ cho biết chúng tương đương nhau.

Điều gì về việc sử dụng danh sách theo nghĩa đen trong tra cứu từ điển?

9

Vấn đề là bộ dữ liệu không thay đổi và danh sách thì không. Hãy xem xét những điều sau đây

d = {} 
li = [1,2,3] 
d[li] = 5 
li.append(4) 

Điều gì nên d[li] trả lại? Nó có cùng danh sách không? Làm thế nào về d[[1,2,3]]? Nó có cùng giá trị, nhưng là một danh sách khác?

Cuối cùng, không có câu trả lời thỏa đáng. Ví dụ: nếu khóa duy nhất hoạt động là khóa gốc, thì nếu bạn không có tham chiếu đến khóa đó, bạn sẽ không bao giờ có thể truy cập lại giá trị đó nữa. Với mỗi khóa được phép khác, bạn có thể tạo khóa mà không có tham chiếu đến khóa gốc.

Nếu cả hai đề xuất của tôi đều hoạt động, thì bạn có các khóa rất khác nhau trả về cùng một giá trị, điều này đáng ngạc nhiên hơn một chút. Nếu chỉ các nội dung gốc hoạt động, thì khóa của bạn sẽ nhanh chóng bị hỏng, vì các danh sách được tạo để sửa đổi.

+0

Vâng, đó là cùng một danh sách vì vậy tôi mong đợi 'd [li]' vẫn còn 5. 'd [[1,2,3]]' sẽ tham chiếu đến một đối tượng danh sách khác làm khóa, vì vậy nó sẽ là một KeyError . Tôi không thực sự thấy bất kỳ vấn đề nào được nêu ra .. ngoại trừ việc cho phép một khóa nhận được rác thu thập có thể làm cho một số giá trị dict không thể tiếp cận. Nhưng đó là một vấn đề thực tế không phải là một vấn đề logic .. – wim

+0

@wim: 'd [list (li)]' là một KeyError là một phần của vấn đề. Trong gần * mọi trường hợp sử dụng khác *, 'li' sẽ không thể phân biệt được với danh sách mới có nội dung giống hệt nhau. Nó hoạt động, nhưng nó phản trực giác với nhiều người. Ngoài ra, lần cuối cùng bạn * thực sự * phải sử dụng danh sách như khóa chính tả là khi nào? Trường hợp sử dụng duy nhất tôi có thể tưởng tượng là khi bạn đang băm tất cả mọi thứ theo danh tính, và trong trường hợp đó bạn chỉ nên làm điều đó thay vì dựa vào '__hash__' và' __eq__' để dựa trên danh tính. – delnan

+0

@delnan Là _problem_ chỉ đơn giản là nó sẽ không phải là rất hữu ích dict vì biến chứng như vậy? hoặc có lý do nào đó tại sao nó thực sự có thể phá vỡ một dict? – wim

2

awnser của bạn có thể được tìm thấy ở đây:

Tại sao Lists Can not Be điển Phím

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

Nguồn & biết thêm: http://wiki.python.org/moin/DictionaryKeys

0

Theo tài liệu Python 2.7.2:

Một đối tượng là hashable nếu nó có một giá trị băm mà không bao giờ thay đổi trong suốt cuộc đời của nó (nó cần một phương pháp hàm băm()) và có thể là so với các đối tượng khác (cần một số eq() hoặc cmp()). Đối tượng Hashable so sánh bằng nhau phải có cùng giá trị băm.

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

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

Tuple là bất biến theo nghĩa bạn không thể thêm, xóa hoặc thay thế các phần tử của nó, nhưng bản thân các phần tử có thể thay đổi. Giá trị băm của danh sách phụ thuộc vào giá trị băm của các phần tử của nó, và do đó nó thay đổi khi bạn thay đổi các phần tử.

Sử dụng id cho danh sách băm sẽ ngụ ý rằng tất cả các danh sách đều khác nhau, điều này sẽ gây ngạc nhiên và bất tiện.

+0

Điều đó không trả lời câu hỏi, phải không? 'hash = id' không phá vỡ bất biến ở cuối đoạn đầu tiên, câu hỏi là tại sao nó không được thực hiện theo cách đó. – delnan

+0

@delnan: Tôi đã thêm đoạn cuối để làm rõ. –

0

Câu trả lời đơn giản cho câu hỏi của bạn là danh sách lớp không thực hiện phương thức băm bắt buộc đối với bất kỳ đối tượng nào muốn được sử dụng làm khóa trong từ điển. Tuy nhiên, lý do tại sao hash không được thực hiện giống như cách nói lớp tuple (dựa trên nội dung của vùng chứa) là do danh sách có thể thay đổi nên việc chỉnh sửa danh sách sẽ yêu cầu tính lại giá trị băm có thể có nghĩa là danh sách trong bây giờ nằm ​​trong xô sai trong bảng băm underling. Lưu ý rằng vì bạn không thể sửa đổi một tuple (không thay đổi) nó không chạy vào vấn đề này.

Một lưu ý phụ là việc thực hiện thực tế tra cứu dictobjects dựa trên thuật toán D từ Knuth Vol. 3, Sec. 6.4. Nếu bạn có cuốn sách đó có sẵn cho bạn, nó có thể là một giá trị đọc, ngoài ra nếu bạn thực sự thực sự quan tâm bạn có thể muốn xem xét các ý kiến ​​nhà phát triển trên thực tế implementation of dictobject here. Nó đi vào chi tiết như thế nào để chính xác nó hoạt động như thế nào.Ngoài ra còn có một python lecture về việc thực hiện các từ điển mà bạn có thể quan tâm. Chúng đi qua định nghĩa về khóa và giá trị băm trong vài phút đầu tiên.

15

Tại sao tôi không thể sử dụng danh sách dưới dạng khóa dict trong python?

>>> d = {repr([1,2,3]): 'value'} 
{'[1, 2, 3]': 'value'} 

(cho bất cứ ai tình cờ về câu hỏi này tìm kiếm một con đường xung quanh nó)

như được giải thích bởi những người khác ở đây, thực sự bạn không thể. Tuy nhiên, bạn có thể sử dụng biểu diễn chuỗi của nó thay vào đó nếu bạn thực sự muốn sử dụng danh sách của mình.

+3

Xin lỗi, tôi không thực sự thấy quan điểm của bạn. Không có gì khác biệt khi sử dụng các chuỗi ký tự như các phím. – wim

+3

Đúng; Tôi vừa thấy rất nhiều câu trả lời thực sự giải thích tại sao bạn không thể sử dụng danh sách về 'khóa phải có thể bẻ khóa', điều đó đúng, tôi muốn đề xuất một cách xung quanh nó, chỉ trong trường hợp ai đó (mới) sẽ tìm kiếm nó ... – Remi

Các vấn đề liên quan