指定されたキーが辞書にすでに存在するかどうかを確認します


2683

キーの値を更新する前に、キーが辞書に存在するかどうかをテストしたいと思いました。次のコードを書きました。

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

これは、このタスクを達成するための最良の方法ではないと思います。辞書のキーをテストするより良い方法はありますか?


31
dict.keys()ドキュメントdocs.python.org/2/library/stdtypes.html#dict.keysによると、呼び出しによりキーのリストが作成されますが、このパターンが翻訳のために真剣な実装で最適化されていなかった場合、私は驚くでしょうにif 'key1' in dict:
Evgeni Sergeev 2013

7
私はようやく私のPythonスクリプトの多くは:(とても遅い:)た理由が分かったので。私が使用してきたので、それのx in dict.keys()鍵をチェックする。そして、Javaでのキーを反復する通常の方法がされているため、それが起こったfor (Type k : dict.keySet())、この習慣が原因for k in dict.keys()にしよりも自然に感じますfor k in dict(それでもパフォーマンスの点でif k in dict.keys()は問題ないでしょうか)。しかし、キーのチェックも問題になり、問題になります...
Evgeni Sergeev

4
@EvgeniSergeev if k in dict_:はdict_のキーにkが存在するかどうかをテストするため、まだ必要ありませんdict_.keys()。(これは、dictの値のテストのように私に読んだので、私を噛みました。しかし、そうではありません。)
ToolmakerSteve

1
@ToolmakerSteveそうですが、必要がないだけでなく、良い習慣でもありません。
Evgeni Sergeev

26
「key in dict」を試してみてください
marcelosalloum 2014年

回答:


3372

inにキーが存在するかどうかをテストするための方法dictです。

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

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

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

デフォルトが必要な場合は、いつでも使用できますdict.get()

d = dict()

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

そして、キーのデフォルト値を常に確認したい場合は、次のようにdict.setdefault()繰り返し使用するかdefaultdictcollectionsモジュールから使用できます。

from collections import defaultdict

d = defaultdict(int)

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

しかし、一般的に、inキーワードはそれを行うための最良の方法です。


74
getとにかく辞書からアイテムを引き出すつもりなら、いつも使っています。アイテムを使用in て辞書から取り出す意味がありません。
Jason Baker、

75
私は完全に同意します。しかし、キーが存在するかどうかを知る必要があるだけの場合、またはキーが定義されている場合とデフォルトを使用している場合を区別する必要がある場合は、inそれを行うための最良の方法です。
クリスB.

5
この回答のリファレンスはpythonのドキュメントにあります
enkash '28年

30
0たとえば、キーが「False」に相当する場合、getは悪いテストです。これを難しい方法で学びました:/
Sebastien

4
キーの失敗数が十分に少ない場合、「try」-「except」が最速であるとは述べられていないため、これが完全な回答であることに同意できません。以下のこの回答を参照してください。stackoverflow.com
Craig Hicks

1547

キーを呼び出す必要はありません。

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

呼び出しキーが行うような線形検索を行うのではなく、辞書のハッシュを使用するので、それははるかに速くなります。


7
それは素晴らしい。内部的にはまだキーのリストをトラバースするだろうという印象を受けましたが、これはセットのメンバーシップをテストするように機能するようです。
Mohan Gulati、

51
@Mohan Gulati:ディクショナリは値にマップされたキーのハッシュテーブルであることを理解していますよね?ハッシュアルゴリズムはキーを整数に変換し、その整数を使用して、一致するハッシュテーブル内の場所を見つけます。en.wikipedia.org/wiki/Hash_table
hughdbrown、2009年

5
@Charles Addis、約50万個のキーを使用した経験から、 "key in dict.keys()"ではなく "key in dict"を書き込むと、少なくとも10倍のパフォーマンス向上が得られます。PEPとZenは、プロジェクトに悪影響を与える場合は無視する必要があるとも述べています。
ivan_bilan 2016年

11
ivan_bilan -私はちょうど半分の百万のキーでは、...これで私自身benchtestを走っif key in d1取っ0.17265701293945312秒。呼び出しif key in d1.keys()はかかりました0.23871088027954102-これはマイクロ最適化の古典的な定義です。0.07884883880615234秒の節約はパフォーマンスの向上にはなりません。
Charles Addis

11
@Eli自分のためだけに実行できるテストを作成しました。結果はあなたを驚かせるかもしれません。キーが50,000以下のディクショナリのkeys()場合、呼び出しを行わないことで、0.01秒の計算上の利点が得られます。約500,000のキーの場合、呼び出しkeys()を行わないと、0.1秒のメリットがあります。〜5,000,000キーの場合、呼び出していないkeys()0.4秒速いですが、5000万キーのCALLINGはkeys()3秒速いです!
Charles Addis

268

inキーワードを使用して、辞書にキーが存在するかどうかをテストできます。

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

変更する前にディクショナリ内のキーの存在を確認する一般的な用途は、値をデフォルトで初期化することです(たとえば、値がリストである場合など、追加できる空のリストがあることを確認したい場合)キーの最初の値を挿入するとき)。このような場合には、そのcollections.defaultdict()タイプに興味があるかもしれません。

古いコードではhas_key()、辞書のキーの存在を確認するための非推奨のメソッドであるのいくつかの使用法を見つけることもあります(key_name in dict_name代わりにを使用してください)。


2
共有したいのは(Python 2.7を使用して)dictsに重点を置いて書いたばかりの実行時間は363.235070で、「dict.keys()のキー」を使用していて、「keys( ) "
Ido_f 2015年

@Ido_fは、ベンチマークを投稿してください。私のベンチマークは3.5と2.7でほとんど違いがありません
Charles Addis

@Ido_f私はあなたのプログラムの何か他のものであったと思うが、実際にはそうではなかったkey in dict.keys()。このチェックを除くすべてのコードを削除してみて、結果を確認してください。
Charles Addis

101

これを短くすることができます:

if 'key1' in dict:
    ...

ただし、これはせいぜい美容上の改善です。なぜこれが最善の方法ではないと思いますか?


100
これは、多くの化粧品の改善よりも。このメソッドを使用してキーを見つける時間はO(1)ですが、キーを呼び出すとリストが生成され、O(n)になります。
Jason Baker、

5
O(1)は完全に正しくないようです。O(log n)のようなものではありませんか?
2015

12
これは、平均してO(1)であり、最悪の場合O(n)である単一のdictルックアップの複雑さです。.list()は常にO(n)になります。wiki.python.org/moin/TimeComplexity
Leonora Tindall

1
これにより、余分な割り当ても回避されます。(タイトなループをもう少し速くするために重要)
nurettin

56

承認された回答の提案された方法(10mループ)の実行速度に関する追加情報:

  • 'key' in mydict 経過時間1.07秒
  • mydict.get('key') 経過時間1.84秒
  • mydefaultdict['key'] 経過時間1.07秒

したがって、inまたはを使用することdefaultdictをお勧めしgetます。


6
getの1.84が1.07 * 2未満であることに完全に同意します;-P
Paul Rigor

54

setdefault代わりにこの方法を使用することをお勧めします。それはあなたが望むすべてを行うように聞こえます。

>>> 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
setdefaultOPの質問とは何が関係していますか?
hughdbrown

18
@hughdbrown「キーの値を更新する前に、キーが辞書に存在するかどうかをテストしたかったのです。」投稿には、本来の目的ではない何かに対する一連の応答を生成するコードが含まれている場合があります。最初の文で述べた目標を達成するために、投稿されたサンプルコードの代わりとなるものではありませんが、setdefaultが最も効果的な方法です。
David Berger、

5
これは、技術的に正しい答えを与えるだけでなく、OPの目標を満たすため、優れた答えです。参照:nedbatchelder.com/blog/201207/…–
Niels Bom

有益な答えの+1は、私に何かを教えてくれました。ただし、それが最良の解決策であるかどうかは、コーダーの意図に依存します。たとえば、「キーの値を更新する前」の意味。おそらく、存在しない場合は例外をスローするでしょう(==新しいキーを追加する権限がない)。多分それはカウントの辞書であり、彼は既存のカウントに1を追加します。その場合、 `d [key] = d.get(key、0)+ 1 'が最もクリーンなソリューションです(クリスが示すように、回答の後書かれた)。(将来の読者が異なるタスクを念頭に置いてここに来る場合に備えて、私はこれについて言及するだけです。)
ToolmakerSteve

1
@ToolmakerSteve True。ここでの問題は、OPの質問が十分に明確ではなかったことです。
Niels Bom

45

Pythonの辞書にはget( 'key'、default)メソッドがあります。したがって、キーがない場合のデフォルト値を設定できます。

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

33

EAFPの使用についてはどうですか(許可よりも許しを求める方が簡単です):

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

他のSO投稿を参照してください。

Pythonまたは

Pythonでのメンバーの存在の確認


12
キーが存在しない可能性が高い場合は、try / exceptの方が高価になる可能性があります。あなたが参照した投稿から:「[結果] 99%の時間結果に実際に反復可能な何かが含まれると期待する場合、私はtry / exceptアプローチを使用します。例外が本当に例外的である場合はより速くなります。結果がNoneの場合時間の50%以上の場合、ifを使用する方が良いでしょう。[...] [A] n ifステートメントのコストが常にかかる場合は、try / exceptブロックを設定するのはほぼ無料です。ただし、実際に例外が発生すると、コストははるかに高い。」stackoverflow.com/a/1835844/1094092
ビルリチャーズ2014


20

結果を得る方法は次のとおりです。

どちらが良いかは、3つの要素に依存します。

  1. 辞書は「通常はキーを持っている」か「通常はキーを持たない」か。
  2. if ... else ... elseif ... elseのような条件を使用するつもりですか?
  3. 辞書の大きさは?

続きを読む:http : //paltman.com/try-except-performance-in-python-a-simple-test/

「in」または「if」の代わりにtry / blockを使用:

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
良いですが、Python 3で実現する必要があります。私はでWebページのスクリプトを変換し2to3、キーがdictにある場合でも、with try構文がwith try構文より常に速いことを確認しました。
Jean Paul、

18

Python 2のみ:(およびPython 2.7はinすでにサポートしています)

あなたはhas_key()メソッドを使うことができます:

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

22
.has_key()廃止れましたin他の回答に示されているように使用する必要があります。
Brad Koch 2013年

12
ところで、私は読んでお勧めALLに既存の回答をOLDそれに答える前に、質問です。この答えは何も追加していません。なぜなら、09年のマイケルの答えにはすでに提案が存在していたからです。(ディスカッションに役立つものを追加する試みを思いとどまらせることを意味するのではありません。続けてください。)
ToolmakerSteve

16

クリスに追加したFYIだけです。B(最良の回答):

d = defaultdict(int)

同様に動作します。その理由は、(ディクショナリを構築するときに)舞台裏で何が行われるかをint()返すため、ドキュメントでは「ファクトリー関数」と呼ばれているためです。0defaultdict


2
カウントのディクショナリーを作成する場合は、カウンターを使用する必要があります(Python 2.7を想定)。何が起こっているのかがより明確になると思うので、defaultdict(lambda: 0)代わりに使用しdefaultdict(int)ました。引数なしで0呼び出す場合、読者は取得する必要はありませんint()。YMMV。
クリスB.14年

9

指定されたキーが辞書にすでに存在するかどうかを確認します

その方法を理解するには、まず、ディクショナリで呼び出すことができるメソッドを調べます。メソッドは次のとおりです。

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

キーがすでに存在するかどうかを確認する残忍な方法は、get()方法かもしれません:

d.get("key")

他の二つの興味深い方法items()keys()音があまりにも多くの仕事のが好きです。それではget()、私たちにとって適切な方法であるかどうかを調べてみましょう。私たちは私たちの口述を持っていますd

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

印刷すると、返されないキーが表示されますNone

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

我々は可能キーが存在するか何もしない場合の情報を取得するためにそれを使用します。しかし、単一のdictを作成する場合は、これを考慮してkey:Noneください。

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

get()一部の値が信頼できる場合、その方法を導くことは信頼できませんNone。この物語は、より幸せな結末を持つべきです。inコンパレータを使用する場合:

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

正しい結果が得られます。Pythonバイトコードを調べます。

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

これは、in比較演算子の信頼性が高いだけでなく、さらに高速であることを示していget()ます。


.get()default値の2番目の引数を持つことができますkey:None。これは、の問題を処理するために使用できます。例: d.get("key", False)
Alex

.get()最速の方法です。別のオプションは、try/ exceptブロックで割り当てることです
HCLivess

7

Python辞書にはと呼ばれるメソッドがあり__contains__ます。ディクショナリにキーがある場合、このメソッドはTrueを返します。それ以外の場合はFalseを返します。

 >>> 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__直接呼び出すことは非常に悪い習慣です。それを行う正しい方法は、関数を呼び出すin演算子である演算子を使用containment checkする__contains__ことです。
user1767754 2017年

@ user1767754使用していfoo = x['foo'] if x.__contains__('foo') else 'bar'ます。inこの式の一部として演算子をどのように使用するのでしょうか?
donrondadon

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

5

ブール演算子を使用してキーが存在するかどうかを確認するもう1つの方法を共有します。

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

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

これは戻ります

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

説明

まず、あなたはPythonで、知っておくべき0Noneまたはゼロの長さを持つオブジェクトはに評価しますFalse。それ以外はすべてに評価されTrueます。ブール演算は左から右に評価され、TrueまたはFalseではなくオペランドを返します。

例を見てみましょう:

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

はに'Some string'評価されるTrueため、残りのorは評価されず、ゼロ除算エラーは発生しません。

ただし、スイッチを切り替えると、1/0最初に評価され、例外が発生します。

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

これは、キーが存在するかどうかを確認するためのパターンに使用できます。

(k in d and 'blah')

同じことをする

if k in d:
    'blah'
else:
    False

これは、キーが存在する場合はすでに正しい結果を返しますが、存在しない場合は 'boo'を出力します。したがって、結果とorそれを'boo'

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

1

forループを使用して辞書を反復処理し、辞書で検索するキーの名前を取得できます。その後、if条件が存在するかどうかを確認します。

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')

このため、出力があるので、コードの上にチェックit is existし、not exist
system123456

線形検索を実行するために、なぜ辞書を使用するのですか?
ジャン=フランソワ・ファーブル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.