질문 배경:
시퀀스는 파이썬에서 가장 오래되고 기본적인 개념 중 하나입니다. 전통적인 예로는 리스트(list), 문자열(str), 튜플(tuple)이 있습니다. 시퀀스와 상호작용하기 위해 특별한 프로토콜이 정의되어 있으며, __getitem__ 및 __len__ 메서드를 구현해야 합니다. 이것은 객체가 "시퀀스처럼 동작하게" 하여 인덱싱, 슬라이스, 루프 작업 및 일부 표준 함수들을 지원할 수 있게 합니다.
문제:
이 메서드를 제대로 구현하지 않으면 사용자 정의 클래스는 인덱싱, for 루프, len()와 같은 함수와 함께 작동할 수 없습니다. 초보 개발자들이 종종 단 하나의 메서드만 구현하거나 예외 처리를 고려하지 않거나 슬라이스(slicing) 지원을 구현하지 않아 비정상적이거나 예기치 않은 동작을 발생시킵니다.
해결책:
인덱싱 및 슬라이스 지원을 위해 __getitem__(self, key) 메서드를 구현하고, len() 함수와 올바른 반복 가능성을 위해 __len__(self) 메서드를 구현해야 합니다. 슬라이스를 지원하기 위해서는 __getitem__에서 key의 유형을 구분하고 슬라이스 객체를 올바르게 처리해야 합니다.
코드 예시:
def is_even(n): return n % 2 == 0 class EvenSequence: def __init__(self, size): self.size = size def __getitem__(self, index): if isinstance(index, slice): return [x for x in range(self.size)[index] if is_even(x)] if index < 0 or index >= self.size: raise IndexError('Index out of bounds') return index if is_even(index) else None def __len__(self): return self.size
주요 특징:
객체가 시퀀스처럼 작동하기 위해 __getitem__만 구현하면 될까요?
부분적으로 그렇습니다. __getitem__만 구현하면 for 루프를 통해 객체를 반복하고 요소를 인덱싱할 수 있지만 len()은 작동하지 않습니다.
코드 예시:
class SeqOnlyGetitem: def __getitem__(self, index): if index >= 10: raise IndexError return index * 2 s = SeqOnlyGetitem() for x in s: print(x) # 작동 (반복 가능) # print(len(s)) # TypeError 오류
부정적 인덱스를 어떻게 처리하고, 처리하지 않으면 어떻게 됩니까?
부정적 인덱스는 파이썬에서 시퀀스의 핵심 특징입니다. 이를 처리하지 않으면 객체가 사용자에게 예기치 않게 동작합니다.
class NegIndex: def __init__(self, data): self.data = data def __getitem__(self, index): if index < 0: index += len(self.data) return self.data[index]
자신의 Sequence 클래스에 contains 또는 __iter__를 구현해야 합니까?
필수는 아닙니다. __getitem__과 __len__이 구현되면 in 함수가 작동하고 for는 이를 사용하여 반복합니다. 이러한 메서드를 직접 구현할 필요는 없지만 성능을 향상시킬 수 있습니다.
개발자는 자신의 클래스에 대해 부정적 인덱스에 대해서만 __getitem__을 구현했습니다. 모듈은 일부 유닛 테스트를 통과했지만, 실제 사용에서 존재하지 않는 인덱스를 가져가려 하거나 부정적 인덱스를 사용할 때 모두 실패했습니다.
장점:
단점:
팀은 두 메서드(getitem 및 len)를 구현하고, 슬라이스와 부정적 인덱스를 고려하며, 올바른 예외를 발생시켰습니다. 최종 클래스는 파이썬의 모든 표준 사례에서 작동했습니다.
장점:
단점: