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

Python 개선 제안 한국어 번역

PEP 304 – 바이트코드 파일 생성 제어

Author:
Skip Montanaro
Status:
Withdrawn
Type:
Standards Track
Created:
22-Jan-2003
Post-History:
27-Jan-2003, 31-Jan-2003, 17-Jun-2005

Table of Contents

번역·라이선스 안내

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

역사적 참고 사항

이 원본 PEP는 철회되었지만, 이 기능의 변형은 결국 Python 3.8용으로 다음 이슈에서 구현되었습니다: https://bugs.python.org/issue33499

이 PEP에서 처음 제기된 여러 문제와 우려 사항은 그 후 몇 년 동안 이루어진 다른 변경으로 해결되었습니다:

  • 잠재적인 보안 문제를 처리하기 위한 격리 모드의 도입
  • 완전히 임포트 훅 기반인 임포트 시스템 구현인 importlib로의 전환
  • PEP 3147의 바이트코드 캐시 레이아웃 변경으로 __pycache__ 하위 디렉터리를 사용하게 되었으며, 여기에는 인터프리터가 별도의 캐시 디렉터리로의 리디렉션을 자동으로 처리하도록 하는 source_to_cache(path)cache_to_source(path) API가 포함됩니다.

초록

이 PEP는 컴파일된 Python 바이트코드 파일의 생성과 위치를 제어하는 메커니즘을 개괄합니다. 이 아이디어는 원래 패치 요청 [1]으로 시작되었으며 python-dev 메일링 리스트에서 논의 스레드 [2]로 발전했습니다. 환경 변수를 도입하면 Python 또는 Python 기반 서드파티 패키지를 설치하는 사람이 설치 시점에 바이트코드 파일을 생성할지 여부와 생성한다면 해당 파일을 어디에 기록할지를 제어할 수 있습니다. 또한 사용자가 애플리케이션 실행 시 바이트코드 파일을 생성할지 여부와 생성한다면 해당 파일을 어디에 기록할지를 제어할 수 있습니다.

제안

Python이 이해하는 환경 변수 목록에 새로운 환경 변수 PYTHONBYTECODEBASE를 추가합니다. PYTHONBYTECODEBASE는 다음과 같이 해석됩니다:

  • 정의되지 않은 경우 Python 바이트코드는 현재 수행되는 것과 정확히 같은 방식으로 생성됩니다. sys.bytecodebase는 루트 디렉터리로 설정됩니다(Unix 및 Mac OSX에서는 /이고, Windows에서는 시작 드라이브(설치 드라이브???)의 루트 디렉터리이며 일반적으로 C:\입니다).
  • 정의되어 있고 사용자가 쓰기 권한을 가진 기존 디렉터리를 가리키는 경우 sys.bytecodebase는 해당 디렉터리로 설정되며, 바이트코드 파일은 해당 위치를 루트로 하는 디렉터리 구조에 기록됩니다.
  • 정의되어 있지만 비어 있는 경우 sys.bytecodebase는 None으로 설정되며 바이트코드 파일 생성은 완전히 억제됩니다.
  • 정의되어 있고 다음 중 하나가 참인 경우:
    • 디렉터리를 가리키지 않는 경우,
    • 디렉터리를 가리키지만 사용자가 쓰기 권한을 가진 디렉터리가 아닌 경우

    경고가 표시되고 sys.bytecodebase는 None으로 설정되며 바이트코드 파일 생성은 완전히 억제됩니다.

시작 초기화가 끝난 후 모든 런타임 참조는 PYTHONBYTECODEBASE 환경 변수가 아니라 sys.bytecodebase를 대상으로 합니다. sys.path는 수정되지 않습니다.

위 내용에서 sys.bytecodebase가 가질 수 있는 유효한 값의 유형은 None 또는 시스템의 유효한 디렉터리를 가리키는 문자열, 이렇게 두 가지뿐임을 알 수 있습니다.

임포트 중에 이 확장은 다음과 같이 작동합니다:

  • 모듈에 대한 일반 검색이 수행됩니다. 검색 순서는 대략 동적으로 로드된 확장 모듈, Python 소스 파일, Python 바이트코드 파일 순입니다. 이 메커니즘이 작동하는 유일한 경우는 Python 소스 파일이 발견된 경우입니다.
  • 소스 모듈을 찾으면 동일한 디렉터리에 있는 바이트코드 파일을 읽으려고 시도합니다. (이전과 동일합니다.)
  • 바이트코드 파일을 찾지 못하면 확장된 디렉터리에서 바이트코드 파일을 읽으려고 시도합니다.
  • 바이트코드 생성이 필요한 경우 생성된 바이트코드는 가능하면 확장된 디렉터리에 기록됩니다.

이 PEP는 바이트코드 파일의 처리 방식을 모듈별 또는 디렉터리별로 제어하는 기능을 제공하는 것에 관한 것이 아님을 유의하십시오.

용어집

  • “바이트코드 베이스”는 sys.bytecodebase의 현재 설정을 가리킵니다.
  • “증강 디렉터리”는 바이트코드 베이스와 소스 파일의 디렉터리 이름으로 형성된 디렉터리를 가리킵니다.
  • “바이트코드 베이스”와 구별해야 할 경우 PYTHONBYTECODEBASE는 환경 변수를 가리킵니다.

바이트코드 파일 찾기

인터프리터가 모듈을 검색할 때는 평소와 같이 sys.path를 사용합니다. 그러나 바이트코드 파일이 있을 가능성을 고려할 때는 바이트코드 파일을 추가로 탐색할 수 있습니다. 먼저, 소스 파일을 포함하는 sys.path의 디렉터리를 사용하여 바이트코드 파일을 확인합니다(현재 동작입니다). 해당 위치에서 유효한 바이트코드 파일을 찾지 못하고(파일이 존재하지 않거나 존재하지만 최신 상태가 아닌 경우) 바이트코드 베이스가 None이 아니면, 바이트코드 베이스를 적절히 접두사로 붙인 sys.path의 디렉터리를 사용하여 두 번째 확인을 수행합니다.

바이트코드 파일 작성

바이트코드 베이스가 None이 아니면 새 바이트코드 파일은 적절히 확장된 디렉터리에 기록되며, sys.path의 디렉터리에 직접 기록되지는 않습니다.

증강 디렉터리 정의

개념적으로 바이트코드 파일의 증강 디렉터리는 바이트코드 베이스를 앞에 붙인 소스 파일이 존재하는 디렉터리입니다. Unix 환경에서는 다음과 같습니다.:

pcb = os.path.abspath(sys.bytecodebase)
if sourcefile[0] == os.sep: sourcefile = sourcefile[1:]
augdir = os.path.join(pcb, os.path.dirname(sourcefile))

단일 루트 디렉터리 트리가 없는 Windows에서는 소스 파일이 포함된 디렉터리의 드라이브 문자를 끝의 콜론을 제거한 후 디렉터리 구성 요소로 취급합니다. 따라서 증강 디렉터리는 다음과 같이 도출됩니다.

pcb = os.path.abspath(sys.bytecodebase)
drive, base = os.path.splitdrive(os.path.dirname(sourcefile))
drive = drive[:-1]
if base[0] == "\\": base = base[1:]
augdir = os.path.join(pcb, drive, base)

바이트코드 베이스 위치 고정

프로그램 시작 중 PYTHONBYTECODEBASE 환경 변수의 값을 절대 경로로 만들고, 유효성을 검사한 후 sys 모듈에 추가하며, 사실상 다음과 같이 처리합니다.:

pcb = os.path.abspath(os.environ["PYTHONBYTECODEBASE"])
probe = os.path.join(pcb, "foo")
try:
    open(probe, "w")
except IOError:
    sys.bytecodebase = None
else:
    os.unlink(probe)
    sys.bytecodebase = pcb

이를 통해 사용자는 바이트코드 베이스를 상대 경로로 지정할 수 있지만, 프로그램 실행 중 현재 작업 디렉터리가 변경되어도 그 영향을 받지 않게 됩니다. (프로그램 실행 중 해당 경로가 이리저리 이동하기를 원하실 것이라고는 상상하기 어렵습니다.)

sys.bytecodebase에는 특별한 점이 없습니다. 사용자가 원하면 런타임에 이를 변경할 수 있지만, 일반적으로는 수정되지 않습니다.

근거

많은 환경에서는 루트가 아닌 사용자가 Python 소스 파일이 포함된 디렉터리에 쓸 수 없습니다. 대부분의 경우 이는 문제가 되지 않습니다. Python 소스는 일반적으로 설치 중에 바이트코드로 컴파일되기 때문입니다. 그러나 바이트코드 파일이 없거나 업데이트해야 하는 상황도 있습니다. 소스 파일이 포함된 디렉터리에 현재 사용자가 쓸 수 없으면 모듈을 가져오는 프로그램이 실행될 때마다 성능 저하가 발생합니다. [3] 특정 상황에서는 경고 메시지가 생성될 수도 있습니다. 디렉터리에 쓸 수 있는 경우에는 서로 다른 두 프로세스가 거의 동시에 바이트코드 파일을 작성하려고 시도할 수 있으며, 그 결과 파일이 손상될 수 있습니다. [4]

RAM 디스크를 사용할 수 있는 환경에서는 성능상의 이유로 이러한 디스크의 디렉터리에 바이트코드 파일을 작성하는 것이 바람직할 수 있습니다. 마찬가지로 Python 소스 코드가 네트워크 파일 시스템에 있는 환경에서는 로컬 디스크에 바이트코드 파일을 캐시하는 것이 바람직할 수 있습니다.

대안

지금까지 제안된 유일한 다른 대안 [1]은 바이트코드 파일을 전혀 작성하지 않도록 인터프리터에 -R 플래그를 추가하는 것 같습니다. 이 제안은 이를 포괄합니다. 명령줄 옵션을 추가하는 것은 분명히 가능하지만, 설치 중에는 인터프리터의 명령줄을 쉽게 사용할 수 없으므로 충분하지 않을 가능성이 큽니다(프로그램 시작 초기에???).

문제

  • 모듈의 __file__ 속성 해석 모듈의 __file__ 속성은 바이트코드 파일의 실제 위치를 반영해야 한다고 생각합니다. 모듈의 소스 코드를 찾으려면 imp.find_module(module)을 사용해야 합니다.
  • 보안 - root가 PYTHONBYTECODEBASE를 설정한 경우는 어떻게 됩니까? 그렇습니다. 이는 보안 위험을 초래할 수 있지만, root 사용자가 하는 다른 많은 일도 마찬가지입니다. root 사용자는 설치 중인 경우를 제외하면 PYTHONBYTECODEBASE를 설정하지 않는 것이 좋습니다. 그래도 이 문제를 최소화할 수 있을지도 모릅니다. root로 실행할 때 인터프리터는 PYTHONBYTECODEBASE가 root 이외의 누구나 쓸 수 있는 디렉터리를 가리키는지 확인해야 합니다. 그렇다면 예외 또는 경고를 발생시키고 sys.bytecodebase를 None으로 설정할 수 있습니다. 또는 다음 항목을 참조하십시오.
  • 추가 보안 - PYTHONBYTECODEBASE가 일반 디렉터리(예: /tmp)를 가리키는 경우는 어떻게 됩니까? 이 경우 기존 바이트코드 파일은 해당 파일이 현재 사용자 또는 root의 소유인 경우에만 로드해야 할 수도 있습니다. (Windows에서는 이것이 중요합니까?)
  • 이 PEP와 import 후크의 상호 작용은 아직 고려되지 않았습니다. 실제로 이 아이디어를 구현하는 가장 좋은 방법은 import 후크일 수도 있습니다. 다음 문서를 참조하십시오: PEP 302.
  • 현재의 (pre-PEP 304) 환경에서는 해당 바이트코드 파일이 생성된 후 소스 파일을 삭제해도 안전합니다. 두 파일이 같은 디렉터리에 있기 때문입니다. 현재 정의된 PEP 304를 적용하면 그렇지 않습니다. 확장 디렉터리의 바이트코드 파일은 소스 파일이 있을 때만 고려되므로, “.pyc”로 끝나는 모듈 파일을 찾을 때는 결코 고려되지 않습니다. 이 동작은 변경되어야 할 수도 있다고 생각합니다.

예제

다음 예제에서는 urllib 소스 코드가 /usr/lib/python2.3/urllib.py에 있으며 /usr/lib/python2.3은 sys.path에 포함되어 있지만 현재 사용자가 쓸 수 없습니다.

  • 바이트코드 기반 디렉터리는 /tmp입니다. /usr/lib/python2.3/urllib.pyc가 존재하며 유효합니다. urllib을 임포트하면 /usr/lib/python2.3/urllib.pyc의 내용이 사용됩니다. 확장 디렉터리는 참조되지 않습니다. 다른 바이트코드 파일은 생성되지 않습니다.
  • 바이트코드 기반 디렉터리는 /tmp입니다. /usr/lib/python2.3/urllib.pyc가 존재하지만 오래된 파일입니다. urllib을 임포트하면 생성된 바이트코드 파일이 /tmp/usr/lib/python2.3 값을 갖는 확장 디렉터리의 urllib.pyc에 기록됩니다. 필요한 경우 중간 디렉터리가 생성됩니다.
  • 바이트코드 베이스는 None입니다. urllib.pyc 파일을 찾을 수 없습니다. urllib을 임포트할 때 바이트코드 파일이 기록되지 않습니다.
  • 바이트코드 베이스는 /tmp입니다. urllib.pyc 파일을 찾을 수 없습니다. urllib을 임포트할 때 생성된 바이트코드 파일은 값이 /tmp/usr/lib/python2.3인 증강 디렉터리에 기록됩니다. 필요에 따라 중간 디렉터리가 생성됩니다.
  • 시작 시 PYTHONBYTECODEBASE는 존재하지 않는 /tmp/foobar입니다. 경고가 발생하고, sys.bytecodebase는 None으로 설정되며, sys.bytecodebase가 이후 유효하고 쓰기 가능한 디렉터리를 가리키도록 변경되지 않는 한 프로그램 실행 중에 바이트코드 파일이 기록되지 않습니다.
  • 시작 시 PYTHONBYTECODEBASE는 /로 설정되는데, 이 디렉터리는 존재하지만 현재 사용자가 쓸 수 없습니다. 경고가 발생하고, sys.bytecodebase는 None으로 설정되며, sys.bytecodebase가 이후 유효하고 쓰기 가능한 디렉터리를 가리키도록 변경되지 않는 한 프로그램 실행 중에 바이트코드 파일이 기록되지 않습니다. 특정 바이트코드 파일을 위해 구성된 증강 디렉터리가 현재 사용자에게 쓰기 가능하더라도, 중요한 것은 바이트코드 베이스 디렉터리 자체가 쓰기 가능한지 여부라는 점에 유의하십시오.
  • 시작 시 PYTHONBYTECODEBASE는 빈 문자열로 설정됩니다. sys.bytecodebase는 None으로 설정됩니다. 그러나 경고는 발생하지 않습니다. urllib을 임포트할 때 urllib.pyc 파일을 찾을 수 없으면 바이트코드 파일이 기록되지 않습니다.

다음에 나오는 Windows 예제에서 urllib 소스 코드는 C:\PYTHON22\urllib.py에 있습니다. C:\PYTHON22는 sys.path에 있지만 현재 사용자가 쓸 수 없습니다.

  • 바이트코드 베이스는 C:\TEMP로 설정됩니다. C:\PYTHON22\urllib.pyc가 존재하며 유효합니다. urllib을 임포트할 때 C:\PYTHON22\urllib.pyc의 내용이 사용됩니다. 증강 디렉터리는 참조되지 않습니다.
  • 바이트코드 베이스는 C:\TEMP로 설정됩니다. C:\PYTHON22\urllib.pyc가 존재하지만 오래되었습니다. urllib을 임포트할 때 새 바이트코드 파일은 값이 C:\TEMP\C\PYTHON22인 증강 디렉터리에 기록됩니다. 필요에 따라 중간 디렉터리가 생성됩니다.
  • 시작 시 PYTHONBYTECODEBASE는 TEMP로 설정되고, 애플리케이션 시작 시 현재 작업 디렉터리는 H:\NET입니다. 따라서 잠재적 바이트코드 베이스는 H:\NET\TEMP입니다. 이 디렉터리가 존재하고 현재 사용자가 쓸 수 있다면, sys.bytecodebase는 그 값으로 설정됩니다. 그렇지 않다면 경고가 발생하고 sys.bytecodebase는 None으로 설정됩니다.
  • 바이트코드 베이스는 C:\TEMP입니다. urllib.pyc 파일을 찾을 수 없습니다. urllib을 임포트할 때 생성된 바이트코드 파일은 값이 C:\TEMP\C\PYTHON22인 증강 디렉터리에 기록됩니다. 필요에 따라 중간 디렉터리가 생성됩니다.

구현

Sourceforge의 패치를 참조하십시오. [6]

참고 자료