Python dicts에서 'has_key ()'또는 'in'을 사용해야합니까?


910

더 나은 일이 궁금합니다.

d = {'a': 1, 'b': 2}
'a' in d
True

또는:

d = {'a': 1, 'b': 2}
d.has_key('a')
True

답변:


1286

in 확실히 더 pythonic입니다.

실제로 has_key()Python 3.x에서 제거되었습니다 .


3
부가로, 파이썬 3에서, d.values에서 >>> 1 () 시도, 대신 키의 가치의 존재를 확인하기
리자

217
그래도 피해야 할 한 가지 반 차례는 "some_dict.keys ()의 키가 아닌"key in some_dict "입니다. 둘 다 의미 상 동등하지만 성능 측면에서는 후자가 훨씬 느립니다 (O (n) 대 O (1)). 나는 사람들이 "in dict.keys ()"가 더 명확하고 더 좋다고 생각하는 것을 보았습니다.
Adam Parkin

2
@AdamParkin 내 답변에 댓글 증명 stackoverflow.com/a/41390975/117471
브루노 Bronosky을

8
@AdamParkin Python 3에서 keys()복사본이 아닌 사전에 대한 설정과 유사한 뷰이므로 x in d.keys()O (1)도 마찬가지 입니다. 아직도, x in d더 파이썬입니다.
Arthur Tacca

2
@AdamParkin 흥미 롭습니다. 나는 그것이 산술 연산 (해시 계산)을 수행하고 조회를 수행하는 x in d.keys()곳에서 메모리 할당을 완료하여 임시 객체를 구성하고 파괴해야 하기 때문이라고 생각합니다 x in d.keys(). 참고 d.keys()아직도 긴 정말 한이 아니라 10 배에 관한 것입니다. 나는 확인하지 않았지만 여전히 O (1) 만 확신합니다.
Arthur Tacca

253

in 우아함뿐만 아니라 (더 이상 사용되지 않는 ;-) 성능뿐만 아니라 다음과 같이 손을 쓰지 않습니다.

$ python -mtimeit -s'd=dict.fromkeys(range(99))' '12 in d'
10000000 loops, best of 3: 0.0983 usec per loop
$ python -mtimeit -s'd=dict.fromkeys(range(99))' 'd.has_key(12)'
1000000 loops, best of 3: 0.21 usec per loop

다음과 같은 관찰이 항상 사실 은 아니지만 , 일반적으로 파이썬에서는 더 빠른 솔루션이 더 우아하고 Pythonic 임을 알 수 있습니다 . 그 이유 -mtimeit는 아니다 - SO 도움이 단지 여기에 수백 나노초 저장 정보와이 -!)


4
감사합니다. "some_dict에서"가 실제로 O (1)보다 훨씬 쉬운 지 확인했습니다 (1999 년으로 99를 높이면 런타임이 거의 동일 함).
Adam Parkin

2
has_keyO (1) 인 것 같습니다.
dan-gph


42

사용 dict.has_key()하는 경우 (그리고 경우에만) 코드는 이전 2.3 이상 (때 파이썬 버전에서 실행 가능한 것이 요구된다 key in dict도입되었다).


1
2013 년의 WebSphere 업데이트는 Jython 2.1을 기본 스크립팅 언어로 사용합니다. 따라서 유감스럽게도 메모 한 지 5 년이 지난 후에도 여전히 유용한 정보입니다.
ArtOfWarfare

23

in실제로 성능을 저하시키는 한 가지 예가 있습니다.

당신이 사용하는 경우 in에만 구현하는 O에 (1) 컨테이너 __getitem__has_key()하지만,하지 __contains__(당신은 O (1)는 O (N) 검색으로 검색 바뀝니다 in통해 선형 검색을 다시 떨어진다 __getitem__).

수정은 분명히 사소한 것입니다.

def __contains__(self, x):
    return self.has_key(x)

6
이 답변은 게시되었을 때 적용 가능했지만 독자의 99.95 %가 안전하게 무시할 수 있습니다. 에서 가장 당신이 뭔가 작업을하는 경우 경우, 이것은 당신이 그것을 알 수 모호.
wizzwizz4

2
이것은 실제로 문제가되지 않습니다. has_key()이다 파이썬이 사전에 특정한 . in/ __contains__는 올바른 API입니다. 전체 스캔이 불가피한 컨테이너의 경우 어쨌든has_key() 메소드 가 없으며 O (1) 접근 방식이 있으면 유스 케이스에 따라 다르므로 개발자가 문제에 대한 올바른 데이터 유형을 선택합니다.
Martijn Pieters

15

has_key는 사전 방법이지만 in모든 컬렉션에서 작동하며 __contains__누락 된 in경우에도 다른 방법을 사용하여 컬렉션을 반복하여 찾을 수 있습니다.


1
또한 반복자 "xrange (90, 200) <=> 90 <= x <200"에서 작동
u0b34a0f6ae

1
… : 이것은 매우 나쁜 생각처럼 보입니다 : 2 대신 50 개의 작업
Clément

1
@ Clément Python 3에서는 실제로 객체를 in테스트하는 것이 매우 효율적 range입니다. xrange그래도 Python 2 에서 의 효율성에 대해서는 잘 모르겠습니다 . ;)
PM 2Ring

파이썬 3에는없는 @ Clément; 값이 범위 내에 있는지 여부 __contains__를 간단히 계산할 수 있습니다 .
Martijn Pieters

1
@AlexandreHuat 타이밍에는 range매번 새 인스턴스 를 생성하는 오버 헤드가 포함 됩니다. 기존 의 단일 인스턴스를 사용하면 "정수 범위의 정수"테스트가 타이밍에서 약 40 % 빠릅니다.
MisterMiyagi

14

dict.has_key () 솔루션은 더 이상 사용되지 않습니다. 'in'사용-숭고한 텍스트 편집기 3

여기서는 'ages'라는 사전의 예를 보았습니다.

ages = {}

# Add a couple of names to the dictionary
ages['Sue'] = 23

ages['Peter'] = 19

ages['Andrew'] = 78

ages['Karren'] = 45

# use of 'in' in if condition instead of function_name.has_key(key-name).
if 'Sue' in ages:

    print "Sue is in the dictionary. She is", ages['Sue'], "years old"

else:

    print "Sue is not in the dictionary"

6
맞지만 이미 답변을 받았지만 Stackoveflow에 오신 것을 환영합니다. 예를 들어 주셔서 감사합니다. 항상 답변을 확인하십시오!
igorgue

@ igorgue는 그녀에게 downvotes에 대해 확신하지 않습니다. 그녀의 대답은 이미 대답 한 것과 비슷할 수 있지만 그 예를 제시합니다. 그렇게 대답하기에 충분하지 않습니까?
Akshat Agarwal

14

Adam Parkin의 의견으로 Alex Martelli의 성능 테스트를 확장합니다 ...

$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 301, in main
    x = t.timeit(number)
  File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 178, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
    d.has_key(12)
AttributeError: 'dict' object has no attribute 'has_key'

$ python2.7 -mtimeit -s'd=dict.fromkeys(range(  99))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0872 usec per loop

$ python2.7 -mtimeit -s'd=dict.fromkeys(range(1999))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0858 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(  99))' '12 in d'
10000000 loops, best of 3: 0.031 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d'
10000000 loops, best of 3: 0.033 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(  99))' '12 in d.keys()'
10000000 loops, best of 3: 0.115 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d.keys()'
10000000 loops, best of 3: 0.117 usec per loop

훌륭한 통계, 때로는 암시적인 것이 명시 적 (적어도 효율성면에서)보다 낫습니다.
varun

@varun 감사합니다. 나는이 대답을 잊었다. 이런 종류의 테스트를 더 자주해야합니다. 나는 사람들 이 The Best Way ™ 에 대해 논하는 긴 글을 정기적으로 읽습니다 . 그러나 나는 이것이 증거 를 얻는 것이 얼마나 쉬운 지 거의 기억하지 못한다 .
Bruno Bronosky

0

이와 같은 것이 있다면 :

t.has_key(ew)

Python 3.X 이상에서 실행하려면 아래로 변경하십시오.

key = ew
if key not in t

6
아니요, 시험을 거꾸로했습니다. 값 참조가 사전의 키이기도 한 경우를 t.has_key(ew)반환 True합니다 ew. key not in t반환 True값이있는 경우 하지 사전에. 또한 key = ew별칭은 매우 중복됩니다. 올바른 철자는 if ew in t입니다. 8 년 전의 답변이 이미 말한 내용입니다.
Martijn Pieters
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.