Python

Python 2.0의 새로운 기능

저자:

A.M. Kuchling 및 Moshe Zadka

소개

새로운 Python 버전인 2.0이 2000년 10월 16일에 출시되었습니다. 이 기사에서는 2.0의 흥미로운 새 기능들을 다루고, 다른 유용한 변경 사항을 강조하며, 코드 재작성이 필요할 수 있는 몇 가지 호환되지 않는 변경 사항을 짚어줍니다.

Python의 개발은 릴리스 사이에 완전히 멈추지 않으며, 버그 수정과 개선이 항상 꾸준히 제출됩니다. 다수의 사소한 수정, 몇 가지 최적화, 추가된 Docstring, 그리고 더 나은 오류 메시지가 2.0에 포함되었습니다. 이를 모두 나열하는 것은 불가능하지만 분명 중요한 변화들입니다. 전체 목록을 확인하려면 공개된 CVS 로그를 참조하십시오. 이러한 진전은 PythonLabs에서 일하는 5명의 개발자가 이제 버그를 수정하는 데 전념할 수 있게 되었기 때문이며, SourceForge로 이동하면서 개선된 의사소통 덕분이기도 합니다.

Python 1.6은 어떤가요?

Python 1.6은 ‘계약상 의무’를 위한 Python 출시라고 생각할 수 있습니다. 핵심 개발팀이 2000년 5월 CNRI를 떠난 후, CNRI는 그동안 CNRI에서 수행된 모든 작업이 포함된 1.6 버전을 제작해 달라고 요청했습니다. 따라서 Python 1.6은 유니코드 지원이라는 가장 중요한 신기능을 포함하여 2000년 5월 기준의 CVS 트리 상태를 나타냅니다. 물론 5월 이후에도 개발이 계속되었으므로, 1.6 트리는 Python 2.0과 향후 호환성을 보장하기 위한 몇 가지 수정 사항을 반영했습니다. 따라서 1.6은 사이드 브랜치가 아니라 Python 진화의 일부입니다.

그렇다면, 여러분이 Python 1.6에 많은 관심을 가져야 할까요? 아마도 그렇지 않습니다. 1.6final과 2.0beta1은 같은 날(2000년 9월 5일) 발표되었으며, 한 달 정도 내에 Python 2.0을 마무리할 계획이었습니다. 유지 관리해야 할 애플리케이션이 있는 경우, 1.6으로 이동하여 문제를 수정하고 한 달 뒤 다시 2.0으로 옮기면서 또 다른 오류가 발생하게 만드는 것보다는 곧바로 2.0으로 가는 것이 훨씬 낫습니다. 이 문서에서 설명하는 매우 흥미로운 기능의 대부분은 5월과 9월 사이에 수행된 많은 작업 덕분에 오직 2.0에만 포함되어 있습니다.

새로운 개발 프로세스

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

SourceForge에서 호스팅되는 서비스 중 가장 중요한 것은 Python 소스 코드가 포함된 버전 관리 저장소인 Python CVS 트리입니다. 이전에는 CVS 트리에 쓰기 권한이 있는 사람이 약 7명 정도였으며, 모든 패치는 이 짧은 명단의 인원 중 한 명에 의해 검토되고 체크인되어야 했습니다. 이는 분명 확장성이 없었습니다. CVS 트리를 SourceForge로 옮기면서 더 많은 사람에게 쓰기 권한을 부여하는 것이 가능해졌습니다. 2000년 9월 기준으로 변경 사항을 체크인할 수 있는 사람이 27명으로 늘어났으며, 이는 4배 증가한 것입니다. 이를 통해 핵심 개발자 소수 그룹의 필터링을 거치지 않아도 되는 대규모 변화가 가능해졌습니다. 예를 들어, 어느 날 Peter Schneider-Kamp는 K&R C 호환성을 제거하고 Python의 C 소스를 ANSI C로 변환하기로 결심했습니다. python-dev 메일링 리스트에서 승인을 받은 후, 그는 약 일주일 동안 이어진 많은 체크인을 단행했고, 다른 개발자들도 돕기 위해 합류하여 작업이 완료되었습니다. 쓰기 권한이 있는 사람이 5명뿐이었다면 아마도 그 작업은 ‘좋긴 하지만 시간과 노력을 들일 가치가 없는’ 것으로 여겨져 끝내 이루어지지 못했을 것입니다.

SourceForge의 서비스를 사용하게 되면서 개발 속도가 괄목할 만하게 향상되었습니다. 이제 패치는 제출되고, 다른 사람들에 의해 의견이 달리고 수정되며, 수락될 가치가 있다고 판단될 때까지 여러 사람 사이에서 오가게 됩니다. 버그는 하나의 중앙 위치에서 추적되며 특정 담당자에게 할당되어 해결될 수 있고, 우리는 열린 버그의 수를 세어 진행 상황을 측정할 수 있습니다. 물론 대가가 따랐습니다. 개발자들은 이제 더 많은 이메일을 처리해야 하고, 더 많은 메일링 리스트를 팔로우해야 하며, 새로운 환경을 위한 특별한 도구들도 작성되어야 했습니다. 예를 들어, SourceForge는 전혀 도움이 되지 않는 기본 패치 및 버그 알림 메시지를 보내기 때문에, Ka-Ping Yee는 더 유용한 메시지를 전송하는 HTML 스크린 스크래퍼를 작성했습니다.

코드를 추가하기 쉬워지면서 코드가 준비되지 않았거나 개발자 그룹의 명확한 합의 없이 체크인되는 등 초기 성장통이 발생하기도 했습니다. 현재 형성된 승인 프로세스는 Apache 그룹에서 사용하는 방식과 어느 정도 유사합니다. 개발자들은 패치에 대해 +1, +0, -0 또는 -1을 투표할 수 있습니다. +1과 -1은 수락이나 거부를 나타내며, +0과 -0는 개발자가 변화에 대체로 무관심하지만 약간의 긍정적 또는 부정적인 견해를 가진 경우를 의미합니다. Apache 모델과 가장 큰 차이점은 표결 결과가 기본적으로 자문용이라는 것입니다. 이는 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월을 기준으로 “Lockstep Iteration”에 대한 PEP 201 부터 “Elementwise/Objectwise Operators”인 PEP 225까지 총 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진수 이스케이프를 사용할 수 있습니다.

유니코드 문자열은 일반 문자열과 마찬가지로 불변 시퀀스 타입입니다. 인덱싱과 슬라이싱이 가능하지만 제자리에서 수정할 수는 없습니다. 유니코드 문자열은 원하는 인코딩으로 변환된 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(string [, encoding]  [, errors] ) 는 8비트 문자열을 유니코드 문자열로 생성합니다. encoding 은 사용할 인코딩의 이름을 나타내는 문자열입니다. errors 매개변수는 현재 인코딩에 유효하지 않은 문자를 처리하는 방식을 지정합니다. 값을 'strict' 으로 전달하면 인코딩 오류 발생 시 예외가 발생하며, 'ignore' 를 사용하면 오류를 무시하고, 'replace' 를 사용하면 문제가 발생할 경우 공식 교체 문자인 U+FFFD를 사용합니다.

  • exec 문과 eval(), getattr(), setattr() 와 같은 다양한 내장 함수들도 일반 문자열뿐만 아니라 유니코드 문자열도 허용합니다. (수정 과정에서 일부 내장 함수가 누락되었을 수 있습니다. 만약 문자열은 지원하지만 유니코드 문자열은 전혀 지원하지 않는 내장 함수를 발견하면 버그로 보고해 주시기 바랍니다.)

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

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

  • encode_func 는 유니코드 문자열을 입력받아 2개 요소의 튜플 (string, length) 를 반환하는 함수입니다. string 은 해당 유니코드 문자열 중 주어진 인코딩으로 변환된 부분(어쩌면 전체)을 포함하는 8비트 문자열이며, length 는 유니코드 문자열 중 어느 정도가 변환되었는지를 나타냅니다.

  • decode_funcencode_func 의 반대 기능으로, 8비트 문자열을 받아 결과 유니코드 문자열인 ustring 과 8비트 문자열 중 얼마만큼이 소비되었는지를 나타내는 정수 length 로 구성된 2개 요소의 튜플 (ustring, length) 를 반환합니다.

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

  • stream_writer 도 마찬가지로 스트림으로의 출력을 인코딩하는 것을 지원하는 클래스입니다. 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()

유니코드를 인식하는 정규표현식은 re 모듈을 통해 사용할 수 있으며, 이 모듈은 Secret Labs AB의 Fredrik Lundh가 작성한 SRE라는 새로운 기본 구현을 포함하고 있습니다.

파이썬 컴파일러가 모든 문자열 리터럴을 유니코드 문자열 리터럴로 해석하게 하는 -U 명령줄 옵션이 추가되었습니다. 이는 향후 파이썬 버전에서 8비트 문자열 지원을 중단하고 유니코드 문자열만 제공할 수 있으므로, 테스트 및 코드의 미래 보장을 위해 사용될 의도로 추가되었습니다.

리스트 컴프리헨션

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

기존의 map()filter() 함수를 이 용도로 사용할 수 있지만, 이를 위해서는 인자로 함수가 필요합니다. 직접 전달할 수 있는 내장 함수가 있다면 상관없지만, 그렇지 않은 경우 필요한 작업을 수행하기 위해 작은 함수를 만들어야 하며, 이때 추가 정보가 필요한 경우 파이썬의 스코핑 규칙으로 인해 결과가 복잡해질 수 있습니다. 앞 단락의 첫 번째 예제인 리스트에서 특정 부분 문자열을 포함하는 모든 문자열을 찾는 경우를 생각해 보십시오. 이를 수행하기 위해 다음과 같이 작성할 수 있습니다:

# 리스트 L이 주어졌을 때, 부분 문자열 S를
# 포함하는 모든 문자열의 목록을 만듭니다.
sublist = filter( lambda s, substring=S:
                    string.find(s, substring) != -1,
                 L)

파이썬의 스코핑 규칙으로 인해, lambda 표현식에 의해 생성된 익명 함수가 어떤 부분 문자열을 검색하는지 알 수 있도록 기본 인자를 사용합니다. 리스트 컴프리헨션을 사용하면 이를 더 깔끔하게 처리할 수 있습니다:

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

리스트 컴프리헨션은 다음과 같은 형태를 가집니다:

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

for...in 절은 반복할 시퀀스를 포함합니다. 시퀀스들이 병렬이 아니라 왼쪽에서 오른쪽으로 순차적으로 반복되기 때문에 서로 다른 길이를 가질 수 있으며, 이 내용은 다음 단락에서 더 자세히 설명합니다. 생성된 리스트의 요소는 expression 의 연속적인 값이 됩니다. 마지막 if 절은 선택 사항이며, 포함된 경우 condition 이 참일 때만 expression 이 평가되어 결과에 추가됩니다.

의미를 명확하게 하기 위해, 리스트 컴프리헨션은 다음 파이썬 코드와 동일합니다:

for expr1 in sequence1:
    for expr2 in sequence2:
    ...
        for exprN in sequenceN:
             if (condition):
                  # 표현식의 값을
                  # 결과 리스트에 추가합니다.

이는 여러 개의 for...in 절이 있을 때 결과 리스트의 길이가 모든 시퀀스 길이의 곱과 같음을 의미합니다. 예를 들어 길이가 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)]

파이썬 문법의 모호성을 피하기 위해, expression 이 튜플을 생성하는 경우 반드시 괄호로 둘러싸야 합니다. 아래의 첫 번째 리스트 컴프리헨션은 구문 오류이며, 두 번째는 올바른 문법입니다:

# 구문 오류
[ x,y for x in seq1 for y in seq2]
# 올바름
[ (x,y) for x in seq1 for y in seq2]

리스트 컴프리헨션의 개념은 원래 함수형 프로그래밍 언어인 Haskell(https://www.haskell.org)에서 유래했습니다. Greg Ewing이 이를 파이썬에 도입해야 한다고 강력하게 주장하며 초기 리스트 컴프리헨션 패치를 작성했고, 이후 python-dev 메일링 리스트에서 오랜 시간 논의를 거쳐 Skip Montanaro에 의해 최신 상태로 유지되었습니다.

증분 대입(Augmented Assignment)

오랫동안 요청된 기능 중 하나인 증분 대입 연산자가 파이썬 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.

증분 대입 연산자는 C 프로그래밍 언어에서 처음 도입되었으며, awk, C++, Java, Perl, PHP와 같은 대부분의 C 파생 언어들도 이를 지원합니다. 증분 대입 패치는 Thomas Wouters에 의해 구현되었습니다.

문자열 메서드

Until now string-manipulation functionality was in the string module, which was usually a front-end for the strop module written in C. The addition of Unicode posed a difficulty for the strop module, because the functions would all need to be rewritten in order to accept either 8-bit or Unicode strings. For functions such as string.replace(), which takes 3 string arguments, that means eight possible permutations, and correspondingly complicated code.

대신 파이썬 2.0은 이 문제를 문자열 타입으로 옮겨서, 8비트 문자열과 유니코드 문자열 모두에서 메서드를 통해 문자열 조작 기능을 사용할 수 있게 합니다.

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

주의할 만한 4월 1일 농담이 한 번 있었음에도 불구하고 변하지 않은 한 가지는 파이썬 문자열은 불변(immutable)이라는 점입니다. 따라서 문자열 메서드는 새로운 문자열을 반환하며, 동작하는 원본 문자열을 수정하지 않습니다.

과거 버전과의 호환성을 위해 오래된 string 모듈이 여전히 존재하지만, 대부분은 새로운 문자열 메서드를 위한 프런트엔드로 작동합니다.

pre-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) 는 이전의 string.join(seq, s) 와 같습니다.

순환 구조의 가비지 수집(Garbage Collection of Cycles)

파이썬의 C 구현은 참조 횟수(reference counting)를 사용하여 가비지 수집을 수행합니다. 모든 파이썬 객체는 자신을 가리키는 참조의 수를 카운트로 유지하며, 참조가 생성되거나 파괴될 때마다 이 카운트를 조정합니다. 참조 횟수가 0에 도달하면 해당 객체에 접근할 수 있는 참조가 더 이상 존재하지 않는 것이므로 객체에 접근할 수 없게 됩니다.

참조 횟수는 몇 가지 장점이 있습니다. 이해하고 구현하기 쉽고, 결과적으로 생성된 구현은 이식성이 높으며 상당히 빠르고, 자체적인 메모리 관리 방식을 구현하는 다른 라이브러리와도 잘 연동됩니다. 참조 횟수의 주요 문제는 객체가 더 이상 접근 불가능한 상태임에도 이를 인식하지 못해 메모리 누수가 발생하는 경우가 있다는 것입니다. 이는 참조의 순환(cycles of references)이 존재할 때 발생합니다.

가장 단순한 형태의 순환인, 자기 자신을 참조하는 클래스 인스턴스를 생각해 보십시오:

instance = SomeClass()
instance.myself = instance

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

만약 다음 코드 라인이 del instance``라면 어떤 일이 발생할까요? ``instance``의 참조 횟수가 1 감소하여 1이 됩니다. ``myself 속성에 있는 참조는 여전히 존재하기 때문입니다. 그러나 이 인스턴스는 파이썬 코드를 통해 더 이상 접근할 수 없으며, 삭제될 수도 있습니다. 여러 객체가 서로를 참조하면 순환을 형성하게 되며, 결과적으로 모든 객체가 누수됩니다.

파이썬 2.0은 접근 불가능한 순환을 찾아내어 관련 객체들을 삭제하는 순환 감지 알고리즘을 주기적으로 실행함으로써 이 문제를 해결합니다. 새로운 gc 모듈은 가비지 수거를 수행하고, 디버깅 통계를 얻으며, 수집기(collector)의 파라미터를 조정하는 함수들을 제공합니다.

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

여러 사람이 이 문제를 해결하고 솔루션에 기여했습니다. 순환 감지 접근 방식의 초기 구현은 Toby Kelsey가 작성했습니다. 현재 알고리즘은 Eric Tiedemann이 CNRI를 방문했을 때 제안되었으며, Guido van Rossum과 Neil Schemenauer가 두 가지 다른 구현을 작성했고 이후 Neil에 의해 통합되었습니다. 그 과정에서 많은 다른 사람들도 의견을 제시했으며, 2000년 3월 python-dev 메일링 리스트 아카이브에 관련 논의 대부분이 포함되어 있습니다. 특히 “Reference cycle collection for Python” 및 “Finalization again”이라는 제목의 스레드를 확인하십시오.

기타 핵심 변경 사항

파이썬의 문법과 내장 함수에 여러 가지 사소한 변경이 가해졌습니다. 어떤 변경도 매우 광범위하지는 않지만 편리한 기능들을 제공합니다.

사소한 언어 변경

새로운 문법을 통해 튜플 형태의 인자 또는 키워드 인자의 딕셔너리를 사용하여 함수를 호출하는 것이 더 편리해졌습니다. 파이썬 1.5 및 이전 버전에서는 내장 함수인 apply() 를 사용했습니다: apply(f, args, kw) 는 함수 f() 를 인자 튜플 args 와 딕셔너리 내의 키워드 인자 kw 로 호출합니다. 파이썬 2.0에서도 apply() 는 동일하게 작동하지만, Greg Ewing의 패치 덕분에 f(*args, **kw) 가 동일한 효과를 달성하는 더 짧고 명확한 방법이 도입되었습니다. 이 문법은 함수 정의 문법과 대칭을 이룹니다:

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

이제 print 문 뒤에 >> file 을 붙여 유닉스 쉘의 리다이렉션 연산자와 유사하게 출력을 파일과 같은 객체로 보낼 수 있습니다. 이전에는 파일과 같은 객체의 write() 메서드를 사용하거나(이는 print 의 편리함과 단순함이 부족합니다), sys.stdout 에 새 값을 할당한 후 이전 값을 복구해야 했습니다. 표준 에러로 출력을 보내는 경우 다음을 작성하는 것이 훨씬 더 쉽습니다:

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

이제 import module as name 또는 from module import name as othername 구문을 사용하여 임포트 시 모듈을 다시 이름 지을 수 있습니다. 이 패치는 Thomas Wouters에 의해 제출되었습니다.

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

이전에는 파이썬 내장 in 연산자를 재정의하여 사용자 정의 버전을 구현할 방법이 없었습니다. obj in seqobj 가 시퀀스 seq 에 포함되어 있을 때 참을 반환하며, 파이썬은 이를 위해 obj 를 찾거나 IndexError 가 발생할 때까지 모든 인덱스를 순차적으로 확인합니다. Moshe Zadka는 in 에 대한 사용자 정의 구현을 제공하는 __contains__() 매직 메서드를 추가하는 패치를 기여했습니다. 또한, C로 작성된 새로운 내장 객체들은 시퀀스 프로토콜의 새로운 슬롯을 통해 자신들에 대한 in 의 의미를 정의할 수 있습니다.

파이썬 초기 버전은 객체를 삭제하기 위해 재귀 알고리즘을 사용했습니다. 깊게 중첩된 데이터 구조는 인터프리터가 C 스택을 가득 채우고 충돌하게 만들 수 있었는데, Christian Tismer가 이 문제를 해결하기 위해 삭제 로직을 다시 작성했습니다. 이와 관련된 문제로, 재귀적 객체를 비교할 때 무한히 재귀하며 충돌이 발생하곤 했습니다. Jeremy Hylton은 코드를 재작성하여 더 이상 충돌하지 않고 유용한 결과를 생성하도록 변경했습니다. 예를 들어, 다음 코드 이후에:

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

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

Itanium 프로세서의 64비트 Windows에서 파이썬을 포팅하는 작업이 진행되었습니다(대부분 ActiveState의 Trent Mick에 의해 수행됨). (혼동스러울 수 있겠지만, Win64에서도 sys.platform 은 여전히 'win32' 입니다. 이는 이식의 편의성을 위해 MS Visual C++가 Itanium에서 코드를 32비트로 처리하기 때문인 것으로 보입니다.) PythonWin은 Windows CE도 지원합니다. 자세한 정보는 https://pythonce.sourceforge.net/ 의 Python CE 페이지를 참조하십시오.

또 다른 새로운 플랫폼으로 Darwin/MacOS X가 있으며, 파이썬 2.0에서 이에 대한 초기 지원이 포함되었습니다. “configure –with-dyld –with-suffix=.x”를 지정하면 동적 로딩(Dynamic loading)이 작동합니다. 더 자세한 지침은 파이썬 소스 배포판의 README를 참조하십시오.

파이썬의 문제점 중 하나인, 코드가 로컬 변수에 값을 할당하기 전에 해당 변수를 참조할 때 빈번하게 발생하는 혼란스러운 NameError 예외를 완화하려고 시도했습니다. 예를 들어, 다음 코드는 1.5.2와 2.0 모두에서 print 문에서 예외를 발생시킵니다. 1.5.2에서는 NameError 가 발생하지만, 2.0에서는 새로운 UnboundLocalError 예외가 발생합니다. UnboundLocalErrorNameError 의 서브클래스이므로, NameError 가 발생하는 것을 기대하는 기존 코드는 계속 작동할 것입니다.

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

두 개의 새로운 예외인 TabErrorIndentationError 가 도입되었습니다. 이들은 모두 SyntaxError 의 서브클래스이며, 파이썬 코드가 적절하게 들여쓰기 되지 않았을 때 발생합니다.

내장 함수 변경 사항

새로운 내장 함수 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 은 최종 출시 버전의 경우 “final”과 같은 문자열이며, 그 외에 “alpha”, “beta” 등이 있을 수 있습니다.

딕셔너리에는 기존 get() 메서리와 유사하게 작동하는 특이한 새 메서드인 setdefault(key, default) 가 있습니다. 다만 키가 없을 경우, setdefault()get() 과 동일하게 default 의 값을 반환할 뿐만 아니라 해당 key 에 대한 값으로 딕셔너리에 삽입합니다. 따라서 다음과 같은 코드들은:

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

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

인터프리터는 C 스택이 가득 차서 core dump나 GPF가 발생하는 것을 방지하기 위해 무한 재귀를 감지하도록 최대 재귀 깊이를 설정합니다. 이전 버전에서는 이 제한이 파이썬을 컴파일할 때 고정되었으나, 2.0에서는 sys.getrecursionlimit()sys.setrecursionlimit() 을 사용하여 최대 재귀 깊이를 읽고 수정할 수 있습니다. 기본값은 1000이며, 특정 플랫폼에 대한 대략적인 최대값을 확인하려면 새 스크립트인 Misc/find_recursionlimit.py 를 실행하면 됩니다.

2.0으로의 이식

새로운 파이썬 릴리스는 이전 버전과의 호환성을 최대한 유지하려고 노력하며, 그 기록도 매우 좋습니다. 그러나 일부 변경 사항은 설계상의 오류를 수정하는 등 중요도가 높아 백호환성(backward compatibility)을 깨뜨리는 것을 피할 수 없는 경우가 있습니다. 이 섹션에는 파이썬 2.0에서 이전 버전의 코드를 망가뜨릴 수 있는 변경 사항들을 나열합니다.

The change which will probably break the most code is tightening up the arguments accepted by some methods. Some methods would take multiple arguments and treat them as a tuple, particularly various list methods such as append() and insert(). In earlier versions of Python, if L is a list, L.append( 1,2 ) appends the tuple (1,2) to the list. In Python 2.0 this causes a TypeError exception to be raised, with the message: ‘append requires exactly 1 argument; 2 given’. The fix is to simply add an extra set of parentheses to pass both values as a tuple: L.append( (1,2) ).

이전 버전의 이 메서드들은 파이썬 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 모듈의 경우 문서를 수정하고 다중 인자 형식을 단지 권장되지 않음(deprecated)으로 표시했습니다. 이 기능은 향후 파이썬 버전에서 다시 강화될 예정입니다.

문자열 리터럴에서 \x 이스케이프는 이제 정확히 2개의 16진수 자릿수만 가져옵니다. 이전에는 ‘x’ 뒤에 오는 모든 16진수 자릿수를 소모하고 결과의 하위 8비트를 취했기 때문에, \x123456\x56 과 동일하게 처리되었습니다.

AttributeErrorNameError 예외의 오류 메시지가 더 친절하게 변경되었으며, 이제 'Spam' instance has no attribute 'eggs' 또는 name 'eggs' is not defined 와 같은 텍스트를 표시합니다. 이전에는 오류 메시지가 누락된 속성 이름인 eggs 만 표시되었으며, 이 사실을 이용하도록 작성된 코드는 2.0에서 작동하지 않을 수 있습니다.

정수(integer)와 장정수(long integer)를 보다 호환 가능하게 만들기 위한 작업이 진행되었습니다. 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 을 생성합니다.

가장 미묘한 장정수 관련 변경 사항은, repr() 은 여전히 포함하지만 장정수의 str() 에 더 이상 뒤에 붙는 ‘L’ 문자가 없다는 것입니다. 많은 사용자가 장정수를 일반 정수와 똑같이 보이게 출력하고 싶어 했으나, 이 문자를 제거하기 위해 번거로운 과정을 거쳐야 했기에 ‘L’이 불편함을 주었습니다. 2.0에서는 더 이상 문제가 되지 않지만, str(longval)[:-1] 을 실행하며 ‘L’이 존재한다고 가정하는 코드는 이제 마지막 자릿수를 잃게 됩니다.

부동 소수점의 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 동작 방식 때문에 파이썬 2.0이 파이썬 1.5.x용으로 빌드된 타사 확장을 가져올 수 없으며, 이 경우 파이썬은 예외를 발생시키고 임포트가 실패하게 됩니다.

Jim Fulton의 ExtensionClass 모듈 사용자는 ExtensionClasses가 이제 isinstance()issubclass() 에 의해 지원되도록 후크가 추가되었음을 알게 되어 기뻐할 것입니다. 이는 더 이상 if type(obj) == myExtensionClass 와 같은 코드를 작성해야 할 필요 없이, 훨씬 자연스러운 if isinstance(obj, myExtensionClass) 를 사용할 수 있음을 의미합니다.

다양한 플랫폼에서 동적 로딩을 지원하기 위해 수많은 #ifdef가 포함되어 있던 Python/importdl.c 파일이 Greg Stein에 의해 정리되고 재구성되었습니다. 이제 importdl.c 는 매우 간결해졌으며, 플랫폼별 코드는 여러 개의 Python/dynload_*.c 파일로 옮겨졌습니다. 또 다른 정리는 다음과 같습니다. Include/ 디렉토리에 다양한 이식성 해결책을 포함하고 있던 수많은 my*.h 파일들이 단일 파일인 Include/pyport.h 로 통합되었습니다.

Vladimir Marangozov의 고대하던 malloc 구조 개편이 완료되어, 파이썬 인터프리터가 C의 표준 malloc() 대신 사용자 정의 할당기를 사용하는 것이 훨씬 쉬워졌습니다. 자세한 문서는 Include/pymem.hInclude/objimpl.h 의 주석을 참조하십시오. 인터페이스를 확정하는 과정에서 이루어진 긴 논의 내용은 python.org의 ‘patches’ 및 ‘python-dev’ 리스트 웹 아카이브를 확인하시기 바랍니다.

최신 버전의 MacOS용 GUSI 개발 환경이 POSIX 스레드를 지원합니다. 따라서 파이썬의 POSIX 스레딩 지원이 이제 Macintosh에서도 작동합니다. 또한 사용자 공간 GNU pth 라이브러리를 사용하는 스레딩 지원도 추가되었습니다.

Windows에서도 스레딩 지원이 강화되었습니다. Windows는 경합(contention)이 발생할 경우에만 커널 객체를 사용하는 스레드 잠금을 지원하며, 경합이 없는 일반적인 경우에는 훨씬 빠른 간단한 함수를 사용합니다. NT 환경에서 파이썬 1.5.2의 스레드 버전은 비스레드 버전보다 두 배 느렸으나, 2.0 변경 사항을 통해 그 차이가 10%로 줄어들었습니다. 이러한 개선사항은 Yakov Markovitch가 기여했습니다.

파이썬 2.0의 소스 코드는 이제 ANSI C 프로토타입만 사용하므로 파이썬을 컴파일하려면 ANSI C 컴파일러가 필요하며, 더 이상 K&R C만 지원하는 컴파일러를 사용할 수 없습니다.

이전의 파이썬 가상 머신은 바이트 코드에서 16비트 숫자를 사용하여 소스 파일의 크기가 제한되었습니다. 특히, 이는 파이썬 소스의 리터럴 리스트 및 딕셔너리의 최대 크기에 영향을 미쳤으며, 때때로 파이썬 코드를 생성하는 개발자들이 이 한계에 부딪히곤 했습니다. Charles G. Waldman의 패치를 통해 해당 제한이 2**16 에서 2**32 로 상향되었습니다.

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

Unix 스타일 시그널 처리기를 위한 래퍼 API가 추가되었습니다. PyOS_getsig() 은 시그널 처리기를 가져오고, PyOS_setsig() 는 새로운 처리기로 설정합니다.

Distutils: 모듈 설치 용이하게 만들기

파이썬 2.0 이전에는 모듈 설치가 매우 번거로운 일이었습니다. 파이썬이 어디에 설치되어 있는지, 혹은 확장 모듈을 위해 어떤 컴파일러 옵션을 사용해야 하는지 자동으로 파악할 방법이 없었기 때문입니다. 소프트웨어 제작자들은 Makefile과 설정 파일을 수정하는 고된 과정을 거쳐야 했으며, 이는 Unix에서만 제대로 작동하고 Windows나 MacOS에서는 지원되지 않았습니다. 파이썬 사용자들은 확장 패키지마다 제각각인 설치 지침을 마주해야 했고, 이로 인해 파이썬 환경을 관리하는 것이 꽤 까다로운 일이었습니다.

Greg Ward가 주도한 배포 유틸리티 SIG에서 제작한 Distutils는 패키지 설치를 훨씬 쉽게 만드는 시스템입니다. 이들은 파이썬 표준 라이브러리의 새로운 부분인 distutils 패키지를 구성합니다. 이상적인 경우, 소스에서 파이썬 모듈을 설치할 때 동일한 단계를 거치게 됩니다: 먼저 타르볼이나 zip 압축을 풀고, “python setup.py install”을 실행하기만 하면 됩니다. 플랫폼은 자동으로 감지되고, 컴파일러가 인식되며, C 확장 모듈이 컴파일되고, 배포본이 적절한 디렉토리에 설치됩니다. 선택적인 명령줄 인수를 통해 설치 과정을 더 세밀하게 제어할 수 있으며, distutils 패키지는 빌드와 설치 분리, 기본 경로 이외의 위치에 구축 또는 설치 등 여러 설정을 기본값 대신 사용할 수 있는 옵션을 제공합니다.

Distutils를 사용하려면 setup.py 스크립트를 작성해야 합니다. 소프트웨어가 .py 파일만 포함하는 간단한 경우, 최소한의 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`와 같은 소스 배포본을 빌드합니다. 새로운 명령을 추가하는 것도 어렵지 않습니다. 이미 RPM 배포 생성을 위한 "bdist_rpm"과 Windows 설치 프로그램 생성을 위한 "bdist_wininst" 명령이 각각 기여되었습니다. Debian 패키지와 Solaris :file:.pkg` 파일 등 다른 배포 형식을 생성하기 위한 명령어들도 현재 다양한 단계로 개발 중에 있습니다.

이 모든 내용은 파이썬 기본 문서 세트에 포함된 새로운 매뉴얼인 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은 xml 패키지의 일부로 SAX2 인터페이스와 축소된 DOM 인터페이스를 포함합니다. 여기서는 이 새로운 인터페이스들에 대한 간략한 개요를 제공하며, 자세한 내용은 파이썬 문서나 소스 코드를 참조하십시오. 현재 Python XML SIG에서도 개선된 문서를 작업 중입니다.

SAX2 지원

SAX는 XML 파싱을 위한 이벤트 기반 인터페이스를 정의합니다. SAX를 사용하려면 SAX 핸들러 클래스를 작성해야 합니다. 핸들러 클래스는 SAX에서 제공하는 다양한 클래스를 상속받으며, XML 파서에 의해 호출될 다양한 메서드들을 재정의합니다. 예를 들어, startElement()endElement() 메서드는 파서가 발견하는 모든 시작 및 종료 태그마다 호출되며, characters() 메서드는 모든 문자 데이터 덩어리마다 호출됩니다.

이벤트 기반 방식의 장점은 문서 전체를 한꺼번에 메모리에 유지할 필요가 없다는 것이며, 이는 매우 큰 문서를 처리할 때 중요합니다. 그러나 복잡한 방식으로 문서 구조를 수정하려 할 경우 SAX 핸들러 클래스를 작성하는 과정이 매우 복잡해질 수 있습니다.

예를 들어, 다음의 작은 예제 프로그램은 시작 및 종료 태그마다 메시지를 출력하는 핸들러를 정의하며, 이를 사용하여 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' )

더 자세한 정보는 파이썬 문서를 참조하거나, 다음 URL의 XML HOWTO를 확인하십시오: https://pyxml.sourceforge.net/topics/howto/xml-howto.html.

DOM 지원

Document Object Model(DOM)은 XML 문서를 트리 구조로 표현하는 방식입니다. 최상위 레벨의 Document 인스턴스는 트리의 루트이며, 단일 자식인 최상위 레벨 Element 인스턴스를 가집니다. 이 Element 는 문자 데이터와 하위 요소를 나타내는 자식 노드들을 가지며, 이러한 노드들은 각각 또 다른 자식 노드들을 가질 수 있습니다. DOM을 사용하면 결과로 생성된 트리를 원하는 방식으로 순회하고, 엘리먼트 및 속성 값에 접근하며, 노드를 삽입하거나 삭제하고, 트리를 다시 XML로 변환할 수 있습니다.

DOM은 XML 문서를 수정하는 데 유용합니다. DOM 트리를 생성하고 새로운 노드를 추가하거나 하위 트리를 재배치하여 수정한 후, 이를 새로운 XML 문서로 출력할 수 있기 때문입니다. 또한 DOM 트리를 수동으로 구성하고 XML로 변환할 수도 있으며, 이는 파일에 <tag1></tag1> 와 같이 직접 쓰는 것보다 더 유연하게 XML 출력을 생성하는 방법이 될 수 있습니다.

파이썬에 포함된 DOM 구현체는 xml.dom.minidom 모듈에 있습니다. 이는 XML 네임스페이스를 지원하는 경량 Level 1 DOM 구현체입니다. DOM 트리를 생성하기 위한 편리한 기능인 parse()parseString() 함수가 제공됩니다:

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

docDocument 인스턴스입니다. DocumentElementText 와 같은 다른 모든 DOM 클래스와 마찬가지로 Node 기본 클래스의 하위 클래스입니다. 따라서 DOM 트리의 모든 노드는 해당 노드와 자식 노드의 XML 표현이 포함된 문자열을 반환하는 toxml() 과 같은 공통 메서드를 지원합니다. 또한 각 클래스는 고유한 전용 메서드를 가집니다. 예를 들어, ElementDocument 인스턴스에는 특정 태그 이름과 일치하는 모든 자식 엘리먼트를 찾는 메서드가 있습니다. 이전 2줄 예제에 이어 설명하면 다음과 같습니다:

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을 설치하면 호환되도록 만들 수 있습니다. 많은 애플리케이션은 파이썬 2.0에 포함된 XML 지원만으로도 실행 가능하지만, 더 복잡한 애플리케이션은 전체 PyXL 패키지가 설치되어야 합니다. 설치 시 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, 그리고 nntplib 이 포함됩니다. 자세한 패치별 세부 사항은 CVS 로그를 참조하십시오.

Brian Gallew가 socket 모듈에 대한 OpenSSL 지원을 기여했습니다. OpenSSL은 소켓을 통해 전송되는 데이터를 암호화하는 Secure Socket Layer의 구현체입니다. 파이썬을 컴파일할 때 Modules/Setup 을 편집하여 SSL 지원을 포함할 수 있으며, 이 기능은 socket 모듈에 socket.ssl(socket, keyfile, certfile) 이라는 추가 함수를 제공하며 소켓 객체를 받아 SSL 소켓을 반환합니다. httpliburllib 모듈도 https:// URL을 지원하도록 변경되었으나, 아직 SSL을 통한 FTP나 SMTP는 구현되지 않았습니다.

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

httplib 1.5 버전과 하위 호환성이 제공되지만, 파이프라이닝과 같은 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 모듈이 제공하는 정규 표현식의 기본 구현이 변경되었습니다. Fredrik Lundh가 작성하고 Hewlett Packard로부터 일부 지원을 받은 새로운 정규 표현식 엔진인 SRE는 8비트 문자열과 유니코드 문자열 모두에 대한 매칭을 지원합니다.

새로운 모듈

여러 개의 새 모듈이 추가되었습니다. 아래에 짧은 설명과 함께 목록을 나열하며, 특정 모듈에 대한 자세한 내용은 2.0 문서를 참조하십시오.

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

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

  • filecmp: 이제 사용 중단된 기존의 cmp, cmpcachedircmp 모듈을 대체합니다. (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가 작성한 Tools/idle/BrowserControl.py 코드를 기반으로 하여 Fred에 의해 표준 라이브러리에 맞게 조정되었습니다.)

  • _winreg: Windows 레지스트리에 대한 인터페이스입니다. _winreg`은 1995년부터 PythonWin의 일부였던 기능들을 수정한 것이며, 현재 핵심 배포판에 추가되고 유니코드를 지원하도록 개선되었습니다. :mod:!_winreg`은 Bill Tutt와 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 개선 및 최적화.

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

  • 탭 너비는 이제 사용자가 설정할 수 있는 옵션입니다. 기존 Python 파일을 열 때, IDLE이 자동으로 들여쓰기 규칙을 감지하고 적용합니다.

  • 다양한 플랫폼에서 브라우저를 호출하여 Python 문서를 브라우저에서 열 수 있는 기능이 추가되었습니다.

  • IDLE에 이제 기본 Python 인터프리터와 매우 유사한 명령줄이 포함됩니다.

  • 많은 곳에 호출 팁(Call tips)이 추가되었습니다.

  • 이제 IDLE을 패키지로 설치할 수 있습니다.

  • 편집기 창 하단에 줄/열 표시줄이 추가되었습니다.

  • 세 가지 새로운 키스트로크 명령: 모듈 확인(Alt-F5), 모듈 가져오기(F5), 스크립트 실행(Ctrl-F5).

삭제 및 더 이상 권장되지 않는(Deprecated) 모듈

몇몇 모듈이 구식이라거나, 동일한 작업을 수행하는 더 나은 방법이 생겨서 제거되었습니다. stdwin 모듈은 더 이상 개발되지 않는 플랫폼 독립적 창 도구용이었으므로 삭제되었습니다.

상당수의 모듈이 lib-old 하위 디렉토리로 이동되었습니다: cmp, cmpcache, dircmp, dump, find, grep, packmail, poly, util, whatsound, zmod. 만약 이동된 모듈을 사용하는 코드가 있다면, 해당 디렉토리를 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.

분실물 보관소