Python cập nhật một khóa trong dict nếu nó không tồn tại


104

Tôi muốn chèn một cặp khóa-giá trị vào dict nếu khóa không có trong dict.keys (). Về cơ bản, tôi có thể làm điều đó với:

if key not in d.keys():
    d[key] = value

Nhưng có cách nào tốt hơn không? Hay giải pháp cho vấn đề này là gì?


Câu trả lời:


145

Bạn không cần phải gọi d.keys(), vì vậy

if key not in d:
    d[key] = value

Là đủ. Không có phương pháp nào rõ ràng hơn, dễ đọc hơn.

Bạn có thể cập nhật lại với dict.get(), giá trị này sẽ trả về giá trị hiện có nếu khóa đã có:

d[key] = d.get(key, value)

nhưng tôi thực sự khuyên bạn không nên làm điều này; đây là mã chơi gôn, cản trở việc bảo trì và khả năng đọc.


Tôi có cần đồng bộ hóa điều này nếu tôi có nhiều luồng sử dụng mã không?
ed22

1
@ ed22 có, vì nó bao gồm nhiều lệnh bytecode, giữa các luồng có thể chuyển đổi.
Martijn Pieters

79

Sử dụng dict.setdefault():

>>> d = {1: 'one'}
>>> d.setdefault(1, '1')
'one'
>>> d    # d has not changed because the key already existed
{1: 'one'}
>>> d.setdefault(2, 'two')
'two'
>>> d
{1: 'one', 2: 'two'}

5
dict.setdefault()thực sự chỉ nên được sử dụng khi cố gắng truy cập giá trị.
Martijn Pieters

13
@MartijnPieters: tại sao điều đó lại quan trọng? Tên setdefault()mô tả rõ ràng những gì đang xảy ra - rằng nó cũng trả về một giá trị không quan trọng và IMO hơi kỳ quặc. Bạn có thể cung cấp một lời giải thích nhanh chóng hoặc một liên kết đến một trong những lý do tại sao điều này không được mong muốn?
mhawke

6
Bạn muốn sử dụng nó trong một biểu thức dự đoán một giá trị để tồn tại, giống như trong một vòng lặp nhóm: for obj in iterable: d.setdefault(key_for_obj(obj), []).append(obj). Không có gì kỳ quặc về giá trị được trả về, đó là toàn bộ điểm của phương pháp .
Martijn Pieters

2
Ngoài ra, nó che khuất những gì bạn đang cố gắng thực hiện, đó là chỉ đặt khóa nếu nó chưa có mặt. Tính khả năng đọc, chỉ cần sử dụng một if key not in d:bài kiểm tra.
Martijn Pieters

6
@MartijnPieters: Cảm ơn bạn đã giải thích. Sau khi đọc chuỗi tài liệu, setdefault()dường như bạn đang hướng đến những gì bạn đã nói. Sử dụng một mã defaultdict(list)sẽ dẫn đến nhiều mã dễ đọc hơn ví dụ của bạn ... vì vậy có lẽ không có ích cho nó trừ khi người ta phải làm việc với các từ điển tiêu chuẩn. Nhìn chung, if key not in dlà rõ ràng hơn.
mhawke

22

Kể từ Python 3.9, bạn có thể sử dụng toán tử | hợp nhất để hợp nhất hai từ điển. Mệnh đề ở bên phải được ưu tiên:

d = { key: value } | d

Lưu ý: điều này tạo ra một từ điển mới với các giá trị được cập nhật.


4
Mặc dù điều này thú vị, nhưng tôi không nghĩ nó dễ đọc hơn câu trả lời được chấp nhận
Justin Furuness

Đối với tôi, thật tuyệt khi biết có cách để hợp nhất hai giáo phái bây giờ
Austin A

5

Với cách sau, bạn có thể chèn nhiều giá trị và cũng có giá trị mặc định nhưng bạn đang tạo một từ điển mới.

d = {**{ key: value }, **default_values}

Tôi đã thử nghiệm nó với câu trả lời được bình chọn nhiều nhất và trung bình thì nó nhanh hơn vì nó có thể thấy trong ví dụ sau,.

Kiểm tra tốc độ so sánh phương pháp dựa trên vòng lặp for với khả năng hiểu chính tả bằng toán tử giải nén Kiểm tra tốc độ so sánh phương pháp dựa trên vòng lặp for với khả năng hiểu chính tả với phương pháp toán tử giải nén.

nếu không có bản sao ( d = default_vals.copy()) nào được thực hiện trong trường hợp đầu tiên thì câu trả lời được bình chọn nhiều nhất sẽ nhanh hơn khi chúng ta đạt được các thứ tự có độ lớn 10**5và lớn hơn. Dấu chân bộ nhớ của cả hai phương pháp đều giống nhau.


1
Vậy tại sao lại đề xuất nó ngay từ đầu
jonathan

1
Giải pháp này có vẻ hoàn toàn hợp lệ đối với tôi. Nó cũng cho phép cập nhật nhiều giá trị trong một lần khai báo.
Rotareti

cảm ơn bạn rất nhiều. Nhưng có vẻ như nên{**default_values, **{ key: value }}
osexp2003

0

Theo các câu trả lời ở trên, phương pháp setdefault () đã làm việc cho tôi.

old_attr_name = mydict.setdefault(key, attr_name)
if attr_name != old_attr_name:
    raise RuntimeError(f"Key '{key}' duplication: "
                       f"'{old_attr_name}' and '{attr_name}'.")

Mặc dù giải pháp này không phải là chung chung. Chỉ phù hợp với tôi trong trường hợp nhất định này. Giải pháp chính xác sẽ là kiểm tra keylần đầu tiên (như đã được khuyến cáo), nhưng với việc setdefault()chúng tôi tránh một lần tra cứu thêm trên từ điển, tức là, mặc dù nhỏ, nhưng vẫn tăng hiệu suất.

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.