Python에서 in 연산자는 요소가 컬렉션에 포함되어 있는지를 정의합니다. 사용자 정의 객체의 경우 x in your_obj 구문을 지원하려면 메서드 __contains__를 구현해야 합니다. 이 메서드가 없으면 인터프리터는 __iter__ 또는 __getitem__을 사용하여 객체를 반복하려고 시도하지만, 그 동작과 효율성은 다를 수 있습니다.
예시:
class MyBag: def __init__(self, items): self.items = items def __contains__(self, value): return value in self.items bag = MyBag([1,2,3]) print(2 in bag) # True print(5 in bag) # False
만약 __iter__만 구현하거나 심지어 __getitem__만 구현하더라도 in은 작동하지만, 덜 효율적이거나 때로는 예상과 다르게 작동할 수 있습니다.
주의사항: 만약 컬렉션이 거대하고 검사 방식이 단순히 리스트 전체를 순회하는 방식을 사용한다면 성능 문제에 직면할 수 있습니다. 빠른 검사를 위해 예를 들어 집합을 사용할 수 있습니다.
in연산자의 올바른 작동을 위해 단지__iter__만 구현하는 것으로 충분한가요? 동작은 어떻게 바뀔까요?
답변:
__contains__가 없으면, Python은 __iter__ (있다면)를 사용하여 요소를 반복하려고 하거나 __getitem__을 사용하여 인덱스 0부터 시작하여 IndexError 예외가 발생할 때까지 시도합니다.예시:
class Weird: def __getitem__(self, idx): if idx < 3: return idx raise IndexError w = Weird() print(2 in w) # True print(5 in w) # False
이야기
한 프로젝트에서 사용자 정의 엔티티 저장 컨테이너는
__iter__만 재정의하고__contains__를 구현하는 것을 잊었습니다.in연산자는 큰 컬렉션에서 지연이 발생할 뿐만 아니라, 반복자가 StopIteration이 아닌 예외를 잘못 던질 때 신비한 오류로 인해 갑자기 실패하기 시작했습니다.
이야기
요소가 인덱스에 따라 "즉석에서" 계산되는 클래스에 대해 개발자는
__getitem__만 구현했습니다. 큰 x로x in obj를 검사하려고 시도했을 때 긴 루프와 메모리 부족 오류가 발생했습니다.in은 IndexError를 만날 때까지 모든 인덱스를 증가시키며 검사하기 때문에입니다.
이야기
한 프로젝트에서는
in을 위해__iter__만 사용하는 맞춤형 사전이 구현되었습니다. 이것은 100,000개의 키에 대해 검색이 밀리초가 아닌 몇 초가 걸리는 문제를 초래했습니다. 이는 표준 dict에서__contains__가 효율적으로 구현되어 있기 때문입니다.