프로그래밍백엔드 개발자

파이썬에서 시퀀스 인터페이스(Sequence)는 어떻게 구현됩니까? __getitem__, __len__와 같은 특수 메서드를 구현할 필요가 있는 이유는 무엇이며, 어떤 함정이 존재합니까?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문 배경:

시퀀스는 파이썬에서 가장 오래되고 기본적인 개념 중 하나입니다. 전통적인 예로는 리스트(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__에서 슬라이스 유형 객체를 처리해야 합니다.
  • __len__을 구현하지 않으면 len()과 일부 표준 함수 목록에서 작업하지 않습니다.

꼬리는 있는 질문들.

객체가 시퀀스처럼 작동하기 위해 __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는 이를 사용하여 반복합니다. 이러한 메서드를 직접 구현할 필요는 없지만 성능을 향상시킬 수 있습니다.

일반적인 오류와 안티 패턴

  • 인덱스 범위를 확인하지 않아 IndexError 또는 예기치 않은 결과로 이어집니다.
  • 슬라이스 지원을 구현하지 않아 obj[2:10:2]가 오류를 발생시킵니다.
  • 부정적 인덱스를 잊습니다 (obj[-1]).

실생활 예시

부정적 사례

개발자는 자신의 클래스에 대해 부정적 인덱스에 대해서만 __getitem__을 구현했습니다. 모듈은 일부 유닛 테스트를 통과했지만, 실제 사용에서 존재하지 않는 인덱스를 가져가려 하거나 부정적 인덱스를 사용할 때 모두 실패했습니다.

장점:

  • 빠른 초기 구현.

단점:

  • 실무에서의 예기치 않은 오류.
  • 사용의 불편함(부정적 인덱스를 통해 마지막 요소를 가져갈 수 없고, 슬라이스가 작동하지 않으며 len()이 작동하지 않음).

긍정적 사례

팀은 두 메서드(getitemlen)를 구현하고, 슬라이스와 부정적 인덱스를 고려하며, 올바른 예외를 발생시켰습니다. 최종 클래스는 파이썬의 모든 표준 사례에서 작동했습니다.

장점:

  • 파이썬 API 관점에서 예측 가능한 동작.
  • 사용의 편리함, 버그 최소화.

단점:

  • 조금 더 많은 코드, 설계 시 세부 사항에 대한 주의가 필요합니다.