LoạiError: loại không thể xóa: 'dict'


174

Đoạn mã này đang gây ra lỗi cho tôi, unhashable type: dictbất cứ ai cũng có thể giải thích cho tôi giải pháp là gì

negids = movie_reviews.fileids('neg')
def word_feats(words):
    return dict([(word, True) for word in words])

negfeats = [(word_feats(movie_reviews.words(fileids=[f])), 'neg') for f in negids]
stopset = set(stopwords.words('english'))

def stopword_filtered_word_feats(words):
    return dict([(word, True) for word in words if word not in stopset])

result=stopword_filtered_word_feats(negfeats)


3
Sẽ hữu ích khi hiển thị báo cáo lỗi để chúng tôi có thể xem dòng nào có vấn đề ...
drevicko 17/2/2015

Câu trả lời:


248

Bạn đang cố gắng sử dụng dictlàm chìa khóa cho người khác dicthoặc trong một set. Điều đó không hoạt động vì các khóa phải được băm. Theo nguyên tắc chung, chỉ các đối tượng bất biến (chuỗi, số nguyên, số float, fro chục, bộ dữ liệu bất biến) là có thể băm (mặc dù có thể có ngoại lệ). Vì vậy, điều này không hoạt động:

>>> dict_key = {"a": "b"}
>>> some_dict[dict_key] = True
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Để sử dụng một dict làm khóa, bạn cần biến nó thành một cái gì đó có thể được băm trước. Nếu dict bạn muốn sử dụng làm khóa chỉ bao gồm các giá trị bất biến, bạn có thể tạo một đại diện có thể băm của nó như thế này:

>>> key = frozenset(dict_key.items())

Bây giờ bạn có thể sử dụng keylàm khóa trong một dicthoặc set:

>>> some_dict[key] = True
>>> some_dict
{frozenset([('a', 'b')]): True}

Tất nhiên bạn cần phải lặp lại bài tập bất cứ khi nào bạn muốn tìm kiếm một cái gì đó bằng cách sử dụng một lệnh:

>>> some_dict[dict_key]                     # Doesn't work
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> some_dict[frozenset(dict_key.items())]  # Works
True

Nếu khóa dictbạn muốn sử dụng làm khóa có các giá trị mà chính chúng là các ký tự và / hoặc danh sách, bạn cần đệ quy "đóng băng" khóa tiềm năng. Đây là điểm khởi đầu:

def freeze(d):
    if isinstance(d, dict):
        return frozenset((key, freeze(value)) for key, value in d.items())
    elif isinstance(d, list):
        return tuple(freeze(value) for value in d)
    return d

2
Cảm ơn, nó hoạt động, tuy nhiên vẫn gặp lỗi nếu giá trị là một dict hoặc danh sách (không thể xóa được), bây giờ tôi đang sử dụng hàm băm (str (my_dict)), hoạt động tốt với tôi.
Steven Du

7
chỉ là một ghi chú từ điển @StevenDu không đảm bảo trật tự, vì vậy str(my_dict)có thể trả về hai chuỗi khác nhau cho cùng một (hoặc khác nhau, nhưng tương đương)
K Raphael

1
Để chuyển đổi froundredet kết quả trở lại dict, chỉ cần gọi dict(the_frozenset).
người dùng

4
Dường như với tôi có frozenset(dict_key.items())khả năng có vấn đề ở chỗ hai ký tự có cùng nội dung nhưng thứ tự chèn khác nhau có thể không dẫn đến cùng một khóa. Thêm một cuộc gọi để sắp xếp () dường như theo thứ tự. Ví dụ frozenset(sorted(dict_key.items())), ngoài ra, froundredet có vẻ như là một lựa chọn kỳ lạ được đưa ra rằng các bộ rõ ràng không có thứ tự. Nó có thể hoạt động tốt trong thực tế, nhưng tuple có vẻ như là một lựa chọn hợp lý hơn với tôi. Tôi đã đi vớituple(sorted(dict_key.items()))
Jason Heiss

Đồng ý với @JasonHeiss
user3732361

6

Một giải pháp khả thi có thể là sử dụng phương thức JSON dumps (), vì vậy bạn có thể chuyển đổi từ điển thành một chuỗi ---

import json

a={"a":10, "b":20}
b={"b":20, "a":10}
c = [json.dumps(a), json.dumps(b)]


set(c)
json.dumps(a) in c

Đầu ra -

set(['{"a": 10, "b": 20}'])
True

2
Nó nên dumps, không phải dump.
Kushan Gunasekera
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.