Python 3.1의 새로운 기능¶
- 저자:
Raymond Hettinger
이 기사에서는 3.0과 비교하여 Python 3.1의 새로운 기능을 설명합니다. Python 3.1은 2009년 6월 27일에 출시되었습니다.
PEP 372: Ordered Dictionaries¶
일반 Python 딕셔너리는 키/값 쌍을 임의의 순서로 반복합니다. 수년에 걸쳐 여러 저자들이 키가 처음에 삽입된 순서를 기억하는 대체 구현을 작성했습니다. 이러한 구현들의 경험을 바탕으로 새로운 collections.OrderedDict 클래스가 도입되었습니다.
OrderedDict API는 기본적으로 일반 딕셔너리와 거의 동일하지만, 키가 처음 삽입된 시점에 따라 보장된 순서로 키와 값을 반복합니다. 새 항목이 기존 항목을 덮어쓰는 경우 원래의 삽입 위치는 변경되지 않습니다. 항목을 삭제하고 다시 삽입하면 끝으로 이동합니다.
표준 라이브러리는 이제 여러 모듈에서 순서 있는 딕셔너리(ordered dictionaries) 사용을 지원합니다. configparser 모듈은 기본적으로 이를 사용합니다. 이를 통해 설정 파일을 원래 순서대로 읽고, 수정하고, 다시 쓸 수 있습니다. collections.namedtuple() 의 *_asdict()* 메서드는 이제 값들이 기본 튜플 인덱스와 동일한 순서로 나타나는 순서 있는 딕셔너리를 반환합니다. json 모듈은 디코더에 의해 OrderedDict가 생성될 수 있도록 object_pairs_hook 을 포함하여 확장되고 있습니다. 또한 PyYAML <https://pyyaml.org/> 와 같은 서드파티 도구도 지원됩니다.
더 보기
- PEP 372 - 순서가 있는 딕셔너리
이 PEP는 Armin Ronacher와 Raymond Hettinger가 작성했으며, 구현은 Raymond Hettinger가 담당했습니다.
순서가 있는 딕셔너리는 삽입 순서를 기억하므로 정렬과 함께 사용하여 정렬된 딕셔너리를 만들 수 있습니다:
>>> # 일반적이지 않은 순서의 딕셔너리
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}
>>> # 키에 따라 정렬된 딕셔너리
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
>>> # 값에 따라 정렬된 딕셔너리
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
>>> # 키 문자열의 길이에 따라 정렬된 딕셔너리
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
새로운 정렬된 딕셔너리는 항목이 삭제될 때 그 정렬 순서를 유지합니다. 그러나 새로운 키가 추가될 때는 해당 키들이 끝에 추가되므로 정렬이 유지되지 않습니다.
PEP 378: 천 단위 구분 기호용 포맷 지정자¶
내장된 format() 함수와 str.format() 메서드는 이제 천 단위 구분 기호를 사용하여 숫자를 포맷하는 간단하고 로케일을 인식하지 않는 방식을 포함하는 미니 언어를 사용합니다. 이는 프로그램 출력의 가독성을 높이고 전문적인 외관을 제공합니다:
>>> format(1234567, ',d')
'1,234,567'
>>> format(1234567.89, ',.2f')
'1,234,567.89'
>>> format(12345.6 + 8901234.12j, ',f')
'12,345.600000+8,901,234.120000j'
>>> format(Decimal('1234567.89'), ',f')
'1,234,567.89'
지원되는 타입은 int, float, complex 및 decimal.Decimal 입니다.
점(.), 공백, 아포스트로피(‘), 언더스코어(_)와 같은 대체 구분 기호를 지정하는 방법에 대한 논의가 진행 중입니다. 로케일을 고려해야 하는 애플리케이션은 이미 천 단위 구분 기호를 지원하는 기존 n 포맷 지정자를 사용해야 합니다.
더 보기
- PEP 378 - 천 단위 구분 기호용 포맷 지정자
이 PEP는 Raymond Hettinger가 작성했으며, Eric Smith와 Mark Dickinson이 구현했습니다.
이외의 언어 변경 사항¶
핵심 파이썬 언어에 가해진 일부 작은 변경 사항은 다음과 같습니다:
__main__.py파일을 포함하는 디렉터리와 zip 아카이브를 인터프리터에 이름을 전달하여 직접 실행할 수 있습니다. 디렉터리 또는 zip 파일은 sys.path의 첫 번째 항목으로 자동 삽입됩니다. (Andy Chu 제안 및 초기 패치; Phillip J. Eby와 Nick Coghlan이 수정한 패치; bpo-1739468.)int()타입에 인수를 이진수로 표현하는 데 필요한 비트 수를 반환하는bit_length메서드가 추가되었습니다:>>> n = 37 >>> bin(37) '0b100101' >>> n.bit_length() 6 >>> n = 2**123-1 >>> n.bit_length() 123 >>> (n+1).bit_length() 124
(Fredrik Johansson, Victor Stinner, Raymond Hettinger, Mark Dickinson이 기여했습니다; bpo-3439.)
format()문자열의 필드에 이제 번호가 자동으로 부여됩니다:>>> 'Sir {} of {}'.format('Gallahad', 'Camelot') 'Sir Gallahad of Camelot'
이전에는 ‘’Sir {0} of {1}’’와 같이 번호가 매겨진 필드가 필요했습니다.
(Eric Smith가 기여했습니다; bpo-5237.)
string.maketrans()함수는 더 이상 사용되지 않으며(deprecated), 새로운 정적 메서드인bytes.maketrans()및bytearray.maketrans()로 대체됩니다. 이 변경 사항은string모듈이 어떤 유형을 지원하는지에 대한 혼란을 해결합니다. 이제str,bytes, 그리고bytearray는 각각 적절한 유형의 중간 변환 테이블을 가진 고유의 maketrans 및 translate 메서드를 보유합니다.(Georg Brandl이 기여했습니다; bpo-5675.)
with문의 구문은 이제 단일 문장에서 여러 개의 컨텍스트 관리자를 허용합니다:>>> with open('mylog.txt') as infile, open('a.out', 'w') as outfile: ... for line in infile: ... if '<critical>' in line: ... outfile.write(line)
새로운 구문이 도입됨에 따라
contextlib.nested()함수는 더 이상 필요하지 않으며 이제 사용되지 않습니다(deprecated).(Georg Brandl과 Mattias Brändström이 기여했습니다; appspot issue 53094.)
x 이 정수일 때
round(x, n)가 이제 정수를 반환합니다. 이전에는 플로트를 반환했습니다:>>> round(1123, -2) 1100
(Mark Dickinson이 기여했습니다; bpo-4707.)
파이썬은 이제 값이 변하지 않으면서 가장 짧은 부동 소수점 표현을 찾는 데 David Gay의 알고리즘을 사용합니다. 이는 이진 부동 소수점 숫자에 관한 혼란을 줄이는 데 도움이 될 것입니다.
이 차이는 이진 부동 소수점에서 정확한 대응값이 없는
1.1과 같은 숫자에서 쉽게 확인할 수 있습니다. 정확한 대응값이 없기 때문에,float('1.1')과 같은 표현식은 가장 가까운 표현 가능한 값으로 계산됩니다. 이 값은 16진수로0x1.199999999999ap+0이며, 10진수로는1.100000000000000088817841970012523233890533447265625입니다. 이 가장 가까운 값은 이전에도 사용되었으며 지금도 후속 부동 소수점 계산에 사용됩니다.새로운 것은 숫자가 표시되는 방식입니다. 이전의 파이썬은 간단한 방식을 사용했습니다.
repr(1.1)의 값은format(1.1, '.17g')로 계산되어'1.1000000000000001'으로 평가되었습니다. 17자리를 사용하는 이점은eval(repr(1.1))이 원래 값으로 정확하게 변환됨을 보장하는 IEEE-754를 활용한다는 것이었습니다. 하지만 단점은 많은 사람이 결과가 혼란스럽다고 느꼈다는 점입니다(이진 부동 소수점 표현의 내재적 한계를 파이썬 자체의 문제로 오해함).repr(1.1)에 대한 새로운 알고리즘은 더 스마트하며'1.1'을 반환합니다. 효과적으로, 이 알고리즘은 모든 동등한 문자열 표현(동일한 기본 부동 소수점 값을 저장하는 것들)을 검색하고 가장 짧은 표현을 반환합니다.새로운 알고리즘은 가능한 경우 더 깔끔한 표현을 생성하는 경향이 있지만, 기본 값을 변경하지는 않습니다. 따라서 표기상으로는 다르게 보일 수 있어도
1.1 + 2.2 != 3.3인 사실은 여전히 동일합니다.새로운 알고리즘은 기본 부동 소수점 구현의 특정 기능에 의존합니다. 필요한 기능이 발견되지 않으면 기존 알고리즘이 계속 사용됩니다. 또한, 텍스트 피클 프로토콜은 이전 알고리즘을 사용하여 교차 플랫폼 이식성을 보장합니다.
(Eric Smith와 Mark Dickinson이 기여했습니다; bpo-1580)
새로운, 개선된, 그리고 더 이상 사용되지 않는 모듈¶
시퀀스 또는 반복 가능(iterable)한 객체 내의 고유 항목을 편리하게 세는 기능을 지원하기 위해
collections.Counter클래스를 추가했습니다:>>> Counter(['red', 'blue', 'red', 'green', 'blue', 'blue']) Counter({'blue': 3, 'red': 2, 'green': 1})
(Raymond Hettinger가 기여했습니다; bpo-1696199.)
Tk 테마 위젯 세트에 접근하기 위한 새 모듈인
tkinter.ttk를 추가했습니다. ttk의 기본 아이디어는 가능한 범위 내에서 위젯의 동작을 구현하는 코드와 외형을 구현하는 코드를 분리하는 것입니다.(Guilherme Polo가 기여했습니다; bpo-2983.)
gzip.GzipFile및bz2.BZ2File클래스가 이제 컨텍스트 관리 프로토콜을 지원합니다:>>> # 쓰기 후 파일 자동 닫기 >>> with gzip.GzipFile(filename, "wb") as f: ... f.write(b"xxx")
(Antoine Pitrou가 기여했습니다.)
decimal모듈이 이제 바이너리float에서 10진 객체를 생성하는 메서드를 지원합니다. 변환은 정확하지만 때로는 놀라울 수 있습니다:>>> Decimal.from_float(1.1) Decimal('1.100000000000000088817841970012523233890533447265625')
길게 출력된 10진 결과는 1.1 을 위해 저장되는 실제 바이너리 분수를 보여줍니다. 1.1 은 이진수로 정확하게 표현될 수 없기 때문에 해당 분수는 많은 자릿수를 가집니다.
(Raymond Hettinger와 Mark Dickinson이 기여했습니다.)
itertools모듈에 두 개의 새로운 함수가 추가되었습니다.itertools.combinations_with_replacement()함수는 순열 및 데카르트 곱을 포함한 조합론을 생성하는 네 가지 기능 중 하나입니다.itertools.compress()함수는 APL의 동명 기능을 모방합니다. 또한, 기존의itertools.count()함수에 선택적 step 인수가 추가되어fractions.Fraction및decimal.Decimal을 포함한 모든 유형의 카운팅 시퀀스를 수용할 수 있습니다:>>> [p+q for p,q in combinations_with_replacement('LOVE', 2)] ['LL', 'LO', 'LV', 'LE', 'OO', 'OV', 'OE', 'VV', 'VE', 'EE'] >>> list(compress(data=range(10), selectors=[0,0,1,1,0,1,0,1,0,0])) [2, 3, 5, 7] >>> c = count(start=Fraction(1,2), step=Fraction(1,6)) >>> [next(c), next(c), next(c), next(c)] [Fraction(1, 2), Fraction(2, 3), Fraction(5, 6), Fraction(1, 1)]
(Raymond Hettinger 작성.)
collections.namedtuple()이 이제 유효하지 않은 필드 이름을 _0, _1 등의 형태의 위치 기반 이름으로 자동 변환해 주는 rename 키워드 인자를 지원합니다. 이는 필드 이름이 CSV 헤더, SQL 필드 목록 또는 사용자 입력과 같은 외부 소스에 의해 생성될 때 유용합니다:>>> query = input() SELECT region, dept, count(*) FROM main GROUPBY region, dept >>> cursor.execute(query) >>> query_fields = [desc[0] for desc in cursor.description] >>> UserQuery = namedtuple('UserQuery', query_fields, rename=True) >>> pprint.pprint([UserQuery(*row) for row in cursor]) [UserQuery(region='South', dept='Shipping', _2=185), UserQuery(region='North', dept='Accounting', _2=37), UserQuery(region='West', dept='Sales', _2=419)]
(Raymond Hettinger가 기여했습니다; bpo-1818.)
re.sub(),re.subn(), 그리고re.split()함수가 이제 flags 파라미터를 수용합니다.(Gregory Smith가 기여했습니다.)
logging모듈은 로깅을 사용하지 않으면서 로깅을 사용하는 라이브러리 코드를 호출하는 애플리케이션을 위해 간단한logging.NullHandler클래스를 구현합니다. Null 핸들러를 설정하면 “No handlers could be found for logger foo”와 같은 불필요한 경고를 억제할 수 있습니다:>>> h = logging.NullHandler() >>> logging.getLogger("foo").addHandler(h)
(Vinay Sajip이 기여했습니다; bpo-4384.)
-m명령줄 스위치를 지원하는runpy모듈은 이제 패키지 이름이 제공될 때__main__서브모듈을 찾아 실행함으로써 패키지 실행을 지원합니다.(Andi Vajda가 기여했습니다; bpo-4195.)
pdb모듈이 이제zipimport`(또는 다른 준수하는 :pep:`302로더)를 통해 로드된 소스 코드를 접근하고 표시할 수 있습니다.(Alexander Belopolsky가 기여했습니다; bpo-4201.)
functools.partial객체를 이제 피클링할 수 있습니다.
(Antoine Pitrou와 Jesse Noller가 제안하고 Jack Diederich가 구현했습니다; bpo-5228.)
상호작용 환경에서
help('@')가 예상대로 작동하도록 심볼에 대한pydoc도움말 주제를 추가했습니다.(David Laban이 기여했습니다; bpo-4739)
unittest모듈은 이제 개별 테스트나 테스트 클래스를 건너뛰는 기능을 지원합니다. 또한, 테스트가 깨져서 실패하는 것이 알려져 있지만, TestResult에서 실패로 계산되어서는 안 되는 “예상된 실패”로 테스트에 표시하는 기능도 지원합니다.:class TestGizmo(unittest.TestCase): @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") def test_gizmo_on_windows(self): ... @unittest.expectedFailure def test_gimzo_without_required_library(self): ...
또한 예외에 대한 테스트가
with문을 사용하는 컨텍스트 관리자와 호환되도록 구축되었습니다:def test_division_by_zero(self): with self.assertRaises(ZeroDivisionError): x / 0
또한,
assertSetEqual(),assertDictEqual(),assertDictContainsSubset(),assertListEqual(),assertTupleEqual(),assertSequenceEqual(),assertRaisesRegexp(),assertIsNone(), 그리고assertIsNotNone()을 포함한 여러 새로운 단언(assertion) 메서드가 추가되었습니다.(Benjamin Peterson 및 Antoine Pitrou가 기여했습니다.)
io모듈에seek()메서드를 위한 세 가지 새로운 상수가 추가되었습니다:SEEK_SET,SEEK_CUR, 그리고SEEK_END.sys.version_info튜플이 이제 네임드 튜플(named tuple)입니다:>>> sys.version_info sys.version_info(major=3, minor=1, micro=0, releaselevel='alpha', serial=2)
(Ross Light가 기여했습니다; bpo-4285.)
nntplib및imaplib모듈이 이제 IPv6를 지원합니다.pickle모듈이 프로토콜 2 이하를 사용할 때 Python 2.x와 더 나은 상호 운용성을 갖도록 조정되었습니다. 표준 라이브러리의 재구성으로 인해 많은 객체의 공식 참조가 변경되었습니다. 예를 들어, Python 2의__builtin__.set은 Python 3에서builtins.set으로 호출됩니다. 이러한 변화는 서로 다른 버전의 Python 간에 데이터를 공유하려는 노력을 방해했습니다. 하지만 이제 프로토콜 2 이하가 선택되면 pickler가 로딩과 덤프 모두에서 이전 Python 2 이름을 자동으로 사용합니다. 이 재매핑은 기본적으로 활성화되어 있지만 fix_imports 옵션으로 비활성화할 수 있습니다:>>> s = {1, 2, 3} >>> pickle.dumps(s, protocol=0) b'c__builtin__\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.' >>> pickle.dumps(s, protocol=0, fix_imports=False) b'cbuiltins\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.'
이 변경의 유감스럽지만 피할 수 없는 부작용은 Python 3.1에서 생성된 프로토콜 2 pickle을 Python 3.0에서 읽을 수 없다는 것입니다. Python 3.x 구현 간에 데이터를 마이그레이션할 때는 가장 최신인 프로토콜 3을 사용해야 합니다. 프로토콜 3은 Python 2.x와의 호환성을 유지하려고 시도하지 않기 때문입니다.
(Alexandre Vassalotti 및 Antoine Pitrou가 기여했습니다, bpo-6137.)
새로운 모듈인
importlib이 추가되었습니다. 이 모듈은import문과 그에 대응하는__import__()함수에 대한 완전하고 이식 가능한 순수 Python 참조 구현을 제공합니다. 이는 임포트 중에 발생하는 동작들을 문서화하고 정의하는 데 있어 상당한 진전을 의미합니다.(Brett Cannon 기여).
최적화들`¶
주요 성능 향상이 추가되었습니다:
새로운 I/O 라이브러리(PEP 3116 에 정의됨)는 대부분 Python으로 작성되었으며, Python 3.0에서 문제가 되는 병목 현상임이 곧 드러났습니다. Python 3.1에서는 I/O 라이브러리가 완전히 C로 다시 작성되었으며, 작업 종류에 따라 2배에서 20배까지 더 빠릅니다. 순수 Python 버전은 여전히
_pyio모듈을 통해 실험용으로 사용할 수 있습니다.(Amaury Forgeot d’Arc 및 Antoine Pitrou가 기여했습니다.)
추적 불가능한 객체만 포함하는 튜플과 딕셔너리가 가비지 컬렉터에 의해 추적되지 않도록 하는 휴리스틱을 추가했습니다. 이는 데이터 유형의 특정 사용 방식에 따라 컬렉션의 크기를 줄이고, 따라서 실행 시간이 긴 프로그램에서 가비지 컬렉션 오버헤드를 줄일 수 있습니다.
(Antoine Pitrou가 기여했습니다, bpo-4688.)
해당 옵션을 지원하는 컴파일러(특히 gcc, SunPro, icc)에서
--with-computed-gotos구성 옵션을 활성화하면, 바이트코드 평가 루프가 새로운 디스패치 메커니즘을 사용하여 컴파일되며 시스템, 컴파일러 및 벤치마크에 따라 최대 20%의 속도 향상을 제공합니다.(Antoine Pitrou 및 다수의 다른 참여자들이 기여했습니다, bpo-4753.)
UTF-8, UTF-16 및 LATIN-1 디코딩이 이제 2배에서 4배 더 빨라졌습니다.
(Antoine Pitrou 및 Amaury Forgeot d’Arc가 기여했습니다, bpo-4868.)
json모듈에 성능을 대폭 향상시키기 위한 C 확장 기능이 추가되었습니다. 또한, API가 수정되어 json이bytes가 아닌str와만 작동하도록 변경되었습니다. 이 변경으로 해당 모듈은 Unicode 기반으로 정의된 JSON 사양 에 더 긴밀하게 부합하게 되었습니다.(Bob Ippolito가 기여했으며, Antoine Pitrou 및 Benjamin Peterson에 의해 Py3.1로 변환되었습니다; bpo-4136.)
이제 언피클링(unpickling) 시 피클된 객체의 속성 이름을 인터닝(interning)합니다. 이는 메모리를 절약하고 피클 크기를 줄여줍니다.
(Jake McGuire 및 Antoine Pitrou가 기여했습니다; bpo-5084.)
IDLE¶
IDLE의 포맷 메뉴에 이제 소스 파일에서 끝에 오는 공백을 제거하는 옵션이 제공됩니다.
(Roger D. Serwy가 기여했습니다; bpo-5150.)
빌드 및 C API 변경사항¶
Python 빌드 프로세스 및 C API의 변경 사항은 다음과 같습니다:
정수는 이제 내부적으로 기본값이 빌드 시 결정되는
2**15또는2**30기반으로 저장됩니다. 이전에는 항상2**15기반으로 저장되었습니다.2**30을 사용하면 64비트 머신에서 상당한 성능 향상을 얻을 수 있지만, 32비트 머신에서의 벤치마크 결과는 엇갈렸습니다. 따라서 기본값은 64비트 머신에서는2**30, 32비트 머신에서는2**15를 사용하는 것입니다. Unix에서는 이 기본값을 무시하기 위해 사용할 수 있는 새로운 설정 옵션인--enable-big-digits가 추가되었습니다.성능 향상을 제외하면 이 변경은 사용자에게 거의 영향을 주지 않으나, 한 가지 예외가 있습니다. 테스트 및 디버깅을 위해 내부 형식에 대한 정보를 제공하는 새로운
sys.int_info가 추가되었으며, 이는 각 자릿수당 비트 수와 각 자릿수를 저장하는 데 사용되는 C 타입의 바이트 크기를 제공합니다:>>> import sys >>> sys.int_info sys.int_info(bits_per_digit=30, sizeof_digit=4)
(마크 디킨슨 기여; bpo-4258.)
PyLong_AsUnsignedLongLong()함수는 이제 음수 pylong 을TypeError대신OverflowError를 발생시켜 처리합니다.(Mark Dickinson 및 Lisandro Dalcrin이 기여했습니다; bpo-5175.)
PyNumber_Int()이(가) 폐지되었습니다. 대신PyNumber_Long()을 사용하십시오.(Mark Dickinson이 기여했습니다; bpo-4910.)
폐지된 기능인
PyOS_ascii_strtod()및PyOS_ascii_atof()를 대체하기 위해 새로운PyOS_string_to_double()함수를 추가했습니다.(Mark Dickinson이 기여했습니다; bpo-5914.)
PyCObjectAPI의 대체재로PyCapsule을 추가했습니다. 주요 차이점은 새 유형이 타입 안전성 정보를 전달하기 위한 잘 정의된 인터페이스와 파괴자(destructor)를 호출하기 위한 덜 복잡한 시그니처를 갖는다는 점입니다. 기존 유형은 문제가 있는 API를 가졌으며 이제 폐지되었습니다.(Larry Hastings가 기여했습니다; bpo-5630.)
Python 3.1로 이식하기¶
이 섹션에서는 앞서 설명한 변경 사항과 코드 수정이 필요할 수 있는 기타 버그 수정을 나열합니다.
새로운 부동 소수점 문자열 표현 방식이 기존의 doctest를 깨뜨릴 수 있습니다. 예를 들어:
def e(): '''Compute the base of natural logarithms. >>> e() 2.7182818284590451 ''' return sum(1/math.factorial(x) for x in reversed(range(30))) doctest.testmod() ********************************************************************** Failed example: e() Expected: 2.7182818284590451 Got: 2.718281828459045 **********************************************************************
pickle 모듈에서 프로토콜 2 이하에 대한 자동 이름 재매핑으로 인해 Python 3.1에서 생성된 피클을 Python 3.0에서 읽을 수 없게 될 수 있습니다. 한 가지 해결책은 프로토콜 3을 사용하는 것입니다. 다른 방법은 fix_imports 옵션을
False로 설정하는 것입니다. 자세한 내용은 위의 논의를 참조하십시오.