Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 279 – enumerate() 내장 함수

Author:
Raymond Hettinger <python at rcn.com>
Status:
Final
Type:
Standards Track
Created:
30-Jan-2002
Python-Version:
2.3
Post-History:


Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 흔히 쓰이는 루프 관용구를 단순화하기 위해 새로운 내장 함수 enumerate()를 도입합니다. 이 함수는 iteritems()가 딕셔너리에 제공하는 것과 같은 이점, 즉 간결하고 읽기 쉬우며 신뢰할 수 있는 인덱스 표기법을 모든 이터러블 컬렉션에 제공합니다.

근거

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

PEP 255에서 제안된 제너레이터는 이터레이터, 특히 내부 실행이나 변수 상태가 복잡한 이터레이터를 더 쉽게 만들기 위한 수단으로 도입되었습니다. 제너레이터를 사용할 수 있게 되면서 PEP 212의 루프 카운터 아이디어를 개선할 수 있게 되었습니다. 그 아이디어들은 인덱스와 값을 함께 이터레이션하는 깔끔한 문법을 제공했지만, 모든 이터러블 객체에 적용되지는 않았습니다. 또한 그 방식에는 전체 시퀀스를 한꺼번에 평가하지 않는 제너레이터가 주는 메모리 효율상의 이점이 없었습니다.

새로운 제안은 이터레이터와 제너레이터를 사용할 수 있게 되면서 비로소 가능해진 내장 함수 enumerate()를 추가하는 것입니다. 이 함수는 iteritems()가 딕셔너리에 제공하는 것과 같은 이점, 즉 간결하고 읽기 쉬우며 신뢰할 수 있는 인덱스 표기법을 모든 이터러블에 제공합니다. zip()과 마찬가지로, 이 함수도 흔히 쓰이는 루프 관용구가 될 것으로 예상됩니다.

이 제안은 기존 구현을 활용하도록 설계되었으며, 통합하는 데 추가 노력이 거의 필요하지 않습니다. 이 제안은 하위 호환성을 유지하며 새로운 키워드를 요구하지 않습니다. 이 제안은 제너레이터가 확정되어 더 이상 __future__에서 임포트하지 않아도 되는 Python 2.3에 포함될 것입니다.

BDFL 선언

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

새로운 내장 함수의 명세

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, 시퀀스, 이터러블 객체 어디에나 동작하는 위 함수와 달리 리스트에만 동작합니다. 또한 그 제안들은 제너레이터가 포함되지 않았던 Python 2.2 이전의 환경에서 제시되고 평가되었습니다. 그 결과, PEP 212의 비제너레이터 버전은 거대한 튜플 리스트로 메모리를 소비한다는 단점이 있었습니다. 여기에서 제시한 제너레이터 버전은 빠르고 가벼우며, 모든 이터러블과 함께 동작하고, 사용자가 시퀀스를 스트림 중간에 중단하더라도 이미 수행한 계산이 낭비되지 않습니다.

관련 문제를 다루는 다른 PEP들도 있습니다. 정수 이터레이터, 정수 for 루프, 그리고 range와 xrange의 인자를 수정하는 PEP가 그것입니다. enumerate() 제안은 다른 제안들을 배제하지 않으며, 그 제안들이 채택되더라도 어떤 이터러블이든 그 항목을 세야 한다는 중요한 요구를 여전히 충족합니다. 다른 제안들은 인덱스를 만들어 내는 수단은 제공하지만, 그에 대응하는 값은 제공하지 않습니다. 이는 파일 객체, 제너레이터, __getitem__으로 정의된 시퀀스처럼 임의 접근을 지원하지 않는 시퀀스가 주어지는 경우에 특히 문제가 됩니다.

비고 B: 거의 모든 PEP 검토자가 이 함수를 환영했지만, 내장 함수를 두어야 하는지에 대해서는 의견이 나뉘었습니다. 별도 모듈을 지지하는 주된 인자는 언어 팽창 속도를 늦추자는 것이었습니다. 내장을 지지하는 주된 인자는 이 함수가 이터러블 인터페이스를 갖춘 모든 객체에 적용할 수 있는 핵심 프로그래밍 스타일의 일부가 될 운명이라는 것이었습니다. zip()이 여러 시퀀스를 순회하는 문제를 해결하듯이, enumerate() 함수는 루프 카운터 문제를 해결합니다.

내장 함수를 하나만 허용한다면 enumerate()가 가장 중요한 범용 도구입니다. 프로그램의 간결성, 명확성, 신뢰성을 높이면서 가장 넓은 범위의 문제를 해결하기 때문입니다.

비고 C: 다양한 대체 이름이 논의되었습니다:

iterindexed() 다섯 음절은 발음하기 번거롭습니다
index() 좋은 동사이지만 .index() 메서드와 혼동될 수 있습니다
indexed() 널리 호응을 얻었지만 형용사는 피해야 합니다
indexer() 명사라서 for 루프 안에서 자연스럽게 읽히지 않았습니다
count() 직접적이고 명시적이지만 다른 맥락에서 자주 쓰입니다
itercount() 직접적이고 명시적이지만 두 사람 이상이 싫어했습니다
iteritems() 딕셔너리의 key:value 개념과 충돌합니다
itemize() amap.items() != list(itemize(amap))이므로 혼란스럽습니다
enum() 간결하지만 enumerate보다 덜 명확하고, 다른 의미로 쓰이는 다른 언어의 enum과 너무 비슷합니다

‘count’가 들어간 이름은 모두 카운트가 0이 아닌 1부터 시작한다는 인상을 준다는 단점도 있었습니다.

‘index’가 들어간 이름은 모두 데이터베이스 언어의 용법과 충돌했습니다. 데이터베이스 언어에서 인덱싱은 선형적인 순서 매기기가 아니라 정렬 연산을 뜻하기 때문입니다.

비고 D: 이 함수는 원래 선택적인 start 인자와 stop 인자를 받는 형태로 제안되었습니다. GvR은 enumerate(seqn,4,6) 함수 호출이 시퀀스의 네 번째와 다섯 번째 요소를 반환하는 슬라이스로도 그럴듯하게 해석될 수 있다고 지적했습니다. 이러한 모호함을 피하기 위해, 루프 카운터로서의 유연성을 잃게 되더라도 선택적 인자를 없앴습니다. 그 유연성은 다음과 같이 1부터 세는 흔한 경우에 가장 중요했습니다:

for linenum, line in enumerate(source,1):  print linenum, line
GvR의 의견:
filter와 map은 변형을 더 늘릴 것이 아니라 없어지고 리스트 컴프리헨션에 흡수되어야 합니다. 저는 차라리 이터레이터 대수를 수행하는 내장 함수(예를 들어 제가 예시로 자주 들었던 iterzip)를 도입하고 싶습니다.

시퀀스와 그 인덱스 집합을 나란히 순회할 방법이 있으면 좋겠다는 아이디어가 마음에 듭니다. 이것은 내장 함수여도 괜찮습니다.

“indexed”라는 이름은 마음에 들지 않습니다. 형용사는 좋은 함수 이름이 되지 못합니다. iterindexed()는 어떻습니까?

Ka-Ping Yee의 의견:
저 역시 제안하신 모든 것에 상당히 만족하며… 추가 내장 함수들(특히 ‘indexed’)은 제가 오랫동안 원해 왔던 것입니다.
Neil Schemenauer의 의견:
새 내장 함수들은 괜찮아 보입니다. Guido는 내장 함수의 수가 너무 많이 늘어나는 것을 우려할 수도 있습니다. 이들을 모듈의 일부로 제안하는 편이 더 나을 수도 있습니다. 모듈을 사용하면 유용한 함수를 많이 추가할 수 있습니다(Haskell에는 우리가 가져다 쓸 만한 함수가 많이 있습니다).
Magnus Lie Hetland의 의견:
indexed는 유용하고 자연스러운 내장 함수가 될 것이라고 생각합니다. 저는 분명히 이것을 많이 사용할 것입니다. indexed()가 매우 마음에 듭니다. +1입니다. 이것으로 PEP 281이 필요 없어지게 되는 것에 아주 만족합니다. 이터레이터 유틸리티를 위한 별도의 모듈을 추가하는 것은 좋은 생각으로 보입니다.
커뮤니티의 의견:
enumerate() 제안에 대한 반응은 거의 100% 호의적이었습니다. 거의 모든 사람이 이 아이디어를 무척 좋아합니다.
저자의 답변:
이러한 의견이 나오기 전에는 네 개의 내장 함수가 제안되었습니다. 의견을 받은 후 xmap, xfilter, xzip은 철회되었습니다. 남은 하나는 언어에 필수적이며 단독으로 제안됩니다. Indexed()는 구현하기가 아주 쉽고 몇 분 만에 문서화할 수 있습니다. 더 중요한 점은, 이 함수가 제너레이터를 명시적으로 사용하지 않는 일상적인 프로그래밍에서도 유용하다는 것입니다.

이 제안에는 원래 iterzip()이라는 함수가 하나 더 포함되어 있었습니다. 그 함수는 이후 itertools 모듈의 izip() 함수로 구현되었습니다.