[Final] PEP 279 - The enumerate() built-in function

원문 링크: PEP 279 - The enumerate() built-in function

상태: Final 유형: Standards Track 작성일: 30-Jan-2002

PEP 279 – enumerate() 내장 함수

  • 작성자: Raymond Hettinger
  • 상태: 최종 (Final)
  • 유형: 표준 트랙 (Standards Track)
  • 생성일: 2002년 1월 30일
  • Python 버전: 2.3
  • 수정 이력: 확인 가능

개요 (Abstract)

이 PEP는 일반적으로 사용되는 반복(looping) 관용구를 간소화하기 위해 새로운 내장 함수 enumerate()를 소개합니다. 이 함수는 모든 iterable 컬렉션(iterable collections)에 iteritems()가 딕셔너리에 제공하는 것과 동일한 이점, 즉 간결하고 읽기 쉬우며 신뢰할 수 있는 인덱스 표기법을 제공합니다.

도입 배경 (Rationale)

Python 2.2는 PEP 234에서 제안된 iterable 인터페이스의 개념을 도입했습니다. iter() 팩토리 함수는 일반적인 호출 규약으로 제공되었으며, Python 전반에 걸쳐 이터레이터(iterators)를 통일된 개념으로 사용하기 위한 깊이 있는 변경이 이루어졌습니다. 이 통합은 매핑(mappings), 시퀀스(sequences), 파일 객체(file objects)에 대한 공통 iterable 인터페이스를 확립하는 형태로 나타났습니다.

PEP 255에서 제안된 제너레이터(Generators)는 이터레이터를 더 쉽게 생성할 수 있는 수단으로 도입되었는데, 특히 복잡한 내부 실행이나 가변 상태를 가진 이터레이터에 유용합니다. 제너레이터의 가용성은 PEP 212의 루프 카운터 아이디어를 개선할 수 있게 했습니다. PEP 212의 아이디어는 인덱스와 값을 사용한 반복에 깔끔한 구문을 제공했지만, 모든 iterable 객체에 적용되지는 않았습니다. 또한, 해당 접근 방식은 전체 시퀀스를 한 번에 평가하지 않는 제너레이터가 제공하는 메모리 친화적인 이점이 없었습니다.

새로운 제안은 이터레이터와 제너레이터가 가능해지면서 추가될 수 있게 된 내장 함수 enumerate()를 추가하는 것입니다. 이 함수는 zip()과 마찬가지로 흔히 사용되는 반복 관용구가 될 것으로 예상됩니다. 이 제안은 기존 구현을 활용하고 통합하는 데 적은 추가 노력이 필요하도록 설계되었습니다. 하위 호환성을 유지하며 새로운 키워드를 필요로 하지 않습니다. 이 제안은 제너레이터가 최종 확정되어 __future__에서 임포트되지 않는 Python 2.3에 포함될 예정이었습니다.

BDFL의 의견 (BDFL Pronouncements)

새로운 내장 함수는 승인(ACCEPTED)되었습니다.

새로운 내장 함수에 대한 명세 (Specification for a new built-in)

enumerate() 함수의 동작은 다음과 같은 의사 코드(pseudo-code)로 설명될 수 있습니다:

def enumerate(collection):
    'Generates an indexed series: (0,coll[0]), (1,coll[1]) ...'
    i = 0
    it = iter(collection)
    while 1:
        yield (i, it.next())
        i += 1

주석 A: PEP 212 루프 카운터 반복(Loop Counter Iteration)은 인덱싱을 달성하기 위한 여러 제안을 논의했습니다. 일부 제안은 리스트에만 작동했지만, 위의 함수는 모든 제너레이터, xrange, 시퀀스 또는 iterable 객체에 작동합니다. 또한, PEP 212의 제안들은 제너레이터가 포함되지 않았던 Python 2.2 이전 환경에서 제시되고 평가되었습니다. 그 결과, PEP 212의 비-제너레이터 버전은 거대한 튜플 리스트로 메모리를 소비하는 단점이 있었습니다. 여기에 제시된 제너레이터 버전은 빠르고 가볍고, 모든 iterable 객체와 작동하며, 사용자가 계산 노력 손실 없이 중간에 시퀀스 사용을 중단할 수 있도록 합니다.

관련 문제(정수 이터레이터, 정수 for-loop, rangexrange의 인자 수정)를 다루는 다른 PEP들도 있습니다. enumerate() 제안은 다른 제안들을 배제하지 않으며, 이들이 채택되더라도 모든 iterable 객체에서 항목을 세어야 하는 중요한 필요를 여전히 충족시킵니다. 다른 제안들은 인덱스를 생성하는 수단을 제공하지만 해당 값은 제공하지 않습니다. 이는 파일 객체, 제너레이터 또는 __getitem__으로 정의된 시퀀스와 같이 무작위 접근(random access)을 지원하지 않는 시퀀스가 주어질 경우 특히 문제가 됩니다.

주석 B: 거의 모든 PEP 검토자들은 이 함수를 환영했지만, 내장 함수로 포함될지에 대해서는 의견이 나뉘었습니다. 별도의 모듈에 넣어야 한다는 주요 주장은 언어의 확장 속도를 늦추기 위함이었습니다. 내장 함수로 포함해야 한다는 주요 주장은 이 함수가 iterable 인터페이스를 가진 모든 객체에 적용될 수 있는 핵심 프로그래밍 스타일의 일부가 될 운명이기 때문입니다. zip()이 여러 시퀀스를 반복하는 문제를 해결하는 것처럼, enumerate() 함수는 루프 카운터 문제를 해결합니다.

하나의 내장 함수만 허용된다면, enumerate()는 프로그램의 간결성(brevity), 명확성(clarity), 신뢰성(reliability)을 향상시키면서 가장 광범위한 문제를 해결하는 가장 중요한 범용 도구입니다.

주석 C: 다양한 대체 이름들이 논의되었습니다:

  • iterindexed(): 5음절로 발음하기 어렵습니다.
  • index(): 좋은 동사이지만 .index() 메서드와 혼동될 수 있습니다.
  • indexed(): 널리 선호되었지만, 형용사는 함수 이름으로 피해야 합니다.
  • indexer(): 명사이지만 for-loop에서 잘 읽히지 않았습니다.
  • count(): 직접적이고 명시적이지만 다른 컨텍스트에서 자주 사용됩니다.
  • itercount(): 직접적이고 명시적이지만 여러 사람에게 싫어함을 받았습니다.
  • iteritems(): 딕셔너리의 key:value 개념과 충돌합니다.
  • itemize(): amap.items() != list(itemize(amap))로 인해 혼란스럽습니다.
  • enum(): 간결하지만 enumerate보다 덜 명확하며, 다른 언어에서 다른 의미를 가진 enum과 너무 유사합니다.

‘count’가 포함된 모든 이름은 카운트가 0이 아닌 1부터 시작한다는 것을 암시하는 단점이 있었습니다. ‘index’가 포함된 모든 이름은 데이터베이스 언어에서 인덱싱이 선형 시퀀싱이 아닌 정렬 작업을 의미하는 것과 충돌했습니다.

주석 D: 이 함수는 원래 선택적 startstop 인자와 함께 제안되었습니다. GvR(Guido van Rossum)은 enumerate(seqn, 4, 6) 함수 호출이 시퀀스의 네 번째와 다섯 번째 요소를 반환하는 슬라이스(slice)와 같은 다른 그럴듯한 해석을 가질 수 있다고 지적했습니다. 모호성을 피하기 위해, 루프 카운터로서의 유연성을 잃더라도 선택적 인자들은 제외되었습니다. 이러한 유연성은 다음과 같이 1부터 세는 일반적인 경우에 가장 중요했습니다:

for linenum, line in enumerate(source, 1):
    print linenum, line

GvR의 의견: filtermap은 사라지고 리스트 컴프리헨션(list comprehensions)에 통합되어야 하며, 더 많은 변형이 생겨서는 안 됩니다. 저는 이터레이터 연산(iterator algebra)을 수행하는 내장 함수(예: 제가 예시로 자주 사용했던 iterzip)를 도입하고 싶습니다.

시퀀스와 해당 인덱스 집합을 병렬로 반복하는 어떤 방법을 갖는다는 아이디어를 좋아합니다. 이것이 내장 함수로 포함되는 것은 괜찮습니다.

‘indexed’라는 이름은 좋아하지 않습니다. 형용사는 좋은 함수 이름을 만들지 못합니다. 혹시 iterindexed()는 어떤가요?

커뮤니티의 반응: enumerate() 제안에 대한 반응은 거의 100% 호의적이었습니다. 거의 모든 사람들이 이 아이디어를 좋아했습니다.

작성자 응답: 이러한 의견이 있기 전에 네 개의 내장 함수가 제안되었습니다. 의견을 들은 후 xmap, xfilter, xzip은 철회되었습니다. 남은 하나는 언어에 필수적이며 단독으로 제안되었습니다. indexed()는 구현하기 매우 쉽고 몇 분 안에 문서화될 수 있습니다. 더 중요한 것은, 명시적인 제너레이터 사용이 포함되지 않는 일상적인 프로그래밍에서 유용하다는 것입니다.

이 제안은 원래 다른 함수 iterzip()을 포함했습니다. 그것은 나중에 itertools 모듈의 izip() 함수로 구현되었습니다.

이 문서는 퍼블릭 도메인에 공개되었습니다.

⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.

Comments