Python, yoksa bir anahtarı dikte günceller


104

Anahtar dict.keys () içinde değilse dict'e bir anahtar / değer çifti eklemek istiyorum. Temelde şununla yapabilirim:

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

Ama daha iyi bir yol var mı? Ya da bu problemin pitonik çözümü nedir?


Yanıtlar:


145

Aramana gerek yok d.keys(), bu yüzden

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

yeterlidir. Daha net, daha okunaklı bir yöntem yok.

dict.get()Anahtar zaten mevcutsa mevcut bir değeri döndürecek şekilde ile tekrar güncelleme yapabilirsiniz :

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

ama buna karşı şiddetle tavsiye ederim; bu kod golfüdür, bakımı ve okunabilirliği engeller.


Kodu kullanan birden fazla iş parçacığım varsa bunu senkronize etmem gerekir mi?
ed22

1
@ ed22 evet, çünkü iş parçacıkları arasında geçiş yapabilen birden fazla bayt kodu komutundan oluşur.
Martijn Pieters

78

Kullanım 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()gerçekten de yalnızca değere erişmeye çalışırken kullanılmalıdır.
Martijn Pieters

13
@MartijnPieters: Bu neden önemli? İsim setdefault(), ne olduğunu açıkça anlatıyor - aynı zamanda bir değer döndürmesi o kadar önemli değil ve biraz tuhaf IMO. Bunun neden arzu edilmediğine dair hızlı bir açıklama veya birine bir bağlantı verebilir misiniz?
mhawke

6
Bir değer bir gruplandırma döngü içinde olduğu gibi, mevcut beklediği bir ifadede kullanıldığında ediyorum: for obj in iterable: d.setdefault(key_for_obj(obj), []).append(obj). Döndürülen değerle ilgili tuhaf bir şey yok , yöntemin tüm noktası bu .
Martijn Pieters

2
Ayrıca, yapmaya çalıştığınız şeyi karartır; bu, yalnızca zaten mevcut değilse bir anahtar ayarlamaktır. Okunabilirlik önemlidir, sadece bir if key not in d:test kullanın .
Martijn Pieters

6
@MartijnPieters: Açıklama için teşekkürler. Dokümanı okuduktan sonra, setdefault()söylediklerinize uygun görünüyor. Bir kullanmak defaultdict(list), örneğinizden daha okunabilir bir kodla sonuçlanır ... bu nedenle, standart sözlüklerle çalışılması gerekmedikçe belki de bunun bir faydası yoktur. Genel if key not in dolarak daha net.
mhawke

22

Python 3.9'dan beri , iki sözlüğü birleştirmek için birleştirme operatörünü | kullanabilirsiniz. Sağdaki dikte önceliklidir:

d = { key: value } | d

Not: Bu, güncellenmiş değerlerle yeni bir sözlük oluşturur.


4
Bu ilginç olsa da, kabul edilen cevaptan daha okunaklı olduğunu düşünmüyorum
Justin Furuness

Benim için, şimdi iki dicti birleştirmenin bir yolu olduğunu bilmek güzel
Austin A

5

Aşağıdakilerle birden çok değer ekleyebilir ve ayrıca varsayılan değerlere sahip olabilirsiniz, ancak yeni bir sözlük oluşturuyorsunuz.

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

Bunu en çok oylanan cevapla test ettim ve ortalama olarak bu, aşağıdaki örnekte görülebileceği gibi daha hızlı.

Döngü tabanlı bir yöntemi, paket açma operatörü ile bir dikt kavrama ile karşılaştıran hız testi For döngüsü tabanlı bir yöntemi dikte kavrama ile unpack operatör yöntemiyle karşılaştıran hız testi.

d = default_vals.copy()ilk durumda herhangi bir kopya ( ) yapılmazsa , en çok oylanan cevap, büyüklük 10**5ve daha büyük sıralara ulaştığımızda daha hızlı olacaktır . Her iki yöntemin bellek ayak izi aynıdır.


1
Öyleyse neden ilk etapta önerin
jonathan

1
Bu çözüm benim için tamamen geçerli görünüyor. Ayrıca, bir bildirimde birden çok değerin güncellenmesine izin verir.
Rotareti

çok teşekkür ederim. Ama öyle görünüyor{**default_values, **{ key: value }}
osexp2003

0

Yukarıdaki cevaplara göre setdefault () yöntemi benim için çalıştı.

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}'.")

Bu çözüm genel olmasa da. Bu belirli durumda bana çok yakıştı. Kesin çözüm, keyilkini kontrol etmektir (daha önce tavsiye edildiği gibi), ancak setdefault()sözlükte fazladan bir aramadan, yani küçük de olsa, ancak yine de bir performans kazanımından kaçınırız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.