'Setdefault' dict yöntemi için kullanım örnekleri


Yanıtlar:


208

Sen söyleyebiliriz defaultdictayarları varsayılan için yararlıdır dicti doldurmadan önce ve setdefaultvarsayılan ayar için yararlıdır iken veya dicti doldurduktan sonra .

Muhtemelen en yaygın kullanım örneği: Öğeleri gruplama (ayrıştırılmamış verilerde, başka kullanımlarda itertools.groupby)

# really verbose
new = {}
for (key, value) in data:
    if key in new:
        new[key].append( value )
    else:
        new[key] = [value]


# easy with setdefault
new = {}
for (key, value) in data:
    group = new.setdefault(key, []) # key might exist already
    group.append( value )


# even simpler with defaultdict 
from collections import defaultdict
new = defaultdict(list)
for (key, value) in data:
    new[key].append( value ) # all keys have a default already

Bazen bir diksiyon oluşturduktan sonra belirli tuşların var olduğundan emin olmak istersiniz. defaultdictbu durumda çalışmaz, çünkü yalnızca açık erişimde anahtarlar oluşturur. Birçok üstbilgi ile HTTP-ish kullandığınızı düşünün - bazıları isteğe bağlıdır, ancak bunlar için varsayılanlar istersiniz:

headers = parse_headers( msg ) # parse the message, get a dict
# now add all the optional headers
for headername, defaultvalue in optional_headers:
    headers.setdefault( headername, defaultvalue )

1
Gerçekten de, bu IMHO, yerine geçmek için başlıca kullanım durumudur defaultdict. İlk paragrafta ne demek istediğinize bir örnek verebilir misiniz?
Eli Bendersky

2
Muhammed Alkarouri: İlk önce dikteyi kopyala ve sonra bazı öğelerin üzerine yaz. Bunu da çok yapıyorum ve sanırım bu en çok tercih edilen deyim setdefault. A defaultdictise, defaultvalueshepsi eşit değilse (yani bazıları 0ve bazıları []) çalışmaz .
Jochen Ritzel

2
@ YHC4k, evet. Bu yüzden kullandım headers = dict(optional_headers). Varsayılan değerlerin hepsinin eşit olmadığı durumda. Ve sonuç, önce HTTP üstbilgilerini alıyorsanız, daha sonra alamadığınızlar için varsayılanları ayarlar. Ve zaten varsa oldukça kullanılabilir optional_headers. Verilen 2 adım kodumu deneyin ve kendinizle karşılaştırın, ne demek istediğimi göreceksiniz.
Muhammad Alkarouri

19
ya da sadece yapmaknew.setdefault(key, []).append(value)
fmalina

2
En iyi cevabın defaultdictdaha da iyi olması garip buluyorum setdefault(şimdi kullanım durumu nerede?). Ayrıca, IMO örneğini ChainMapdaha iyi idare eder http.
YvesgereY

29

Genellikle setdefaultbu işlevde olduğu gibi anahtar kelime bağımsız değişken dikte için kullanın :

def notify(self, level, *pargs, **kwargs):
    kwargs.setdefault("persist", level >= DANGER)
    self.__defcon.set(level, **kwargs)
    try:
        kwargs.setdefault("name", self.client.player_entity().name)
    except pytibia.PlayerEntityNotFound:
        pass
    return _notify(level, *pargs, **kwargs)

Anahtar kelime argümanları alan işlevlerin etrafındaki sarmalayıcılardaki argümanları ayarlamak için harikadır.


16

defaultdict varsayılan değer yeni bir liste gibi statik olduğunda harikadır, ancak dinamikse çok fazla değildir.

Örneğin, dizeleri benzersiz ints ile eşleştirmek için bir sözlüğe ihtiyacım var. defaultdict(int)varsayılan değer için her zaman 0 kullanır. Aynı şekilde, defaultdict(intGen())daima 1 üretir.

Bunun yerine, düzenli bir karar kullandım:

nextID = intGen()
myDict = {}
for lots of complicated stuff:
    #stuff that generates unpredictable, possibly already seen str
    strID = myDict.setdefault(myStr, nextID())

dict.get(key, nextID())Bu değerlerin daha sonra da başvurabilmem gerektiğinden bunun yeterli olmadığını unutmayın .

intGen otomatik olarak bir int artırır ve değerini döndüren inşa küçük bir sınıftır:

class intGen:
    def __init__(self):
        self.i = 0

    def __call__(self):
        self.i += 1
    return self.i

Birinin bunu yapmanın bir yolu varsa, defaultdictonu görmek isterim.


defaultdict (bir alt sınıf) ile yapmanın bir yolu için şu soruya bakın: stackoverflow.com/questions/2912231/…
weronika

8
Sen yerini alabilir intGenile itertools.count().next.
Antimon

7
nextID()myDict.setdefault()döndürdüğü değer a olarak kullanılmasa bile, her değer çağrıldığında değeri artırılacaktır strID. Bu bir şekilde savurgan görünüyor ve setdefault()genel olarak sevmediğim şeylerden birini gösteriyor - yani defaultaslında kullanılıp kullanılmadığını tartışmasını her zaman değerlendiriyor .
martineau

Sen ile bunu yapabilirsiniz defaultdict: myDict = defaultdict(lambda: nextID()). Daha sonra, strID = myDict[myStr]döngüde.
musiphil

3
Defaultdict ile tanımladığınız davranışı elde etmek için neden sadece myDict = defaultdict(nextID)?
forty_two

10

setdefault()Bir 'de varsayılan bir değer istediğimde kullanıyorum OrderedDict. Her iki yapan bir standart Python toplama yoktur, ama orada olan yolları böyle bir koleksiyon uygulamaktır.


10

Yanıtların çoğu belirtildiği gibi setdefaultveya defaultdictbir anahtar olmadığında varsayılan bir değer belirlemenize izin verir. Bununla birlikte, kullanım durumları ile ilgili küçük bir uyarıya dikkat çekmek istiyorum setdefault. Python yorumlayıcısı yürütüldüğünde setdefault, anahtar sözlükte bulunsa bile işleve ilişkin ikinci argümanı her zaman değerlendirir. Örneğin:

In: d = {1:5, 2:6}

In: d
Out: {1: 5, 2: 6}

In: d.setdefault(2, 0)
Out: 6

In: d.setdefault(2, print('test'))
test
Out: 6

Gördüğünüz gibi print, sözlükte zaten 2 tane olmasına rağmen yürütüldü. setdefaultÖrneğin, gibi bir optimizasyon için kullanmayı planlıyorsanız bu özellikle önemli hale gelir memoization. İkinci bağımsız değişken olarak özyinelemeli işlev çağrısı eklerseniz setdefault, Python işlevi her zaman özyinelemeli olarak çağırdığı için herhangi bir performans elde edemezsiniz.

Notlamadan bahsedildiği için, not işleviyle bir işlevi geliştirmeyi düşünüyorsanız functools.lru_cache dekoratör kullanmak daha iyi bir alternatiftir. lru_cache özyinelemeli bir işlev için önbellek gereksinimlerini daha iyi işler.


8

Muhammed'in dediği gibi, sadece bazen varsayılan bir değer belirlemek istediğiniz durumlar vardır. Bunun harika bir örneği, önce doldurulan, sonra sorgulanan bir veri yapısıdır.

Bir üçlü düşünün. Bir sözcük eklerken, bir alt düğüm gerekli ancak mevcut değilse, üçgeni genişletmek için oluşturulmalıdır. Bir kelimenin varlığını sorgularken, eksik bir alt düğüm kelimenin bulunmadığını ve yaratılmaması gerektiğini belirtir.

Bir defaultdict bunu yapamaz. Bunun yerine, get ve setdefault yöntemleriyle düzenli bir diksiyon kullanılmalıdır.


5

Teorik olarak, bazen bir varsayılan ayarlamak ve bazen yapmak istemezseniz setdefaultyine de kullanışlı olacaktır . Gerçek hayatta böyle bir kullanım örneğiyle karşılaşmadım.

Bununla birlikte, ilginç bir kullanım örneği standart kitaplıktan gelir (Python 2.6, _threadinglocal.py):

>>> mydata = local()
>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]

Kullanmanın __dict__.setdefaultoldukça faydalı bir durum olduğunu söyleyebilirim .

Düzenleme : Bu olduğu gibi, bu standart kitaplıktaki tek örnektir ve bir yorumdadır. Öyleyse varlığını haklı çıkarmak için yeterli bir durum yeterli olmayabilir setdefault. Yine de, bir açıklama:

Nesneler niteliklerini öznitelikte saklar __dict__. __dict__Gerçekleştikçe , öznitelik nesne oluşturulduktan sonra herhangi bir zamanda yazılabilir. Ayrıca bir sözlük değil defaultdict. Genel durumda objelerin sahip olması mantıklı değildir __dict__bir şekilde defaultdictbu nitelikleri olarak tüm yasal tanımlayıcıları sahip her nesneyi yapacak çünkü. Dolayısıyla, Python nesnelerinde __dict__.setdefault, yararlı olmadığı düşünülürse, onu tamamen silmenin dışında, herhangi bir değişiklikten vazgeçemem .


1
Ayrıntılı bir açıklama yapabilir misiniz - _dict .setdefault'u özellikle yararlı kılan nedir ?
Eli Bendersky

1
@Eli: Bence asıl nokta __dict__uygulama a dictdeğil, a değil defaultdict.
Katriel

1
Peki. setdefaultPython'da kalmayı umursamıyorum , ama şimdi neredeyse işe yaramaz olduğunu merak ediyor.
Eli Bendersky

@Eli: Katılıyorum. Bugün olmasaydı, bunun tanıtımı için yeterli nedenlerin olduğunu düşünmüyorum. Ancak zaten orada olmak, zaten kullanan tüm kodlar göz önüne alındığında, onu kaldırmak için tartışmak zor olurdu.
Muhammad Alkarouri

1
Savunma programlama altında dosya. setdefaultvar olan veya olmayan bir anahtar aracılığıyla bir dikte atadığınızı açıkça belirtir ve mevcut değilse, varsayılan bir değerle oluşturulmasını istersiniz: örneğin d.setdefault(key,[]).append(value). Programın başka bir yerinde alist=d[k]k'nin hesaplandığı yerde yaparsınız ve k d'de değilse bir istisna atılmasını istersiniz (bu, varsayılan bir karar gerektirebilir assert k in dveya hattaif not ( k in d): raise KeyError
nigel222 10:15

3

defaultdictOver dict( dict.setdefault) 'nin bir dezavantajı, bir defaultdictnesnenin EVERYTIME olmayan bir anahtarın yeni bir öğe oluşturmasıdır (örneğin ==, ile print). Ayrıca defaultdictsınıf genellikle sınıftan çok daha az yaygındır dict, IME'yi serileştirmek daha zordur.

PS IMO işlevleri | bir nesneyi mutasyona uğratmayacak yöntemler, bir nesneyi mutasyona uğratmamalıdır.


Her seferinde yeni bir nesne yaratması gerekmez. Bunun defaultdict(lambda l=[]: l)yerine kolayca yapabilirsiniz .
Artyer

6
@Artyer'in önerdiği şeyi asla yapmayın - değiştirilebilir varsayılanlar sizi ısıracaktır.
Brandon Humpert

2

Yararlılığını göstermek için bazı setdefault örnekleri:

"""
d = {}
# To add a key->value pair, do the following:
d.setdefault(key, []).append(value)

# To retrieve a list of the values for a key
list_of_values = d[key]

# To remove a key->value pair is still easy, if
# you don't mind leaving empty lists behind when
# the last value for a given key is removed:
d[key].remove(value)

# Despite the empty lists, it's still possible to 
# test for the existance of values easily:
if d.has_key(key) and d[key]:
    pass # d has some values for key

# Note: Each value can exist multiple times!
"""
e = {}
print e
e.setdefault('Cars', []).append('Toyota')
print e
e.setdefault('Motorcycles', []).append('Yamaha')
print e
e.setdefault('Airplanes', []).append('Boeing')
print e
e.setdefault('Cars', []).append('Honda')
print e
e.setdefault('Cars', []).append('BMW')
print e
e.setdefault('Cars', []).append('Toyota')
print e

# NOTE: now e['Cars'] == ['Toyota', 'Honda', 'BMW', 'Toyota']
e['Cars'].remove('Toyota')
print e
# NOTE: it's still true that ('Toyota' in e['Cars'])

2

Kabul edilen cevabı yeniden yazdım ve yeni başlayanlar için hazırladım.

#break it down and understand it intuitively.
new = {}
for (key, value) in data:
    if key not in new:
        new[key] = [] # this is core of setdefault equals to new.setdefault(key, [])
        new[key].append(value)
    else:
        new[key].append(value)


# easy with setdefault
new = {}
for (key, value) in data:
    group = new.setdefault(key, []) # it is new[key] = []
    group.append(value)



# even simpler with defaultdict
new = defaultdict(list)
for (key, value) in data:
    new[key].append(value) # all keys have a default value of empty list []

Ayrıca, yöntemleri başvuru olarak kategorize:

dict_methods_11 = {
            'views':['keys', 'values', 'items'],
            'add':['update','setdefault'],
            'remove':['pop', 'popitem','clear'],
            'retrieve':['get',],
            'copy':['copy','fromkeys'],}

1

Ben setdefault sık sık kullandığınızda, bu olsun, bir sözlükte bir varsayılan (!!!) ayarlama; biraz yaygın olarak os.environ sözlük:

# Set the venv dir if it isn't already overridden:
os.environ.setdefault('VENV_DIR', '/my/default/path')

Daha az özlü olarak, bu şöyle görünür:

# Set the venv dir if it isn't already overridden:
if 'VENV_DIR' not in os.environ:
    os.environ['VENV_DIR'] = '/my/default/path')

Ortaya çıkan değişkeni de kullanabileceğinizi belirtmek gerekir:

venv_dir = os.environ.setdefault('VENV_DIR', '/my/default/path')

Ancak bu, varsayılan kararların varlığından daha az gerekli.


1

Sanmıyorum başka bir kullanım durumu yukarıda bahsedildi. Bazen, nesnelerin birincil örneğinin önbellekte olduğu kimlikleriyle kimliklerinin önbelleğini saklarsınız ve eksik olduğunda önbelleği ayarlamak istersiniz.

return self.objects_by_id.setdefault(obj.id, obj)

Her seferinde nasıl obj elde ederseniz edin, her bir farklı kimlik için her zaman tek bir örnek tutmak istediğinizde bu yararlıdır. Örneğin, nesne öznitelikleri bellekte güncellendiğinde ve depolamaya kaydetme ertelendiğinde.


1

Çok önemli bir kullanım örneği, sadece karşılaştım: dict.setdefault() sadece tek bir kanonik nesne (eşit olan birden çok nesnenin aksine) istediğinizde çok iş parçacıklı kod için harika.

Örneğin, (Int)FlagPython 3.6.0'daki Enum'un bir hatası vardır : bir bileşik (Int)Flagüye için birden çok iş parçacığı yarışıyorsa, birden fazla iş parçacığı olabilir:

from enum import IntFlag, auto
import threading

class TestFlag(IntFlag):
    one = auto()
    two = auto()
    three = auto()
    four = auto()
    five = auto()
    six = auto()
    seven = auto()
    eight = auto()

    def __eq__(self, other):
        return self is other

    def __hash__(self):
        return hash(self.value)

seen = set()

class cycle_enum(threading.Thread):
    def run(self):
        for i in range(256):
            seen.add(TestFlag(i))

threads = []
for i in range(8):
    threads.append(cycle_enum())

for t in threads:
    t.start()

for t in threads:
    t.join()

len(seen)
# 272  (should be 256)

Çözüm, setdefault()hesaplanan kompozit üyeyi kaydetmenin son adımı olarak kullanmaktır - daha önce başka bir tane kaydedilmişse, yenisi yerine kullanılır ve benzersiz Enum üyelerini garanti eder.


0

[Düzenle] Çok yanlış! Setdefault her zaman long_computation'ı tetikler, Python istekli olur.

Tuttle'ın cevabına genişleyen. Benim için en iyi kullanım durumu önbellek mekanizmasıdır. Onun yerine:

if x not in memo:
   memo[x]=long_computation(x)
return memo[x]

hangi 3 satır ve 2 veya 3 arama tüketir, ben mutlu yazmak :

return memo.setdefault(x, long_computation(x))

İyi örnek. Hala 3 çizginin daha anlaşılır olduğunu düşünüyorum, ama belki de beynim settafault'u takdir etmek için büyüyecek.
Bob Stein

5
Bunlar eşdeğer değil. İlkinde long_computation(x), sadece eğer denir x not in memo. Halbuki ikincisinde long_computation(x)her zaman çağrılır. Yalnızca atama koşulludur, eşdeğer kod setdefaultşöyle görünür: v = long_computation(x)/ if x not in memo:/ memo[x] = v.
Dan D.


0

Farklı kullanım durumu setdefault(), önceden ayarlanmış bir anahtarın değerinin üzerine yazmak istemediğiniz durumdur . defaultdictüzerine yazarken setdefault(), değil. İç içe sözlükler için, yalnızca anahtar henüz ayarlanmadıysa bir varsayılan ayarlamak istediğiniz durum daha sıktır, çünkü mevcut alt sözlüğü kaldırmak istemezsiniz. Bu, kullandığınız zamandır setdefault().

İle örnek defaultdict:

>>> from collection import defaultdict()
>>> foo = defaultdict()
>>> foo['a'] = 4
>>> foo['a'] = 2
>>> print(foo)
defaultdict(None, {'a': 2})

setdefault üzerine yazmaz:

>>> bar = dict()
>>> bar.setdefault('a', 4)
>>> bar.setdefault('a', 2)
>>> print(bar)
{'a': 4}
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.