Belirli bir anahtarın sözlükte zaten mevcut olup olmadığını kontrol edin


2683

Anahtarın değerini güncellemeden önce bir anahtarın sözlükte olup olmadığını test etmek istedim. Aşağıdaki kodu yazdım:

if 'key1' in dict.keys():
  print "blah"
else:
  print "boo"

Bence bu, bu görevi yerine getirmenin en iyi yolu değil. Sözlükteki bir anahtarı test etmenin daha iyi bir yolu var mı?


31
Arama dict.keys(), docs.python.org/2/library/stdtypes.html#dict.keys belgelerine göre bir anahtar listesi oluşturur, ancak bu modelin ciddi bir uygulamada çeviri için optimize edilmemesi durumunda şaşırırdım için if 'key1' in dict:.
Evgeni Sergeev

7
Sonunda benim Python komut birçok :( kadar yavaş :) vardı neden öğrendim Yani. Ben kullanıyorum da ondan x in dict.keys()tuşları kontrol etmek için. Ve Java anahtarları üzerinde yineleme için her zamanki gibi çünkü bu oldu for (Type k : dict.keySet()), bu alışkanlığı neden for k in dict.keys()için daha doğal hissediyorum for k in dict(bu hala performans açısından iyi olmalı?), ama sonra tuşları kontrol etmek if k in dict.keys()de olur , bu bir sorun ...
Evgeni Sergeev

4
@EvgeniSergeev, dict_'in KEYS'inde if k in dict_:k olup olmadığını test eder, bu yüzden hala ihtiyacınız yoktur dict_.keys(). (Bu, beni dikte bir değer için yaptığı test gibi okuduğu için ısırdı . Ama değil.)
ToolmakerSteve

1
@ToolmakerSteve Doğru, ama sadece ona ihtiyacınız değil, iyi bir uygulama değil.
Evgeni Sergeev

26
"Key in dict" i deneyin
marcelosalloum

Yanıtlar:


3370

ina tuşunun varlığını test etmenin amaçlanan yoludur dict.

d = {"key1": 10, "key2": 23}

if "key1" in d:
    print("this will execute")

if "nonexistent key" in d:
    print("this will not")

Bir varsayılan istiyorsanız, her zaman aşağıdakileri kullanabilirsiniz dict.get():

d = dict()

for i in range(100):
    key = i % 10
    d[key] = d.get(key, 0) + 1

ve her zaman birini kullanabilirsiniz herhangi anahtarı için varsayılan bir değer sağlamak istiyorsa dict.setdefault()mükerrer veya defaultdictgelen collectionsmodül, şöyle:

from collections import defaultdict

d = defaultdict(int)

for i in range(100):
    d[i % 10] += 1

ancak genel olarak, inanahtar kelime bunu yapmanın en iyi yoludur.


74
Genellikle sadece getöğeyi sözlükten çekecek olursam kullanırım . Kullanarak anlamı yok in ve sözlüğe dışına öğeyi çekerek.
Jason Baker

75
Tamamen katılıyorum. Ancak yalnızca bir anahtarın var olup olmadığını bilmeniz gerekiyorsa veya anahtarın tanımlandığı bir durum ile varsayılanı kullandığınız bir durum arasında ayrım yapmanız gerekiyorsa in, bunu yapmanın en iyi yolu budur.
Chris

5
Bu cevap için referans python belgelerinde
enkash

30
0Örneğin , anahtar "False" ile eşdeğerse get kötü bir testtir . Bunu zor yoldan öğrendim: /
Sebastien

4
Anahtar başarısız sayısı yeterince az olduğunda 'denemek' - 'dışında' en hızlı olacağından bahsetmediği için bu tam bir cevap olduğunu kabul edemem. Aşağıdaki cevaba bakınız: stackoverflow.com/a/1602945/4376643
Craig Hicks

1546

Anahtarları aramak zorunda değilsiniz:

if 'key1' in dict:
  print("blah")
else:
  print("boo")

Bu, arama tuşlarının yapacağı doğrusal bir arama yapmak yerine sözlüğün hashini kullandığından çok daha hızlı olacaktır.


7
Bu harika. İçeride hala anahtar listesini geçeceği izlenimi altındaydım, ancak bunun bir sette üyeliği test etmek gibi çalıştığını görüyorum.
Mohan Gulati

51
@Mohan Gulati: Bir sözlüğün değerlerle eşlenmiş bir anahtarlar hashtable olduğunu anlıyor musunuz? Bir karma algoritması anahtarı bir tamsayıya dönüştürür ve tamsayı karma tablosunda eşleşen bir konumu bulmak için kullanılır. en.wikipedia.org/wiki/Hash_table
hughdbrown

5
@Charles Addis, yaklaşık yarım milyon anahtarla çalışma deneyiminden "dict.keys ()" yerine "dikte anahtar" yazarken en az 10 kat performans artışı elde edersiniz. PEP ve Zen ayrıca projeniz için kötü olmaları durumunda bunları görmezden gelmeniz gerektiğini belirtir.
ivan_bilan

11
ivan_bilan - Bu konuda kendi testimi yaptım ... Yarım milyon anahtarda saniyeler if key in d1sürdü 0.17265701293945312. Arama if key in d1.keys()geldi 0.23871088027954102- bu bir mikro optimizasyonun klasik tanımıdır. 0.07884883880615234Saniye kazanmak bir performans artışı değildir.
Charles Addis

11
@Eli Sadece senin için bir test hazırladım. Sonuçlar sizi şaşırtabilir. ~ 50.000 tuşlu dikte için, arama keys()yapmamanız size 0,01 ikinci hesaplama avantajı sağlar. ~ 500.000 anahtar için, çağırmamak keys()size .1 ikinci avantaj sağlar. ~ 5.000.000 anahtar için, arama yapmamak keys().4 saniye daha hızlıdır, ancak 50.000.000 anahtar için ARAMA keys()3 SANAT DAHA HIZLI!
Charles Addis

268

Sen kullanarak, sözlükte bir anahtarın varlığını test edebilirsiniz içinde anahtar kelime:

d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False

Sözlükte bir anahtarın varlığını değiştirmeden önce yaygın olarak kullanılan bir değer, değeri varsayılan olarak başlatmaktır (örneğin, değerleriniz listeler ise ve ekleyebileceğiniz boş bir liste olduğundan emin olmak istiyorsanız) bir anahtarın ilk değerini girerken). Bu gibi durumlarda collections.defaultdict(), ilgilendiğiniz türü bulabilirsiniz .

Eski kodda, has_key()sözlüklerdeki anahtarların varlığını kontrol etmek için kullanımdan kaldırılmış bir yöntemden bazı kullanımlar da bulabilirsiniz (sadece key_name in dict_namebunun yerine kullanın).


2
Paylaşmak istedim (Python 2.7 kullanarak) az önce yazdığım bir şeyin çalışma süresinin, diktelere dayalı olarak, "key in dict.keys ()" kullanarak 363.235070 olduğunu ve yalnızca ) "
Ido_f

@Ido_f, karşılaştırmalı değerlendirmelerinizi gönderin, çünkü karşılaştırmalı değerlendirmelerim 3.5 ve 2.7'de neredeyse hiçbir fark yok
Charles Addis

@Ido_f Programınızda başka bir şey olduğunu sanıyorum, ama aslında değil key in dict.keys(). Bu kontrol dışındaki tüm kodları kaldırmayı deneyin ve sonucunuzun ne olduğunu görün.
Charles Addis

101

Bunu kısaltabilirsiniz:

if 'key1' in dict:
    ...

Bununla birlikte, bu en iyi ihtimalle kozmetik bir gelişmedir. Neden bunun en iyi yol olmadığını düşünüyorsun?


100
Bu kozmetik bir gelişmeden çok daha fazlasıdır. Bu yöntemi kullanarak bir anahtar bulma süresi O (1) iken, çağrı tuşları bir liste oluşturur ve O (n) olur.
Jason Baker

5
O (1) pek doğru görünmüyor. Bunun O (log n) gibi bir şey olmadığından emin misiniz?
spektrumlar

12
Ortalama bir O (1) ve en kötü O (n) olan tek bir dikte aramasının karmaşıklığıdır. .list () her zaman O (n) olur. wiki.python.org/moin/TimeComplexity
Leonora Tindall

1
bu da fazladan bir tahsisi önler. (sıkı döngüler biraz daha hızlı yapmak için önemlidir)
nurettin

56

Kabul edilen yanıtlayıcının önerdiği yöntemlerin (10m döngüler) hızlı yürütülmesi hakkında ek bilgi için:

  • 'key' in mydict geçen süre 1.07 sn
  • mydict.get('key') geçen süre 1.84 sn
  • mydefaultdict['key'] geçen süre 1.07 sn

Bu nedenle inveya defaultdictkullanılması önerilir get.


6
get'nin 1.84'lerinin <1.07 * 2; --P
Paul Rigor

54

Bunun setdefaultyerine yöntemi kullanmanızı tavsiye ederim . Kulağa istediğin her şeyi yapacak gibi geliyor.

>>> d = {'foo':'bar'}
>>> q = d.setdefault('foo','baz') #Do not override the existing key
>>> print q #The value takes what was originally in the dictionary
bar
>>> print d
{'foo': 'bar'}
>>> r = d.setdefault('baz',18) #baz was never in the dictionary
>>> print r #Now r has the value supplied above
18
>>> print d #The dictionary's been updated
{'foo': 'bar', 'baz': 18}

9
Ne gelmez setdefaultOP'ın soruyla ilgisi var?
hughdbrown

18
@hughdbrown "Anahtarın değerini güncellemeden önce sözlükte bir anahtar olup olmadığını test etmek istedim." Bazen yayınlar, orijinal hedef olmayan bir şeye yanıt telaşı üreten kod içerir. İlk cümlede belirtilen hedefe ulaşmak için, gönderilen örnek kodun yerine bir yedek olmamasına rağmen setdefault en etkili yöntemdir.
David Berger

5
Bu üstün yanıttır, çünkü teknik olarak doğru cevabı vermek yerine OP'nin hedefini karşılar. Bakınız: nedbatchelder.com/blog/201207/…
Niels Bom

Bana bir şeyler öğreten bilgilendirici bir cevap için +1. Ancak, bunun en iyi çözüm olup olmadığı kodlayıcının aklında ne olduğuna bağlıdır; örneğin "anahtarın değerini güncellemeden önce" nin anlamı. Belki mevcut değilse bir istisna atacaktır (== yeni anahtar ekleme izni yok). Belki bir sayım sözlüğüdür ve mevcut sayıya 1 ekleyecektir, bu durumda `d [key] = d.get (anahtar, 0) + 1 'en temiz çözümdür (Chris'in gösterdiği gibi, cevabınızdan sonra) yazılmıştı). (Gelecekte okuyucular buraya gelince farklı görevler düşünülerek bundan bahsetmekten rahatsız oluyorum.)
ToolmakerSteve

1
@ToolmakerSteve Doğru. Buradaki sorun OP'nin sorusunun yeterince açık olmamasıydı.
Niels Bom

45

Python'daki sözlük bir get ('key', default) yöntemine sahiptir. Böylece, anahtar olmaması durumunda varsayılan bir değer ayarlayabilirsiniz.

values = {...}
myValue = values.get('Key', None)

33

EAFP'yi kullanmaya ne dersiniz (affetme izni istemekten daha kolaydır):

try:
   blah = dict["mykey"]
   # key exists in dict
except KeyError:
   # key doesn't exist in dict

Diğer SO yayınlarına bakın:

Python'da try vs if kullanma veya

Python'da üye varlığını kontrol etme


12
Anahtarın genellikle mevcut olmaması durumunda, deneme / hariç tutma daha pahalı olabilir. Referans verdiğiniz gönderiden: "[I] f zaman sonucunun% 99'unun gerçekten yinelenebilir bir şey içereceğini umuyorsunuz, try / hariç yaklaşımını kullanırdım. İstisnalar gerçekten istisnai ise daha hızlı olacaktır. zamanın% 50'sinden fazla, eğer if kullanmak muhtemelen daha iyidir. [...] [A] n deyimi her zaman size mal oluyorsa, bir try / hariç blok ayarlamak neredeyse ücretsizdir.Ancak bir İstisna meydana geldiğinde, maliyeti çok daha yüksek. " stackoverflow.com/a/1835844/1094092
billrichards

28

Üçlü operatör kullanma:

message = "blah" if 'key1' in dict else "booh"
print(message)

20

Sonuçları elde etmenin yolları:

Hangisi daha iyi 3 şeye bağlıdır:

  1. Sözlükte 'normalde anahtar var' veya 'normalde anahtar yok'.
  2. İf ... else ... elseif ... else gibi koşulları kullanmayı düşünüyor musunuz?
  3. Sözlük ne kadar büyük?

Daha Fazla Oku: http://paltman.com/try-except-performance-in-python-a-simple-test/

'İn' veya 'if' yerine try / block kullanımı:

try:
    my_dict_of_items[key_i_want_to_check]
except KeyError:
    # Do the operation you wanted to do for "key not present in dict".
else:
    # Do the operation you wanted to do with "key present in dict."

2
İyi ama python 3 için gerçekleştirilmesi gerekir. Ben web sayfasının komut dosyası ile dönüştürdüm 2to3ve anahtar sözlüğü söz konusu olduğunda bile try sözdizimi ile try sözdizimi her zaman daha hızlı olduğunu gördüm.
Jean Paul

18

Yalnızca Python 2: (ve python 2.7 desteği in zaten )

has_key () yöntemini kullanabilirsiniz:

if dict.has_key('xyz')==1:
    #update the value for the key
else:
    pass

22
.has_key()edilmiş kaldırıldı ; indiğer cevaplarda gösterildiği gibi kullanmalısınız .
Brad Koch

12
BTW, cevaplamadan önce ESKİ bir soruya TÜM mevcut cevapları okumanızı tavsiye ederim . Bu cevap hiçbir şey eklemedi, çünkü öneri Michael'ın cevabında '09'dan beri vardı. (Tartışmaya faydalı bir şey ekleme girişiminden vazgeçmek istemiyorum.
Denemeye

16

Chris'e bir FYI ekliyor. B (en iyi cevap):

d = defaultdict(int)

Ayrıca çalışır; Bunun sebebi, (sözlük oluştururken) perde arkasında olan şeyleri int()döndürmek , dolayısıyla dokümantasyondaki "Fabrika İşlevi" ismidir.0defaultdict


2
Bir sayım sözlüğü oluşturuyorsanız, Sayacı (Python 2.7 varsayarak) kullanıyor olmalısınız . Bunun defaultdict(lambda: 0)yerine kullandım defaultdict(int)çünkü neler olduğunu daha net düşünüyorum; argüman olmadan 0ararsanız , okuyucunun aldığını bilmesine gerek yoktur int(). YMMV.
Chris B.

9

Belirli bir anahtarın sözlükte zaten mevcut olup olmadığını kontrol edin

Bunun nasıl yapılacağı hakkında fikir edinmek için önce sözlükte hangi yöntemleri arayabileceğimizi denetleriz. İşte yöntemler:

d={'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}

Python Dictionary clear()       Removes all Items
Python Dictionary copy()        Returns Shallow Copy of a Dictionary
Python Dictionary fromkeys()    Creates dictionary from given sequence
Python Dictionary get()         Returns Value of The Key
Python Dictionary items()       Returns view of dictionary (key, value) pair
Python Dictionary keys()        Returns View Object of All Keys
Python Dictionary pop()         Removes and returns element having given key
Python Dictionary popitem()     Returns & Removes Element From Dictionary
Python Dictionary setdefault()  Inserts Key With a Value if Key is not Present
Python Dictionary update()      Updates the Dictionary 
Python Dictionary values()      Returns view of all values in dictionary

Anahtarın zaten var olup olmadığını kontrol etmek için acımasız yöntem yöntem olabilir get():

d.get("key")

Diğer iki ilginç yöntem items()ve keys()ses çok fazla iş gibi. Öyleyse get()bizim için doğru yöntem olup olmadığını inceleyelim . Bizim sözümüz d:

d= {'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}

Yazdırma, sahip olmadığımız anahtarı gösterir None:

print(d.get('key')) #None
print(d.get('clear')) #0
print(d.get('copy')) #1

Biz olabilir anahtar mevcut veya hiç ise bilgi almak için kullanabilirsiniz. Ama tek bir diksiyon oluşturursak bunu düşünün key:None:

d= {'key':None}
print(d.get('key')) #None
print(d.get('key2')) #None

get()Bazı değerlerin olması durumunda bu yönteme öncülük etmek güvenilir değildir None. Bu hikayenin daha mutlu bir sonu olmalı. inKarşılaştırıcıyı kullanırsak :

print('key' in d) #True
print('key2' in d) #False

Doğru sonuçları alıyoruz. Python bayt kodunu inceleyebiliriz:

import dis
dis.dis("'key' in d")
#   1           0 LOAD_CONST               0 ('key')
#               2 LOAD_NAME                0 (d)
#               4 COMPARE_OP               6 (in)
#               6 RETURN_VALUE

dis.dis("d.get('key2')")
#   1           0 LOAD_NAME                0 (d)
#               2 LOAD_METHOD              1 (get)
#               4 LOAD_CONST               0 ('key2')
#               6 CALL_METHOD              1
#               8 RETURN_VALUE

Bu inkarşılaştırma operatörün sadece daha güvenilir değil, daha hızlı olduğunu gösterir get().


.get()defaultdeğer için ikinci bir argüman olabilir , bu da nerede sorunu ele almak için kullanılabilir key:None. örnek: d.get("key", False)
Alex

.get()en hızlı yoldur. Başka bir seçenek bir try/ exceptblokta
atamaktır

7

Python sözlüğü denilen yönteme sahiptir __contains__. Sözlükte başka bir anahtar varsa bu yöntem True değerini False döndürür.

 >>> temp = {}

 >>> help(temp.__contains__)

Help on built-in function __contains__:

__contains__(key, /) method of builtins.dict instance
    True if D has a key k, else False.

2
__contains__Doğrudan aramak çok kötü bir uygulamadır . Bunu yapmanın doğru yolu , işlevi çağıran inoperatörü kullanmaktır . containment check__contains__
user1767754

@ user1767754 kullanıyorum foo = x['foo'] if x.__contains__('foo') else 'bar'. inOperatörün bu ifadenin bir parçası olarak nasıl kullanılabileceği hakkında bir fikrin var mı?
donrondadon

1
foo = x['foo'] if 'foo' in x else 'bar'
Ray Wu

5

Boole işleçlerini kullanarak bir anahtarın var olup olmadığını denetlemenin bir yolunu daha paylaşma.

d = {'a': 1, 'b':2}
keys = 'abcd'

for k in keys:
    x = (k in d and 'blah') or 'boo'
    print(x) 

Bu geri döner

>>> blah
>>> blah
>>> boo
>>> boo

açıklama

Önce Python, bilmelidir ki 0, Noneya sıfır uzunlukta nesneleri için değerlendirmek False. Diğer her şey değerlendirilir True. Boole işlemleri soldan sağa değerlendirilir ve işleneni Doğru veya Yanlış olarak döndürmez.

Bir örnek görelim:

>>> 'Some string' or 1/0 
'Some string'
>>>

Yana 'Some string'olarak değerlendirilirse True, geri kalanı ordeğerlendirilmez ve yükseltilmiş sıfır hata bir ayırım yoktur.

Ancak geçiş yaparsak, sipariş 1/0önce değerlendirilir ve bir istisna oluşturur:

>>> 1/0 or 'Some string'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 

Bunu, bir anahtar olup olmadığını kontrol etmek için kalıp olarak kullanabiliriz.

(k in d and 'blah')

aynı şeyi yapar

if k in d:
    'blah'
else:
    False

Bu, anahtar varsa doğru sonucu döndürür, ancak yoksa 'boo' yazmasını isteriz. Demek ki sonuç almak ve orbunu'boo'

>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>> 

1

forSözlük üzerinde yineleme yapmak ve sözlükte bulmak istediğiniz anahtarın adını almak için loop'u kullanabilirsiniz , bundan sonra ifdurumun kullanılıp kullanılmadığını kontrol edin :

dic = {'first' : 12, 'second' : 123}
for each in dic:
    if each == 'second': 
        print('the key exists and the corresponding value can be updated in the dictionary')

kod çıktısını kontrol edin, çünkü bunun çıktısı it is existvenot exist
system123456

doğrusal arama yapmak için neden sözlük kullanıyorsunuz?
Jean-François Fabre
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.