Python

Python 2.0에서 추가된 기능

저자:

A.M. Kuchling과 Moshe Zadka

소개

파이썬의 새로운 버전인 2.0이 2000년 10월 16일에 출시되었습니다. 이 문서는 2.0에서 도입된 흥미로운 새 기능들을 다루고, 다른 유용한 변경 사항 몇 가지를 강조하며, 코드를 재작성해야 할 수 있는 호환되지 않는 변경 사항을 알려줍니다.

Python의 개발은 릴리스 사이에 결코 완전히 멈추지 않으며, 버그 수정과 개선 사항의 꾸준한 흐름이 항상 제출되고 있습니다. 2.0에는 수많은 사소한 수정 사항, 몇 가지 최적화, 추가 docstring, 그리고 더 나은 오류 메시지가 포함되었습니다. 이들을 모두 목록으로 만들기는 불가능하겠지만, 확실히 중요합니다. 전체 목록을 보고 싶다면 공개적으로 이용 가능한 CVS 로그를 참고하십시오. 이러한 발전은 PythonLabs에서 일하는 다섯 명의 개발자들이 버그 수정에 시간을 쓰고 급여를 받는 것과 SourceForge로 마이그레이션하면서 개선된 커뮤니케이션 덕분입니다.

Python 1.6은 어떤가요?

Python 1.6은 ‘계약적 의무’ 릴리스로 간주할 수 있습니다. 코어 개발팀이 2000년 5월에 CNRI를 떠난 후, CNRI는 CNRI에서 수행된 모든 Python 작업을 포함하는 1.6 릴리스 생성을 요청했습니다. 따라서 Python 1.6은 유니코드 지원이 가장 중요한 새로운 기능이었으며, 2000년 5월 기준의 CVS 트리 상태를 나타냅니다. 물론 개발은 5월 이후에도 계속되었으므로, 1.6 트리는 Python 2.0과 순방향 호환성을 보장하기 위한 몇 가지 수정 사항을 받았습니다. 따라서 1.6은 측면 브랜치가 아니라 Python 진화의 일부입니다.

그러니 파이썬 1.6에 많은 관심을 가져야 할까요? 아마 아닐 겁니다. 1.6final 및 2.0beta1 배포판은 같은 날(2000년 9월 5일) 출시되었으며, 계획은 한 달 정도 안에 파이썬 2.0을 완성하는 것이었습니다. 만약 유지보수해야 할 애플리케이션이 있다면, 1.6으로 이동하여 무언가를 깨뜨리고 그것들을 수정한 다음, 또다시 2.0으로 옮기면서 한 달 안에 또다시 문제가 생기는 것보다는 그냥 바로 2.0으로 가는 것이 훨씬 좋습니다. 이 문서에 설명된 흥미로운 기능들 대부분은 2.0에만 포함되어 있는데, 이는 5월부터 9월 사이에 많은 작업이 이루어졌기 때문입니다.

새 개발 프로세스

파이썬 2.0에서 가장 중요한 변화는 아예 코드 자체에 있는 것이 아니라, 파이썬 개발 방식 그 자체에 있다는 것입니다: 2000년 5월에 파이썬 개발자들은 소스 코드를 저장하고, 버그 보고서를 추적하며, 패치 제출 대기열을 관리하기 위해 SourceForge가 제공하는 도구들을 사용하기 시작했습니다. Python 2.0의 버그를 보고하거나 패치를 제출하려면, https://sourceforge.net/projects/python/에 위치한 파이썬 프로젝트 페이지에서 사용할 수 있는 버그 추적 및 패치 관리 도구를 사용하십시오.

SourceForge에 호스팅되는 가장 중요한 서비스 중 하나는 파이썬의 소스 코드를 포함하는 버전 제어 저장소인 Python CVS 트리였습니다. 이전에는 이 CVS 트리에 쓰기 접근 권한을 가진 사람이 약 7명 정도였고, 모든 패치는 이 짧은 목록의 사람 중 한 명에 의해 검사되고 체크되어야 했습니다. 당연히 이것은 매우 확장성이 떨어졌습니다. CVS 트리를 SourceForge로 옮기면서 더 많은 사람들에게 쓰기 접근 권한을 부여하는 것이 가능해졌는데, 2000년 9월 기준으로 변경 사항을 체크인할 수 있는 사람이 4배 증가하여 27명이 되었습니다. 이는 소수의 핵심 개발자 그룹을 통해 필터링되어야 했다면 시도되지 않았을 대규모 변경을 가능하게 했습니다. 예를 들어, 어느 날 Peter Schneider-Kamp는 K&R C 호환성을 포기하고 파이썬의 C 소스 코드를 ANSI C로 변환하기로 마음먹었습니다. python-dev 메일링 리스트에서 승인을 받은 후, 그는 약 일주일에 걸친 연속적인 체크인들을 시작했고, 다른 개발자들이 도움을 주었고, 작업은 완료되었습니다. 만약 쓰기 접근 권한이 5명밖에 없었다면, 아마 이 작업은 “괜찮지만 필요한 시간과 노력을 들일 가치는 없다”고 여겨져 결코 끝나지 못했을 것입니다.

SourceForge 서비스를 사용하게 된 것은 개발 속도에 놀라운 증가를 가져왔습니다. 이제 패치들은 원래 제출자가 아닌 다른 사람들에 의해 제출되고, 코멘트되며, 수정되고, 패치가 체크인할 가치가 있다고 판정될 때까지 사람들 사이에서 오고 갑니다. 버그는 하나의 중앙 위치에서 추적되어 고치를 위해 특정 사람에게 할당될 수 있으며, 오픈된 버그 수를 세어 진행 상황을 측정할 수 있습니다. 이것이 비용 없이 온 것은 아닙니다: 개발자들은 이제 처리할 이메일이 더 많아졌고, 따라야 할 메일링 리스트가 더 많아졌으며, 새로운 환경을 위해 특별한 도구들이 작성되어야 했습니다. 예를 들어, SourceForge는 완전히 도움이 되지 않는 기본 패치 및 버그 알림 이메일을 보내기 때문에 Ka-Ping Yee는 더 유용한 메시지를 보내는 HTML 스크린 스크래퍼를 작성했습니다.

코드 추가의 용이성은 초기 몇 가지 성장통을 야기했는데, 예를 들어 코드가 준비되기 전에 체크인되거나 개발자 그룹으로부터 명확한 합의 없이 이루어지기도 했습니다. 나타난 승인 프로세스는 Apache 그룹에서 사용되는 것과 다소 유사합니다. 개발자는 패치에 대해 +1, +0, -0, 또는 -1로 투표할 수 있습니다. +1과 -1은 수용 또는 거부를 의미하며, +0과 -0은 개발자가 변화에 대부분 무관심하지만 약간의 긍정적이거나 부정적인 기울기를 가진다는 것을 의미합니다. Apache 모델에서 가장 중요한 변화는 투표가 본질적으로 자문(advisory)적이라는 점이며, 이를 통해 영구 독재자(Benevolent Dictator For Life) 지위를 가진 Guido van Rossum에게 일반적인 의견이 무엇인지 알릴 수 있습니다. 그는 여전히 투표 결과를 무시하고 커뮤니티와 의견이 다르더라도 변경 사항을 승인하거나 거부할 수 있습니다.

실제 패치를 생성하는 것이 새로운 기능을 추가하는 마지막 단계이며, 일반적으로는 좋은 설계를 구상하던 이전 작업에 비해 쉽습니다. 새로운 기능에 대한 논의는 종종 길고 복잡한 메일링 리스트 스레드로 폭발하여 토론을 따라가기 어렵게 만들고, 아무도 python-dev의 모든 게시물을 읽을 수 없습니다. 따라서, 인터넷 RFC 프로세스를 모델로 하여 Python Enhancement Proposals (PEPs)를 작성하기 위해 비교적 공식적인 절차가 마련되었습니다. PEP는 제안된 새로운 기능을 설명하는 초안 문서이며, 커뮤니티가 합의에 도달할 때까지 지속적으로 수정됩니다. PEP 1 소개의 “PEP Purpose and Guidelines” 구절을 인용하면 다음과 같습니다:

PEP는 Python Enhancement Proposal의 약자입니다. PEP는 파이썬 커뮤니티에 정보를 제공하거나 파이썬의 새로운 기능을 설명하는 설계 문서입니다. PEP는 이 기능에 대한 간결한 기술 사양과 근거를 제공해야 합니다.

저희는 PEP가 새로운 기능을 제안하고, 문제에 대한 커뮤니티 입력을 수집하며, 파이썬 개발 과정에 들어간 설계 결정을 문서화하기 위한 주요 메커니즘이 되기를 기대합니다. PEP 작성자는 커뮤니티 내에서 합의를 구축하고 반대 의견을 문서화할 책임이 있습니다.

PEP 편집 프로세스, 스타일 및 형식에 대한 자세한 내용은 PEP 1 의 나머지 부분을 읽어보십시오. PEP는 SourceForge의 Python CVS 트리에 보관되어 있으며, Python 2.0 배포판에는 포함되어 있지 않지만, https://peps.python.org/에서도 HTML 형태로 확인할 수 있습니다. 2000년 9월 기준으로 PEP 201, “Lockstep Iteration”부터 PEP 225, “Elementwise/Objectwise Operators”까지 총 25개의 PEP가 있습니다.

유니코드(Unicode)

Python 2.0에서 가장 큰 새로운 기능은 새로운 기본 데이터 형식인 유니코드 문자열입니다. 유니코드는 ASCII가 사용하는 8비트 숫자 대신 16비트 숫자를 사용하여 문자를 표현하므로, 65,536개의 고유한 문자를 지원할 수 있습니다.

최종 유니코드 지원 인터페이스는 python-dev 메일링 리스트에서 셀 수 없이 많은 격렬한 논의를 거쳐 완성되었으며, 주로 Fredrik Lundh의 유니코드 문자열 타입 구현을 기반으로 Marc-André Lemburg가 구현했습니다. 이 인터페이스에 대한 자세한 설명은 PEP 100, “Python Unicode Integration”으로 작성되었습니다. 본 문서는 유니코드 인터페이스에 관한 가장 중요한 사항들을 다루겠습니다.

파이썬 소스 코드에서 유니코드 문자열은 u"string" 형식으로 작성합니다. 임의의 유니코드 문자는 새로운 이스케이프 시퀀스인 \uHHHH 를 사용하여 쓸 수 있으며, 여기서 HHHH 는 0000부터 FFFF까지의 4자리 16진수 숫자입니다. 기존의 \xHH 이스케이프 시퀀스를 사용할 수도 있고, U+01FF까지의 문자에 대해서는 \777 로 표현되는 팔진수 이스케이프를 사용할 수 있습니다.

유니코드 문자열은 일반 문자열과 마찬가지로 불변 시퀀스 타입입니다. 인덱싱 및 슬라이싱이 가능하지만, 제자리에서 수정할 수는 없습니다. 유니코드 문자열에는 원하는 인코딩으로 8비트 문자열을 반환하는 encode( [encoding] ) 메서드가 있습니다. 인코딩은 ‘ascii’, ‘utf-8’, ‘iso-8859-1’ 등과 같은 문자열로 이름이 지정됩니다. 코덱 API는 새 인코딩을 구현하고 등록하기 위해 정의되며, 이렇게 하여 파이썬 프로그램 전체에서 사용할 수 있게 됩니다. 인코딩이 지정되지 않은 경우, 기본 인코딩은 일반적으로 7비트 ASCII이지만, site.py`의 수정된 버전에서 ``sys.setdefaultencoding(encoding)` 함수를 호출하여 파이썬 설치에 대해 변경할 수 있습니다.

8비트 문자열과 유니코드 문자열을 결합하면 항상 기본 ASCII 인코딩을 사용하여 유니코드로 강제됩니다. 'a' + u'bc' 의 결과는 u'abc' 가 됩니다.

유니코드 지원을 위해 새로운 내장 함수들이 추가되었고, 기존 내장 함수들도 다음과 같이 수정되었습니다:

  • unichr(ch) 은 문자 ch 를 포함하는 1문자 길이의 유니코드 문자열을 반환합니다.

  • ord(u)u 가 1문자의 일반 또는 유니코드 문자열일 경우, 해당 문자를 정수로 나타내는 숫자를 반환합니다.

  • unicode(문자열 [, 인코딩]  [, 오류처리] ) 은 8비트 문자열로부터 유니코드 문자열을 생성합니다. 인코딩 는 사용할 인코딩 이름을 지정하는 문자열입니다. 오류처리 매개변수는 현재 인코딩에 대해 유효하지 않은 문자의 처리를 지정하며, 'strict' 값을 전달하면 모든 인코딩 오류 발생 시 예외가 발생하고, 'ignore' 를 사용하면 오류가 조용히 무시되며, 'replace' 는 문제 발생 시 U+FFFD라는 공식 대체 문자(replacement character)를 사용합니다. 다음 예제들은 그 차이점들을 보여줍니다:

  • exec 구문과, eval(), getattr(), 그리고 setattr() 와 같은 다양한 내장 함수들도 유니코드 문자열뿐만 아니라 일반 문자열도 허용합니다. (이러한 수정 과정에서 간과된 내장 함수가 있을 수 있으니, 문자열을 받지만 유니코드 문자열을 전혀 받지 못하는 내장 함수를 발견하면 버그로 보고해 주십시오.)

새로운 모듈인 unicodedata 는 유니코드 문자 속성에 대한 인터페이스를 제공합니다. 예를 들어, unicodedata.category(u'A') 은 ‘Lu’(글자 L)라는 2문자열을 반환하며, 여기서 ‘L’은 이것이 글자임을 의미하고 ‘u’는 대문자임을 의미합니다. 또한, unicodedata.bidirectional(u'\u0660') 은 ‘AN’, 즉 U+0660가 아랍어 숫자임을 의미합니다.

codecs 모듈에는 기존 인코딩을 찾아보고 새로운 인코딩을 등록하는 함수들이 포함되어 있습니다. 새로운 인코딩을 구현하려는 경우가 아니라면, 대부분 codecs.lookup(encoding) 함수를 사용하게 되며, 이 함수는 4개의 요소를 가진 튜플: (encode_func, decode_func, stream_reader, stream_writer) 를 반환합니다.

  • encode_func 은 유니코드 문자열을 받아 두 요소로 구성된 튜플 (string, length) 을 반환하는 함수입니다. 여기서 string 은 주어지기로 인코딩된 유니코드 문자열의 일부(혹은 전체)를 담고 있는 8비트 문자열이며, length 는 변환된 유니코드 문자열이 얼마나 많은 부분을 차지했는지 알려줍니다.

  • decode_funcencode_func 의 반대 기능을 하며, 8비트 문자열을 받아 결과로 나오는 유니코드 문자열 ustring 과 8비트 문자열 중 얼마나 많은 부분이 소비되었는지 알려주는 정수 length 를 포함하는 두 요소로 구성된 튜플 (ustring, length) 을 반환합니다.

  • stream_reader 는 스트림으로부터 입력을 디코딩(decoding)하는 것을 지원하는 클래스입니다. stream_reader(file_obj)read(), readline(), 그리고 readlines() 메서드를 지원하는 객체를 반환합니다. 이 메서드들은 모두 주어진 인코딩으로 변환하여 유니코드 문자열을 반환할 것입니다.

  • 마찬가지로 stream_writer 는 스트림으로 출력을 인코딩(encoding)하는 것을 지원하는 클래스입니다. stream_writer(file_obj)write()writelines() 메서드를 지원하는 객체를 반환합니다. 이 메서드들은 유니코드 문자열을 예상하며, 출력 시 주어진 인코딩으로 변환합니다.

예를 들어 다음 코드는 유니코드 문자열을 파일에 쓰고 UTF-8로 인코딩합니다:

import codecs

unistr = u'\u0660\u2000ab ...'

(UTF8_encode, UTF8_decode,
 UTF8_streamreader, UTF8_streamwriter) = codecs.lookup('UTF-8')

output = UTF8_streamwriter( open( '/tmp/output', 'wb') )
output.write( unistr )
output.close()

다음 코드는 그 파일에서 UTF-8 입력을 읽습니다:

input = UTF8_streamreader( open( '/tmp/output', 'rb') )
print repr(input.read())
input.close()

Unicode를 인식하는 정규식은 re 모듈을 통해 사용할 수 있으며, 이 모듈에는 Secret Labs AB의 Fredrik Lundh가 작성한 SRE라는 새로운 기반 구현체가 있습니다.

-U 명령줄 옵션이 추가되었는데, 이는 Python 컴파일러가 모든 문자열 리터럴을 유니코드 문자열 리터럴로 해석하게 만듭니다. 이것은 테스트와 사용자 코드의 미래 대비를 위해 사용되도록 의도되었습니다. 왜냐하면 파이썬의 향후 버전에서는 8비트 문자열에 대한 지원을 중단하고 유니코드 문자열만 제공할 수도 있기 때문입니다.

리스트 컴프리헨션

리스트는 파이썬의 핵심 데이터 타입이며, 많은 프로그램에서 리스트를 특정 시점에 조작합니다. 리스트에 대한 두 가지 일반적인 작업은 반복하거나, 특정 기준을 충족하는 요소만 추출하거나, 각 요소에 함수를 적용하는 것입니다. 예를 들어, 문자열 리스트가 주어져 있고 주어진 부분 문자열을 포함하는 모든 문자열을 뽑아내거나, 각 줄의 끝 공백을 제거하고 싶을 수 있습니다.

기존의 map()filter() 함수를 이 목적에 사용할 수 있지만, 이들은 인자 중 하나로 함수를 필요로 합니다. 직접 전달할 수 있는 기존 내장 함수가 있다면 문제는 없지만, 그렇지 않다면 필요한 작업을 수행하는 작은 함수를 작성해야 하는데, 파이썬의 스코핑 규칙상 그 작은 함수가 추가 정보를 필요로 할 경우 결과가 지저분해집니다. 이전 단락의 첫 번째 예시인 리스트에서 주어진 부분 문자열을 포함하는 모든 문자열을 찾는 것을 가져와서 이 과정을 수행할 수 있습니다:

[msgid]
# Given the list L, make a list of all strings
# containing the substring S.
sublist = filter( lambda s, substring=S:
                     string.find(s, substring) != -1,
                  L)
[msgstr]
[msgstr]
# 리스트 L을 받아 부분 문자열 S를 포함하는 모든 문자열의 리스트로 만듭니다.
sublist = filter( lambda s, substring=S:
                     string.find(s, substring) != -1,
                  L)

[msgid] Because of Python’s scoping rules, a default argument is used so that the anonymous function created by the lambda expression knows what substring is being searched for. List comprehensions make this cleaner:: [msgstr] 파이썬의 스코핑 규칙 때문에, 익명 함수가 lambda 표현시에 어떤 부분 문자열이 검색되는지 알 수 있도록 기본 인자가 사용됩니다. 리스트 컴프리헨션은 이를 더 깔끔하게 만듭니다:

[msgid]
sublist = [ s for s in L if string.find(s, S) != -1 ]
[msgstr]
sublist = [ s for s in L if string.find(s, S) != -1 ]

[msgid] List comprehensions have the form:: [msgstr] 리스트 컴프리헨션은 다음과 같은 형태를 가집니다:

[ expression for expr in sequence1
             for expr2 in sequence2 ...
             for exprN in sequenceN
             if condition ]

[msgid] The forin clauses contain the sequences to be iterated over. The sequences do not have to be the same length, because they are not iterated over in parallel, but from left to right; this is explained more clearly in the following paragraphs. The elements of the generated list will be the successive values of expression. The final if clause is optional; if present, expression is only evaluated and added to the result if condition is true. [msgstr] forin 절은 반복할 시퀀스들을 포함합니다. 이 시퀀스들은 병렬로 (not) 반복되는 것이 아니라 왼쪽에서 오른쪽으로 반복되기 때문에 같은 길이를 가질 필요는 없습니다. 이는 다음 단락에서 더 명확하게 설명됩니다. 생성된 리스트의 요소들은 expression 의 연속적인 값들입니다. 마지막 if 절은 선택 사항이며, 존재할 경우 condition 이 참일 때만 expression 이 평가되어 결과에 추가됩니다.

[msgid] To make the semantics very clear, a list comprehension is equivalent to the following Python code:: [msgstr] 세미한 의미를 매우 명확하게 하기 위해, 리스트 컴프리헨션은 다음 파이썬 코드와 동등합니다:

[msgid]
for expr1 in sequence1:
    for expr2 in sequence2:
    ...
        for exprN in sequenceN:
             if (condition):
                  # Append the value of
                  # the expression to the
                  # resulting list.
[msgstr]
for expr1 in sequence1:
    for expr2 in sequence2:
    ...
        for exprN in sequenceN:
             if (condition):
                  # 표현식의 값을
                  # 결과 리스트에 추가합니다.

[msgid] This means that when there are multiple forin clauses, the resulting list will be equal to the product of the lengths of all the sequences. If you have two lists of length 3, the output list is 9 elements long:: [msgstr] 이는 여러 개의 forin 절이 있을 때, 결과 리스트가 모든 시퀀스 길이의 곱과 같다는 것을 의미합니다. 길이가 3인 두 개의 리스트가 있는 경우, 출력 리스트는 9개의 요소를 가집니다:

seq1 = 'abc'
seq2 = (1,2,3)
>>> [ (x,y) for x in seq1 for y in seq2]
[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1),
('c', 2), ('c', 3)]

[msgid] To avoid introducing an ambiguity into Python’s grammar, if expression is creating a tuple, it must be surrounded with parentheses. The first list comprehension below is a syntax error, while the second one is correct:: [msgstr] 파이썬 문법에 모호성을 도입하는 것을 피하기 위해, 만약 expression 이 튜플을 생성하고 있다면, 반드시 괄호로 둘러싸여야 합니다. 아래의 첫 번째 리스트 컴프리헨션은 구문 오류이고, 두 번째 것은 올바릅니다:

[msgid]
# Syntax error
[ x,y for x in seq1 for y in seq2]
# Correct
[ (x,y) for x in seq1 for y in seq2]
[msgstr]
# 구문 오류
[ x,y for x in seq1 for y in seq2]
# 올바릅니다
[ (x,y) for x in seq1 for y in seq2]

[msgid] The idea of list comprehensions originally comes from the functional programming language Haskell (https://www.haskell.org). Greg Ewing argued most effectively for adding them to Python and wrote the initial list comprehension patch, which was then discussed for a seemingly endless time on the python-dev mailing list and kept up-to-date by Skip Montanaro. [msgstr] 리스트 컴프리헨션의 아이디어는 원래 함수형 프로그래밍 언어인 Haskell(https://www.haskell.org)에서 왔습니다. Greg Ewing은 파이썬에 이를 추가하는 것에 대해 가장 효과적으로 주장했고, 최초의 리스트 컴프리헨션 패치를 작성했으며, 이것은 그 후 python-dev 메일링 리스트에서 끝없이 논의되었고 Skip Montanaro에 의해 최신 상태로 유지되었습니다.

[msgid] Augmented Assignment [msgstr] 증분 대입

[msgid] Augmented assignment operators, another long-requested feature, have been added to Python 2.0. Augmented assignment operators include +=, -=, *=, and so forth. For example, the statement a += 2 increments the value of the variable a by 2, equivalent to the slightly lengthier a = a + 2. [msgstr] 증분 대입 연산자는 오랫동안 요청되었던 또 다른 기능으로, Python 2.0에 추가되었습니다. 증분 대입 연산자에는 +=, -=, *= 등이 포함됩니다. 예를 들어, 구문 a += 2 는 변수 a 의 값을 2만큼 증가시키며, 이는 약간 더 길지만 동일한 a = a + 2 와 같습니다.

The full list of supported assignment operators is +=, -=, *=, /=, %=, **=, &=, |=, ^=, >>=, and <<=. Python classes can override the augmented assignment operators by defining methods named __iadd__(), __isub__(), etc. For example, the following Number class stores a number and supports using += to create a new instance with an incremented value.

class Number:
    def __init__(self, value):
        self.value = value
    def __iadd__(self, increment):
        return Number( self.value + increment)

n = Number(5)
n += 3
print n.value

The __iadd__() special method is called with the value of the increment, and should return a new instance with an appropriately modified value; this return value is bound as the new value of the variable on the left-hand side.

[msgid] Augmented assignment operators were first introduced in the C programming language, and most C-derived languages, such as awk, C++, Java, Perl, and PHP also support them. The augmented assignment patch was implemented by Thomas Wouters. [msgstr] 증분 대입 연산자는 처음에는 C 프로그래밍 언어에 도입되었으며, awk, C++, Java, Perl, PHP와 같은 대부분의 C 기반 언어도 이를 지원합니다. 증분 대입 패치는 Thomas Wouters가 구현했습니다.

[msgid] String Methods [msgstr] 문자열 메서드

지금까지 문자열 조작 기능은 일반적으로 C로 작성된 string 모듈에 있었으며, 이것은 보통 strop 모듈의 프런트엔드 역할을 했습니다. 유니코드의 추가는 strop 모듈에 어려움을 주었는데, 그 이유는 함수들이 8-비트 문자열이나 유니코드 문자열을 모두 허용하도록 다시 작성되어야 했기 때문입니다. 세 개의 문자열 인수를 받는 :func:`!string.replace`와 같은 함수는 여덟 가지 가능한 순열을 의미하며, 이는 복잡한 코드 구조를 요구합니다.

대신 파이썬 2.0은 문제를 문자열 타입으로 옮기면서, 문자열 조작 기능을 8-비트 문자열과 유니코드 문자열 모두의 메서드를 통해 사용 가능하게 했습니다.

>>> 'andrew'.capitalize()
'Andrew'
>>> 'hostname'.replace('os', 'linux')
'hlinuxtname'
>>> 'moshe'.find('sh')
2

변화하지 않은 점 중 하나는 주목할 만한 에이프일즈식 장난과는 별개로, 파이썬 문자열은 불변하다는 것입니다. 따라서 문자열 메서드는 새로운 문자열을 반환하며, 자신에게 작동하는 문자열을 수정하지 않습니다.

오래된 string 모듈도 하위 호환성을 위해 남아 있지만, 주로 새로운 문자열 메서드의 프런트엔드 역할을 합니다.

2.0 버전 이전에 병렬로 존재하지 않았지만, 상당히 오랫동안 JPython에서 존재했던 두 가지 메서드는 startswith()endswith() 입니다. s.startswith(t)s[:len(t)] == t 와 동일하며, s.endswith(t)s[-len(t):] == t 와 같습니다.

특별히 언급할 가치가 있는 또 다른 메서드는 join() 입니다. 문자열의 join() 메서드는 단일 매개변수, 즉 문자열 시퀀스를 받으며, 인자 순서만 반대로 한 옛날 string 모듈의 string.join() 함수와 동일합니다. 다시 말해, s.join(seq) 는 이전의 old string.join(seq, s) 와 동일합니다.

순환 가비지 수거 (Garbage Collection of Cycles)

파이썬의 C 구현은 참조 카운팅을 사용하여 가비지 컬렉션을 구현합니다. 모든 파이썬 객체는 자신을 가리키는 참조 횟수를 유지하며, 참조가 생성되거나 파괴될 때마다 이 횟수를 조정합니다. 참조 횟수가 0에 도달하면 해당 객체는 더 이상 접근할 수 없게 됩니다. 왜냐하면 객체에 접근하려면 그 객체에 대한 참조가 필요하고, 카운트가 0이면 더 이상의 참조가 존재하지 않기 때문입니다.

참조 횟수는 다음과 같은 장점을 가지고 있습니다: 이해하고 구현하기 쉽고, 그 결과로 나온 구현은 이식성이 좋고, 상당히 빠르며, 자체 메모리 처리 체계를 구현하는 다른 라이브러리와도 잘 반응합니다. 참조 횟수의 주요 문제는 가끔 객체가 더 이상 접근할 수 없다는 사실을 인지하지 못하여 메모리 누수가 발생한다는 것입니다. 이는 참조 사이클이 있을 때 발생합니다.

자기 자신을 참조하는 클래스 인스턴스의 가장 간단한 순환 구조를 고려해 봅시다:

instance = SomeClass()
instance.myself = instance

위의 두 줄 코드가 실행된 후, instance``의 참조 횟수는 2입니다. 하나의 참조는 ``'instance'``라는 변수로부터 오고, 다른 하나는 인스턴스의 ``myself 속성에서 옵니다.

만약 다음 코드가 del instance``라면 어떻게 될까요? ``instance``의 참조 횟수는 1 감소하여, 참조 횟수는 1이 됩니다; ``myself 속성의 참조는 여전히 존재합니다. 그러나 인스턴스는 더 이상 파이썬 코드를 통해 접근할 수 없게 되었고 삭제될 수 있습니다. 객체들이 서로를 참조하는 경우 여러 객체가 순환 구조에 참여하여 모든 객체가 누수될 수 있습니다.

파이썬 2.0은 주기적으로 비접근 가능한 사이클을 찾는 탐지 알고리thm을 실행함으로써 이 문제를 해결하며, 관련된 객체들을 삭제합니다. 새로운 gc 모듈은 가비지 컬렉션을 수행하고, 디버깅 통계를 얻고, 컬렉터의 매개변수를 조정하기 위한 함수를 제공합니다.

순환 감지 알고리즘 실행에는 시간이 걸리기 때문에 추가 오버헤드가 발생합니다. Python 2.0을 사용한 순환 수집 경험을 통해, Python 2.1에서는 신중하게 조정하여 오버헤드를 최소화할 수 있기를 기대합니다. 성능 저하가 얼마나 될지는 명확하지 않은데, 이는 벤치마킹하기 까다롭고 프로그램이 객체를 생성하고 파괴하는 빈도에 결정적으로 달려 있기 때문입니다. 만약 아주 작은 속도 저하조차 감당할 수 없거나 순환 수집에 문제가 있다고 의심된다면, configure 스크립트를 실행할 때 --without-cycle-gc 스위치를 지정하여 Python 컴파일 시점에 순환 감지를 비활성화할 수 있습니다.

이 문제는 여러 사람이 해결하려고 노력하며 솔루션에 기여했습니다. 초기 순환 감지 접근 방식 구현은 Toby Kelsey가 작성했습니다. 현재 알고리즘은 Eric Tiedemann이 CNRI 방문 중에 제안했으며, Guido van Rossum과 Neil Schemenauer는 서로 다른 두 개의 구현을 작성했고 이는 나중에 Neil에 의해 통합되었습니다. 그 과정에서 많은 사람들이 의견을 제시했습니다. python-dev 메일링 목록의 2000년 3월 보관소에는 “Reference cycle collection for Python” 및 “Finalization again”이라는 제목의 스레드에 특히 관련 토론 내용이 가장 많이 담겨 있습니다.

기타 핵심 변경 사항

Python의 구문 및 내장 함수에 다양한 사소한 변경이 이루어졌습니다. 이 변경 사항들은 크게 와닿지 않지만 편리하게 사용할 수 있습니다.

사소한 언어 변경 사항

새로운 구문은 주어진 함수를 튜플 형태의 인자 및/또는 키워드 인자 딕셔너리로 호출하는 것을 더 편리하게 만듭니다. Python 1.5 이전에는 apply() 내장 함수를 사용해야 했습니다: apply(f, args, kw) 는 함수 f() 에 인자 튜플 args 와 딕셔너리 kw 의 키워드 인자를 호출합니다. apply() 는 2.0에서도 동일하지만, Greg Ewing의 패치 덕분에 f(*args, **kw) 가 같은 효과를 얻는 더 짧고 명확한 방법입니다. 이 구문은 함수 정의의 구문과 대칭적입니다:

def f(*args, **kw):
    # args는 위치 인자 튜플이고,  # kw는 키워드 인자 딕셔너리입니다.
    ...

print 문은 이제 Unix 쉘의 리디렉션 연산자와 유사하게 print 뒤에 >> file`를 추가하여 파일 같은 객체로 출력 방향을 지정할 수 있습니다. 이전에는 출력을 간편성과 단순성이 떨어지는 파일 같은 객체의 :meth:!write` 메서드를 사용하거나, `sys.stdout`에 새 값을 할당한 다음 기존 값을 복구해야 했습니다. 표준 오류(standard error)로 출력을 보내는 것이 훨씬 쉽습니다:

print >> sys.stderr, "Warning: action field not supplied"

모듈을 임포트할 때 import module as name 또는 from module import name as othername 구문을 사용하여 이름 변경할 수 있습니다. 이 패치는 Thomas Wouters가 제출했습니다.

% 연산자를 사용할 때 새로운 형식 스타일이 제공됩니다. ‘%r’는 인자의 repr() 을 삽입합니다. 이것은 기존의 str() 을 삽입하는 ‘%s’ 형식 스타일과의 대칭성 고려로 추가되었습니다. 예를 들어, '%r %s' % ('abc', 'abc')'abc' abc 를 포함하는 문자열을 반환합니다.

이전에는 Python의 내장 in 연산자를 오버라이드하고 커스텀 버전을 구현하는 클래스를 만들 방법이 없었습니다. obj in seqobj 가 시퀀스 seq 에 존재하는 경우 true를 반환합니다. Python은 이 작업을 수행하기 위해 obj 가 발견될 때나 IndexError 가 발생할 때까지 시퀀스의 모든 인덱스를 간단히 시도하여 계산합니다. Moshe Zadka가 in 에 대한 커스텀 구현을 제공하는 __contains__() 매직 메소드를 추가한 패치를 기여했습니다. 또한, C로 작성된 새로운 내장 객체는 시퀀스 프로토콜의 새 슬롯을 통해 해당 객체에 in 이 무엇을 의미하는지 정의할 수 있습니다.

이전 버전의 Python은 객체를 삭제하기 위해 재귀 알고리즘을 사용했습니다. 깊게 중첩된 데이터 구조는 인터프리터를 C 스택으로 가득 채워 충돌하게 할 수 있었습니다.; Christian Tismer가 이 문제를 해결하기 위해 삭제 로직을 다시 작성했습니다. 관련해서, 재귀 개체 비교 시 무한 재귀에 빠져 충돌하기도 했으며; Jeremy Hylton이 코드를 수정하여 더 이상 충돌하지 않고 유용한 결과를 생성하도록 했습니다. 예를 들어, 다음 코드 이후에:

a = []
b = []
a.append(a)
b.append(b)

비교 a==b 는 두 재귀 데이터 구조가 동형이기 때문에 true를 반환합니다. 이 구현으로 이어지는 논의와 유용한 관련 링크는 2000년 4월 python-dev 메일링 리스트 보관소의 “trashcan and PR#7” 스레드를 참조하십시오. 참고로 비교 연산도 이제 예외를 발생시킬 수 있습니다. Python의 초기 버전에서는 cmp(a,b) 와 같은 비교 연산이 사용자 정의 __cmp__() 메서드가 오류를 만나더라도 항상 답변을 제공하는 경향이 있었는데, 이는 결과 예외가 단순히 조용히 무시되었기 때문입니다.

Python을 Itanium 프로세서의 64비트 Windows로 포팅하는 작업이 완료되었습니다. 이는 주로 ActiveState의 Trent Mick에 의해 진행되었습니다. (혼란스럽게도, sys.platform 는 Win64에서 “win32”를 유지하는데, 이는 포팅 편의상 MS Visual C++가 Itanium에서 코드를 32비트로 처리하는 것 같습니다.) PythonWin은 Windows CE도 지원하며; 더 자세한 정보는 https://pythonce.sourceforge.net/ 의 Python CE 페이지를 참조하십시오.

또 다른 새로운 플랫폼은 Darwin/MacOS X입니다. 초기 지원은 Python 2.0부터 이루어졌습니다. 동적 로딩이 작동하며, “configure –with-dyld –with-suffix=.x”로 지정할 수 있습니다. 더 많은 지침은 Python 소스 배포판의 README를 참조하십시오.

코드에서 변수가 값을 할당받기 전에 로컬 변수를 참조할 때 자주 혼란을 주는 NameError 예외를 완화하려는 시도가 있었습니다. 예를 들어, 다음 코드는 1.5.2와 2.0 모두의 print 구문에서 예외를 발생시킵니다.; 1.5.2에서는 NameError 예외가 발생하고, 2.0에서는 새로운 UnboundLocalError 예외가 발생합니다. :exc:`UnboundLocalError`는 :exc:`NameError`의 서브 클래스이므로, :exc:`NameError`가 발생할 것으로 예상하는 기존 코드는 여전히 작동해야 합니다:

def f():
    print "i=",i
    i = i + 1
f()

두 가지 새로운 예외인 :exc:`TabError`와 :exc:`IndentationError`가 도입되었습니다. 둘 다 :exc:`SyntaxError`의 서브 클래스이며, Python 코드가 잘못 들여쓰기된 것으로 발견될 때 발생합니다.

내장 함수 변경 사항

새로운 내장 함수 zip(seq1, seq2, ...) 가 추가되었습니다. zip() 은 각 인자 시퀀스에서 i번째 요소를 포함하는 튜플 목록을 반환합니다. zip()map(None, seq1, seq2) 의 차이점은, 시퀀스가 모두 같은 길이가 아닌 경우 map() 은 시퀀스를 None 으로 패딩하는 반면, zip() 은 반환된 목록을 가장 짧은 인자 시퀀스의 길이로 자릅니다.

int()long() 함수는 이제 첫 번째 인수가 문자열인 경우 선택적 “base” 매개변수를 받습니다. int('123', 10) 은 123을 반환하는 반면, int('123', 16) 은 291을 반환합니다. int(123, 16) 은 “can’t convert non-string with explicit base”라는 메시지를 가진 TypeError 예외를 발생시킵니다.

sys 모듈에 더 상세한 버전 정보를 담는 새로운 변수가 추가되었습니다. sys.version_info 는 튜플 (major, minor, micro, level, serial) 입니다. 예를 들어, 가상의 2.0.1beta1의 경우, sys.version_info(2, 0, 1, 'beta', 1) 이 됩니다. level 은 최종 릴리스의 경우 “alpha”, “beta”, 또는 “final”와 같은 문자열입니다.

딕셔너리는 기존 get() 메서드와 유사하게 작동하는 새로운 메서드 setdefault(key, default) 를 가집니다. 하지만 키가 누락된 경우, setdefault()default 의 값을 반환할 뿐만 아니라 get() 처럼 해당 키에 대해 그 값을 딕셔너리에 삽입합니다. 따라서 다음 코드 라인:

if dict.has_key( key ): return dict[key]
else:
    dict[key] = []
    return dict[key]

단일 return dict.setdefault(key, []) 구문으로 줄일 수 있습니다.

인터프리터는 C 스택을 가득 채우고 코어 덤프나 GPF를 유발하기 전에 무한 재귀를 포착할 수 있도록 최대 재귀 깊이를 설정합니다. 이전에 이 한계는 Python을 컴파일할 때 고정되었었지만, 2.0에서는 sys.getrecursionlimit() 및 :func:`sys.setrecursionlimit`을 사용하여 최대 재귀 깊이를 읽고 수정할 수 있습니다. 기본값은 1000이며, 주어진 플랫폼에 대한 대략적인 최대값은 새로운 스크립트인 :file:`Misc/find_recursionlimit.py`를 실행하여 찾을 수 있습니다.

2.0으로 포팅하기

새로운 Python 릴리스는 이전 릴리스와의 호환성을 유지하려고 노력하며, 그 기록은 매우 좋았습니다. 하지만 때로는 초기 디자인 결정이 실제로 잘못된 것으로 판명되어 수정되는 등 유용한 변경 사항들이 존재하기 때문에, 하위 호환성 파기가 항상 피할 수 있는 것은 아닙니다. 이 섹션에서는 이전 Python 코드의 동작을 중단시킬 수 있는 Python 2.0의 변경 사항들을 나열합니다.

가장 많은 코드를 깨뜨릴 가능성이 높은 변화는 일부 메서드에서 받아들이는 인자들을 엄격하게 제어한 것입니다. 어떤 메서드는 여러 인자를 받아서 튜플로 취급했는데, 특히 append()0에서는 이로 인해 'append requires exactly 1 argument; 2 given'라는 메시지를 포함하는 :exc:`TypeError() 예외가 발생합니다. 해결책은 두 값을 모두 튜플로 전달하기 위해 단순히 여분의 한 쌍의 소괄호를 추가하는 것입니다: L.append( (1,2) ).

이러한 메서드들의 이전 버전은 인자를 파싱하기 위해 Python의 C 인터페이스에서 오래된 함수를 사용했기 때문에 더 관대했습니다. 2.0에서는 현재 인자 파싱 함수인 PyArg_ParseTuple() 을 사용하도록 현대화되었으며, 이는 더 유용한 오류 메시지를 제공하고 다중 인자 호출을 오류로 처리합니다. 만약 절대적으로 2.0을 사용해야 하지만 코드를 수정할 수 없다면, Objects/listobject.c 를 편집하고 오래된 동작을 보존하기 위해 전처리기 심볼 NO_STRICT_LIST_APPEND 을 정의하여 사용할 수 있습니다. 하지만 이는 권장되지 않습니다.

socket 모듈의 일부 함수들은 여전히 이런 방식으로 관대합니다. 예를 들어, IP 주소를 나타내는 튜플을 전달하는 socket.connect_( ('hostname', 25) ) 가 올바른 형식이며, socket.connect_('hostname', 25) 도 작동합니다. socket.connect_exsocket.bind 역시 비슷하게 관대했습니다. 2.0alpha1에서 이 함수들이 엄격해졌지만, 문서가 사실상 오류가 있는 다중 인자 형식을 사용했기 때문에 많은 사람들이 더 엄격한 검사로 인해 깨지게 되는 코드를 작성했습니다. GvR은 대중의 반응에 직면하여 변경 사항을 철회했으므로, socket 모듈의 문서는 수정되었고 다중 인자 형식은 단순히 ‘사용 중단됨’으로 표시되었습니다. 이는 향후 Python 버전에서 다시 엄격하게 조정될 예정 입니다.

문자열 리터럴의 \x 이스케이프는 이제 정확히 2개의 16진수 자릿수를 사용합니다. 이전에는 ‘x’ 뒤따르는 모든 16진수 자릿수를 소비하고 결과값의 최하위 8비트를 취했기 때문에, \x123456\x56 과 동등했습니다.

AttributeErrorNameError 예외는 더 사용자 친화적인 오류 메시지를 가집니다. 이 메시지의 내용은 ‘Spam’ instance has no attribute ‘eggs’ 또는 name ‘eggs’ is not defined와 유사할 것입니다. 이전에는 오류 메시지가 누락된 속성 이름 eggs 만이었기 때문에, 이를 활용하여 작성된 코드는 2.0에서 깨지게 됩니다.

정수 및 긴 정수가 다소 상호 교환 가능하게 변경하는 작업이 진행되었습니다. 1.5.2 버전에서는 Solaris용 대용량 파일 지원이 추가되어 2 GiB보다 큰 파일을 읽을 수 있게 되었습니다. 이로 인해 파일 객체의 tell() 메서드가 일반 정수 대신 긴 정수를 반환하게 되었습니다. 일부 코드는 두 파일 오프셋을 빼서 결과를 시퀀스에 곱하거나 문자열 슬라이싱하는 데 사용하려고 했으나, 이는 TypeError 를 발생시켰습니다. 2.0에서는 긴 정수를 사용하여 시퀀스를 곱하거나 슬라이싱할 수 있으며 직관적으로 예상되는 대로 동작합니다; 3L * 'abc' 는 ‘abcabcabc’를 생성하고, (0,1,2,3)[2L:4L] 는 (2,3)을 생성합니다. 또한 긴 정수는 이전에 오직 정수만 허용되었던 여러 컨텍스트, 예를 들어 파일 객체의 seek() 메서드나 % 연산자가 지원하는 서식(%d, %i, %x 등)에서 사용할 수 있습니다. 예를 들어, "%d" % 2L**64 는 문자열 18446744073709551616 를 생성합니다.

가장 미묘한 긴 정수 변경 사항은 str() 이 더 이상 끝에 ‘L’ 문자를 가지지 않게 되었다는 것인데, 비록 repr() 에는 아직 포함되어 있습니다. 결정을 위해 그 문자를 제거해야 했기 때문에 긴 정수를 일반 정수처럼 보이도록 인쇄하고 싶었던 많은 사람들에게 ‘L’은 거슬렸습니다. 2.0에서는 더 이상 문제가 아니지만, str(longval)[:-1] 를 수행하고 ‘L’이 있다고 가정하는 코드는 이제 마지막 숫자를 잃게 될 것입니다.

Float의 repr() 을 가져오는 것은 str() 과 이제 다른 포맷팅 정밀도를 사용합니다. repr() 은 C의 sprintf() 에 대해 %.17g 형식 문자열을 사용하며, 반면 str() 은 이전처럼 %.12g 를 사용합니다. 그 결과, 일부 숫자들에 대해 repr()str() 보다 더 많은 소수점 자릿수를 표시할 수 있습니다. 예를 들어, 숫자 8.1은 이진수로 정확하게 표현될 수 없으므로, repr(8.1) 는 ‘8.0999999999999996’이고, str(8.1)은 ‘8.1’입니다.

모든 표준 예외를 클래스 대신 문자열로 변경했던 -X 명령줄 옵션이 제거되었으며, 이제 표준 예외는 항상 클래스가 될 것입니다. 표준 예외를 포함하는 exceptions 모듈은 Barry Warsaw와 Fredrik Lundh가 작성한 파이썬에서 내장 C 모듈로 번역되었습니다.

확장/내장 변경 사항

일부 변경 사항은 내부적으로 처리되어 C 확장 모듈을 작성하거나 더 큰 애플리케이션에 파이썬 인터프리터를 임베딩하는 사람들에게만 나타날 것입니다. 파이썬의 C API와 관련되지 않은 경우, 이 섹션은 안전하게 건너뛰셔도 됩니다.

파이썬 C API의 버전 번호가 증가했으므로 1.5.2 용으로 컴파일된 C 확장은 2.0에서 사용하려면 다시 컴파일해야 합니다. Windows에서는 DLL 작동 방식 때문에 Python 2.0이 Python 1.5.x용으로 빌드된 타사 확장 모듈을 가져오는 것이 불가능하므로, Python은 예외를 발생시키고 임포트가 실패할 것입니다.

Jim Fulton의 ExtensionClass 모듈 사용자는 이제 훅이 추가되어 ExtensionClasses가 isinstance()issubclass() 모두에서 지원됨을 알게 되어 기뻐할 것입니다. 이는 if type(obj) == myExtensionClass 와 같은 코드를 기억해야 할 필요가 없다는 것을 의미하며, 대신 더 자연스러운 if isinstance(obj, myExtensionClass) 를 사용할 수 있습니다.

다양한 플랫폼에서 동적 로딩을 지원하기 위한 많은 #ifdef들이었던 Python/importdl.c 파일은 Greg Stein에 의해 정리되고 재구성되었습니다. importdl.c`는 이제 상당히 작아졌고, 플랫폼별 코드는 여러 개의 :file:`Python/dynload_*.c 파일로 이동했습니다. 또 다른 정리 사항: Include/ 디렉토리에는 다양한 이식성 꼼수(portability hacks)를 담은 my*.h 파일들도 있었는데, 이는 단일 파일인 :file:`Include/pyport.h`로 병합되었습니다.

Vladimir Marangozov가 오랫동안 기다려온 malloc 재구조화가 완료되어 파이썬 인터프리터가 C의 표준 malloc() 대신 사용자 정의 할당자를 사용할 수 있게 되었습니다. 문서의 경우, :file:`Include/pymem.h`와 :file:`Include/objimpl.h`의 주석을 읽으십시오. 이 인터페이스가 확정되는 동안의 길고 자세한 토론 내용은 python.org의 ‘patches’ 및 ‘python-dev’ 목록 웹 아카이브를 참조하십시오.

MacOS용 GUSI 개발 환경의 최신 버전은 POSIX 스레드를 지원합니다. 따라서 파이썬의 POSIX 스레딩 지원 기능이 이제 매킨토시에서도 작동합니다. 사용자 공간 GNU pth 라이브러리를 사용한 스레딩 지원도 기여되었습니다.

윈도우에서의 스레딩 지원 또한 향상되었습니다. 윈도우는 경합이 발생하는 경우에만 커널 객체를 사용하는 스레드 잠금을 지원하며, 일반적인 경쟁 상황에서는 속도가 한 자릿수(order of magnitude) 더 빠른 단순 함수를 사용합니다. NT용 Python 1.5.2의 스레드 버전은 비스레드 버전보다 두 배 느리고; 2.0 변경 사항 덕분에 차이는 단지 10%에 불과합니다. 이 개선 사항들은 Yakov Markovitch가 기여했습니다.

Python 2.0의 소스 코드는 이제 ANSI C 프로토타입만 사용하므로, 파이썬을 컴파일하려면 이제 ANSI C 컴파일러가 필요하며 K&R C만을 지원하는 컴파일러를 사용하는 것은 불가능합니다.

이전에 Python 가상 머신은 바이트 코드에 16비트 숫자를 사용하여 소스 파일의 크기를 제한했습니다. 특히, 이는 파이썬 소스에서 리터럴 리스트와 딕셔너리의 최대 크기에 영향을 미쳤습니다. 때때로 파이썬 코드를 생성하는 사람들이 이 제한에 부딪히곤 했습니다. Charles G. Waldman의 패치는 제한을 2**16 에서 2**32 까지 높였습니다.

모듈 초기화 시간에 모듈 딕셔너리에 상수를 추가하기 위해 세 가지 새로운 편의 함수가 추가되었습니다: PyModule_AddObject(), PyModule_AddIntConstant(), 및 :c:func:`PyModule_AddStringConstant`입니다. 각 함수는 모듈 객체, 추가할 이름을 포함하는 널 종료 C 문자열, 그리고 이름에 할당될 값을 위한 세 번째 인수를 받습니다. 이 세 번째 인수는 각각 파이썬 객체, C long, 또는 C 문자열입니다.

유닉스 스타일 시그널 핸들러를 위해 래퍼 API가 추가되었습니다. :c:func:`PyOS_getsig`는 시그널 핸들러를 가져오고 :c:func:`PyOS_setsig`는 새 핸들러를 설정합니다.

Distutils: 모듈을 쉽게 설치하기로 만들기

Python 2.0 이전에 모듈을 설치하는 것은 번거로운 일이었습니다. 파이썬이 어디에 설치되었는지, 또는 확장 모듈에 사용할 컴파일러 옵션이 무엇인지 자동으로 알아낼 방법이 없었습니다. 소프트웨어 작성자들은 Makefiles와 설정 파일을 수정하는 어려운 의식을 거쳐야 했으며, 이는 유닉스에서만 실제로 작동하고 윈도우와 MacOS는 지원되지 않았습니다. 파이썬 사용자는 여러 확장 패키지마다 크게 다른 설치 지침에 직면하여, 파이썬 설치 관리가 다소 번거로운 일이었습니다.

배포 유틸리티를 담당하는 Greg Ward가 Distutils를 만들었으며, 이는 패키지 설치를 훨씬 쉽게 만드는 시스템입니다. 이들은 파이썬 표준 라이브러리의 새로운 부분인 distutils 패키지를 형성합니다. 최상의 경우, 소스에서 파이썬 모듈을 설치하려면 동일한 단계를 필요로 합니다: 먼저 단순히 tarball이나 zip 압축 파일을 풀어야 하고, 다음으로 “python setup.py install”을 실행하면 됩니다. 플랫폼은 자동으로 감지되고, 컴파일러가 인식되며, C 확장 모듈이 컴파일되고, 배포판이 적절한 디렉토리에 설치됩니다. 선택적 명령줄 인수는 설치 과정에 대한 더 많은 제어 기능을 제공하며, distutils 패키지는 기본값을 재정의할 수 있는 여러 위치를 제공합니다. 빌드와 설치 분리, 비기본 디렉토리에서 빌드 또는 설치 등이 있습니다.

Distutils를 사용하려면 setup.py 스크립트를 작성해야 합니다. 소프트웨어에 .py 파일만 포함되는 간단한 경우, 최소한의 :file:`setup.py`는 몇 줄로 충분합니다:

from distutils.core import setup
setup (name = "foo", version = "1.0",
       py_modules = ["module1", "module2"])

소프트웨어가 몇 개의 패키지로 구성되어 있다면 setup.py 파일은 그렇게 복잡하지 않습니다:

from distutils.core import setup
setup (name = "foo", version = "1.0",
       packages = ["package", "package.subpackage"])

C 확장 기능이 가장 복잡한 케이스일 수 있습니다. 여기는 PyXML 패키지에서 가져온 예시입니다:

from distutils.core import setup, Extension

expat_extension = Extension('xml.parsers.pyexpat',
     define_macros = [('XML_NS', None)],
     include_dirs = [ 'extensions/expat/xmltok',
                      'extensions/expat/xmlparse' ],
     sources = [ 'extensions/pyexpat.c',
                 'extensions/expat/xmltok/xmltok.c',
                 'extensions/expat/xmltok/xmlrole.c', ]
       )
setup (name = "PyXML", version = "0.5.4",
       ext_modules =[ expat_extension ] )

Distutils 또한 소스 및 바이너리 배포본을 만드는 작업을 처리할 수 있습니다. “python setup.py sdist”로 실행되는 “sdist” 명령어는 foo-1.0.tar.gz`와 같은 소스 배포판을 빌드합니다. 새로운 명령어를 추가하는 것은 어렵지 않으며, "bdist_rpm" "bdist_wininst" 명령어는 각각 RPM 배포판과 소프트웨어용 Windows 설치 관리자를 생성하도록 기여되어 왔습니다. Debian 패키지 Solaris :file:.pkg` 파일과 같은 다른 배포 형식의 명령은 개발 과정에 있습니다.

이 모든 내용은 기본적인 Python 설명서와 통합되는 새 매뉴얼인 Distributing Python Modules 에 문서화되어 있습니다.

XML 모듈

Python 1.5.2는 Sjoerd Mullender가 기여한 xmllib 모듈 형태로 간단한 XML 파서를 포함했습니다. 1.5.2 버전 출시 이후로, XML 처리를 위한 두 가지 다른 인터페이스가 일반화되었습니다: SAX2 (Simple API for XML의 버전 2)는 xmllib`와 유사성이 있는 이벤트 기반 인터페이스를 제공하며, DOM(Document Object Model)은 XML 문서를 순회 수정할 있는 노드 트리를 제공하는 트리 기반 인터페이스를 제공합니다. Python 2.0에는 :mod:`xml 패키지의 일부로 SAX2 인터페이스와 축소된 DOM 인터페이스가 포함되어 있습니다. 여기서는 이 새로운 인터페이스들에 대한 간략한 개요를 제공할 것입니다. 전체 세부 정보는 Python 설명을 참조하거나 소스 코드를 확인하십시오. 또한, Python XML SIG도 개선된 문서를 작업하고 있습니다.

SAX2 지원

SAX는 XML 구문 분석을 위한 이벤트 기반 인터페이스를 정의합니다. SAX를 사용하려면 SAX 핸들러 클래스를 작성해야 합니다. 핸들러 클래스는 SAX에서 제공하는 다양한 클래스들을 상속받고, XML 파서에 의해 호출될 여러 메서드를 오버라이드합니다. 예를 들어, startElement()endElement() 메서드는 파서가 만나는 시작/끝 태그마다 호출되며, characters() 메서드는 문자 데이터의 모든 청크에 대해 호출됩니다.

이벤트 기반 접근 방식의 장점은 전체 문서가 어느 한 시점에 메모리에 상주할 필요가 없다는 것입니다. 이는 정말 큰 문서를 처리하는 경우 중요합니다. 그러나 관련성 있는 방식으로 문서 구조를 수정하려고 하면 SAX 핸들러 클래스를 작성하기가 매우 복잡해질 수 있습니다.

예를 들어, 이 작은 예제 프로그램은 시작 및 끝 태그마다 메시지를 출력하는 핸들러를 정의하고, 이를 사용하여 파일 :file:`hamlet.xml`을 파싱합니다:

from xml import sax

class SimpleHandler(sax.ContentHandler):
    def startElement(self, name, attrs):
        print 'Start of element:', name, attrs.keys()

    def endElement(self, name):
        print 'End of element:', name

# Create a parser object
parser = sax.make_parser()

# Tell it what handler to use
handler = SimpleHandler()
parser.setContentHandler( handler )

# Parse a file!
parser.parse( 'hamlet.xml' )

더 자세한 정보는 Python 설명을 참조하거나 https://pyxml.sourceforge.net/topics/howto/xml-howto.html의 XML HOWTO를 참고하십시오.

DOM 지원

문서 객체 모델(Document Object Model)은 XML 문서를 위한 트리 기반 표현입니다. 최상위 Document 인스턴스는 트리의 루트이며, 하나의 자식으로 최상위 Element 인스턴스를 가집니다. 이 :class:`!Element`는 문자 데이터를 나타내는 노드와 추가적인 하위 요소를 가지며, 이는 다시 더 많은 자식을 가질 수 있습니다. DOM을 사용하면 원하는 방식으로 결과 트리를 순회하고, 요소 및 속성 값을 액세스하며, 노드를 삽입하고 제거할 수 있고, 트리를 XML로 변환할 수 있습니다.

DOM은 XML 문서를 수정하는 데 유용합니다. DOM 트리를 생성하고 새로운 노드를 추가하거나 하위 트리를 재배열하여 수정한 다음, 출력으로 새 XML 문서를 생성할 수 있기 때문입니다. 또한 수동으로 DOM 트리를 구성하고 이를 XML로 변환할 수도 있는데, 이는 단순히 “<tag1>…”를 파일에 쓰는 것보다 더 유연한 방식일 수 있습니다.

파이썬과 함께 제공되는 DOM 구현은 xml.dom.minidom 모듈에 있습니다. 이것은 XML 네임스페이스를 지원하는 레벨 1 DOM의 경량 구현입니다. DOM 트리를 생성하기 위해 편리 함수인 parse`와 :func:()!parseString`을 사용할 수 있습니다:

from xml.dom import minidom
doc = minidom.parse('hamlet.xml')

doc is a Document instance. Document, like all the other DOM classes such as Element and Text, is a subclass of the Node base class. All the nodes in a DOM tree therefore support certain common methods, such as toxml() which returns a string containing the XML representation of the node and its children. Each class also has special methods of its own; for example, Element and Document instances have a method to find all child elements with a given tag name. Continuing from the previous 2-line example:

perslist = doc.getElementsByTagName( 'PERSONA' )
print perslist[0].toxml()
print perslist[1].toxml()

Hamlet XML 파일의 경우, 위의 몇 줄이 출력됩니다:

<PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>

문서의 루트 요소는 doc.documentElement 로 사용할 수 있으며, 자식 노드는 삭제, 추가 또는 제거를 통해 쉽게 수정할 수 있습니다:

root = doc.documentElement

# 첫 번째 자식 제거
root.removeChild( root.childNodes[0] )

# 새 첫 번째 자식을 끝으로 이동
root.appendChild( root.childNodes[0] )

# 새 첫 번째 자식 (원래 세 번째 자식)을 20번째 자식보다 앞에 삽입합니다.
root.insertBefore( root.childNodes[0], root.childNodes[20] )

다시 한번, 다양한 Node 클래스와 해당 메서드의 전체 목록을 보려면 파이썬 문서를 참조하시길 바랍니다.

PyXML과의 관계

XML Special Interest Group은 오랫동안 XML 관련 파이썬 코드를 작업해 왔습니다. SIG의 웹페이지(https://www.python.org/community/sigs/current/xml-sig)에서 얻을 수 있는 PyXML이라는 코드 배포판이 있습니다. PyXML 배포판은 또한 xml 패키지 이름을 사용했습니다. 만약 PyXML을 사용했던 프로그램을 작성했다면, 2.0 xml 패키지와의 호환성에 대해 궁금하실 것입니다.

답변은 파이썬 2.0의 xml 패키지가 PyXML과 호환되지 않는다는 것이지만, 최신 버전의 PyXML을 설치하여 호환되게 만들 수 있다는 것입니다. 많은 애플리케이션은 Python 2.0에 포함된 XML 지원만으로 충분하지만, 더 복잡한 애플리케이션에서는 전체 PyXML 패키지가 설치되어야 합니다. 설치되면, PyXML 버전 0.6.0 이상은 파이썬에 배포된 xml 패키지를 대체하고 표준 패키지의 엄격한 상위 집합이며, 다양한 추가 기능을 제공합니다. PyXML의 일부 추가 기능에는 다음이 포함됩니다:

  • FourThought, Inc.에서 만든 완전한 DOM 구현체인 4DOM입니다.

  • Lars Marius Garshol이 작성한 xmlproc 검증 파서입니다.

  • Fredrik Lundh가 작성한 sgmlop 파서 액셀러레이터 모듈입니다.

모듈 변경 사항

파이썬의 광범위한 표준 라이브러리에 많은 개선과 버그 수정이 이루어졌습니다. 영향받은 모듈 중 일부에는 readline, ConfigParser, cgi, calendar, posix, readline, xmllib, aifc, chunk, wave, random, shelve, 및 :mod:`!nntplib`가 포함됩니다. 정확한 패치별 세부 사항은 CVS 로그를 참조하십시오.

Brian Gallew가 socket 모듈에 OpenSSL 지원을 기여했습니다. OpenSSL은 소켓을 통해 전송되는 데이터를 암호화하는 Secure Socket Layer의 구현입니다. 파이썬을 컴파일할 때, SSL 지원을 포함하도록 Modules/Setup 파일을 수정할 수 있으며, 이는 socket 모듈에 socket.ssl(socket, keyfile, certfile)``라는 추가 기능을 추가합니다. 함수는 소켓 객체를 받아 SSL 소켓을 반환합니다. 또한 :mod:`httplib <http>`와 :mod:`urllib` 모듈도 ``https:// URL을 지원하도록 변경되었지만, SSL을 통한 FTP 또는 SMTP 구현은 없습니다.

httplib 모듈이 Greg Stein에 의해 HTTP/1.1을 지원하도록 재작성되었습니다.

:mod:`!httplib`의 1.5 버전과의 하위 호환성은 제공되지만, pipelining과 같은 HTTP/1.1 기능을 사용하려면 다른 인터페이스를 사용하도록 코드를 재작성해야 합니다.

Tkinter 모듈은 이제 Tcl/Tk 버전 8.1, 8.2 또는 8.3을 지원하며 이전 버전인 7.x에 대한 지원은 중단되었습니다. Tkinter 모듈은 또한 Tk 위젯에서 유니코드 문자열 표시를 지원합니다. 또한, Fredrik Lundh가 create_linecreate_polygon 과 같은 작업을 많이 빠르게 만드는 최적화를 기여했습니다.

curses 모듈은 Oliver Andrich의 개선된 버전부터 시작하여, 색상, 대체 문자 집합 지원, 패드 및 마우스 지원과 같은 ncurses와 SYSV curses의 많은 추가 기능을 제공하도록 크게 확장되었습니다. 이는 이 모듈이 BSD curses만 사용하는 운영 체제와 더 이상 호환되지 않음을 의미하지만, 현재 유지 관리되는 OS 중에서 이러한 범주에 속하는 것은 없는 것 같습니다.

2.0의 유니코드 지원에 대한 이전 토론에서 언급했듯이, re 모듈이 제공하는 정규식의 기본 구현이 변경되었습니다. Hewlett Packard가 부분적으로 자금을 지원하고 Fredrik Lundh가 작성한 새로운 정규 표현식 엔진인 SRE는 8비트 문자열과 유니코드 문자열 모두를 매칭할 수 있도록 지원합니다.

새로운 모듈

여러 개의 새로운 모듈이 추가되었습니다. 간단하게 설명을 나열할 것이며, 특정 모듈에 대한 자세한 내용은 2.0 문서를 참조하십시오.

  • atexit: 파이썬 인터프리터가 종료되기 전에 호출되도록 함수를 등록하는 용도입니다. 현재 sys.exitfunc 를 직접 설정하는 코드는 대신 atexit 모듈을 사용하도록 변경해야 하며, atexit 을 임포트하고 종료 시 호출할 함수와 함께 atexit.register() 를 호출해야 합니다. (Skip Montanaro 기여.)

  • codecs, encodings, unicodedata: 새로운 유니코드 지원의 일부로 추가되었습니다.

  • filecmp: 더 이상 사용되지 않는 이전의 cmpcmpcache, 그리고 dircmp 모듈을 대체합니다. (Gordon MacMillan 및 Moshe Zadka 기여.)

  • gettext: 이 모듈은 GNU gettext 메시지 카탈로그 라이브러리에 인터페이스를 제공하여 파이썬 프로그램을 위한 국제화(I18N) 및 현지화(L10N) 지원을 합니다. (Barry Warsaw가 Martin von Löwis, Peter Funk, James Henstridge의 개별 기여로부터 통합했습니다.)

  • linuxaudiodev: 기존 sunaudiodev 모듈의 쌍이 되는 Linux의 /dev/audio 장치에 대한 지원입니다. (Peter Bosch 기여, Jeremy Hylton가 수정.)

  • mmap: Windows 및 Unix 모두에서 메모리 맵 파일로의 인터페이스를 제공합니다. 파일 내용은 메모리에 직접 매핑될 수 있으며, 이 경우 가변 문자열처럼 작동하여 내용을 읽고 수정할 수 있습니다. 심지어 re 모듈과 같이 일반 문자열을 예상하는 함수에도 전달할 수 있습니다. (Sam Rushing 기여, A.M. Kuchling이 일부 확장.)

  • pyexpat: Expat XML 파서에 대한 인터페이스를 제공합니다. (Paul Prescod 기여.)

  • robotparser: 웹 사이트의 특정 영역을 정중하게 피하는 웹 스파이더를 작성하는 데 사용되는 robots.txt 파일을 구문 분석합니다. 이 파서는 robots.txt 파일의 내용을 받아들여 규칙 세트를 구축하고, 주어진 URL의 가져오기 가능성에 대한 질문에 답할 수 있습니다. (Skip Montanaro 기여.)

  • tabnanny: 모호한 들여쓰기를 검사하기 위한 파이썬 소스 코드용 모듈/스크립트입니다. (Tim Peters 기여.)

  • UserString: 문자열처럼 동작하는 객체를 파생시키는 데 유용한 기반 클래스입니다.

  • webbrowser: 특정 URL에서 웹 브라우저를 실행하는 플랫폼 독립적인 방법을 제공하는 모듈입니다. 각 플랫폼에 대해 다양한 브라우저가 특정 순서로 시도됩니다. 사용자는 BROWSER 환경 변수를 설정하여 어떤 브라우저가 실행될지 변경할 수 있습니다. (원래 Eric S. Raymond의 urllib 패치에서 유사한 기능을 추가함으로써 영감을 받았으나, 최종 모듈은 Fred Drake가 :file:`Tools/idle/BrowserControl.py`로 원래 구현하고 Fred가 표준 라이브러리를 위해 적용했습니다.)

  • _winreg: An interface to the Windows registry. _winreg is an adaptation of functions that have been part of PythonWin since 1995, but has now been added to the core distribution, and enhanced to support Unicode. _winreg was written by Bill Tutt and Mark Hammond.

  • zipfile: ZIP 형식 아카이브를 읽고 쓰는 모듈입니다. 이 아카이브는 DOS/Windows에서 PKZIP`에 의해 또는 Unix에서 :program:`zip`에 의해 생성된 것으로, :program:`gzip\ -형식 파일(은 gzip 모듈이 지원함)와 혼동해서는 안 됩니다. (James C. Ahlstrom 기여.)

  • imputil: 기존의 ihooks 모듈에 비해 사용자 정의 임포트 훅을 작성할 수 있는 더 간단한 방법을 제공하는 모듈입니다. (Greg Stein이 구현했으며, 그 과정에서 python-dev에서 많은 논의가 있었습니다.)

IDLE 개선 사항

IDLE은 Tkinter를 사용하여 작성된 공식 파이썬 크로스-플랫폼 IDE입니다. Python 2.0에는 IDLE 0.6이 포함되어 있으며, 이 버전에서 여러 새로운 기능과 개선 사항이 추가되었습니다. 개요:

  • 구문 강조 및 자동 들여쓰기 영역을 중심으로 UI가 향상되고 최적화되었습니다.

  • 클래스 브라우저에서 이제 모듈의 최상위 함수와 같은 더 많은 정보를 표시합니다.

  • 탭 너비가 사용자 설정 옵션으로 추가되었습니다. 기존 파이썬 파일을 열 때 IDLE은 자동적으로 들여쓰기 관례를 감지하고 이에 맞춰 조정됩니다.

  • 다양한 플랫폼의 브라우저에서 호출하는 기능에 대한 지원이 추가되었습니다. 이는 파이썬 문서를 웹 브라우저로 열 때 사용됩니다.

  • IDLE에는 이제 명령줄 인터프리터가 포함되어 있으며, 이는 순수한 Python 인터프리터와 매우 유사합니다.

  • 여러 위치에 호출 팁이 추가되었습니다.

  • IDLE을 패키지로 설치할 수 있게 되었습니다.

  • 편집기 창 하단에 이제 줄/열 바가 있습니다.

  • 세 가지 새로운 키 입력 명령이 추가되었습니다: 모듈 확인 Alt-F5, 모듈 임포트 F5, 및 스크립트 실행 Ctrl-F5.

삭제되고 사용 중단된 모듈들

몇 개의 모듈이 사용 불가능하거나 더 나은 방식으로 같은 작업을 수행할 수 있기 때문에 제거되었습니다. stdwin 모듈은 사라졌습니다. 이 모듈은 더 이상 개발되지 않는 플랫폼 독립적인 윈도우 키트를 위한 것이었습니다.

여러 모듈이 lib-old 서브 디렉토리로 이동했습니다: cmp, cmpcache, dircmp, dump, find, grep, packmail, poly, util, whatsound, zmod. 만약 사용하는 모듈이 lib-old 로 이동한 경우, 해당 디렉토리를 sys.path 에 추가하여 다시 사용할 수 있지만, 이들 모듈을 사용하는 코드를 업데이트하실 것을 권장합니다.

감사합니다

저자들은 이 문서의 다양한 초안을 제안하고 수정하며 도와준 다음 분들께 감사드립니다: David Bolen, Mark Hammond, Gregg Hauser, Jeremy Hylton, Fredrik Lundh, Detlef Lannert, Aahz Maruch, Skip Montanaro, Vladimir Marangozov, Tobias Polzin, Guido van Rossum, Neil Schemenauer, 그리고 Russ Schmidt.

분실물 보관소