주어진 키가 사전에 이미 존재하는지 확인


2683

키 값을 업데이트하기 전에 사전에 키가 있는지 테스트하고 싶었습니다. 다음 코드를 작성했습니다.

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

나는 이것이이 작업을 수행하는 가장 좋은 방법은 아니라고 생각합니다. 사전에서 키를 테스트하는 더 좋은 방법이 있습니까?


31
docs.python.org/2/library/stdtypes.html#dict.keysdict.keys() 문서에 따르면 호출 하면 키 목록이 생성 되지만 심각한 구현 에서이 패턴이 번역에 최적화되지 않은 경우 놀랍습니다. 에 . if 'key1' in dict:
Evgeni Sergeev

7
나는 결국 내 파이썬 스크립트의 많은 :( 느린 :) 있었다 이유를 발견 그래서. 내가 사용하고 있기 때문의 x in dict.keys()키를 확인하기 위해. 그리고 자바에서 키를 반복하는 일반적인 방법이 있기 때문에 그 일이 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_의 KEYS에 k가 있는지 테스트하므로 여전히 필요하지 않습니다 dict_.keys(). (이것은 dict 의 가치 에 대한 테스트처럼 나에게 읽었을 때 나를 조금만 먹었다. 그러나 그렇지 않다.)
ToolmakerSteve

1
@ToolmakerSteve 그렇습니다.하지만 꼭 필요한 것은 아니며 좋은 습관이 아닙니다.
Evgeni Sergeev

26
"key in dict"시도
marcelosalloum

답변:


3370

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()반복적으로 또는 모듈 defaultdict에서 사용할 수 있습니다 collections.

from collections import defaultdict

d = defaultdict(int)

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

그러나 일반적으로 in키워드가 가장 좋은 방법입니다.


74
get어쨌든 사전에서 항목을 꺼내려고 할 때 일반적으로 사용 합니다. 사전에서 항목 을 사용 in 하고 꺼내는 데 의미가 없습니다 .
Jason Baker

75
난 전적으로 동의합니다. 그러나 키가 존재하는지 알 필요가 있거나 키가 정의 된 경우와 기본값을 사용하는 경우를 구별해야하는 경우 in가장 좋은 방법입니다.
Chris B.

5
이 답변에 대한 참조 는 python docs
enkash

30
0예를 들어 키가 "False"와 같은 경우 get은 잘못된 테스트 입니다. 이 어려운 방법을 배웠습니다 : /
Sebastien

4
키 실패 횟수가 충분히 적을 때 'try'- 'except'가 가장 빠를 것이라고 언급하지 않았 으므로이 완전한 대답에 동의 할 수는 없습니다.
Craig Hicks

1546

키를 호출 할 필요가 없습니다.

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

호출 키가 수행하는 선형 검색을 수행하는 대신 사전의 해싱을 사용하므로 훨씬 빠릅니다 .


7
그거 좋다. 내부적으로 여전히 키 목록을 탐색한다는 인상을 받았지만 세트에서 멤버쉽을 테스트하는 것과 더 비슷하게 작동합니다.
Mohan Gulati

51
@Mohan Gulati : 사전은 값에 매핑 된 키의 해시 테이블이라는 것을 알고 있습니까? 해싱 알고리즘은 키를 정수로 변환하고 정수는 해시 테이블에서 일치하는 위치를 찾는 데 사용됩니다. en.wikipedia.org/wiki/Hash_table
hughdbrown

5
@Charles Addis는 약 50 만 개의 키를 사용한 경험에서 "key in dict.keys ()"대신 "key in dict"를 작성할 때 성능이 10 배 이상 향상되었습니다. PEP와 Zen은 또한 프로젝트에 좋지 않은 경우 무시해야한다고 말합니다.
ivan_bilan 2016 년

11
ivan_bilan-방금 이것에 대해 나 자신의 벤치 테스트를 실행했습니다 ... 50 만 키에 몇 초가 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 초 빠르지 만 50,000,000 키의 부름은 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
(파이썬 2.7을 사용하여) 방금 dicts를 기반으로 방금 작성한 것의 실행 시간은 "key in dict.keys ()"를 사용하여 363.235070이었고 "keys ( ) "
Ido_f

@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)와 같지 않습니까?
스펙트럼

12
단일 dict 조회의 복잡성으로 평균 O (1) 및 최악의 O (n)입니다. .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
get1.84s가 <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 '이 가장 깨끗한 솔루션입니다 (Chris가 대답 한 것처럼) 작성되었습니다). (나는 미래의 독자들이 여기에 와서 다른 과제를 염두
ToolmakerSteve

1
@ToolmakerSteve True. 여기서 문제는 OP의 질문이 명확하지 않다는 것입니다.
Niels Bom

45

파이썬의 사전에는 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 게시물보기 :

파이썬의 경우 대 시도를 사용 하거나

파이썬에서 멤버 존재 확인


12
키가 종종 존재하지 않을 경우 시도 / 제외가 더 비쌀 수 있습니다. "[I] f 시간 결과의 99 %에 실제로 반복 가능한 내용이 포함될 것으로 예상합니다. try / except 접근 방식을 사용하겠습니다. 예외가 실제로 예외 일 경우 더 빠릅니다. 결과가 None 인 경우 [...] [A] n if 문이 항상 비용이 든다면 try / except 블록을 설정하는 것이 거의 자유롭지 만 실제로 예외가 발생하면 비용이 훨씬 더 높습니다. " stackoverflow.com/a/1835844/1094092
billrichards 2014 년

28

삼항 연산자 사용 :

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

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
파이썬 3에서는 좋았지 만 실현해야합니다. 웹 페이지의 스크립트를로 변환 2to3했으며 키가 dict에있는 경우에도 try try 구문이 with try 구문보다 항상 빠릅니다.
Jean Paul

18

파이썬 2 만 : (그리고 파이썬 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

12
BTW, 나는 OLD 질문에 대한 기존의 모든 답변을 읽기 전에 읽는 것이 좋습니다 . 이 답변은 마이클의 답변에 이미 '09 년부터 제안이 있었기 때문에 아무것도 추가하지 않았습니다. (나는 토론에 유용한 것을 추가하려는 시도를 자제하려는 것이 아닙니다. 계속 노력하십시오.)
ToolmakerSteve

16

크리스에 덧붙이는 것만으로 B (최고의 답변) :

d = defaultdict(int)

잘 작동합니다. 이유는 호출하는 것입니다 int()반환하는 0것입니다있는 defaultdict"공장 기능"이 문서에 따라서, (사전을 구성 할 때) 무대 뒤에서 않는 이름입니다.


2
카운트 사전을 만드는 경우 카운터 를 사용해야합니다 (Python 2.7 가정). 그리고 나는 무슨 일이 더 명확하다고 생각하기 때문에 defaultdict(lambda: 0)대신에 사용 defaultdict(int)했습니다. 당신은 인수없이 0전화 하면 독자는 당신이 얻을 알 필요가 없습니다 int(). YMMV.
Chris B.

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

올바른 결과를 얻습니다. 파이썬 바이트 코드를 살펴볼 수 있습니다 :

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()defaultvalue에 대한 두 번째 인수를 가질 수 있습니다.이 인수는 where 문제를 처리하는 데 사용될 수 있습니다 key:None. 예 : d.get("key", False)
Alex

.get()가장 빠른 방법입니다. 또 다른 옵션은 try/ except블록 에 할당하는 것입니다
HCLivess

7

파이썬 사전에는이라는 메소드가 __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

@ 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

부울 연산자를 사용하여 키가 있는지 확인하는 또 다른 방법을 공유합니다.

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

설명

첫째로 당신은 파이썬에서 것을 알아야한다 0, None또는 제로 길이 개체로 평가 False. 다른 모든 것은로 평가됩니다 True. 부울 연산은 왼쪽에서 오른쪽으로 평가되며 True 또는 False가 아닌 피연산자를 반환합니다.

예를 보자.

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

'Some string'평가 되기 때문에 True나머지는 or평가되지 않으며 0으로 나누기 오류가 발생하지 않습니다.

그러나 우리가 전환하면 순서 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 existnot exist
같으

선형 검색을 수행하는 경우 사전을 사용하는 이유는 무엇입니까?
Jean-François Fabre
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.