[Rejected] PEP 276 - Simple Iterator for ints
원문 링크: PEP 276 - Simple Iterator for ints
상태: Rejected 유형: Standards Track 작성일: 12-Nov-2001
PEP 276 – int
를 위한 단순 이터레이터
- 작성자: Jim Althoff
- 상태: 거부됨 (Rejected)
- 유형: 표준 트랙 (Standards Track)
- 생성일: 2001년 11월 12일
- Python 버전: 2.3
요약 (Abstract)
Python 2.1부터 이터레이터(Iterator) 기능(PEP 234)이 추가되었으며, 이는 다양한 코딩 상황에서 유용하고 편리하다는 것이 입증되었습니다. Python의 for-loop
제어 구조는 2.1 릴리스부터 이터레이터 프로토콜을 사용하며, list
, tuple
, dictionary
, string
, file
과 같은 내장 타입에 대한 이터레이터를 제공합니다.
이 PEP는 내장 타입인 int
(types.IntType
)에 이터레이터를 추가할 것을 제안합니다. 이러한 이터레이터는 Python에서 특정 for-loop
코딩을 단순화할 수 있을 것입니다.
BDFL (Benevolent Dictator For Life)의 선언 (BDFL Pronouncement)
이 PEP는 2005년 6월 17일, python-dev
메일링 리스트에 대한 공지와 함께 거부되었습니다.
원래의 필요성 대부분은 Python 2.3에 채택된 enumerate()
함수로 충족되었습니다. 또한, 이 제안은 다음과 같은 오용을 허용하고 장려할 수 있다는 문제가 있었습니다.
>>> for i in 3: print i
0
1
2
마찬가지로, 다음과 같은 문장의 구문 오류를 비활성화할 수 있다는 점도 도움이 되지 않았습니다.
x, = 1
상세 사양 (Specification)
이 PEP는 types.IntType
(즉, 내장 타입 int
)의 인스턴스를 인자로 받아 iter()
내장 함수가 호출될 때 반환되는 이터레이터를 정의합니다.
반환된 이터레이터는 다음과 같이 동작합니다.
i
가types.IntType
의 인스턴스(int
)이고i > 0
이라고 가정할 때:iter(i)
는 이터레이터 객체를 반환합니다.- 해당 이터레이터 객체는
0, 1, 2, ..., i-1
순서의 정수를 순회합니다.
예시:
iter(5)
는0, 1, 2, 3, 4
순서의 정수를 순회하는 이터레이터 객체를 반환합니다.i <= 0
인 경우,iter(i)
는 “빈(empty)” 이터레이터를 반환합니다. 즉,next()
메서드를 처음 호출할 때StopIteration
을 발생시킵니다.
다른 말로, 이 이터레이터의 조건과 의미는 range()
및 xrange()
함수의 조건 및 의미와 일치합니다.
int
i
와 연관된 0, 1, 2, ..., i-1
시퀀스는 Python 프로그래밍의 맥락에서 “자연스럽다”고 간주됩니다. 이는 Python의 시퀀스에 대한 내장 인덱싱 프로토콜과 일치하기 때문입니다. 예를 들어, Python의 list
와 tuple
은 0부터 시작하여 len(object)-1
로 끝나는 인덱스(양수 인덱스 사용 시)를 가집니다. 즉, 이러한 객체들은 0, 1, 2, ..., len(object)-1
시퀀스로 인덱싱됩니다.
제안 배경 (Rationale)
일반적인 프로그래밍 방식은 객체 컬렉션을 가져와서 컬렉션의 각 항목에 대해 정해진 순서로 어떤 작업을 적용하는 것입니다. Python은 이 일반적인 방식을 처리하기 위해 “for in
” 루프 제어 구조를 제공합니다.
그러나, “인덱싱된(indexed)” 컬렉션의 각 항목에 접근하기 위해 각 인덱스를 순회하고 해당 인덱스를 사용하여 컬렉션의 각 항목에 접근하는 것이 필요하거나 더 편리한 경우가 발생합니다.
예시: 2차원 “테이블” 객체가 있다고 가정했을 때, 테이블의 각 행의 첫 번째 열에 어떤 작업을 적용해야 할 수 있습니다. 테이블의 구현에 따라 각 행과 각 열에 개별 객체로 접근하는 것이 불가능할 수 있습니다. 대신, 행 인덱스와 열 인덱스를 사용하여 테이블의 셀에 접근할 수 있습니다. 이런 경우, 원하는 테이블 항목에 접근하기 위해 인덱스 시퀀스를 순회하는 방식이 필요합니다.
또 다른 일반적인 예는 두 개 이상의 컬렉션을 병렬로 처리해야 하는 경우나 컬렉션에서 두 번째 항목마다 접근해야 하는 경우입니다. 컬렉션의 항목에 대한 접근이 인덱스 계산을 통해 용이해지는 다른 많은 예시들이 있으며, 이는 항목 자체에 직접 접근하는 대신 인덱스에 접근해야 함을 의미합니다.
이러한 방식을 “indexed for-loop
” 방식이라고 부릅니다. 일부 프로그래밍 언어는 이 방식을 처리하기 위한 내장 구문을 제공합니다. Python에서 indexed for-loop
방식을 구현하기 위한 일반적인 규칙은 내장 range()
또는 xrange()
함수를 사용하여 인덱스 시퀀스를 생성하는 것입니다.
예시:
for rowcount in range(table.getRowCount()):
print table.getValueAt(rowcount, 0)
또는
for rowcount in xrange(table.getRowCount()):
print table.getValueAt(rowcount, 0)
indexed for-loop
방식에 대한 논의는 Python 커뮤니티에서 종종 이루어졌습니다. 이 디자인 방식에서 range()
또는 xrange()
함수를 사용해야 할 필요성은 다음과 같은 이유로 비판받기도 합니다.
- 새로운 Python 프로그래머에게 명확하지 않다.
- 숙련된 Python 프로그래머에게도 오류 발생 가능성이 높다 (잊어버리기 쉽다).
xrange()
와range()
의 차이점과 권장 사용법을 이해해야 하는 사람들에게 혼란스럽고 산만하다.- 특히
len()
함수와 결합할 때 다루기 어렵다 (xrange(len(sequence))
). - 다른 언어의 동등한 메커니즘만큼 편리하지 않다.
- 성가시고, “흠(wart)”으로 여겨진다.
이러한 방식에 대해 Python이 더 나은 메커니즘을 제공할 수 있는 방법에 대한 제안들이 때때로 제시됩니다. 최근 사례로는 PEP 204 “Range Literals” 및 PEP 212 “Loop Counter Iteration”이 있습니다.
대부분의 경우, 이러한 제안에는 Python의 구문 변경 및 기타 “무거운(heavyweight)” 변경 사항이 포함됩니다. 여기서의 어려움 중 일부는 새로운 구문을 주장하는 것이 “일반적인 인덱싱”에 대한 포괄적인 해결책을 의미하며, 이는 다음과 같은 측면을 포함해야 하기 때문입니다.
- 시작 인덱스 값 (starting index value)
- 끝 인덱스 값 (ending index value)
- 단계 값 (step value)
- 열린 구간 (open intervals) 대 닫힌 구간 (closed intervals) 대 반열린 구간 (half opened intervals)
포괄적이고, 간단하며, 일반적이고, Python답고, 많은 사람들에게 매력적이며, 구현하기 쉽고, 기존 구조와 충돌하지 않으며, 기존 구조를 과도하게 오버로드하지 않는 새로운 구문을 찾는 것은 예상보다 어렵다는 것이 입증되었습니다.
이 PEP에 제시된 제안은 이미 사용 가능한 입증된 메커니즘(Python 2.1부터)인 이터레이터를 사용하여 가장 일반적인 경우를 돕는 간단한 “경량(lightweight)” 솔루션을 제안함으로써 문제를 해결하고자 합니다.
for-loop
는 Python 2.1부터 이미 “이터레이터” 프로토콜을 사용하므로, 이 PEP에서 제안된 types.IntType
에 이터레이터를 추가하면 indexed for-loop
방식에 대해 다음과 같은 단축 기능을 기본적으로 활성화할 수 있습니다.
for rowcount in table.getRowCount():
print table.getValueAt(rowcount, 0)
range()
또는 xrange()
함수를 사용하는 현재 메커니즘과 비교하여 이 접근 방식의 이점은 다음과 같습니다.
- 더 간단하다 (Simpler).
- 더 깔끔하다 (Less cluttered).
- 당면한 문제에 집중한다 (Focuses on the problem at hand) (보조적인 구현 지향 함수인
range()
및xrange()
에 의존할 필요 없이).
다른 변경 제안과 비교하면:
- 새로운 구문이 필요 없다 (Requires no new syntax).
- 새로운 키워드가 필요 없다 (Requires no new keywords).
- 새롭고 잘 확립된 이터레이터 메커니즘을 활용한다 (Takes advantage of the new and well-established iterator mechanism).
그리고 일반적으로:
list
,tuple
,dictionary
,string
,file
과 같은 다른 내장 타입에 대해 이미 포함된 (Python 2.1부터) 이터레이터 기반 “편의” 변경 사항과 일치합니다.
하위 호환성 (Backwards Compatibility)
제안된 메커니즘은 새로운 구문이나 키워드를 요구하지 않으므로 일반적으로 하위 호환됩니다. 모든 기존의 유효한 Python 프로그램은 수정 없이 계속 작동해야 합니다.
그러나 이 제안은 현재 유효하지 않은 특정 문장이 현재 제안에 따라 유효하게 된다는 점에서 완벽하게 하위 호환되지 않습니다. Tim Peters는 두 가지 예를 지적했습니다.
range()
또는xrange()
를 포함하는 것을 잊어버린 일반적인 경우:for rowcount in table.getRowCount(): print table.getValueAt(rowcount, 0)
Python 2.2에서는
TypeError
예외가 발생합니다. 현재 제안에 따르면, 위 문장은 유효하며 (아마도) 의도한 대로 작동할 것입니다. 이것은 좋은 점일 것입니다. Tim이 언급했듯이, 이것은 “range
를 잊어버린 실수”의 일반적인 경우입니다.- 튜플 언패킹(tuple unpacking)을 사용할 때 오타를 내는 (바라건대) 매우 드문 경우:
x, = 1
Python 2.2에서는
TypeError
예외가 발생합니다. 현재 제안에 따르면, 위 문장은 유효하며x
를0
으로 설정할 것입니다. PEP 작성자는 이 오타가 얼마나 흔한지, 또는 현재 제안 하에서 이러한 오류를 잡아내기 얼마나 어려운지에 대한 데이터가 없습니다. 그는 이러한 경우가 자주 발생하지 않으며, 발생하더라도 비교적 쉽게 수정할 수 있을 것이라고 생각합니다.
쟁점 (Issues)
Python 관심 메일링 리스트에서 PEP 276에 대한 광범위한 논의는 다양한 의견을 제시했습니다. 일부는 찬성하고, 일부는 중립적이며, 일부는 반대했습니다. 찬성하는 사람들은 정수에 대한 단순한 이터레이터의 유용성, 편리함, 학습 용이성, 단순성에 대한 위의 주장에 동의하는 경향이 있었습니다.
PEP 276에 대한 쟁점은 다음과 같습니다.
range
/xrange
사용은 현재로서는 괜찮다.- 응답: 일부는 그렇게 생각하지만, 다른 사람들은 동의하지 않습니다.
- 정수
n
에 대해0, 1, 2, ..., n-1
시퀀스를 순회하는 것은 직관적이지 않다. “for i in 5:
“는 (일부에 의해) “명확하지 않다”고 여겨집니다. 일부는 이러한 사용법이 “올바른 느낌”이 없기 때문에 싫어합니다. 일부는 이러한 유형의 사용법이 정수를 시퀀스로 보도록 강요하며, 이것이 잘못되었다고 믿기 때문에 싫어합니다. 일부는for-loop
이 임의의 이터레이터보다는 명시적인 시퀀스를 다루는 것으로 보는 것을 선호하기 때문에 싫어합니다.- 응답: 일부는 제안된 방식을 좋아하고 간단하고 우아하며 배우기 쉽고 사용하기 쉽다고 봅니다. 일부는 이 문제에 대해 중립적입니다. 다른 사람들은 앞서 언급했듯이 싫어합니다.
iter(5)
가0,1,2,3,4
시퀀스로 매핑되는 것이 명확한가?- 응답: 위에서 언급했듯이, Python은 0에서 시작하여 시퀀스 길이보다 하나 작은 값의 인덱스에서 끝나는 시퀀스 인덱싱에 대한 강력한 규칙을 가지고 있다는 점을 감안할 때, 제안된 시퀀스는 Python 프로그래머에게 합리적으로 직관적이며 유용하고 실용적이라고 주장됩니다. 더 중요한 것은, 일단 이 규칙을 배우면 기억하기 매우 쉽다고 주장됩니다.
range
함수의 독스트링(doc string)은range(n)
과 길이가n
인 리스트의 인덱스 사이의 자연스럽고 유용한 연관성을 언급합니다.
- 응답: 위에서 언급했듯이, Python은 0에서 시작하여 시퀀스 길이보다 하나 작은 값의 인덱스에서 끝나는 시퀀스 인덱싱에 대한 강력한 규칙을 가지고 있다는 점을 감안할 때, 제안된 시퀀스는 Python 프로그래머에게 합리적으로 직관적이며 유용하고 실용적이라고 주장됩니다. 더 중요한 것은, 일단 이 규칙을 배우면 기억하기 매우 쉽다고 주장됩니다.
- 잠재적 모호성:
for i in 10: print i
가
for i in (10,): print i
로 오해될 수 있다.
- 응답: 이것은 현재 Python의 문자열과 정확히 동일한 상황입니다 (위 코드에서
10
을'spam'
으로 바꾸는 것과 같습니다).
- 응답: 이것은 현재 Python의 문자열과 정확히 동일한 상황입니다 (위 코드에서
- 너무 일반적이다: 최신 Python 릴리스에서는
for-loop
과 같이 이터레이터가 암시적으로 호출되는 컨텍스트가 있습니다. 일부는for-loop
를 제외하고 다른 컨텍스트에서 정수에 대한 이터레이터가 호출되는 것이 예상치 못한 동작과 버그로 이어질 수 있다고 우려합니다. 위에서 언급된 “x, = 1
” 예시가 좋은 예입니다.- 응답: 작성자의 관점에서 PEP 276 논의에서 식별된 위의 예시들은 미묘하고 감지하기 어려운 오류로 이어질 수 있는 방식으로 우발적으로 오용될 것으로 보이지 않았습니다.
- 또한, 이 제안의 사양 섹션에 설명된 내용을 변형하여 이 문제를 처리하는 방법이 있는 것으로 보입니다.
int
클래스에__iter__
메서드를 추가하는 대신,for-loop
처리 코드를 변경하여 (본질적으로) 다음과 같이 변환하는 것입니다.for i in n: # when isinstance(n,int) is 1
를
for i in xrange(n):
이 접근 방식은
for-loop
에서__iter__
메서드와 동일한 결과를 제공하지만 다른 어떤 컨텍스트에서도 정수 값에 대한 순회를 방지할 수 있습니다. 예를 들어,list
와tuple
은__iter__
를 가지고 있지 않으며 특별한 코드로 처리됩니다. 정수 값은 또 다른 특별한 경우가 될 것입니다.
- “
i in n
“은 매우 부자연스러워 보인다.- 응답: 일부는 “
i in len(mylist)
“가 쉽게 이해되고 유용할 것이라고 생각합니다. 일부는 특히 “i in 5
“와 같이 리터럴이 사용될 때 이를 싫어합니다. 이전 문제에 대한 응답에서 언급된 변형이 구현된다면 이 문제는 논외입니다. 그렇지 않다면,int
클래스에 항상TypeError
를 발생시키는__contains__
메서드를 정의하여 이 문제를 해결할 수도 있습니다. 이렇게 하면 “i in n
“의 동작이 현재 Python과 동일해집니다.
- 응답: 일부는 “
- 표준 “
for item in collection:
” 방식이 분명히 더 나을 때, 초보자들이indexed for-loop
방식을 사용하지 않도록 막을 수 있다.- 응답: 표준 방식은 적합할 때 너무 좋아서 추가적인 “당근”이나 “채찍”이 필요하지 않습니다. 반면에,
indexed for-loop
방식의 어색함 때문에 표준 방식의 과용/오용 사례가 눈에 띄기도 합니다.for item in sequence: print sequence.index(item)
- 응답: 표준 방식은 적합할 때 너무 좋아서 추가적인 “당근”이나 “채찍”이 필요하지 않습니다. 반면에,
- 왜 더 큰 변경을 제안하지 않는가?
- PEP 276에 대한 반대 의견의 대부분은 시작 값, 끝 값, 단계 값뿐만 아니라 열린, 닫힌, 반열린(반닫힌) 정수 구간의 변형을 처리할 만큼 충분히 일반적인 정수 시퀀스를 지정하는 더 일반적인 문제에 대처하기 위해 Python에 훨씬 더 큰 변경을 선호하는 사람들로부터 나왔습니다. 이러한 많은 제안들이 논의되었습니다.
- 여기에는 다음이 포함됩니다.
- 리터럴 리스트에서 정수 시퀀스를 지정하기 위한 Haskell과 유사한 표기법 추가
- 시퀀스를 지정하기 위한 슬라이싱(slicing) 표기법의 다양한 사용
- 루프 헤더에서 관계형 연산자를 사용할 수 있도록
for-in
루프의 구문 변경 - 정수-구간(integer-interval) 클래스 생성과 관계형 연산자 또는 나눗셈 연산자를 오버로드하여 정수-구간 객체에 “슬라이싱”을 제공하는 메서드 추가
- 기타
- 많은 논쟁이 있었지만, 이러한 대규모 제안에 대한 압도적인 합의는 없었습니다.
- 분명히 PEP 276은 그러한 대규모 변경을 제안하지 않고 특정 문제 영역에 초점을 맞추고 있습니다. 논의 기간이 끝날 무렵, 몇몇 발표자들은 제시된 더 야심찬 제안들에 비해 PEP 276의 좁은 초점과 단순성에 찬성했습니다. 그러한 대규모의 대안적인 제안에 대한 PEP의 필요성에 대한 합의가 있는 것으로 보였습니다. 이러한 인식을 고려하여 다양한 대안적 제안에 대한 자세한 내용은 여기서 더 이상 논의되지 않습니다.
구현 (Implementation)
현재 구현은 제공되지 않지만, 간단할 것으로 예상됩니다. 작성자는 이 제안의 아이디어를 테스트하기 위한 수단으로 __iter__
메서드(Python으로 작성됨)가 있는 int
의 서브클래스를 구현했습니다.
저작권 (Copyright)
이 문서는 퍼블릭 도메인(public domain)에 공개되었습니다.
⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.
Comments