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

Python 개선 제안 한국어 번역

PEP 273 – Zip 아카이브에서 모듈 임포트하기

Author:
James C. Ahlstrom <jim at interet.com>
Status:
Final
Type:
Standards Track
Created:
11-Oct-2001
Python-Version:
2.3
Post-History:
26-Oct-2001

Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 zip 아카이브에서 Python 모듈 *.py, *.py[co]와 패키지를 임포트하는 기능을 추가합니다. os.listdir를 사용할 수 있으면 같은 코드가 일반 디렉터리 임포트의 속도를 높이는 데에도 사용됩니다.

참고

Zip 임포트는 Python 2.3에 추가되었지만, 최종 구현은 이 PEP에서 설명하는 것과 다른 방식을 사용합니다. 2.3 구현은 SourceForge 패치 #652586 [1]이며, 이 패치는 PEP 302에서 설명하는 새로운 임포트 훅을 추가합니다.

따라서 이 PEP의 나머지 부분은 역사적인 의미만 있습니다.

명세

현재 sys.path는 디렉터리 이름 문자열의 리스트입니다. 이 PEP가 구현되면 sys.path의 항목은 zip 파일 아카이브를 가리키는 문자열일 수 있습니다. Zip 아카이브는 패키지 임포트를 지원하기 위해 하위 디렉터리 구조를 포함할 수 있습니다. Zip 아카이브는 하위 디렉터리와 정확히 같은 방식으로 임포트를 처리합니다.

구현은 Python 코어의 C 코드로 되어 있으며 지원되는 모든 Python 플랫폼에서 동작합니다.

Zip 아카이브에는 어떤 파일이든 들어 있을 수 있지만, 임포트할 수 있는 것은 *.py와 *.py[co] 파일뿐입니다. 동적 모듈(*.pyd, *.so)의 zip 임포트는 허용되지 않습니다.

현재 sys.path에 기본 디렉터리 이름이 있는 것처럼, 기본 zip 아카이브 이름도 추가됩니다. 그렇지 않으면 아카이브에서 모든 Python 라이브러리 파일을 임포트할 방법이 없습니다.

하위 디렉터리 동등성

현재 및 향후 규칙에 따른 패키지 임포트를 지원할 수 있도록, zip 아카이브는 정확히 하위 디렉터리 트리처럼 취급되어야 합니다. 모든 zip 데이터는 중앙 디렉터리(Central Directory)에서 가져오며, 데이터는 올바라야 하고, 엉터리 zip 파일은 지원하지 않습니다.

sys.path에 “/A/B/SubDir”와 “/C/D/E/Archive.zip”이 들어 있고, Q 패키지에서 modfoo를 임포트하려 한다고 가정합시다. 그러면 import.c는 경로와 확장자의 목록을 생성하고 파일을 찾습니다. 생성되는 경로 목록은 zip 임포트의 경우에도 달라지지 않습니다. import.c가 “/A/B/SubDir/Q/R/modfoo.pyc” 경로를 생성한다고 가정합시다. 그러면 “/C/D/E/Archive.zip/Q/R/modfoo.pyc” 경로도 생성합니다. SubDir 경로를 찾는 것은 아카이브에서 “Q/R/modfoo.pyc”를 찾는 것과 정확히 동등합니다.

/A/B/SubDir/* 및 그 모든 하위 디렉터리를 zip으로 압축한다고 가정합시다. 그러면 여러분의 zip 파일은 하위 디렉터리와 똑같이 임포트를 처리합니다.

음, 꼭 그렇지는 않습니다. zip 파일로는 동적 모듈의 임포트를 처리할 수 없습니다. 동적 모듈은 .dll, .pyd, .so 같은 확장자를 가집니다. 동적 모듈은 운영 체제에 의존적이며, 아마 파일에서만 로드할 수 있을 것입니다. zip 파일에서 동적 모듈을 추출하여 일반 파일에 기록한 다음 로드하는 것이 가능할 수도 있습니다. 하지만 그렇게 하려면 임시 파일을 만들어야 하고 모든 dynload_*.c를 다루어야 하므로, 아마 좋은 생각은 아닐 것입니다.

*.pyc를 임포트하려 할 때 그 파일을 사용할 수 없으면 대신 *.pyo가 사용됩니다. *.pyo를 찾을 때는 그 반대입니다. *.pyc와 *.pyo 중 어느 것도 사용할 수 없거나 매직 넘버가 유효하지 않으면, *.py가 컴파일되어 임포트에 사용되지만 컴파일된 파일은 저장되지 않습니다. Python은 보통 그 파일을 *.py와 같은 디렉터리에 쓰지만, zip 파일에 쓰기를 원하지 않는 것은 분명합니다. zip 아카이브가 있는 디렉터리에 기록할 수도 있지만, 그러면 디렉터리가 어수선해지며, 예를 들어 그 디렉터리가 /usr/bin이라면 바람직하지 않습니다.

컴파일된 파일을 기록하지 못하면 zip 임포트가 매우 느려지며, 사용자는 무엇이 문제인지 알아내지 못할 가능성이 높습니다. 따라서 *.pyc와 *.pyo를 *.py와 함께 아카이브에 넣는 것이 가장 좋습니다.

효율성

zip 아카이브에서 파일을 찾는 유일한 방법은 선형 탐색입니다. 따라서 sys.path에 있는 각 zip 파일에 대해 그 안의 이름들을 한 번 검색하고, 그 이름들과 기타 관련 데이터를 정적 Python 딕셔너리에 넣습니다. 키는 sys.path의 아카이브 이름과 아카이브 내 파일 이름(하위 디렉터리 포함)을 결합한 것입니다. 이는 import.c가 생성하는 이름과 정확히 같으므로 조회가 쉬워집니다.

이와 동일한 메커니즘이 디렉터리(zip이 아닌) 임포트의 속도를 높이는 데에도 사용됩니다. 아래를 참조하십시오.

zlib

압축된 zip 아카이브는 압축 해제를 위해 zlib이 필요합니다. 다른 어떤 임포트보다 먼저 zlib의 임포트를 시도합니다. zlib을 사용할 수 없으면 압축된 파일의 임포트는 “missing zlib” 메시지와 함께 실패합니다.

부팅

Python은 스스로 site.py를 임포트하며, 이것은 os, nt, ntpath, stat, UserDict를 임포트합니다. 또한 sitecustomize.py도 임포트하는데, 이 모듈은 더 많은 모듈을 임포트할 수 있습니다. zip 임포트는 site.py가 임포트되기 전에 사용할 수 있어야 합니다.

sys.path에 기본 디렉터리가 있는 것처럼, 기본 zip 아카이브도 하나 이상 있어야 합니다.

문제는 그 이름을 무엇으로 할 것인가입니다. 이름은 Python 버전과 연결되어야 합니다. 그래야 같은 머신에 여러 Python 버전이 있을 때에도 Python 실행 파일이 그에 해당하는 라이브러리를 올바르게 찾을 수 있습니다.

sys.path에 이름을 하나 추가합니다. Unix에서는 디렉터리가 sys.prefix + "/lib"이고, 파일 이름은 "python%s%s.zip" % (sys.version[0], sys.version[2])입니다. 따라서 Python 2.2이고 접두사가 /usr/local이면, 경로 /usr/local/lib/python2.2/는 이미 sys.path에 있고, /usr/local/lib/python22.zip이 추가됩니다. Windows에서는 파일이 python22.dll의 전체 경로에서 “dll”을 “zip”으로 바꾼 것입니다. zip 아카이브 이름은 항상 sys.path의 두 번째 항목으로 삽입됩니다. 첫 번째 항목은 main.py가 있는 디렉터리입니다(Tim에게 감사드립니다).

디렉터리 임포트

zip 임포트 속도를 높이는 데 사용하는 정적 Python 딕셔너리는 일반 디렉터리 임포트 속도를 높이는 데에도 사용할 수 있습니다. sys.path에서 zip 아카이브가 아닌 각 항목에 대해 os.listdir을 호출하고, 디렉터리 내용을 딕셔너리에 추가합니다. 그러면 이중 루프에서 fopen()을 호출하는 대신 딕셔너리만 확인하면 됩니다. 이렇게 하면 임포트 속도가 크게 향상됩니다. os.listdir이 존재하지 않으면 딕셔너리를 사용하지 않습니다.

벤치마크

사례 원본 2.2a3 os.listdir 사용 Zip 비압축 Zip 압축
1 3.2 2.5 3.2->1.02 2.3 2.5 2.3->0.87 1.66->0.93 1.5->1.07
2 2.8 3.9 3.0->1.32 사례 1과 같습니다.
3 5.7 5.7 5.7->5.7 2.1 2.1 2.1->1.8 1.25->0.99 1.19->1.13
4 9.4 9.4 9.3->9.35 사례 3과 같습니다.

사례 1: 로컬 드라이브 C:, sys.path가 기본값입니다. 사례 2: 로컬 드라이브 C:, 파일이 있는 디렉터리가 sys.path의 끝에 있습니다. 사례 3: 네트워크 드라이브, sys.path가 기본값입니다. 사례 4: 네트워크 드라이브, 파일이 있는 디렉터리가 sys.path의 끝에 있습니다.

벤치마크는 Pentium 4 호환 기종(1.4 GHz, 256 MB)에서 수행했습니다. 이 컴퓨터는 Windows 2000을 실행했으며 Linux/Samba 네트워크 서버를 함께 사용했습니다. 시간의 단위는 초이며, 약 100개의 Lib 모듈을 임포트하는 데 걸린 시간입니다. 사례 2와 4는 “올바른” 디렉터리를 sys.path의 끝으로 옮긴 것입니다. “Uncomp”는 압축하지 않은 zip 아카이브를, “Compr”는 압축한 zip 아카이브를 뜻합니다.

처음 시간은 시스템을 재부팅한 직후의 시간이고, “->” 뒤의 시간은 반복 실행한 후의 시간입니다. 재부팅 후 C:에서 임포트하는 시간은 “Original” 사례에서 편차가 꽤 크지만, 더 현실적인 값입니다.

사용자 정의 임포트

이 로직은 필요한 Python 모듈(이 경우 os)을 사용할 수 있게 될 때까지 기본 검색 방식으로 임포트할 수 있음을 보여 줍니다. 이를 사용하여 사용자 정의 임포터를 부트스트랩할 수 있습니다. 예를 들어 __init__.py에 “importer()”가 있으면 이를 임포트에 사용할 수 있습니다. “importer()”는 os 및 다른 모듈을 자유롭게 임포트할 수 있으며, 이러한 임포트는 기본 메커니즘으로 처리됩니다. 이 PEP는 사용자 정의 임포터를 정의하지 않으며, 이 내용은 참고용일 뿐입니다.

구현

C 구현이 SourceForge 패치 492105로 제공됩니다. 패치 652586과 현재 CVS로 대체되었습니다. [2]

더 새로운 버전(Paul Moore가 최신 CVS에 맞게 갱신함)은 645650입니다. 패치 652586과 현재 CVS로 대체되었습니다. [3]

Just van Rossum이 만든 경쟁 구현은 652586이며, 이는 PEP 302의 최종 구현의 기반이 되었습니다. PEP 273은 PEP 302의 임포트 훅을 사용하여 구현되었습니다. [1]

참고 문헌