Làm cách nào để khởi tạo từ điển danh sách trống trong Python?


88

Nỗ lực tạo danh sách từ điển theo chương trình của tôi không cho phép tôi xử lý các khóa từ điển riêng lẻ. Bất cứ khi nào tôi tạo từ điển danh sách và cố gắng thêm vào một khóa, tất cả chúng đều được cập nhật. Đây là một trường hợp thử nghiệm rất đơn giản:

data = {}
data = data.fromkeys(range(2),[])
data[1].append('hello')
print data

Kết quả thực tế: {0: ['hello'], 1: ['hello']}

Kết quả mong đợi: {0: [], 1: ['hello']}

Đây là những gì hoạt động

data = {0:[],1:[]}
data[1].append('hello')
print data

Kết quả thực tế và mong đợi: {0: [], 1: ['hello']}

Tại sao fromkeysphương pháp không hoạt động như mong đợi?

Câu trả lời:


111

Truyền []làm đối số thứ hai để dict.fromkeys()đưa ra một kết quả khá vô dụng - tất cả các giá trị trong từ điển sẽ là cùng một đối tượng danh sách.

Trong Python 2.7 trở lên, thay vào đó, bạn có thể sử dụng văn bản đọc hiểu lưỡng tính:

data = {k: [] for k in range(2)}

Trong các phiên bản Python trước, bạn có thể sử dụng

data = dict((k, []) for k in range(2))

3
Đây là một hành vi khá không trực quan, bất kỳ ý tưởng nào về lý do tại sao cùng một đối tượng được sử dụng cho tất cả các khóa?
Bar

2
@Bar Bởi vì không có gì khác mà hàm có thể làm trong ngữ nghĩa của ngôn ngữ Python. Bạn chuyển một đối tượng duy nhất được sử dụng làm giá trị cho tất cả các khóa, do đó, đối tượng duy nhất đó được sử dụng cho tất cả các khóa. fromkeys()Thay vào đó, phương thức này sẽ tốt hơn nếu chấp nhận một hàm gốc, vì vậy chúng ta có thể chuyển vào listdưới dạng một hàm và funciton đó sẽ được gọi một lần cho mỗi khóa được tạo, nhưng đó không phải là API thực tế của dict.fromkeys().
Sven Marnach

3
Điều này không trực quan chút nào. Tôi mất một giờ để tìm. Cảm ơn
Astrid

1
Điều tương tự cũng xảy ra nếu bạn truyền dict () làm đối số thứ hai. Hành vi rất khó hiểu.
Orly

@Orly Điều này là do đầu tiên một từ điển trống được tạo và sau đó một tham chiếu đến nó được chuyển cho tất cả các lần khởi tạo.
Dr_Zaszuś

83

Sử dụng defaultdict thay vì:

from collections import defaultdict
data = defaultdict(list)
data[1].append('hello')

Bằng cách này, bạn không phải khởi tạo trước tất cả các khóa bạn muốn sử dụng cho danh sách.

Điều đang xảy ra trong ví dụ của bạn là bạn sử dụng một danh sách (có thể thay đổi):

alist = [1]
data = dict.fromkeys(range(2), alist)
alist.append(2)
print data

sẽ xuất ra {0: [1, 2], 1: [1, 2]}.


2
Trong trường hợp của tôi, tôi cần khởi tạo tất cả các khóa trước để phần còn lại của logic chương trình có thể hoạt động như mong đợi, nhưng nếu không thì đây sẽ là một giải pháp tốt. Cảm ơn.
Martin Burch

Tôi đoán những gì còn thiếu trong câu trả lời này đang nói rằng giải pháp này hoạt động, trái ngược với giải pháp của OP, bởi vì listđây không phải là một danh sách trống, mà là một kiểu (hoặc bạn có thể xem nó như một hàm tạo có thể gọi, tôi đoán vậy). Vì vậy, mỗi khi một khóa bị thiếu được thông qua, một danh sách mới được tạo ra thay vì sử dụng lại khóa cũ.
Dr_Zaszuś

8

Bạn đang điền vào từ điển của mình các tham chiếu vào một danh sách để khi bạn cập nhật danh sách, bản cập nhật sẽ được phản ánh trên tất cả các tham chiếu. Thay vào đó, hãy thử đọc hiểu từ điển. Xem Tạo từ điển với khả năng hiểu danh sách bằng Python

d = {k : v for k in blah blah blah}

gợi ý tuyệt vời về việc khởi tạo các giá trị từ điển ... cảm ơn cobie! Tôi đã mở rộng ví dụ của bạn để đặt lại các giá trị trong từ điển hiện có, d. Tôi đã thực hiện điều này như sau: d = {k: 0 for k in d}
John

Là gì vtrong câu trả lời này?
Dr_Zaszuś

-2

Bạn có thể sử dụng cái này:

data[:1] = ['hello']

2
Có thể hữu ích cho OP để giải thích tại sao điều này hoạt động. Câu hỏi ban đầu đăng aks tại sao nó không hoạt động như mong đợi.
william.taylor. 09

@ william.taylor.09 Rõ ràng là tại sao điều này hoạt động, phải không?
Conner Dassen

OP đang hỏi "Tại sao phương thức fromkeys không hoạt động như mong đợi?"
william.taylor. 09
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.