Python

Python 2.3의 새로운 기능

저자:

A.M. Kuchling

이 기사에서는 Python 2.3의 새로운 기능을 설명합니다. Python 2.3은 2003년 7월 29일에 출시되었습니다.

Python 2.3의 주요 주제는 2.2에서 추가된 기능 중 일부를 다듬고, 핵심 언어에 작지만 유용한 다양한 개선 사항을 추가하며, 표준 라이브러리를 확장하는 것입니다. 이전 버전에서 도입된 새로운 객체 모델은 18개월 동안의 버그 수정과 새로운 스타일 클래스의 성능을 향상시킨 최적화 노력을 통해 개선되었습니다. sum()enumerate() 와 같은 몇 가지 새로운 내장 함수가 추가되었습니다. 이제 in 연산자를 부분 문자열 검색에 사용할 수 있습니다(예: "ab" in "abc"True 를 반환함).

다양한 새로운 라이브러리 기능 중 일부로는 Boolean, set, heap, date/time 데이터 타입, ZIP 형식의 아카이브에서 모듈을 가져오는 능력, 오랫동안 기다려온 Python 카탈로그에 대한 메타데이터 지원, 업데이트된 버전의 IDLE, 메시지 로깅, 텍스트 래핑, CSV 파일 파싱, 명령줄 옵션 처리, BerkeleyDB 데이터베이스 사용 등을 위한 모듈 등이 포함됩니다. 새롭게 추가되거나 개선된 모듈 목록은 매우 방대합니다.

이 기사는 새로운 기능에 대한 전체 사양을 제공하는 대신 편리한 개요를 제공합니다. 자세한 내용은 Python 라이브러리 참조(Python Library Reference) 및 Python 참조 매뉴얼(Python Reference Manual)과 같은 Python 2.3 문서를 참조하십시오. 전체 구현 내용과 설계 근거를 이해하려면 특정 신기능에 대한 PEP를 참조하십시오.

PEP 218: 표준 Set 데이터 타입

새로운 sets 모듈은 set 데이터 타입의 구현을 포함합니다. Set 클래스는 수정 가능한(mutable) 집합으로, 멤버를 추가하거나 제거할 수 있습니다. ImmutableSet 클래스는 수정할 수 없는 집합이며, 따라서 ImmutableSet 인스턴스는 딕셔너리 키로 사용할 수 있습니다. 집합은 딕셔너리를 기반으로 구축되므로 집합 내의 요소는 해시 가능(hashable)해야 합니다.

다음은 간단한 예제입니다:

>>> import sets
>>> S = sets.Set([1,2,3])
>>> S
Set([1, 2, 3])
>>> 1 in S
True
>>> 0 in S
False
>>> S.add(5)
>>> S.remove(3)
>>> S
Set([1, 2, 5])
>>>

집합의 합집합과 교집합은 union()intersection() 메서드로 계산할 수 있으며, 대안적인 표기법으로 비트 연산자 &| 를 사용할 수 있습니다. 가변 집합 또한 이러한 메서드들의 인플레이스(in-place) 버전인 union_update()intersection_update() 를 제공합니다.

>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([4,5,6])
>>> S1.union(S2)
Set([1, 2, 3, 4, 5, 6])
>>> S1 | S2                  # 대체 표기법
Set([1, 2, 3, 4, 5, 6])
>>> S1.intersection(S2)
Set([])
>>> S1 & S2                  # 대체 표기법
Set([])
>>> S1.union_update(S2)
>>> S1
Set([1, 2, 3, 4, 5, 6])
>>>

두 집합의 대칭 차(symmetric difference)를 구하는 것도 가능합니다. 이는 합집합 중 교집합에 포함되지 않는 모든 요소의 집합입니다. 다른 표현 방식으로는 대칭 차가 정확히 하나의 집합에만 속하는 모든 요소를 포함한다고 할 수 있습니다. 이 역시 대체 표기법(^)이 있으며, 이름이 다소 복잡한 symmetric_difference_update() 라는 인플레이스 버전도 존재합니다.

>>> S1 = sets.Set([1,2,3,4])
>>> S2 = sets.Set([3,4,5,6])
>>> S1.symmetric_difference(S2)
Set([1, 2, 5, 6])
>>> S1 ^ S2
Set([1, 2, 5, 6])
>>>

또한 한 집합이 다른 집합의 부분집합인지 또는 상위집합인지 확인하는 issubset()issuperset() 메서드가 있습니다:

>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([2,3])
>>> S2.issubset(S1)
True
>>> S1.issubset(S2)
False
>>> S1.issuperset(S2)
True
>>>

더 보기

PEP 218 - 내장 세트 객체 타입 추가

Greg V. Wilson이 작성한 PEP. Greg V. Wilson, Alex Martelli, GvR에 의해 구현되었습니다.

PEP 255: 간단한 제너레이터

Python 2.2에서 제너레이터가 from __future__ import generators 지시어로 활성화할 수 있는 선택적 기능으로 추가되었습니다. 2.3에서는 제너레이터를 별도로 활성화할 필요 없이 항상 사용할 수 있으며, 이는 yield 가 이제 항상 키워드임을 의미합니다. 이 섹션의 나머지 부분은 “What’s New in Python 2.2” 문서의 제너레이터 설명 내용을 복사한 것이므로, Python 2.2 출시 당시의 해당 문서를 읽어본 분들은 이 섹션의 나머지 부분을 건너뛰어도 좋습니다.

당신은 파이썬이나 C에서 함수 호출이 어떻게 작동하는지 잘 알고 있을 것입니다. 함수를 호출하면 로컬 변수가 생성되는 전용 네임스페이스가 할당됩니다. 함수가 return 문에 도달하면 로컬 변수가 제거되고 결과값이 호출자에게 반환됩니다. 나중에 동일한 함수를 호출하면 새로운 세트의 로컬 변수가 생성됩니다. 하지만, 만약 함수를 종료할 때 로컬 변수가 사라지지 않는다면 어떨까요? 나중에 중단했던 부분부터 함수를 다시 재개할 수 있다면 어떨까요? 이것이 제너레이터가 제공하는 기능입니다; 제너레이터는 재개 가능한 함수로 생각될 수 있습니다.

다음은 제너레이터 함수의 가장 간단한 예입니다:

def generate_ints(N):
    for i in range(N):
        yield i

제너레이터를 위해 새로운 키워드인 yield 가 도입되었습니다. yield 문이 포함된 모든 함수는 제너레이터 함수이며, 이는 파이썬의 바이트 코드 컴파일러에 의해 감지되어 함수를 특별하게 컴파일합니다.

When you call a generator function, it doesn’t return a single value; instead it returns a generator object that supports the iterator protocol. On executing the yield statement, the generator outputs the value of i, similar to a return statement. The big difference between yield and a return statement is that on reaching a yield the generator’s state of execution is suspended and local variables are preserved. On the next call to the generator’s .next() method, the function will resume executing immediately after the yield statement. (For complicated reasons, the yield statement isn’t allowed inside the try block of a tryfinally statement; read PEP 255 for a full explanation of the interaction between yield and exceptions.)

generate_ints() 제너레이터의 사용 예시입니다:

>>> gen = generate_ints(3)
>>> gen
<generator object at 0x8117f90>
>>> gen.next()
0
>>> gen.next()
1
>>> gen.next()
2
>>> gen.next()
Traceback (most recent call last):
  File "stdin", line 1, in ?
  File "stdin", line 2, in generate_ints
StopIteration

for i in generate_ints(5) 또는 a,b,c = generate_ints(3) 와 같이 작성할 수 있습니다.

제너레이터 함수 내부에서 return 문은 값 없이만 사용할 수 있으며, 이는 값의 나열이 끝났음을 의미합니다. 그 이후로 제너레이터는 더 이상 어떠한 값도 반환할 수 없습니다. return 5 와 같이 값이 포함된 return 문은 제너레이터 함수 내에서 구문 오류입니다. 또한 제너레이터 결과의 종료는 수동으로 StopIteration 을 발생시키거나, 실행 흐름이 함수의 끝까지 도달하게 함으로써 나타낼 수도 있습니다.

직접 클래스를 작성하고 제너레이터의 모든 지역 변수를 인스턴스 변수로 저장함으로써 수동으로 제너레이터와 동일한 효과를 얻을 수도 있습니다. 예를 들어, 정수 리스트를 반환하는 과정을 self.count 를 0으로 설정하고 next() 메서드가 self.count 를 증가시켜 반환하도록 구현할 수 있습니다. 하지만 다소 복잡한 제너레이터의 경우 해당 클래스를 작성하는 것이 훨씬 더 번거로울 것입니다. Lib/test/test_generators.py 에는 더 흥미로운 예시들이 포함되어 있습니다. 가장 간단한 예제는 재귀적으로 제너레이터를 사용하여 트리를 중위 순회(in-order traversal)하는 기능을 구현합니다.

# 트리 노드를 중위 순회(in-order)로 생성하는 재귀적 제너레이터
def inorder(t):
    if t:
        for x in inorder(t.left):
            yield x
        yield t.label
        for x in inorder(t.right):
            yield x

Lib/test/test_generators.py 에 있는 다른 두 가지 예제는 N-여왕 문제(NxN 체스판에서 서로를 위협하지 않도록 N개의 여왕을 배치하는 문제)와 기사의 여행(기사가 NxN 체스판의 모든 칸을 중복 방문 없이 한 번씩 거쳐가는 경로 찾기)에 대한 해결책을 제공합니다.

제너레이터 개념은 다른 프로그래밍 언어, 특히 제너레이터 개념이 중심인 Icon(https://www2.cs.arizona.edu/icon/)에서 유래했습니다. Icon에서는 모든 표현식과 함수 호출이 제너레이터처럼 동작합니다. https://www2.cs.arizona.edu/icon/docs/ipd266.htm의 “An Overview of the Icon Programming Language”에 수록된 예제 하나가 이러한 모습이 어떠한지 보여줍니다:

sentence := "Store it in the neighboring harbor"
if (i := find("or", sentence)) > 5 then write(i)

Icon에서 find() 함수는 부분 문자열 “or”이 발견되는 인덱스인 3, 23, 33을 반환합니다. if 문에서 i 에 처음으로 3이라는 값이 할당되지만, 3은 5보다 작으므로 비교가 실패하고 Icon은 두 번째 값인 23으로 다시 시도합니다. 23은 5보다 크므로 비교가 성공하며 코드는 화면에 23을 출력합니다.

파이썬은 제너레이터를 핵심 개념으로 채택하는 데 있어 Icon만큼 멀리 나아가지는 않았습니다. 제너레이터는 파이썬의 핵심 언어의 일부로 간주되지만, 이를 배우거나 사용하는 것이 강제 사항은 아닙니다. 만약 여러분이 가진 문제를 해결하는 데 도움이 되지 않는다면 자유롭게 무시하셔도 좋습니다. 그러나 아이콘과 비교했을 때 파이썬 인터페이스만의 독특한 특징은 제너레이터의 상태가 다른 함수로 전달되거나 데이터 구조에 저장될 수 있는 구체적인 객체(이터레이터)로 표현된다는 점입니다.

더 보기

PEP 255 - 단순 제너레이터

Neil Schemenauer, Tim Peters, Magnus Lie Hetland이 작성했습니다. 대부분은 Neil Schemenauer와 Tim Peters가 구현했으며, Python Labs 팀이 다른 수정 사항을 반영했습니다.

PEP 263: 소스 코드 인코딩

이제 파이썬 소스 파일을 서로 다른 문자 세트 인코딩으로 선언할 수 있습니다. 인코딩은 소스 파일의 첫 번째 또는 두 번째 줄에 특별한 형식의 주석을 포함하여 선언됩니다. 예를 들어, UTF-8 파일은 다음과 같이 선언될 수 있습니다:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

그러한 인코딩 선언이 없으면 기본으로 사용되는 인코딩은 7비트 ASCII입니다. 인코딩 선언이 없으면서 8비트 문자가 포함된 문자열 리터럴을 포함하는 모듈을 실행하거나 가져올 경우, 파이썬 2.3에서는 DeprecationWarning 이 발생하며, 2.4 버전부터는 구문 오류(syntax error)로 처리됩니다.

인코딩 선언은 유니코드 문자열 리터럴에만 영향을 미치며, 해당 리터럴은 지정된 인코딩을 사용하여 유니코드로 변환됩니다. 주의할 점은 파이썬 식별자는 여전히 ASCII 문자만 허용되므로 일반적인 알파뉴메릭 이외의 문자를 사용하는 변수 이름을 사용할 수는 없습니다.

더 보기

PEP 263 - 파이썬 소스 코드 인코딩 정의

Marc-André Lemburg와 Martin von Löwis가 작성하였으며, Suzuki Hisao와 Martin von Löwis가 구현하였습니다.

PEP 273: ZIP 아카이브에서 모듈 가져오기

새로운 zipimport 모듈은 ZIP 포맷의 아카이브에서 모듈을 가져오는 기능을 지원합니다. 해당 모듈을 명시적으로 임포트할 필요는 없습니다. ZIP 아카이브의 파일 이름이 sys.path 에 추가되면 자동으로 임포트됩니다. 예를 들면:

amk@nyman:~/src/python$ unzip -l /tmp/example.zip
Archive:  /tmp/example.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
     8467  11-26-02 22:30   jwzthreading.py
 --------                   -------
     8467                   1 file
amk@nyman:~/src/python$ ./python
Python 2.3 (#1, Aug 1 2003, 19:54:32)
>>> import sys
>>> sys.path.insert(0, '/tmp/example.zip')  # Add .zip file to front of path
>>> import jwzthreading
>>> jwzthreading.__file__
'/tmp/example.zip/jwzthreading.py'
>>>

sys.path 의 항목은 이제 ZIP 아카이브의 파일 이름이 될 수 있습니다. ZIP 아카이브는 모든 종류의 파일을 포함할 수 있지만, *.py, *.pyc, 또는 *.pyo 라는 이름의 파일만 임포트할 수 있습니다. 만약 아카이브에 *.py 파일만 포함되어 있다면, 파이썬은 해당 *.pyc 파일을 추가하여 아카이브를 수정하려고 시도하지 않습니다. 즉, ZIP 아카이브에 *.pyc 파일이 포함되어 있지 않으면 임포트 속도가 다소 느려질 수 있습니다.

아카이브 내의 경로를 지정하여 특정 하위 디렉터리에서만 임포트하도록 할 수도 있습니다. 예를 들어, /tmp/example.zip/lib/`라는 경로는 아카이브 내의 :file:`lib/ 하위 디렉터리에서만 임포트합니다.

더 보기

PEP 273 - Zip 아카이브에서 모듈 임포트

구현을 함께 제공한 James C. Ahlstrom이 작성했습니다. 파이썬 2.3은 PEP 273 의 명세를 따르지만, PEP 302 에 설명된 임포트 훅을 사용하는 Just van Rossum의 구현을 사용합니다. 새로운 임포트 훅에 대한 설명은 PEP 302: 새로운 임포트 훅 섹션을 참조하십시오.

PEP 277: Windows NT용 유니코드 파일 이름 지원

Windows NT, 2000, 및 XP에서 시스템은 파일 이름을 유니코드 문자열로 저장합니다. 기존에 파이썬은 파일 이름을 바이트 문자열로 표현해 왔으나, 이 방식은 일부 파일 이름에 접근할 수 없게 만들므로 부적절합니다.

파이썬은 이제 대부분의 파일 이름을 요구하는 모든 함수(특히 내장 함수인 open())에서 임의의 유니코드 문자열을 사용하는 것을 허용합니다. os.listdir`에 유니코드 문자열을 전달하면 파이썬은 유니코드 문자열 목록을 반환합니다. 새로운 함수인 :func:()!os.getcwdu`는 현재 디렉터리를 유니코드 문자열로 반환합니다.

바이트 문자열도 여전히 파일 이름으로 작동하며, Windows에서 파이썬은 이를 mbcs 인코딩을 사용하여 투명하게 유니코드(Unicode)로 변환합니다.

Other systems also allow Unicode strings as file names but convert them to byte strings before passing them to the system, which can cause a UnicodeError to be raised. Applications can test whether arbitrary Unicode strings are supported as file names by checking os.path.supports_unicode_filenames, a Boolean value.

MacOS에서 os.listdir() 은 이제 유니코드 파일 이름을 반환할 수 있습니다.

더 보기

PEP 277 - Windows NT용 유니코드 파일 이름 지원

Neil Hodgson이 작성했으며, Neil Hodgson, Martin von Löwis, Mark Hammond가 구현했습니다.

PEP 278: Universal Newline(유니버설 줄 넘김) 지원

오늘날 사용되는 세 가지 주요 운영체제는 Microsoft Windows, Apple의 Macintosh OS, 그리고 다양한 Unix 파생형입니다. 크로스 플랫폼 작업 시 발생하는 사소한 불편함 중 하나는 이 세 플랫폼이 모두 텍스트 파일의 줄 끝을 표시하는 데 서로 다른 문자를 사용한다는 점입니다. Unix는 linefeed(ASCII 문자 10), MacOS는 carriage return(ASCII 문자 13)을 사용하며, Windows는 carriage return과 newline이 합쳐진 두 개의 문자 시퀀스를 사용합니다.

파이썬의 파일 객체는 이제 파이썬이 실행되는 플랫폼이 따르는 규칙 이외의 줄 끝 관례도 지원할 수 있습니다. 'U' 또는 'rU' 모드로 파일을 열면 universal newlines 모드에서 읽기용으로 열립니다. 세 가지 모두의 줄 끝 관례가 read()readline() 과 같은 다양한 파일 메서드에 의해 반환되는 문자열 내에서 '\n' 으로 변환됩니다.

Universal newline 지원은 모듈을 임포트하거나 execfile() 함수로 파일을 실행할 때도 사용됩니다. 이는 파이썬 모듈이 줄 끝을 변환할 필요 없이 세 가지 운영체제 모두에서 공유될 수 있음을 의미합니다.

파이썬을 컴파일할 때 configure 스크립트를 실행할 때 --without-universal-newlines 옵션을 지정하여 이 기능을 비활성화할 수 있습니다.

더 보기

PEP 278 - Universal Newline(유니버설 줄 넘김) 지원

Jack Jansen이 작성하고 구현했습니다.

PEP 279: enumerate()

새로운 내장 함수인 enumerate`는 특정 루프를 조금 명확하게 만들어 줍니다. *thing*이 반복자(iterator) 또는 시퀀스인 경우, ``enumerate(thing)``은 ``(0, thing[0])`(), (1, thing[1]), (2, thing[2]) 등의 값을 반환하는 반복자를 반환합니다.

리스트의 모든 요소를 변경하는 일반적인 관용구는 다음과 같습니다:

for i in range(len(L)):
    item = L[i]
    # ... item을 기반으로 결과 계산 ...
    L[i] = result

이것은 enumerate() 를 사용하여 다음과 같이 다시 작성할 수 있습니다:

for i, item in enumerate(L):
    # ... item을 기반으로 결과 계산 ...
    L[i] = result

더 보기

PEP 279 - enumerate() 내장 함수

Raymond D. Hettinger가 작성하고 구현했습니다.

PEP 282: logging 패키지

로그를 작성하기 위한 표준 패키지인 logging 이 파이썬 2.3에 추가되었습니다. 이 패키지는 다양한 방식으로 필터링하고 처리할 수 있는 로그 출력을 생성하는 강력하고 유연한 메커니즘을 제공합니다. 표준 형식으로 작성된 설정 파일을 사용하여 프로그램의 로깅 동작을 제어할 수 있습니다. 파이썬은 표준 에러나 파일 또는 소켓에 로그 레코드를 기록하거나, 시스템 로그로 보내거나, 특정 주소로 이메일을 보내는 등의 핸들러를 포함하고 있으며, 물론 사용자 정의 핸들러 클래스를 작성할 수도 있습니다.

Logger 클래스는 주요 클래스입니다. 대부분의 애플리케이션 코드는 애플리케이션의 특정 하위 시스템에서 사용되는 하나 이상의 Logger 객체를 다룹니다. 각 Logger 는 이름으로 식별되며, 이름은 . 을 컴포넌트 구분자로 사용하여 계층 구조로 구성됩니다. 예를 들어, server, server.auth, server.network 라는 이름의 Logger 인스턴스를 가질 수 있습니다. 후자의 두 인스턴스는 계층 구조에서 server 아래에 위치합니다. 이는 server 의 상세 수준을 높이거나 server 메시지를 다른 핸들러로 보내면 그 변경 사항이 server.authserver.network 에 기록되는 레코드에도 적용됨을 의미합니다. 또한 모든 다른 로거의 부모인 루트 Logger 가 있습니다.

단순한 용도의 경우, logging 패키지는 항상 루트 로그를 사용하는 몇 가지 편의 함수를 포함합니다:

import logging

logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning:config file %s not found', 'server.conf')
logging.error('Error occurred')
logging.critical('Critical error -- shutting down')

이것은 다음과 같은 출력을 생성합니다:

WARNING:root:Warning:config file server.conf not found
ERROR:root:Error occurred
CRITICAL:root:Critical error -- shutting down

기본 설정에서 정보(informational) 및 디버깅 메시지는 생략되고 출력은 표준 에러로 전송됩니다. 루트 로거에 setLevel() 메서드를 호출하여 정보 및 디버그 메시지의 표시를 활성화할 수 있습니다.

warning() 호출에서 문자열 포맷팅 연산자의 사용에 주의하십시오. 로깅 메시지를 위한 모든 함수는 인자 (msg, arg1, arg2, ...) 를 받아 msg % (arg1, arg2, ...) 의 결과인 문자열을 기록합니다.

또한 가장 최근의 추적 정보를 기록하는 exception() 함수가 있습니다. 키워드 인수 exc_info 에 참(true) 값을 지정하면 다른 모든 함수도 추적 정보를 기록합니다.

def f():
    try:    1/0
    except: logging.exception('Problem recorded')

f()

이것은 다음과 같은 출력을 생성합니다:

ERROR:root:Problem recorded
Traceback (most recent call last):
  File "t.py", line 6, in f
    1/0
ZeroDivisionError: integer division or modulo by zero

조금 더 복잡한 프로그램은 루트 로거 이외의 로거를 사용합니다. 특정 로그를 가져오는 데는 getLogger(name) 함수가 사용되며, 아직 존재하지 않는 경우 해당 로거를 생성합니다. getLogger(None) 은 루트 로거를 반환합니다.

log = logging.getLogger('server')
 ...
log.info('Listening on port %i', port)
 ...
log.critical('Disk full')
 ...

로그 레코드는 일반적으로 계층 구조 위로 전파되므로, server.auth 에 기록된 메시지는도 serverroot 에서 확인할 수 있습니다. 하지만 Logger 는 그 자신의 propagate 속성을 False 로 설정하여 이를 방지할 수 있습니다.

logging 패키지는 사용자 정의가 가능한 더 많은 클래스를 제공합니다. Logger 인스턴스가 메시지를 기록하도록 요청받으면, 하나 이상의 다양한 Handler 인스턴스로 전송되는 LogRecord 인스턴스를 생성합니다. 로거와 핸들러는 또한 필터 목록을 연결할 수 있으며, 각 필터는 LogRecord 를 무시하거나 전달하기 전에 레코드를 수정할 수 있습니다. 최종 출력 시, LogRecord 인스턴스는 Formatter 클래스에 의해 텍스트로 변환됩니다. 이 모든 클래스는 사용자가 직접 작성한 클래스로 대체할 수 있습니다.

이러한 모든 기능으로 인해 logging 패키지는 가장 복잡한 애플리케이션에도 충분한 유연성을 제공합니다. 이는 특징에 대한 불완전한 개요일 뿐이므로, 자세한 내용은 패키지의 참조 문서를 확인하십시오. PEP 282 를 읽는 것도 도움이 될 것입니다.

더 보기

PEP 282 - 로깅 시스템

Vinay Sajip와 Trent Mick이 작성했으며, Vinay Sajip이 구현했습니다.

PEP 285: 불리언(Boolean) 타입

파이썬 2.3에 Boolean 타입이 추가되었습니다. __builtin__ 모듈에 두 개의 새로운 상수인 TrueFalse 가 추가되었습니다. (TrueFalse 상수는 파이썬 2.2.1에서 내장 기능으로 추가되었으나, 2.2.1 버전에서는 단순히 1과 0의 정수 값으로 설정되어 별도의 타입이 아니었습니다.)

이 새로운 타입에 대한 타입 객체는 bool 로 명명되며, 이의 생성자는 어떤 파이썬 값도 가져와서 True 또는 False 로 변환합니다.

>>> bool(1)
True
>>> bool(0)
False
>>> bool([])
False
>>> bool( (1,) )
True

대부분의 표준 라이브러리 모듈과 내장 함수가 불리언(Boolean)을 반환하도록 변경되었습니다.

>>> obj = []
>>> hasattr(obj, 'append')
True
>>> isinstance(obj, list)
True
>>> isinstance(obj, tuple)
False

파이썬의 불리언(Boolean)은 코드를 더 명확하게 만들기 위한 주요 목표로 추가되었습니다. 예를 들어, 어떤 함수를 읽는 중에 return 1 이라는 문장을 마주친다면, 1 이 불리언 참 값인지, 인덱스인지, 아니면 다른 양에 곱해지는 계수인지 궁금할 수 있습니다. 하지만 해당 문장이 return True 라면 반환값의 의미가 매우 명확해집니다.

파이썬의 불리언은 엄격한 타입 체크를 위해 추가된 것이 아닙니다. Pascal과 같은 매우 엄격한 언어라면 불리언을 사용한 산술 연산을 막고, if 문 내의 표현식이 항상 불리언 결과로 평가되도록 요구할 것입니다. 파이썬은 PEP 285 에서 명시하는 바와 같이 그렇게 엄격하지 않으며 앞으로도 그럴 것이 없습니다. 이는 리스트나 튜플 또는 임의의 객체로 평가되는 표현식이라도 if 문에서 여전히 사용할 수 있음을 의미합니다. 불리언 타입은 int 클래스의 서브클래스이므로 불리언을 사용한 산술 연산이 여전히 작동합니다.

>>> True + 1
2
>>> False + 1
1
>>> False * 75
0
>>> True * 75
75

한 문장으로 요약하자면, TrueFalse 는 정수 값 1과 0을 표기하는 대안적인 방법이며, 유일한 차이점은 str()repr()'1'''0'' 대신 'True''False' 라는 문자열을 반환한다는 것입니다.

더 보기

PEP 285 - bool 타입 추가

GvR이 작성하고 구현했습니다.

PEP 293: 코덱 에러 처리 콜백

유니코드 문자열을 바이트 문자열로 인코딩할 때 인코딩할 수 없는 문자가 나타날 수 있습니다. 지금까지 파이썬은 에러 처리를 “strict”(UnicodeError 발생), “ignore”(문자 건너뛰기), 또는 “replace”(출력 문자열에 물음표 사용) 중에서 선택할 수 있게 했으며, 기본 동작은 “strict”였습니다. 이러한 오류에 대해 변환된 문자열에 XML 문자 참조나 HTML 엔티티 참조를 삽입하는 것과 같은 대안적인 처리 방식을 지정하는 것이 유용할 수 있습니다.

이제 파이썬은 다양한 처리 전략을 추가할 수 있는 유연한 프레임워크를 갖추고 있습니다. codecs.register_error() 를 사용하여 새로운 에러 처리기를 추가할 수 있으며, 이후 코덱은 codecs.lookup_error() 를 통해 해당 에러 처리기에 접근할 수 있습니다. C로 작성된 코덱을 위해 이에 상응하는 C API도 추가되었습니다. 에러 처리기는 변환되는 문자열, 에러가 감지된 위치, 대상 인코딩과 같은 필요한 상태 정보를 받습니다. 그 후 핸들러는 예외를 발생시키거나 대체 문자열을 반환할 수 있습니다.

이 프레임워크를 사용하여 두 가지 추가 에러 처리기가 구현되었습니다: “backslashreplace”는 인코딩할 수 없는 문자를 표현하기 위해 파이썬 백슬래시 인용을 사용하며, “xmlcharrefreplace”는 XML 문자 참조를 생성합니다.

더 보기

PEP 293 - 코덱 에러 처리 콜백

Walter Dörwald가 작성하고 구현했습니다.

PEP 301: Distutils용 패키지 인덱스 및 메타데이터

오랫동안 요청되었던 파이썬 카탈로그 지원이 2.3 버전에서 처음 도입됩니다.

카탈로그의 핵심은 새로운 Distutils register 명령입니다. python setup.py register 를 실행하면 패키지 이름, 버전, 유지 관리자, 설명 등과 같은 메타데이터를 수집하여 중앙 카탈로그 서버로 전송합니다. 생성된 카탈로그는 https://pypi.org에서 확인할 수 있습니다.

카탈로그를 좀 더 유용하게 만들기 위해 Distutils setup() 함수에 새로운 선택적 classifiers 키워드 인자가 추가되었습니다. 소프트웨어를 분류하는 데 도움이 되는 Trove 스타일의 문자열 목록을 제공할 수 있습니다.

이전 버전의 Distutils와 호환되도록 작성된 분류기가 포함된 setup.py 예시입니다:

from distutils import core
kw = {'name': "Quixote",
      'version': "0.5.1",
      'description': "A highly Pythonic Web application framework",
      # ...
      }

if (hasattr(core, 'setup_keywords') and
    'classifiers' in core.setup_keywords):
    kw['classifiers'] = \
        ['Topic :: Internet :: WWW/HTTP :: Dynamic Content',
         'Environment :: No Input/Output (Daemon)',
         'Intended Audience :: Developers'],

core.setup(**kw)

모든 분류 목록은 python setup.py register --list-classifiers 를 실행하여 확인할 수 있습니다.

더 보기

PEP 301 - Distutils용 패키지 인덱스 및 메타데이터

Richard Jones가 작성하고 구현했습니다.

PEP 302: 새로운 임포트 훅

Python 1.3에서 ihooks 모듈이 도입된 이후 커스텀 임포트 훅을 작성하는 것이 가능해졌으나, 새로운 임포트 훅을 작성하는 것이 어렵고 복잡하여 만족도가 높지 않았습니다. imputiliu 모듈과 같은 다양한 대안이 제안되었지만, 어느 것도 많은 지지를 얻지 못했으며 C 코드에서 쉽게 사용할 수도 없었습니다.

PEP 302 는 이전 작업들, 특히 Gordon McMillan의 iu 모듈에서 아이디어를 빌려왔습니다. sys 모듈에 세 가지 새로운 항목이 추가됩니다:

  • sys.path_hooks 는 호출 가능한 객체들의 목록이며, 대부분은 클래스입니다. 각 호출 가능 객체는 경로가 포함된 문자열을 받아 이 경로에서 임포트를 처리하는 임포터(importer) 객체를 반환하거나, 해당 경로를 처리할 수 없는 경우 ImportError 예외를 발생시킵니다.

  • sys.path_importer_cache 는 각 경로에 대한 임포터 객체를 캐싱하므로, sys.path_hooks 를 각 경로마다 한 번만 탐색하면 됩니다.

  • sys.meta_pathsys.path 를 확인하기 전에 탐색되는 임포터 객체들의 목록입니다. 이 리스트는 처음에 비어 있지만, 사용자 코드가 객체를 추가할 수 있습니다. 이 리스트에 추가된 객체를 통해 추가적인 빌트인 모듈이나 프로즌(frozen) 모듈을 임포트할 수 있습니다.

임포터 객체는 find_module(fullname, path=None) 라는 단일 메서드를 가져야 합니다. fullnamestring 또는 distutils.core 와 같은 모듈이나 패키지 이름이 됩니다. find_module()load_module(fullname) 이라는 단일 메서드를 가지며, 해당 모듈 객체를 생성하여 반환하는 로더(loader) 객체를 반환해야 합니다.

따라서 파이썬의 새로운 임포트 로직에 대한 의사 코드는 다음과 같습니다(약간 단순화됨. 자세한 내용은 PEP 302 를 참조하십시오):

for mp in sys.meta_path:
    loader = mp(fullname)
    if loader is not None:
        <module> = loader.load_module(fullname)

for path in sys.path:
    for hook in sys.path_hooks:
        try:
            importer = hook(path)
        except ImportError:
            # ImportError, so try the other path hooks
            pass
        else:
            loader = importer.find_module(fullname)
            <module> = loader.load_module(fullname)

# Not found!
raise ImportError

더 보기

PEP 302 - 새로운 임포트 훅

Just van Rossum과 Paul Moore가 작성하였으며, Just van Rossum이 구현했습니다.

PEP 305: 쉼표로 구분된 파일

쉼표로 구분된 파일은 데이터베이스와 스프레드시트에서 데이터를 내보낼 때 자주 사용되는 형식입니다. 파이썬 2.3에서는 쉼표로 구분된 파일을 위한 파서를 추가했습니다.

쉼표로 구분된 형식은 언뜻 보기에 매우 간단해 보입니다:

Costs,150,200,3.95

한 줄을 읽고 line.split(',') 를 호출하는 것보다 더 간단할 수 있을까요? 하지만 쉼표를 포함할 수 있는 문자열 데이터가 들어오면 상황이 복잡해집니다:

"Costs",150,200,3.95,"Includes taxes, shipping, and sundry items"

크고 복잡한 정규 표현식으로도 이를 파싱할 수 있지만, 새로운 csv 패키지를 사용하는 것이 훨씬 간단합니다:

import csv

input = open('datafile', 'rb')
reader = csv.reader(input)
for line in reader:
    print line

reader() 함수는 여러 가지 옵션을 받습니다. 필드 구분자는 쉼표에 국한되지 않으며 어떤 문자로든 변경할 수 있으며, 인용 및 줄 바꿈 문자도 마찬가지로 변경 가능합니다.

쉼표로 구분된 파일의 다양한 방언(dialect)을 정의하고 등록할 수 있습니다. 현재는 모두 마이크로소프트 엑셀에서 사용되는 두 가지 방언이 있습니다. 별도의 csv.writer 클래스는 튜플이나 리스트의 연속으로부터 쉼표로 구분된 파일을 생성하며, 구분자를 포함하는 문자열은 인용 처리합니다.

더 보기

PEP 305 - CSV 파일 API

Kevin Altis, Dave Cole, Andrew McNamara, Skip Montanaro, Cliff Wells가 작성하고 구현했습니다.

PEP 307: 피클 강화

picklecPickle 모듈은 2.3 개발 주기 동안 개선되었습니다. 2.2에서 새 스타일의 클래스는 어렵지 않게 피클링할 수 있었지만, 매우 압축된 형태로 피클링되지는 않았습니다. PEP 307 에서는 새 스타일의 클래스가 기존 방식의 클래스보다 세 배나 긴 피클 문자열을 생성하는 간단한 예시를 언급합니다.

해결책은 새로운 피클 프로토콜을 도입하는 것이었습니다. pickle.dumps() 함수는 오랫동안 텍스트 또는 바이너리 플래그를 지원해 왔습니다. 2.3에서 이 플래그는 불리언에서 정수로 재정의되었습니다. 0은 이전 텍스트 모드 피클 형식, 1은 이전 바이너리 형식이며, 이제 2는 새로운 2.3 전용 형식입니다. 새로운 상수인 pickle.HIGHEST_PROTOCOL 을 사용하여 사용할 수 있는 가장 고도화된 프로토콜을 선택할 수 있습니다.

언피클링은 더 이상 안전한 작업으로 간주되지 않습니다. 2.2의 pickle`은 안전하지 않은 클래스가 언피클되는 것을 방지하기 위한 훅(특히 :attr:!__safe_for_unpickling__` 속성)을 제공했으나, 이 코드는 한 번도 검증된 적이 없으므로 2.3에서 모두 제거되었습니다. 파이썬의 어떤 버전에서도 신뢰할 수 없는 데이터를 언피클링해서는 안 됩니다.

새 스타일 클래스의 피클링 오버헤드를 줄이기 위해 세 가지 특수 메서드인 __getstate__(), __setstate__(), 및 __getnewargs__() 를 사용하여 피클링을 사용자 정의할 수 있는 새 인터페이스가 추가되었습니다. 이 메서드들의 전체 의미는 PEP 307 을 참조하십시오.

피클을 더욱 압축하는 방법으로, 이제 피클된 클래스를 식별하기 위해 긴 문자열 대신 정수 코드를 사용할 수 있습니다. 파이썬 소프트웨어 재단(Python Software Foundation)에서 표준화된 코드 목록을 관리하며, 개인용으로 사용할 수 있는 범위의 코드도 제공됩니다. 현재까지는 별도의 코드가 지정되지 않았습니다.

더 보기

PEP 307 - 피클 프로토콜 확장

Guido van Rossum과 Tim Peters가 작성하고 구현했습니다.

확장 슬라이스

Python 1.4부터 슬라이싱 구문은 선택적인 세 번째 “step” 또는 “stride” 인수를 지원해 왔습니다. 예를 들어, L[1:10:2], L[:-1:1], L[::-1] 는 모두 유효한 Python 구문입니다. 이 기능은 세 번째 인자를 광범위하게 사용하는 Numerical Python 개발자들의 요청으로 Python에 추가되었습니다. 그러나 Python의 내장 리스트(list), 튜플(tuple), 문자열(string) 시퀀스 타입은 이 기능을 지원하지 않아 시도할 경우 TypeError 가 발생했습니다. Michael Hudson이 이 결함을 해결하기 위한 패치를 기여했습니다.

예를 들어, 이제 짝수 인덱스를 가진 리스트의 요소들을 쉽게 추출할 수 있습니다:

>>> L = range(10)
>>> L[::2]
[0, 2, 4, 6, 8]

음수 값도 동일한 리스트를 역순으로 복사하는 데 사용될 수 있습니다:

>>> L[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

이 기능은 튜플, 배열, 문자열에서도 작동합니다:

>>> s='abcd'
>>> s[::2]
'ac'
>>> s[::-1]
'dcba'

리스트나 배열과 같은 가변 시퀀스가 있는 경우 확장 슬라이스에 할당하거나 삭제할 수 있지만, 확장 슬라이스와 일반 슬라이스에 대한 할당 사이에는 몇 가지 차이점이 있습니다. 일반 슬라이스에 대한 할당은 시퀀스의 길이를 변경하는 데 사용될 수 있습니다:

>>> a = range(3)
>>> a
[0, 1, 2]
>>> a[1:3] = [4, 5, 6]
>>> a
[0, 4, 5, 6]

확장 슬라이스는 이처럼 유연하지 않습니다. 확장 슬라이스에 할당할 때, 문장의 오른쪽에 있는 리스트는 교체되는 슬라이스와 동일한 수의 항목을 포함해야 합니다:

>>> a = range(4)
>>> a
[0, 1, 2, 3]
>>> a[::2]
[0, 2]
>>> a[::2] = [0, -1]
>>> a
[0, 1, -1, 3]
>>> a[::2] = [0,1,2]
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: attempt to assign sequence of size 3 to extended slice of size 2

삭제는 더 간단합니다:

>>> a = range(4)
>>> a
[0, 1, 2, 3]
>>> a[::2]
[0, 2]
>>> del a[::2]
>>> a
[1, 3]

이제 내장 시퀀스의 __getitem__() 메서드에 슬라이스 객체를 전달할 수 있습니다:

>>> range(10).__getitem__(slice(0, 5, 2))
[0, 2, 4]

또는 서브스크립트에서 슬라이스 객체를 직접 사용할 수 있습니다:

>>> range(10)[slice(0, 5, 2)]
[0, 2, 4]

확장 슬라이싱을 지원하는 시퀀스 구현을 간소화하기 위해, 이제 슬라이스 객체는 indices(length) 메서드를 가집니다. 이 메서드는 시퀀스의 길이를 입력받아 range() 에 직접 전달할 수 있는 (start, stop, step) 튜플을 반환합니다. indices() 는 생략되거나 범위를 벗어난 인덱스를 일반 슬라이스와 일관된 방식으로 처리합니다 (이 단순해 보이는 문구 뒤에는 복잡한 세부 사항들이 숨어 있습니다!). 이 메서드는 다음과 같이 사용하도록 설계되었습니다:

class FakeSeq:
    ...
    def calc_item(self, i):
        ...
    def __getitem__(self, item):
        if isinstance(item, slice):
            indices = item.indices(len(self))
            return FakeSeq([self.calc_item(i) for i in range(*indices)])
        else:
            return self.calc_item(i)

이 예제를 통해 내장된 slice 객체가 이제 슬라이스 타입의 형(type) 객체이며 더 이상 함수가 아님을 알 수 있습니다. 이는 int, str 등이 동일한 변화를 겪었던 Python 2.2와 일치합니다.

이외의 언어 변경 사항

다음은 Python 2.3이 핵심 Python 언어에 적용한 모든 변경 사항입니다.

  • 본 문서의 PEP 255: 간단한 제너레이터 섹션에 설명된 대로, yield 문은 이제 항상 키워드로 처리됩니다.

  • 본 문서의 PEP 279: enumerate() 섹션에 설명된 대로, 새로운 내장 함수인 enumerate() 가 추가되었습니다.

  • 본 문서의 PEP 285: 불리언(Boolean) 타입 섹션에 설명된 대로, 내장된 bool 타입과 함께 두 개의 새로운 상수인 TrueFalse 가 추가되었습니다.

  • 이제 문자열이나 부동 소수점이 정수에 들어갈 수 없을 정도로 큰 경우, int() 타입 생성자는 OverflowError 를 발생시키는 대신 long 정수를 반환합니다. 이로 인해 isinstance(int(expression), int) 가 False라는 역설적인 결과가 나올 수 있지만, 실제 상황에서 문제가 될 가능성은 낮아 보입니다.

  • 내장 타입은 이제 본 문서의 확장 슬라이스 섹션에 설명된 대로 확장 슬라이싱 구문을 지원합니다.

  • 새로 추가된 내장 함수인 sum(iterable, start=0) 은 이터러블 객체 내의 숫자 항목들을 합산하여 그 합을 반환합니다. sum() 은 숫자만 허용하므로 여러 문자열을 연결하는 데 사용할 수 없습니다. (Alex Martelli 기여.)

  • 기존의 list.insert(pos, value)pos 가 음수일 때 리스트의 맨 앞에 value 를 삽입했습니다. 이제 이 동작이 슬라이스 인덱싱과 일관되도록 변경되어, pos 가 -1인 경우 마지막 요소 앞에 값이 삽입되는 등의 방식으로 작동합니다.

  • 리스트 내에서 value*를 찾아 인덱스를 반환하는 ``list.index(value)``는 이제 검색 범위를 리스트의 일부로 제한하기 위한 선택적 *startstop 인자를 받습니다.

  • 딕셔너리에 새로운 메서드인 pop(key[, *default*]) 가 추가되었습니다. 이 메서드는 key 에 해당하는 값을 반환하고 해당 키/값 쌍을 딕셔너리에서 제거합니다. 요청한 키가 딕셔너리에 없는 경우, default 가 지정되어 있으면 default 를 반환하고 그렇지 않으면 KeyError 를 발생시킵니다.

    >>> d = {1:2}
    >>> d
    {1: 2}
    >>> d.pop(4)
    Traceback (most recent call last):
      File "stdin", line 1, in ?
    KeyError: 4
    >>> d.pop(1)
    2
    >>> d.pop(1)
    Traceback (most recent call last):
      File "stdin", line 1, in ?
    KeyError: 'pop(): dictionary is empty'
    >>> d
    {}
    >>>
    

    또한 제공된 이터레이터 iterable 에서 키를 가져오고 모든 값을 value (기본값은 None)로 설정하는 딕셔너리를 생성하는 새로운 클래스 메서드인 dict.fromkeys(iterable, value) 가 추가되었습니다.

    (Raymond Hettinger 기여.)

    또한, dict() 생성자는 작은 딕셔너리를 쉽게 만들기 위해 키워드 인수를 허용합니다:

    >>> dict(red=1, blue=2, green=3, black=4)
    {'blue': 2, 'black': 4, 'green': 3, 'red': 1}
    

    (Just van Rossum 기여.)

  • assert 문은 더 이상 __debug__ 플래그를 확인하지 않으므로, __debug__ 에 값을 할당하여 어설션을 비활성화할 수 없습니다. -O 스위치를 사용하여 Python을 실행하면 여전히 어설션을 실행하지 않는 코드가 생성됩니다.

  • 대부분의 형(type) 객체가 이제 호출 가능하므로 이를 사용하여 함수, 클래스, 모듈과 같은 새로운 객체를 생성할 수 있습니다. (이는 이제 types 모듈에서 사용 가능한 형 객체를 사용할 수 있으므로, 향후 Python 버전에서 new 모듈이 폐기될 수 있음을 의미합니다.) 예를 들어, 다음 코드로 새로운 모듈 객체를 생성할 수 있습니다:

    >>> import types
    >>> m = types.ModuleType('abc','docstring')
    >>> m
    <module 'abc' (built-in)>
    >>> m.__doc__
    'docstring'
    
  • 폐기 예정인 기능을 알리는 새로운 경고인 PendingDeprecationWarning 이 추가되었습니다. 이 경고는 기본적으로 출력되지 않습니다. 향후 폐기될 기능의 사용 여부를 확인하려면 명령줄에 -Walways::PendingDeprecationWarning:: 를 입력하거나 warnings.filterwarnings() 를 사용하십시오.

  • raise "Error occurred" 와 같은 문자열 기반 예외를 폐기하는 과정이 시작되었습니다. 이제 문자열을 던지면(raising) PendingDeprecationWarning 이 발생합니다.

  • 변수 이름으로 None 을 사용하는 경우 이제 SyntaxWarning 경고가 발생합니다. 향후 Python 버전에서 None 은 마침내 키워드가 될 수 있습니다.

  • Python 2.1에서 도입된 파일 객체의 xreadlines() 메서드는 이제 파일이 자체 이터레이터로 동작하기 때문에 더 이상 필요하지 않습니다. xreadlines`는 원래 파일의 모든 줄을 순회하는 빠른 방법으로 도입되었으나, 이제는 단순히 ``for line in file_obj``라고 작성하면 됩니다. 또한 파일 객체에는 파일에 사용되는 인코딩을 제공하는 새로운 읽기 전용 :attr:()!encoding` 속성이 있으며, 파일에 쓰이는 유니코드 문자열은 주어진 인코딩을 사용하여 자동으로 바이트로 변환됩니다.

  • 새 스타일 클래스에서 사용되는 메서드 결정 순서(MRO)가 변경되었습니다. 다만, 매우 복잡한 상속 계층을 가진 경우에만 차이를 느낄 수 있습니다. 고전적(classic) 클래스는 이 변경의 영향을 받지 않습니다. Python 2.2는 원래 클래스의 조상들에 대한 위상 정렬(topological sort)을 사용했으나, 2.3은 논문 “A Monotonic Superclass Linearization for Dylan” 에 기술된 C3 알고리즘을 사용합니다. 이 변경의 동기를 이해하려면 Michele Simionato의 기사 Python 2.3 메서드 결정 순서 를 읽거나, https://mail.python.org/pipermail/python-dev/2002-October/029035.html의 메시지로 시작하는 python-dev 스레드를 읽어보십시오. Samuele Pedroni가 이 문제를 처음 지적하고 C3 알고리즘을 코딩하여 수정을 구현했습니다.

  • Python은 N개의 바이트코드를 실행한 후 스레드 간을 전환함으로써 멀티스레드 프로그램을 실행합니다. N의 기본값이 10에서 100으로 증가하여, 전환 오버헤드가 줄어들어 싱글 스레드 애플리케이션의 속도가 향상되었습니다. 일부 멀티스레드 애플리케이션은 응답 속도가 느려질 수 있으나, 이는 sys.setcheckinterval(N) 을 사용하여 제한을 낮은 숫자로 다시 설정함으로써 쉽게 해결할 수 있습니다. 이 제한은 새로운 sys.getcheckinterval() 함수로 가져올 수 있습니다.

  • 한 가지 사소하지만 영향력이 큰 변화는 Python에 포함된 모듈에 의해 정의된 확장형의 이름이 이제 타입 이름 앞에 모듈과 '.' 을 포함한다는 것입니다. 예를 들어, Python 2.2에서 소켓(socket)을 생성하고 그 {{obj}}의 __class__ 를 출력하면 다음과 같은 결과가 나왔습니다:

    >>> s = socket.socket()
    >>> s.__class__
    <type 'socket'>
    

    2.3에서는 다음과 같이 나옵니다:

    >>> s.__class__
    <type '_socket.socket'>
    
  • 구형과 신형 스타일 클래스 간의 알려진 불호환성 중 하나가 제거되었습니다. 이제 신형 스타일 클래스의 __name____bases__ 어트리뷰트에 할당할 수 있습니다. __bases__ 에 할당할 수 있는 것에 대해서는 인스턴스의 __class__ 어트리뷰션에 대한 할당과 유사한 몇 가지 제한이 있습니다.

문자열 변경 사항

  • 문자열에 대한 in 연산자의 작동 방식이 변경되었습니다. 이전에는 XY 가 문자열인 경우 X in Y 를 평가할 때 X 는 단일 문자로만 가능했습니다. 이제 이는 바뀌어, X 는 어떤 길이의 문자열도 될 수 있으며, XY 의 부분 문자열이면 X in YTrue 를 반환합니다. X 가 빈 문자열인 경우 결과는 항상 True 입니다.

    >>> 'ab' in 'abcd'
    True
    >>> 'ad' in 'abcd'
    False
    >>> '' in 'abcd'
    True
    

    이것은 부분 문자열이 시작되는 위치를 알려주지 않으므로, 해당 정보가 필요한 경우 find() 문자열 메서드를 사용하십시오.

  • strip(), lstrip(), 및 rstrip() 문자열 메서드에 이제 제거할 문자를 지정하는 선택적 인자가 추가되었습니다. 기본값은 여전히 모든 공백 문자를 제거하는 것입니다:

    >>> '   abc '.strip()
    'abc'
    >>> '><><abc<><><>'.strip('<>')
    'abc'
    >>> '><><abc<><><>\n'.strip('<>')
    'abc<><><>\n'
    >>> u'\u4000\u4001abc\u4000'.strip(u'\u4000')
    u'\u4001abc'
    >>>
    

    (Simon Brunning이 제안하고 Walter Dörwald가 구현함.)

  • startswith()endswith() 문자열 메서드가 이제 startend 매개변수로 음수를 허용합니다.

  • 또 다른 새로운 문자열 메서드는 (원래 string 모듈의 함수였던) zfill() 입니다. zfill() 은 숫자 문자열을 지정된 너비가 될 때까지 왼쪽에 0으로 채웁니다. % 연산자가 여전히 zfill() 보다 더 유연하고 강력하다는 점에 유의하십시오.

    >>> '45'.zfill(4)
    '0045'
    >>> '12345'.zfill(4)
    '12345'
    >>> 'goofy'.zfill(6)
    '0goofy'
    

    (Walter Dörwald 기여.)

  • 새로운 형 객체인 basestring 이 추가되었습니다. 8비트 문자열과 유니코드 문자열 모두 이 타입을 상속하므로, isinstance(obj, basestring) 은 두 종류의 문자열 모두에 대해 True 를 반환합니다. 이는 완전히 추상적인 형이므로 basestring 인스턴스를 생성할 수 없습니다.

  • 인턴된 문자열은 더 이상 불멸(immortal)이 아니며, 인턴된 문자열의 내부 딕셔너리만이 해당 문자를 참조하고 있는 경우 일반적인 방식으로 가비지 컬렉션됩니다. (Oren Tirosh 구현.)

최적화들`

  • 신형 스타일 클래스 인스턴스 생성이 훨씬 빨라졌습니다. 이제 고전적 클래스보다 빠릅니다!

  • 리스트 객체의 sort() 메서드가 Tim Peters에 의해 대폭 재작성되었으며, 구현이 훨씬 더 빨라졌습니다.

  • Karatsuba 곱셈 알고리즘을 도입하여 큰 long 정수의 곱셈이 훨씬 더 빨라졌습니다. 이 알고리즘은 초등학교 방식의 곱셈 알고리즘에 필요한 O(n2)보다 확장성이 더 좋습니다. (원래 패치는 Christopher A. Craig가 작성하고 Tim Peters가 대폭 수정함.)

  • SET_LINENO 연산 코드가 삭제되었습니다. 이는 컴파일러의 특성에 따라 약간의 속도 향상을 제공할 수 있습니다. 자세한 설명은 기타 변경 사항 및 수정 섹션을 참조하십시오. (Michael Hudson이 제거함.)

  • xrange() 객체가 이제 자체 이터레이터를 가지게 되어 for i in xrange(n)for i in range(n) 보다 약간 더 빠릅니다. (Raymond Hetikker에 의해 패치됨.)

  • 함수 인라이닝이나 일부 코드 제거와 같이 성능을 향상시키기 위해 여러 주요 지점에서 소규모 재배치가 이루어졌습니다. (주로 GvR에 의해 구현되었으나, 많은 사람이 단일 변경 사항을 기여했습니다.)

2.3 최적화의 최종 결과로, Python 2.3은 pystone 벤치마크를 Python 2.2보다 약 25% 더 빠르게 실행합니다.

새로운, 개선된, 그리고 더 이상 사용되지 않는 모듈

여느 때와 마찬가지로 Python 표준 라이브러리에 다수의 개선 사항과 버그 수정이 포함되었습니다. 다음은 모듈 이름의 알파벳 순서에 따른 주요 변경 사항의 일부입니다. 더 상세한 목록을 확인하려면 소스 트리의 Misc/NEWS 파일을 참조하거나 CVS 로그를 통해 자세한 내용을 확인할 수 있습니다.

  • array 모듈이 이제 'u'' 형식 문자를 사용하여 Unicode 문자 배열을 지원합니다. 또한 배열은 ``+= 할당 연산자를 사용하여 다른 배열의 내용을 추가하고, *= 할당 연산자를 사용하여 배열을 반복할 수 있습니다. (Jason Orendorff가 기여함.)

  • bsddb 모듈이 PyBSDDB 패키지의 4.1.6 버전으로 교체되어 BerkeleyDB 라이브러리의 트랜잭션 기능에 대해 더 완전한 인터페이스를 제공합니다.

    이전 버전의 모듈은 bsddb185 로 이름이 변경되었으며 더 이상 자동으로 빌드되지 않습니다. 이를 활성화하려면 Modules/Setup 을 편집해야 합니다. 새 bsddb 패키지는 이전 모듈과 호환되도록 설계되었으므로, 호환성 문제가 발견되면 반드시 버그를 보고하십시오. Python 2.3으로 업그레이드할 때, 새 인터프리터가 새로운 버전의 기반 BerkeleyDB 라이브러리와 함께 컴파일된 경우 데이터베이스 파일을 새 버전으로 변환해야 할 가능성이 매우 높습니다. 이는 배포판의 Tools/scripts 디렉토리에서 찾을 수 있는 새로운 스크립트인 db2pickle.pypickle2db.py 를 사용하여 비교적 쉽게 수행할 수 있습니다. 이미 PyBSDDB 패키지를 사용 중이고 이를 bsddb3 로 임포트하고 있었다면, import 문을 bsddb 로 가져오도록 변경해야 합니다.

  • 새로운 bz2 모듈은 bz2 데이터 압축 라이브러리에 대한 인터페이스입니다. bz2로 압축된 데이터는 일반적으로 해당하는 zlib압축 데이터보다 크기가 작습니다. (Gustavo Niemeyer가 기여함.)

  • 새로운 datetime 모듈에 표준 날짜/시간 타입 세트가 추가되었습니다. 자세한 내용은 다음 섹션을 참조하십시오.

  • Distutils Extension 클래스가 이제 확장이 의존하는 추가 소스 파일을 나열하기 위한 depends 라는 추가 생성자 인수를 지원합니다. 이를 통해 Distutils는 종속성 파일 중 어느 하나라도 수정되면 모듈을 다시 컴파일할 수 있습니다. 예를 들어, sampmodule.c 가 헤더 파일인 sample.h 를 포함하는 경우, 다음과 같이 Extension 객체를 생성합니다:

    ext = Extension("samp",
                    sources=["sampmodule.c"],
                    depends=["sample.h"])
    

    sample.h 를 수정하면 모듈이 다시 컴파일됩니다. (Jeremy Hylton이 기여함.)

  • Distutils의 기타 사소한 변경 사항: 이제 CC, CFLAGS, CPP, LDFLAGS, 및 CPPFLAGS 환경 변수를 확인하고, 이를 사용하여 Python 구성 설정 값을 덮어씁니다. (Robert Weber가 기여함.)

  • 이전에는 doctest 모듈이 공개된 메서드와 함수의 독스트링에서만 테스트 사례를 검색했지만, 이제는 비공개 항목도 조사합니다. DocTestSuite() 함수는 일련의 doctest 테스트로부터 unittest.TestSuite 객체를 생성합니다.

  • 새로운 gc.get_referents(object) 함수는 object 가 참조하는 모든 객체의 리스트를 반환합니다.

  • getopt 모듈에 기존 getopt() 함수와 동일한 인자를 지원하면서 GNU 스타일 스캔 모드를 사용하는 새 함수인 gnu_getopt() 가 추가되었습니다. 기존의 getopt() 는 옵션이 아닌 인수가 나타나면 즉시 옵션 처리를 중단하지만, GNU 스타일 모드에서는 처리가 계속되므로 옵션과 인자가 섞여서 올 수 있습니다. 예를 들어:

    >>> getopt.getopt(['-f', 'filename', 'output', '-v'], 'f:v')
    ([('-f', 'filename')], ['output', '-v'])
    >>> getopt.gnu_getopt(['-f', 'filename', 'output', '-v'], 'f:v')
    ([('-f', 'filename'), ('-v', '')], ['output'])
    

    (Peter Åstrand가 기여함.)

  • grp, pwd, 및 resource 모듈이 이제 향상된 튜플을 반환합니다:

    >>> import grp
    >>> g = grp.getgrnam('amk')
    >>> g.gr_name, g.gr_gid
    ('amk', 500)
    
  • gzip 모듈이 이제 2 GiB를 초과하는 파일을 처리할 수 있습니다.

  • 새로운 heapq 모듈은 힙 큐 알고리즘의 구현을 포함합니다. 힙은 모든 인덱스 k*에 대해 ``heap[k] <= heap[2*k+1]`` 및 ``heap[k] <= heap[2*k+2]``를 만족하도록 항목을 부분적으로 정렬된 순서로 유지하는 배열 형태의 데이터 구조입니다. 이를 통해 가장 작은 항목을 빠르게 제거할 수 있으며, 힙 속성을 유지하면서 새 항목을 삽입하는 것은 *O(log n)이 소요됩니다. (우선순위 큐 데이터 구조에 대한 자세한 정보는 https://xlinux.nist.gov/dads//HTML/priorityque.html를 참조하십시오.)

    heapq 모듈은 다른 가변 Python 시퀀스 타입 위에서 힙 속성을 유지하면서 항목을 추가하고 제거하는 heappush()heappop() 함수를 제공합니다. 다음은 파이썬 리스트를 사용하는 예제입니다:

    >>> import heapq
    >>> heap = []
    >>> for item in [3, 7, 5, 11, 1]:
    ...    heapq.heappush(heap, item)
    ...
    >>> heap
    [1, 3, 5, 11, 7]
    >>> heapq.heappop(heap)
    1
    >>> heapq.heappop(heap)
    3
    >>> heap
    [5, 7, 11]
    

    (Kevin O’Connor가 기여함.)

  • IDLE 통합 개발 환경이 IDLEfork 프로젝트(https://idlefork.sourceforge.net)의 코드를 사용하여 업데이트되었습니다. 가장 주목할 만한 특징은 개발 중인 코드가 이제 서브프로세스에서 실행되므로, 더 이상 수동으로 reload() 를 수행할 필요가 없다는 것입니다. IDLE의 핵심 코드는 표준 라이브러리의 idlelib 패키지로 통합되었습니다.

  • imaplib 모듈이 이제 SSL 기반의 IMAP을 지원합니다. (Piers Lauder와 Tino Lange가 기여함.)

  • itertools 은 ML 및 Haskell 언어에서 제공하는 다양한 함수에서 영감을 얻은, 이터레이터와 함께 사용하기 유용한 여러 함수를 포함합니다. 예를 들어, itertools.ifilter(predicate, iterator)predicate() 함수가 True 를 반환하는 이터레이터의 모든 요소를 반환하며, itertools.repeat(obj, N)objN 번 반환합니다. 모듈에 다른 기능이 많이 포함되어 있으니 자세한 내용은 패키지의 참조 문서를 확인하십시오. (Raymond Hetikker가 기여함.)

  • math 모듈에 라디안과 도 단위를 서로 변환하는 두 개의 새 함수인 degrees(rads)radians(degs) 가 추가되었습니다. math.sin()math.cos() 와 같은 math 모듈의 다른 함수들은 항상 라디언스 단위로 측정된 입력값을 요구해 왔습니다. 또한, e10 이외의 밑에 대한 로그를 더 쉽게 계산할 수 있도록 math.log() 에 선택적 base 인수가 추가되었습니다. (Raymond Hetikker가 기여함.)

  • os 모듈의 기반이 되는 posix 모듈에 여러 새로운 POSIX 함수(getpgid(), killpg(), lchown(), loadavg(), major(), makedev(), minor(), 및 mknod())가 추가되었습니다. (Gustavo Niemeyer, Geert Jansen, Denis S. Otkidach가 기여함.)

  • os 모듈에서 *stat() 계열 함수들이 이제 타임스탬프의 소수점 이하 초 단위를 보고할 수 있습니다. 이러한 타임스탬프는 time.time() 이 반환하는 값과 유사하게 실수(float)로 표현됩니다.

    테스트 중에 타임스탬프가 실수(float)인 경우 일부 애플리케이션이 작동하지 않는다는 것이 발견되었습니다. 호환성을 위해, 2에서 처음 도입된 기능)를 사용할 때는, 실수 반환을 활성화하기 위해 :func:!os.stat_float_times`를 호출하지 않는 한 타임스탬프가 여전히 정수로 표현됩니다:

    >>> os.stat("/tmp").st_mtime
    1034791200
    >>> os.stat_float_times(True)
    >>> os.stat("/tmp").st_mtime
    1034791200.6335014
    

    Python 2.4에서 기본값은 항상 실수를 반환하는 것으로 변경될 예정입니다.

    애플리케이션 개발자는 모든 라이브러리가 부동 소수점 타임스탬프를 처리할 때 올바르게 작동하거나 튜플 API를 사용하는 경우에만 이 기능을 활성화해야 합니다. 사용 시, 해당 기능은 매번 사용할 때마다 활성화하는 대신 애플리케이션 수준에서 활성화되어야 합니다.

  • optparse 모듈은 옵션 값을 특정 파이썬 유형으로 변환하고 사용법 메시지를 자동으로 생성하는 명령 줄 인자용 새 파서(parser)를 포함합니다. 자세한 내용은 다음 섹션을 참조하십시오.

  • 문서화된 적이 없는 오래된 linuxaudiodev 모듈은 더 이상 사용되지 않으며(deprecated), ossaudiodev 라는 이름의 새 버전이 추가되었습니다. OSS 사운드 드라이버는 리눅스 이외의 플랫폼에서도 사용할 수 있으므로 모듈의 이름이 변경되었으며, 인터페이스도 정리되고 다양한 방식으로 업데이트되었습니다. (Greg Ward와 Nicholas FitzRoy-Dale이 기여함.)

  • 새로운 platform 모듈은 실행 중인 플랫폼의 다양한 속성을 파악하려는 여러 기능을 포함합니다. 아키텍처, CPU 유형, Windows OS 버전, 리눅스 배포판 버전 등을 확인하는 함수들이 있습니다. (Marc-André Lemburg가 기여함.)

  • pyexpat 모듈이 제공하는 파서 객체는 이제 선택적으로 문자 데이터를 버퍼링할 수 있어, 문자 데이터 처리기(handler)에 대한 호출 횟수를 줄이고 성능을 높일 수 있습니다. 파서 객체의 buffer_text 속성을 True 로 설정하면 버퍼링이 활성화됩니다.

  • random 모듈에 sample(population, k) 함수가 추가되었습니다. population 은 인구의 요소를 포함하는 시퀀스 또는 xrange 객체이며, sample() 은 선택된 요소를 대체하지 않고 population에서 k 개의 요소를 선택합니다. klen(population) 까지의 어떤 값도 될 수 있습니다. 예를 들어:

    >>> days = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'St', 'Sn']
    >>> random.sample(days, 3)      # 3개 선택
    ['St', 'Sn', 'Th']
    >>> random.sample(days, 7)      # 7개 선택
    ['Tu', 'Th', 'Mo', 'We', 'St', 'Fr', 'Sn']
    >>> random.sample(days, 7)      # 다시 7개 선택
    ['We', 'Mo', 'Sn', 'Fr', 'Tu', 'St', 'Th']
    >>> random.sample(days, 8)      # 여덟 개를 선택할 수 없음
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "random.py", line 414, in sample
          raise ValueError, "sample larger than population"
    ValueError: sample larger than population
    >>> random.sample(xrange(1,10000,2), 10)   # 10000 미만의 홀수 10개 선택
    [3407, 3805, 1505, 7023, 2401, 2267, 9733, 3151, 8083, 9195]
    

    random 모듈은 이제 C로 구현된 새로운 알고리즘인 메르센 트위스터(Mersenne Twister)를 사용합니다. 이는 이전 알고리즘보다 빠르고 더 광범위하게 연구되었습니다.

    (모든 변경 사항은 Raymond Hetikker가 기여했습니다.)

  • readline 모듈에 get_history_item(), get_current_history_length(), 및 redisplay() 와 같은 여러 새로운 기능이 추가되었습니다.

  • rexecBastion 모듈은 더 이상 지원되지 않으며(dead), 이를 임포트하려고 하면 RuntimeError 가 발생합니다. 새로운 스타일의 클래스는 rexec 이 제공하는 제한된 실행 환경에서 벗어날 수 있는 새로운 방법을 제공하며, 이들을 수정하려는 의도나 시간적 여유가 없습니다. rexec 를 사용하는 애플리케이션이 있다면 다른 것을 사용하도록 재작성하십시오.

    (Python 2.2나 2.1을 계속 사용한다고 해서 애플리케이션이 더 안전해지는 것은 아닙니다. 해당 버전의 rexec 모듈에는 알려진 버그가 있기 때문입니다. 다시 말씀드리면, rexec 를 사용 중이라면 즉시 사용을 중단하십시오.)

  • rotor 모듈은 암호화에 사용되는 알고리즘이 안전하지 않다고 판단되어 더 이상 권장되지 않습니다(deprecated). 암호화가 필요한 경우 별도로 제공되는 여러 개의 AES 파이썬 모듈 중 하나를 사용하십시오.

  • shutil 모듈에 파일이나 디렉터리를 새 위치로 재귀적으로 이동시키는 move(src, dest) 함수가 추가되었습니다.

  • signal 에 더 고급의 POSIX 신호 처리가 추가되었으나, 여러 플랫폼에서 안정적으로 작동하게 하는 것이 불가능함이 밝혀져 다시 제거되었습니다.

  • socket 모듈이 이제 타임아웃을 지원합니다. 소켓 객체에서 settimeout(t) 메서드를 호출하여 t 초의 타임아웃을 설정할 수 있습니다. 이후에 완료까지 t 초 이상 걸리는 소켓 작업은 중단되고 socket.timeout 예외를 발생시킵니다.

    원래 타임아웃 구현은 Tim O’Malley에 의해 수행되었습니다. Michael Gilfix가 이를 파이썬 socket 모듈에 통합하고 긴 검토 과정을 거치도록 이끌었습니다. 코드가 체크인된 후, Guido van Rossum이 일부를 재작성했습니다. (이는 협력적인 개발 프로세스의 좋은 사례입니다.)

  • Windows에서 socket 모듈은 이제 Secure Sockets Layer (SSL) 지원을 포함하여 제공됩니다.

  • C 매크로 PYTHON_API_VERSION`의 값이 이제 Python 레벨에서 ``sys.api_version``으로 노출됩니다. 현재 예외는 새로운 :func:!sys.exc_clear` 함수를 호출하여 해제할 수 있습니다.

  • 새로운 tarfile 모듈은 tar-format 아카이브 파일에서 읽고 쓰는 것을 지원합니다. (Lars Gustäbel 기여)

  • 새로운 textwrap 모듈은 텍스트 단락을 포함하는 문자열을 래핑하기 위한 함수들을 포함합니다. wrap(text, width) 함수는 문자열을 받아 선택한 너비를 넘지 않도록 줄 바꿈이 된 리스트를 반환합니다. fill(text, width) 함수는 단일 문자열을 반환하며, 선택한 너분 내에 들어오도록 재포맷팅됩니다. (짐작하시겠지만, fill()wrap() 을 기반으로 구축되었습니다. 예시:

    >>> import textwrap
    >>> paragraph = "Not a whit, we defy augury: ... more text ..."
    >>> textwrap.wrap(paragraph, 60)
    ["Not a whit, we defy augury: there's a special providence in",
     "the fall of a sparrow. If it be now, 'tis not to come; if it",
     ...]
    >>> print textwrap.fill(paragraph, 35)
    Not a whit, we defy augury: there's
    a special providence in the fall of
    a sparrow. If it be now, 'tis not
    to come; if it be not to come, it
    will be now; if it be not now, yet
    it will come: the readiness is all.
    >>>
    

    이 모듈에는 텍스트 래핑 전략을 실제로 구현하는 TextWrapper 클래스도 포함되어 있습니다. TextWrapper 클래스와 wrap()fill() 함수는 서식을 미세 조정하기 위해 여러 추가 키워드 인수를 지원합니다. (Greg Ward 기여.) 자세한 내용은 모듈 문서를 참조하십시오.

  • threadthreading 모듈에는 스레드가 지원되지 않는 플랫폼의 경우 thread 모듈 인터페이스에 아무것도 하지 않는 구현을 제공하는 보조 모듈인 dummy_thread`와 :mod:!dummy_threading`가 있습니다. 의도는 다음 코드를 맨 위에 배치함으로써 스레드 인식 모듈(스레드를 실행에 의존하지 않는)의 복잡성을 단순화하는 것입니다:

    try:
        import threading as _threading
    except ImportError:
        import dummy_threading as _threading
    

    이 예제에서, 사용되는 모듈이 반드시 실제 threading 모듈은 아님을 명확하게 하기 위해 모듈 이름으로 _threading`이 사용됩니다. 코드는 스레드 지원 여부와 관계없이 :mod:!_threading`의 함수를 호출하고 클래스를 사용할 수 있어, if 문을 피하고 코드를 약간 더 명확하게 만듭니다. 이 모듈이 마법처럼 멀티스레드 코드를 스레드 없이 실행되게 만드는 것은 아닙니다; 다른 스레드가 반환하거나 어떤 동작을 수행하기를 기다리는 코드는 단순히 영원히 멈추게 됩니다.

  • time 모듈의 strptime() 함수는 플랫폼 C 라이브러리의 strptime() 구현을 사용하기 때문에 오랫동안 성가신 문제였습니다. 플랫폼마다 때때로 이상한 버그가 발생하기 때문입니다. Brett Cannon은 모든 플랫폼에서 동일하게 동작해야 하는 순수 Python으로 작성된 이식 가능한 구현을 제공했습니다.

  • 새로운 timeit 모듈은 Python 코드 조각이 실행되는 데 걸리는 시간을 측정하는 데 도움을 줍니다. timeit.py 파일은 명령 줄에서 직접 실행하거나, 해당 모듈의 Timer 클래스를 임포트하여 직접 사용할 수 있습니다. 8비트 문자열을 빈 유니코드 문자열을 추가하여 변환하는 것이 빠른지 아니면 unicode() 함수를 사용하는 것이 더 빠른지 확인하는 짧은 예제는 다음과 같습니다:

    import timeit
    
    timer1 = timeit.Timer('unicode("abc")')
    timer2 = timeit.Timer('"abc" + u""')
    
    # Run three trials
    print timer1.repeat(repeat=3, number=100000)
    print timer2.repeat(repeat=3, number=100000)
    
    # On my laptop this outputs:
    # [0.36831796169281006, 0.37441694736480713, 0.35304892063140869]
    # [0.17574405670166016, 0.18193507194519043, 0.17565798759460449]
    
  • Tix 모듈은 현재 버전의 Tix 패키지를 위해 다양한 버그 수정과 업데이트를 거쳤습니다.

  • Tkinter 모듈은 이제 스레드가 활성화된 버전의 Tcl과 함께 작동합니다. Tcl의 스레딩 모델은 위젯이 생성된 스레드에서만 접근되어야 함을 요구하며, 다른 스레드에서의 접근은 Tcl의 패닉을 유발할 수 있습니다. 특정 Tcl 인터페이스에 대해 Tkinter`는 이제 명령을 마샬링하여 올바른 스레드로 전달하고 결과를 기다리는 방식을 통해 다른 스레드에서 위젯이 접근될 이를 자동으로 회피합니다. 다른 인터페이스들은 자동으로 처리될 없으나, :mod:!Tkinter`는 이제 그러한 액세스 시 예외를 발생시켜 사용자가 최소한 문제를 파악할 수 있도록 합니다. 이 변경 사항에 대한 자세한 설명은 https://mail.python.org/pipermail/python-dev/2002-December/031107.html을 참조하십시오. (Martin von Löwis 구현)

  • _tkinter`를 통해 Tcl 메서드를 호출할 이상 문자열만 반환하지 않습니다. 대신, Tcl이 다른 객체를 반환하는 경우 해당 객체가 있으면 Python에 대응하는 객체로 변환되며, 없으면 :class:!_tkinter.Tcl_Obj` 객체로 래핑됩니다. 이 동작은 tkapp 객체의 wantobjects() 메서드를 통해 제어할 수 있습니다.

    Tkinter 모듈을 통해 _tkinter 를 사용할 때(대부분의 Tkinter 애플리케이션이 그러하듯), 이 기능은 항상 활성화됩니다. Tkinter는 가능한 경우 문자열 결과를 항상 Python 유형으로 변환하므로 호환성 문제가 발생하지 않습니다.

    호환되지 않는 부분이 발견되면, 첫 번째 tkapp 객체를 생성하기 전에 Tkinter 모듈의 wantobjects 변수를 false로 설정하여 이전 동작을 복구할 수 있습니다.

    import Tkinter
    Tkinter.wantobjects = 0
    

    이 변경으로 인해 발생하는 모든 문제는 버그로 보고해야 합니다.

  • UserDict 모듈은 최소 매핑 인터페이스를 이미 가진 클래스에 대해 모든 딕셔너리 메서드를 정의하는 새로운 DictMixin 클래스를 포함합니다. 이는 shelve 모듈의 클래스들과 같이 딕셔너리를 대체할 수 있는 클래스를 작성하는 것을 크게 간소화해 줍니다.

    믹스인을 슈퍼클래스로 추가하면 클래스가 __getitem__(), __setitem__(), __delitem__(), 그리고 keys() 를 정의할 때 전체 딕셔너리 인터페이스가 제공됩니다. 예를 들어:

    >>> import UserDict
    >>> class SeqDict(UserDict.DictMixin):
    ...     """Dictionary lookalike implemented with lists."""
    ...     def __init__(self):
    ...         self.keylist = []
    ...         self.valuelist = []
    ...     def __getitem__(self, key):
    ...         try:
    ...             i = self.keylist.index(key)
    ...         except ValueError:
    ...             raise KeyError
    ...         return self.valuelist[i]
    ...     def __setitem__(self, key, value):
    ...         try:
    ...             i = self.keylist.index(key)
    ...             self.valuelist[i] = value
    ...         except ValueError:
    ...             self.keylist.append(key)
    ...             self.valuelist.append(value)
    ...     def __delitem__(self, key):
    ...         try:
    ...             i = self.keylist.index(key)
    ...         except ValueError:
    ...             raise KeyError
    ...         self.keylist.pop(i)
    ...         self.valuelist.pop(i)
    ...     def keys(self):
    ...         return list(self.keylist)
    ...
    >>> s = SeqDict()
    >>> dir(s)      # See that other dictionary methods are implemented
    ['__cmp__', '__contains__', '__delitem__', '__doc__', '__getitem__',
     '__init__', '__iter__', '__len__', '__module__', '__repr__',
     '__setitem__', 'clear', 'get', 'has_key', 'items', 'iteritems',
     'iterkeys', 'itervalues', 'keylist', 'keys', 'pop', 'popitem',
     'setdefault', 'update', 'valuelist', 'values']
    

    (Raymond Hettinger가 기여했습니다.)

  • xml.dom.minidom 의 DOM 구현은 이제 DOM 노드의 toxml()toprettyxml() 메서드에 선택적 인코딩 인수를 제공하여 특정 인코딩으로 XML 출력을 생성할 수 있습니다.

  • xmlrpclib 모듈은 이제 Python의 None 과 같은 nil 데이터 값을 처리하기 위한 XML-RPC 확장을 지원합니다. 역 마셜링 시 XML-RPC 응답에서 nil 값은 항상 지원됩니다. None 을 포함하는 요청을 생성하려면 Marshaller 인스턴스를 생성할 때 allow_none 파라미터에 true 값을 제공해야 합니다.

  • 새로운 DocXMLRPCServer 모듈을 사용하면 스스로 설명하는 XML-RPC 서버를 작성할 수 있습니다. 데모 모드(프로그램으로 실행)에서 실행하여 동작 방식을 확인해 보십시오. 웹 브라우저로 RPC 서버에 접속하면 pydoc 스타일의 문서가 생성되고, xmlrpclib을 해당 서버에 연결하면 실제 메서드를 호출할 수 있습니다. (Brian Quinlan이 기여함.)

  • 국제화된 도메인 이름(RFCs 3454, 3490, 3491, 3492) 지원이 추가되었습니다. 유니코드 도메인 이름과 해당 이름의 ASCII 호환 인코딩(ACE) 사이를 변환하는 데 “idna” 인코딩을 사용할 수 있습니다.

    >{}>{}> u"www.Alliancefrançaise.nu".encode("idna")
    'www.xn--alliancefranaise-npb.nu'
    

    socket 모듈이 확장되어 유니코드 호스트네임을 C 라이브러리로 전달하기 전에 ACE 버전으로 투명하게 변환합니다. httplibftplib`와 같이 호스트네임을 다루는 모듈들도 유니코드 호스트네임을 지원하며, :mod:!httplib`은 도메인 이름의 ACE 버전을 사용하여 HTTP Host 헤더를 전송합니다. urllib`은 URL의 ``path` 부분이 오직 ASCII로만 구성된 경우 유니코드 호스트네임을 포함한 유니코드 URL을 지원합니다.

    이 변경 사항을 구현하기 위해 stringprep 모듈, mkstringprep 도구 및 punycode 인코딩이 추가되었습니다.

날짜/시간 유형

타임스탬프를 표현하기에 적합한 날짜 및 시간 유형이 datetime 모듈로 추가되었습니다. 이 타입들은 다양한 달력이나 화려한 기능은 지원하지 않으며, 시간을 표현하는 기본 원칙을 따릅니다.

The three primary types are: date, representing a day, month, and year; time, consisting of hour, minute, and second; and datetime, which contains all the attributes of both date and time. There’s also a timedelta class representing differences between two points in time, and time zone logic is implemented by classes inheriting from the abstract tzinfo class.

datetime 인스턴스는 적절한 생성자에 키워드 인수를 제공하거나(예: datetime.date(year=1972, month=10, day=15)), 여러 클래스 메서드 중 하나를 사용하여 생성할 수 있습니다. 예를 들어, today() 클래스 메서드는 현재 로컬 날짜를 반환합니다.

생성된 날짜/시간 클래스의 인스턴스는 모두 불변입니다. 객체로부터 포맷된 문자열을 생성하기 위한 여러 메서드가 있습니다:

>>> import datetime as dt
>>> now = dt.datetime.now()
>>> now.isoformat()
'2002-12-30T21:27:03.994956'
>>> now.ctime()  # Only available on date, datetime
'Mon Dec 30 21:27:03 2002'
>>> now.strftime('%Y %d %b')
'2002 30 Dec'

replace() 메서드는 date 또는 datetime 인스턴스의 하나 이상의 필드를 수정하고 새로운 인스턴스를 반환합니다:

>>> d = dt.datetime.now()
>>> d
datetime.datetime(2002, 12, 30, 22, 15, 38, 827738)
>>> d.replace(year=2001, hour=12)
datetime.datetime(2001, 12, 30, 12, 15, 38, 827738)
>>>

인스턴스는 비교, 해싱이 가능하며 문자열로 변환될 수 있습니다(결과는 isoformat() 과 동일합니다). datedatetime 인스턴스는 서로 뺄 수 있으며, timedelta 인스턴스와 더할 수 있습니다. 가장 큰 특징적인 결여는 문자열을 파싱하여 date 또는 datetime 객체를 얻어오는 기능을 위한 표준 라이브러리 지원이 없다는 점입니다.

자세한 정보는 모듈의 레퍼런스 문서를 참조하십시오. (Tim Peters 기여)

optparse 모듈

getopt 모듈은 명령 줄 인수를 간단하게 파싱합니다. 새로운 optparse 모듈(원래 이름은 Optik)은 Unix 관례를 따르며 더 복잡한 명령 줄 파싱을 제공하며, --help 에 대한 출력을 자동으로 생성하고 다양한 옵션에 대해 서로 다른 동작을 수행할 수 있습니다.

먼저 OptionParser 인스턴스를 생성하고 프로그램의 옵션을 정의합니다.

import sys
from optparse import OptionParser

op = OptionParser()
op.add_option('-i', '--input',
              action='store', type='string', dest='input',
              help='set input filename')
op.add_option('-l', '--length',
              action='store', type='int', dest='length',
              help='set maximum length of output')

그 다음 parse_args() 메서드를 호출하여 명령 줄을 파싱합니다.

options, args = op.parse_args(sys.argv[1:])
print options
print args

이것은 모든 옵션 값을 포함하는 객체와 나머지 인자들이 포함된 문자열 리스트를 반환합니다.

다양한 인수를 사용하여 스크립트를 호출하면 이제 예상대로 작동합니다. 길이(length) 인자는 자동으로 정수로 변환됩니다.

$ ./python opt.py -i data arg1
<Values at 0x400cad4c: {'input': 'data', 'length': None}>
['arg1']
$ ./python opt.py --input=data --length=4
<Values at 0x400cad2c: {'input': 'data', 'length': 4}>
[]
$

도움말 메시지가 자동으로 생성됩니다:

$ ./python opt.py --help
usage: opt.py [options]

options:
  -h, --help            show this help message and exit
  -iINPUT, --input=INPUT
                        set input filename
  -lLENGTH, --length=LENGTH
                        set maximum length of output
$

자세한 내용은 모듈의 문서를 참조하십시오.

Optik은 Greg Ward가 작성했으며, Getopt SIG 독자들의 제안이 반영되었습니다.

Pymalloc: 특수 객체 할당자

Vladimir Marangozov가 작성한 특수 객체 할당자인 Pymalloc은 파이썬 2.1에 추가된 기능입니다. Pymalloc은 시스템 malloc() 보다 빠르고, 파이썬 프로그램에서 일반적인 메모리 할당 패턴에 대해 더 적은 메모리 오버헤드를 갖도록 설계되었습니다. 이 할당자는 C의 malloc() 함수를 사용하여 대규모 메모리 풀을 확보한 다음, 이러한 풀에서 작은 메모리 요청을 처리합니다.

2.1 및 2.2 버전에서 pymalloc은 실험적 기능이었으며 기본적으로 활성화되지 않았습니다. 파이썬을 컴파일할 때 configure 스크립트에 --with-pymalloc 옵션을 제공하여 명시적으로 활성화해야 했습니다. 2.3 버전에서는 pymalloc이 더욱 개선되었으며 이제 기본으로 활성화됩니다. 기능을 비활성화하려면 --without-pymalloc 을 입력해야 합니다.

이 변경 사항은 파이썬으로 작성된 코드에는 영향을 주지 않으나, pymalloc이 C 확장 모듈의 버그를 노출할 수 있습니다. C 확장 모듈의 작성자는 pymalloc을 활성화한 상태에서 코드를 테스트해야 합니다. 일부 잘못된 코드는 런타임에 코어 덤프(core dump)를 발생시킬 수 있기 때문입니다.

문제를 일으키는 한 가지 특히 흔한 오류가 있습니다. 파이썬 C API에는 이전에 단순히 C 라이브러리의 malloc()free() 의 별칭(alias)이었던 많은 메모리 할당 함수들이 존재했으며, 이는 서로 맞지 않는 함수를 실수로 호출하더라도 오류를 감지할 수 없었음을 의미합니다. 객체 할당자가 활성화되면 이러한 함수들은 더 이상 malloc()free() 의 별칭이 아니며, 메모리를 해제할 때 잘못된 함수를 호출하면 코어 덤프가 발생할 수 있습니다. 예를 들어, PyObject_Malloc() 을 사용하여 할당된 메모리는 free() 가 아니라 PyObject_Free() 로 해제해야 합니다. 파이썬에 포함된 몇몇 모듈들이 이 문제에 걸려 수정되었으며, 의심할 여지 없이 동일한 문제를 가진 외부 모럼더리도 더 있을 것입니다.

이 변경의 일환으로, 혼란스러운 다중 메모리 할당 인터페이스가 두 가지 API 패밀리로 통합되었습니다. 한 패밀리로 할당된 메모리는 다른 패밀리의 함수로 조작해서는 안 됩니다. 하나는 메모리 청크(chunk)를 할당하기 위한 패밀리이며, 다른 하나는 특히 파이썬 객체를 할당하기 위한 전용 함수들의 패밀리입니다.

Tim Peters의 노고 덕분에 2.3 버전의 pymalloc은 확장 모듈과 인터프리터 자체 모두에서 메모리 덮어쓰기 및 중복 해제를 감지하는 디버깅 기능을 제공합니다. 이 기능을 활성화하려면 configure`를 실행할 때 :option:!–with-pydebug` 옵션을 사용하여 파이썬 인터프리터를 디버그 버전으로 컴파일하십시오.

확장 프로그램 작성자를 돕기 위해, 파이썬 2.3 소스에 Misc/pymemcompat.h 헤더 파일이 포함되어 배포됩니다. 이를 통해 파이썬 확장 프로그램은 1.5.2 이후의 모든 버전을 대상으로 컴파일하면서도 2.3 버전의 메모리 할당 인터페이스를 사용할 수 있습니다. 이 파일을 파이썬 소스 배포판에서 복사하여 본인의 확장 프로그램 소스와 함께 번들링하면 됩니다.

더 보기

https://hg.python.org/cpython/file/default/Objects/obmalloc.c

pymalloc 구현에 대한 자세한 내용은 파이썬 소스 코드 내의 Objects/obmalloc.c 파일 상단의 주석을 참조하십시오. 위 링크는 python.org SVN 브라우저 내의 해당 파일을 가리킵니다.

빌드 및 C API 변경사항

Python 빌드 프로세스 및 C API의 변경 사항은 다음과 같습니다:

  • 가비지 컬렉션에 사용되는 순환 검출 구현이 안정적인 것으로 입증되어 이제 필수 기능으로 포함되었습니다. 더 이상 순환 검출 없이 파이썬을 컴파일할 수 없으며, configure`의 :option:!–with-cycle-gc` 스위치도 삭제되었습니다.

  • 파이썬의 configure 스크립트를 실행할 때 --enable-shared`를 제공하면 이제 파이썬을 선택적으로 공유 라이브러리(:file:`libpython2.3.so)로 빌드할 수 있습니다. (Ondrej Palkovsky가 기여함.)

  • DL_EXPORTDL_IMPORT 매크로는 이제 폐지되었습니다. 파이썬 확장 모듈의 초기화 함수는 이제 새로운 매크로인 PyMODINIT_FUNC 를 사용하여 선언해야 하며, 파이썬 코어는 일반적으로 PyAPI_FUNCPyAPI_DATA 매크로를 사용합니다.

  • configure 스크립트에 --without-doc-strings 를 제공하면 내장 함수 및 모듈의 docstring 없이 인터프리터를 컴파일할 수 있습니다. 이 방식은 파이썬 실행 파일 크기를 약 10% 줄여주지만, 파이썬 내장 기능에 대한 도움말을 얻을 수 없음을 의미합니다. (Gustavo Niemeyer가 기여함.)

  • PyArg_NoArgs() 매크로는 이제 폐지되었으므로 해당을 사용하는 코드는 수정되어야 합니다. 파이썬 2.2 이상 버전에서는 메서드 정의 테이블에 METH_NOARGS 플래그를 지정하여 인자가 없음을 알릴 수 있으며, 이 경우 인수 확인 절차를 생략할 수 있습니다. 만약 파이썬 2.2 이전 버전과의 호환성이 중요하다면 대신 PyArg_ParseTuple(args, "") 을 사용할 수도 있지만, 이는 METH_NOARGS 를 사용하는 것보다 느립니다.

  • PyArg_ParseTuple() 이 다양한 크기의 부호 없는 정수를 위한 새로운 형식 문자를 지원합니다: unsigned char 를 위한 B, unsigned short int 를 위한 H, unsigned int 를 위한 I, 그리고 unsigned long long 을 위한 K.

  • PyObject_DelItem(mapping, PyString_New(key)) 의 약칭으로 새 함수인 PyObject_DelItemString(mapping, char *key) 가 추가되었습니다.

  • 파일 객체가 이제 내부 문자열 버퍼를 다르게 관리하며, 필요한 경우 이를 기하급수적으로 늘립니다. 이로 인해 Lib/test/test_bufio.py 의 벤치마크 테스트 속도가 상당히 향상되었습니다(한 측정 결과에 따르면 57초에서 1.7초로 단축됨).

  • 메서드의 PyMethodDef 구조에서 METH_CLASS 또는 METH_STATIC 플래그를 설정하여 C 확장 타입에 대한 클래스 및 정적 메서드를 정의할 수 있습니다.

  • 파이썬에 Expat XML 파서의 소스 코드 복사본이 포함되어, 시스템 버전이나 로컬 설치된 Expat에 대한 의존성이 제거되었습니다.

  • 확장 기능에서 타입 객체를 동적으로 할당하는 경우, __module____name__ 속성과 관련된 규칙의 변경 사항을 유의해야 합니다. 요약하자면, 타입의 딕셔너리에 '__module__' 키가 포함되어 있는지 확인해야 합니다. 이제 마지막 마침표 앞까지를 모듈 이름으로 설정하는 방식은 의도한 효과를 얻지 못합니다. 자세한 내용은 API 참조 문서를 읽거나 소스를 확인하십시오.

포트별 변경 사항

EMX 런타임 환경을 사용하는 IBM OS/2 포트 지원이 메인 파이썬 소스 트리에 병합되었습니다. EMX는 OS/2 시스템 API 상의 POSIX 에뮬레이션 계층입니다. EMX용 파이썬 포트는 EMX 런타임에서 제공하는 모든 POSIX 유사 기능을 지원하려고 시도하며 대부분 성공합니다. 단, fork()fcntl() 은 기반 에뮬레이션 계층의 제한으로 인해 제한됩니다. IBM의 Visual Age 컴파일러를 사용하는 표준 OS/2 포트 또한 EMX 포트를 CVS에 통합하는 과정에서 대소문자 구분 임포트 의미론을 지원하게 되었습니다. (Andrew MacIntyre가 기여함.)

MacOS에서 하위 호환성을 개선하기 위해 대부분의 툴박스 모듈이 약한 링크(weaklinked)로 처리됩니다. 이는 현재 OS 버전에서 단일 루틴이 누락되었더라도 모듈 로드가 실패하지 않음을 의미합니다. 대신, 누락된 루틴을 호출하면 예외가 발생하게 됩니다. (Jack Jansen이 기여함.)

파이썬 소스 배포판의 Misc/RPM/ 디렉토리에 있는 RPM spec 파일이 2.3 버전에 맞춰 업데이트되었습니다. (Sean Reifschneider가 기여함.)

파이썬에서 지원하는 다른 새로운 플랫폼에는 AtheOS (http://www.atheos.cx/), GNU/Hurd, 그리고 OpenVMS가 포함됩니다.

기타 변경 사항 및 수정

평소와 마찬가지로 소스 트리 전반에 걸쳐 수많은 개선 사항과 버그 수정이 포함되었습니다. CVS 변경 로그를 확인한 결과 파이썬 2.2와 2.3 사이에서 523개의 패치가 적용되고 514개의 버그가 수정되었으며, 두 수치 모두 실제보다 적게 집계된 것일 가능성이 높습니다.

주요 변경 사항 중 일부는 다음과 같습니다:

  • PYTHONINSPECT 환경 변수가 설정된 경우, 파이썬 인터프리터는 파이썬 프로그램을 실행한 후 마치 -i 옵션을 사용하여 호출된 것처럼 대화형 프롬프트로 진입합니다. 이 환경 변수는 파이썬 인터프리터를 실행하기 전에 설정하거나, 파이썬 프로그램 실행 과정 중에 설정할 수 있습니다.

  • regrtest.py 스크립트에서 이제 “foo 를 제외한 모든 리소스”를 허용하는 방법이 제공됩니다. -u 옵션에 전달되는 리소스 이름 앞에 하이픈('-')을 붙여 “이 리소스를 제거함”을 의미할 수 있습니다. 예를 들어, ‘-uall,-bsddb ‘ 옵션을 사용하여 bsddb 를 제외한 모든 리소스를 활성화할 수 있습니다.

  • 문서 구축에 사용되는 도구들이 이제 유닉스뿐만 아니라 Cygwin에서도 작동합니다.

  • SET_LINENO 명령어가 삭제되었습니다. 아주 오래전에는 이 명령어가 트레이스백에서 라인 번호를 생성하고 추적 함수(예: pdb)를 지원하기 위해 필요했습니다. 파이썬 1.5부터 트레이스백의 라인 번호는 “python -O”와 호환되는 다른 메커니즘을 사용하여 계산되어 왔습니다. 파이썬 2.3에서는 Michael Hudson이 추적 함수 호출 시점을 결정하는 유사한 방식을 구현하여 SET_LINENO 가 더 이상 필요 없게 되었습니다.

    파이썬을 -O 없이 실행할 때 약간의 속도가 향상되는 것 외에 파이썬 코드에서 결과적인 차이를 감지하기는 어려울 것입니다.

    프레임 객체의 f_lineno 필드에 액세스하는 C 확장은 대신 PyCode_Addr2Line(f->f_code, f->f_lasti) 를 호출해야 합니다. 이렇게 하면 이전 버전의 Python에서 “python -O” 옵션 하에서도 코드가 의도한 대로 작동하게 됩니다.

    유용한 새로운 기능으로, 이제 트레이스 함수가 프레임 객체의 f_lineno 어트리뷰트에 값을 할당하여 다음에 실행될 줄을 변경할 수 있습니다. 이 기능을 활용한 jump 명령이 pdb 디버거에 추가되었습니다. (Richie Hindle 구현)

Python 2.3으로 이식하기

이 섹션은 코드 변경이 필요할 수 있는 이전에 설명된 변경 사항을 나열합니다:

  • yield 은 이제 항상 키워드입니다. 코드에서 이를 변수 이름으로 사용한 경우 다른 이름을 선택해야 합니다.

  • 문자열 XY 에 대하여, X 가 두 개 이상의 문자로 구성된 경우에도 이제 X in Y 가 작동합니다.

  • int() 타입 생성자는 이제 문자열이나 부동 소수점 수가 정수에 담기에는 너무 커서 OverflowError 를 발생시키는 대신 long 정수를 반환합니다.

  • 8비트 문자가 포함된 유니코드 문자열이 있는 경우, 파일 상단에 주석을 추가하여 파일의 인코딩(UTF-8, Latin-1 등)을 선언해야 합니다. 자세한 내용은 PEP 263: 소스 코드 인코딩 섹션을 참조하십시오.

  • _tkinter`를 통해 Tcl 메서드를 호출할 이상 문자열만 반환하지 않습니다. 대신 Tcl이 다른 객체를 반환하는 경우, 해당 객체가 존재한다면 파이썬에 대응하는 객체로 변환되며, 대응하는 객체가 없다면 :class:!_tkinter.Tcl_Obj` 객체로 래핑됩니다.

  • 0xffffffff 와 같은 큰 8진수 및 16진수 리터럴은 이제 FutureWarning 을 발생시킵니다. 현재 이들은 32비트 숫자로 저장되어 음수 값이 되지만, Python 2.4에서는 양의 long 정수가 됩니다.

    이 경고를 해결하는 방법은 몇 가지가 있습니다. 양수 값이 꼭 필요한 경우 리터럴 끝에 L 을 추가하면 됩니다. 낮은 비트가 설정된 32비트 정수를 얻으려고 하며 이전에 ~(1 << 31) 과 같은 표현식을 사용했다면, 모든 비트를 먼저 설정하고 원하는 상위 비트를 해제하는 것이 가장 명확합니다. 예를 들어, 최상위 비트(bit 31)만 해제하려면 0xffffffffL &~(1L<<31) 이라고 작성할 수 있습니다.

  • 이제 __debug__ 에 값을 할당하여 어설션(assertion)을 비활성화할 수 없습니다.

  • Distutils의 setup() 함수에 depends 와 같은 다양한 새로운 키워드 인자가 추가되었습니다. 이전 버전의 Distutils는 알 수 없는 키워드가 전달되면 중단됩니다. 해결 방법은 setup.py 에서 새 기능인 get_distutil_options() 함수의 존재 여부를 확인하고, 해당 기능을 지원하는 Distutils 버전에서만 새로운 키워드를 사용하는 것입니다:

    from distutils import core
    
    kw = {'sources': 'foo.c', ...}
    if hasattr(core, 'get_distutil_options'):
        kw['depends'] = ['foo.h']
    ext = Extension(**kw)
    
  • 변수 이름으로 None 을 사용하는 경우 이제 SyntaxWarning 이 발생합니다.

  • Python에 포함된 모듈에 의해 정의된 확장 타입의 이름은 이제 타입 이름 앞에 모듈명과 '.' 을 포함합니다.

감사의 말

필자는 이 문서의 다양한 초안에 대해 제언과 수정 및 도움을 준 다음 분들에게 감사드립니다: Jeff Bauer, Simon Brunning, Brett Cannon, Michael Chermside, Andrew Dalke, Scott David Daniels, Fred L. Drake, Jr., David Fraser, Kelly Gerber, Raymond Hettinger, Michael Hudson, Chris Lambert, Detlef Lannert, Martin von Löwis, Andrew MacIntyre, Lalo Martins, Chad Netzer, Gustavo Niemeyer, Neal Norwitz, Hans Nowak, Chris Reedy, Francesco Ricciardi, Vinay Sajip, Neil Schemenauer, Roman Suzi, Jason Tishler, Just van Rossum.

분실물 보관소