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

Python 개선 제안 한국어 번역

PEP 3114 – 이터레이터 메서드 iterator.next()의 이름을 iterator.__next__()로 변경

Author:
Ka-Ping Yee <ping at zesty.ca>
Status:
Final
Type:
Standards Track
Created:
04-Mar-2007
Python-Version:
3.0
Post-History:


Table of Contents

번역·라이선스 안내

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

초록

Python 2.x의 이터레이터 프로토콜은 두 개의 메서드로 구성됩니다. 이터러블 객체에서 호출되어 이터레이터를 내놓는 __iter__()와, 이터레이터 객체에서 호출되어 시퀀스의 다음 항목을 내놓는 next()입니다. for 루프를 사용하여 이터러블 객체를 순회하면 이 두 메서드가 모두 암묵적으로 호출됩니다. 이 PEP는 언어 수준 프로토콜의 일부로서 메서드가 암묵적으로 호출되는 Python의 다른 모든 프로토콜과 일관되도록 next 메서드의 이름을 __next__로 바꿀 것을 제안합니다. 또한 다른 프로토콜을 명시적으로 호출하는 방식과 일관되도록, __next__ 메서드를 호출하는 next라는 이름의 내장 함수를 도입할 것을 제안합니다.

이중 밑줄이 붙은 이름

Python에서는 언어 자체에 속하는 이름을 구별하기 위해 이름의 앞뒤에 이중 밑줄을 붙입니다. 인터프리터가 암묵적으로 사용하거나 생성하는 속성과 메서드는 이 명명 규칙을 따릅니다. 몇 가지 예는 다음과 같습니다.

  • __file__ - 인터프리터가 자동으로 생성하는 속성
  • __dict__ - 인터프리터에게 특별한 의미를 가지는 속성
  • __init__ - 인터프리터가 암묵적으로 호출하는 메서드

이 규칙은 프로그래머가 명시적으로 정의하는 __init__ 같은 메서드뿐만 아니라 이름을 명시적으로 지정해야만 접근할 수 있는 __file__ 같은 속성에도 적용된다는 점에 유의하십시오. 따라서 이 규칙은 인터프리터가 사용하는 또는 생성하는 이름을 포함합니다.

(“프로토콜”이라고 불리는 모든 것이 이중 밑줄 이름을 가진 메서드로 이루어져 있는 것은 아닙니다. 예를 들어, __contains__ 메서드에 이중 밑줄이 붙은 이유는 x in y라는 언어 구문이 __contains__를 암묵적으로 호출하기 때문입니다. 하지만 read 메서드는 파일 프로토콜의 일부임에도 이중 밑줄이 붙지 않는데, x.read()를 암묵적으로 호출하는 언어 구문이 없기 때문입니다.)

이중 밑줄을 사용하면 Python 언어 정의에 속하는 이름들을 위한 별도의 네임스페이스가 만들어지므로, 프로그래머는 언어에서 정의한 용도를 가진 이름과 모르는 사이에 충돌할 걱정 없이 문자로 시작하는 변수, 속성, 메서드를 자유롭게 만들 수 있습니다. (예약된 키워드와 충돌하는 것은 여전히 우려 사항이지만, 적어도 이 경우에는 즉시 문법 오류가 발생합니다.)

이터레이터의 next 메서드 이름은 이 규칙의 예외입니다. next 메서드를 명시적으로 호출하는 부분이 어디에도 없는 코드라도, 그러한 메서드가 존재한다는 이유만으로 자신도 모르게 영향을 받을 수 있습니다. 따라서 이 PEP는 이터레이터가 next 메서드 대신 __next__ 메서드를 가져야 한다고 제안합니다(의미는 변경하지 않습니다).

이중 밑줄 메서드와 내장 함수

Python 언어는 이중 밑줄 이름을 가진 메서드를 정의하여 구현하거나 사용자 정의할 수 있는 여러 프로토콜을 정의합니다. 어느 경우든 프로토콜은 인터프리터 안에 C 함수로 구현된 내부 메서드가 제공합니다. Python에서 정의된 객체의 경우, 이 C 함수는 이중 밑줄 이름을 가진 Python 메서드를 암묵적으로 호출하여 사용자 정의를 지원합니다(단순히 Python 메서드를 호출하는 것 외에 약간의 추가 작업을 하는 경우가 많습니다.)

때로는 프로토콜이 구문 구성 요소에 의해 호출됩니다.

  • x[y] –> 내부 tp_getitem –> x.__getitem__(y)
  • x + y –> 내부 nb_add –> x.__add__(y)
  • -x –> 내부 nb_negative –> x.__neg__()

때로는 구문 구성 요소가 없지만, 그래도 프로토콜을 명시적으로 호출할 수 있으면 유용합니다. 이러한 경우를 위해 Python은 이름은 같지만 이중 밑줄이 없는 내장 함수를 제공합니다.

  • len(x) –> 내부 sq_length –> x.__len__()
  • hash(x) –> 내부 tp_hash –> x.__hash__()
  • iter(x) –> 내부 tp_iter –> x.__iter__()

이 패턴에 따르면 next를 처리하는 자연스러운 방법은 정확히 같은 방식으로 동작하는 next 내장 함수를 추가하는 것입니다.

  • next(x) –> 내부 tp_iternext –> x.__next__()

또한 getattr 및 iter 내장 함수의 방식을 따라, next 내장 함수가 선택적인 두 번째 인자로 센티널 값을 받도록 할 것을 제안합니다. 인자 두 개로 호출되면 next는 StopIteration 예외를 잡아서, 예외를 전파하는 대신 센티널 값을 반환합니다. 이로써 iter와 next 사이에 멋진 이중성이 생깁니다:

iter(함수, 센티널) <–> next(이터레이터, 센티널)

이전 제안

이 제안은 새로운 아이디어가 아닙니다. 여기서 제안하는 아이디어는 python-dev에서 BDFL의 지지를 받았으며 [1] 원래의 이터레이터 PEP인 PEP 234에서도 언급되어 있습니다:

(In retrospect, it might have been better to go for __next__()
and have a new built-in, next(it), which calls it.__next__().
But alas, it's too late; this has been deployed in Python 2.2
since December 2001.)

반대 의견

내장 함수를 더 추가하는 것에 대해 몇 가지 반대 의견이 있었습니다. 특히 Martin von Loewis는 다음과 같이 썼습니다 [2]:

I dislike the introduction of more builtins unless they have a true
generality (i.e. are likely to be needed in many programs). For this
one, I think the normal usage of __next__ will be with a for loop, so
I don't think one would often need an explicit next() invocation.

It is also not true that most protocols are explicitly invoked through
builtin functions. Instead, most protocols are can be explicitly invoked
through methods in the operator module. So following tradition, it
should be operator.next.

...

As an alternative, I propose that object grows a .next() method,
which calls __next__ by default.

전환 계획

2to3 변환 도구에 두 가지 변환이 추가됩니다 [3]:

  • 이름이 next인 메서드 정의는 __next__로 이름이 바뀝니다.
  • next 메서드를 명시적으로 호출하는 코드는 내장 next 함수를 호출하는 코드로 대체됩니다. 예를 들어 x.next()는 next(x)가 됩니다.

Collin Winter는 모듈 수준에서 next에 대한 바인딩이 있는지에 따라 두 번째 변환의 수행 여부를 자동으로 결정할 수 있는지 검토했으며 [4] 그 방식이 “보기 흉하고 느릴” 것이라는 결론을 내렸습니다. 대신 변환 도구는 그러한 바인딩을 감지하면 경고를 내보냅니다. Collin은 다음 조건에 대해 경고할 것을 제안했습니다 [5]:

  • next에 대한 모듈 수준 대입.
  • 이름이 next인 함수의 모듈 수준 정의.
  • next라는 이름의 모듈 수준 임포트.
  • __builtin__.next에 대한 대입.

승인

이 PEP는 2007년 3월 6일에 Guido가 승인했습니다 [6].

구현

필요한 변경 사항(2to3 도구 제외)을 담은 패치는 Georg Brandl이 작성했으며 리비전 54910으로 커밋되었습니다.

참고 문헌