[Final] PEP 488 - Elimination of PYO files

원문 링크: PEP 488 - Elimination of PYO files

상태: Final 유형: Standards Track 작성일: 20-Feb-2015

PEP 488 – PYO 파일 제거

초록 (Abstract)

이 PEP는 Python에서 PYO 파일 개념을 제거할 것을 제안합니다. 바이트코드 파일이 최적화 수준에 따라 분리되어 저장되는 방식을 계속 지원하기 위해, 최적화가 적용된 경우 바이트코드 저장소 디렉터리 내의 PYC 파일 이름에 최적화 수준을 포함하도록 확장할 것을 제안합니다.

배경 (Rationale)

현재 Python의 바이트코드 파일은 PYCPYO 두 가지 형태로 존재합니다. 인터프리터 시작 시 최적화 수준이 지정되지 않으면(-O 옵션 미지정) PYC 파일이 생성되고 읽힙니다. 반면, -O 또는 -OO와 같은 최적화 수준이 지정되면 PYO 파일이 읽고 쓰입니다.

문제는 PYC 파일이 Peepholer 최적화 외에 다른 최적화가 없음을 명확히 하는 반면, PYO 파일은 최적화 수준 1(-O)과 최적화 수준 2(-OO) 모두 .pyo 확장자를 재사용하여 어떤 최적화 수준이 적용되었는지 알 수 없다는 점입니다.

이러한 모호성은 다음과 같은 문제를 야기합니다.

  • 코드 실행의 불일치: 사용자가 모든 PYO 파일이 동일한 최적화 수준으로 생성되었는지 확인하지 않으면, 인터프리터가 다른 최적화 수준으로 컴파일된 코드를 혼합하여 사용할 수 있습니다.
  • 불필요한 파일 변경 (File Churn): 최적화 수준을 변경하거나 이전에 생성된 PYO 파일의 최적화 수준을 확신할 수 없을 때마다 모든 PYO 파일을 삭제해야 하는 번거로움이 있습니다. 이는 불필요한 파일 쓰기 작업을 유발합니다.
  • 사전 컴파일의 어려움: .pyo 확장자가 여러 최적화 수준에 재사용되면서 모든 최적화 수준에 대한 바이트코드 파일을 미리 컴파일하는 것이 불가능합니다.
  • 배포 효율성 저하: 바이트코드 전용 모듈을 배포할 때 코드 난독화나 파일 크기 축소를 위해 .pyc.pyo 파일을 모두 배포하는 것은 비효율적입니다. 이 PEP에서는 비최적화 .pyc 파일 이름으로만 로드하도록 합니다.

제안 (Proposal)

PYO 파일의 모호성을 제거하기 위해, 이 PEP는 PYO 파일과 .pyo 확장자 개념을 없앨 것을 제안합니다. 최적화 수준을 명확히 하고 __pycache__ 디렉터리에서 최적화된 바이트코드 파일을 불필요하게 다시 생성하는 것을 방지하기 위해, 바이트코드 파일 이름에 최적화 수준을 포함시킬 것입니다.

최적화 수준이 지정되지 않은 경우, 기존의 .pyc 파일 이름 형식이 그대로 사용됩니다.

예를 들어, Python 3.5에서 foo.py라는 소스 파일은 인터프리터의 최적화 수준(없음, -O, -OO)에 따라 다음과 같은 바이트코드 파일을 가질 수 있습니다.

  • 0 (최적화 없음): foo.cpython-35.pyc (기존과 동일)
  • 1 (-O): foo.cpython-35.opt-1.pyc
  • 2 (-OO): foo.cpython-35.opt-2.pyc

현재 바이트코드 파일 이름은 importlib.util.cache_from_source() 함수에 의해 PEP 3147에서 정의된 형식인 '{name}.{cache_tag}.pyc'를 사용하여 생성됩니다.

이 PEP는 최적화 수준이 지정된 경우 파일 이름 형식을 다음과 같이 변경할 것을 제안합니다.

'{name}.{cache_tag}.opt-{optimization}.pyc'

여기서 opt- 접두사는 캐시 태그와 시각적으로 구분되며, 최적화 수준은 캐시 태그 뒤에 배치되어 모듈 이름과 캐시 태그를 기준으로 한 사전식 정렬 순서를 유지합니다. opt-는 자체 설명적이며, 숫자 0과의 혼동을 피하기 위해 선택되었습니다. 구분자로 하이픈 대신 마침표를 사용하여 최적화 수준이 인터프리터 버전의 일부가 아님을 명확히 합니다.

이 변경 사항은 import 성능에 영향을 미치지 않습니다. __pycache__ 디렉터리에 잠재적으로 더 많은 바이트코드 파일이 생길 수 있지만, import 시스템은 이미 인터프리터의 최적화 수준에 따라 단일 바이트코드 파일을 찾으므로 stat 호출 횟수에는 변화가 없습니다.

이 PEP의 잠재적인 단점은 .pyc 파일 수의 증가와 그에 따른 저장 공간 사용량 증가입니다. 그러나 이러한 문제가 되는 플랫폼의 경우 sys.dont_write_bytecode를 사용하여 바이트코드 생성을 비활성화하고 오프라인으로 제어할 수 있습니다.

구현 (Implementation)

importlib

importlib.util.cache_from_source()는 바이트코드 파일 경로를 노출하고 importlib에 의해 직접 사용되므로 가장 중요한 변경이 필요합니다. Python 3.4의 함수 시그니처는 다음과 같습니다.

importlib.util.cache_from_source(path, debug_override=None)

이 PEP는 Python 3.5에서 시그니처를 다음과 같이 변경할 것을 제안합니다.

importlib.util.cache_from_source(path, debug_override=None, *, optimization=None)

새로 도입된 키워드 전용 매개변수 optimization은 파일 이름에 지정될 최적화 수준을 제어합니다. 인수가 None이면 인터프리터의 현재 최적화 수준이 가정됩니다. optimization에 전달되는 인수는 str()로 변환되며 str.isalnum()True여야 합니다. 빈 문자열이 전달되면 최적화 수준 추가가 억제되어 이 PEP 이전의 파일 이름 형식으로 돌아갑니다.

debug_override 매개변수는 더 이상 사용되지 않을 것입니다. False 값은 optimization=1과 동등하며, True 값은 optimization=''를 나타냅니다. debug_overrideNone이 아닌 값이 주어지면 Deprecation Warning이 발생합니다.

importlib.machinery의 바이트코드 파일 접미사와 관련된 다양한 모듈 속성도 업데이트될 것입니다. DEBUG_BYTECODE_SUFFIXESOPTIMIZED_BYTECODE_SUFFIXES는 모두 더 이상 사용되지 않음으로 문서화되고 BYTECODE_SUFFIXES와 동일한 값으로 설정됩니다.

표준 라이브러리의 나머지 부분

py_compilecompileall 모듈에 의해 노출되는 다양한 함수들은 새로운 바이트코드 파일 이름 의미론을 따르도록 업데이트될 것입니다. compileall 모듈의 CLI는 직접적인 영향을 받지 않습니다.

호환성 고려 사항 (Compatibility Considerations)

Python 3.2부터 바이트코드 파일을 직접 조작하는 모든 코드는 이 변경 사항이 코드에 미치는 영향을 고려해야 합니다. importlib.util.cache_from_source()debug_override 인수를 설정하던 코드는 최적화 수준 2의 바이트코드 파일 경로를 원할 경우 주의가 필요합니다.

바이트코드 전용 모듈을 배포하는 사람들은 .pyc 파일과 함께 .pyo 파일을 배포하는 것이 더 이상 유용하지 않으므로, 사용할 최적화 수준을 선택해야 합니다. 코드 난독화나 배포 크기 축소를 위해 단일 .pyc만 배포하는 것이 이러한 사용 사례에 유리할 것입니다. Python 3.5에서 바이트코드 파일의 매직 넘버가 변경되었기 때문에 기존 .pyo 파일을 지원할 필요가 없습니다.

기각된 아이디어 (Rejected Ideas)

CPython에서 최적화 수준을 완전히 제거하는 것

일부에서는 CPython의 다양한 최적화 수준을 수용하는 대신 완전히 제거해야 한다고 제안했습니다. 이 주장은 JIT와 같은 런타임 최적화를 통해 상당한 성능 향상을 얻을 수 있으며, 사전 실행 바이트코드 최적화를 통해서는 얻을 수 없다는 것입니다.

이 아이디어는 기존 CPython의 최적화 수준이 유용하다고 생각하는 사람들이 존재한다는 사실을 무시하기 때문에 이 PEP에서 기각되었습니다.

파일 이름에서 최적화 수준의 대체 형식

opt- 접두사를 사용하고 최적화 수준을 캐시 태그와 파일 확장자 사이에 배치하는 것이 중요하지 않다는 의견도 있었습니다. 다양한 다른 형식들이 고려되었지만, 파일 정렬 순서 변경, 캐시 태그와의 모호성, 또는 자체 설명 부족 등의 이유로 기각되었습니다. 비공식 설문조사 결과, PEP가 제안한 형식을 선호하는 경향이 분명했습니다.

바이트코드 메타데이터에 최적화 수준 포함

바이트코드의 최적화 수준을 파일 이름이 아닌 파일의 메타데이터에 포함해야 한다는 제안도 있었습니다. 이는 모든 인터프리터가 한 번에 하나의 바이트코드 사본만 가질 수 있음을 의미합니다. 최적화 수준을 변경하려면 바이트코드를 다시 작성해야 하지만, 관리해야 할 파일은 하나만 있을 것입니다.

이 제안은 Python이 종종 루트 수준 애플리케이션으로 설치되며, 이 경우 표준 라이브러리 모듈의 바이트코드 파일을 수정하는 것이 항상 가능하다는 사실 때문에 기각되었습니다. 이러한 상황에서 통합자(integrators)는 사용자에게 적합한 최적화 수준을 추측해야 할 것입니다. 여러 최적화 수준이 동시에 존재할 수 있도록 함으로써 통합자들이 추측할 필요 없이 사용자가 원하는 최적화 수준을 활용할 수 있게 됩니다.

이 문서는 공개 도메인에 배치되었습니다. —

PEP 488 요약:

PEP 488은 Python에서 .pyo 파일 개념을 제거하고 모든 최적화된 바이트코드 파일을 .pyc 확장자로 통합하는 것을 제안합니다. 기존에는 최적화 수준에 따라 .pyc.pyo로 나뉘었지만, .pyo 파일은 최적화 수준 1(-O)과 2(-OO)를 구분하지 못해 모호성을 야기하고 불필요한 파일 관리를 초래했습니다. 이 PEP는 이러한 문제를 해결하기 위해 최적화 수준을 바이트코드 파일 이름(예: foo.cpython-35.opt-1.pyc)에 명시적으로 포함하도록 변경합니다. 이는 importlib 모듈과 표준 라이브러리의 관련 함수들을 업데이트하며, debug_override 매개변수를 비활성화합니다. 이로 인해 파일 수가 증가할 수 있지만, 호환성 및 명확성 측면에서 이점을 제공합니다.## PEP 488 – PYO 파일 제거

초록 (Abstract)

이 PEP는 Python에서 PYO 파일 개념을 제거하고, 최적화 수준을 바이트코드 저장소 디렉터리 내의 PYC 파일 이름에 포함시켜 바이트코드 파일의 최적화 수준별 분리 지원을 유지할 것을 제안합니다.

배경 (Rationale)

현재 Python의 바이트코드 파일은 .pyc.pyo 두 가지 형태로 존재합니다. 인터프리터 시작 시 최적화 수준이 지정되지 않으면(.O 옵션 미지정) .pyc 파일이 생성되고 읽히며, -O 또는 -OO와 같은 최적화 수준이 지정되면 .pyo 파일이 읽고 쓰입니다.

문제는 .pyo 파일이 최적화 수준 1(-O)과 최적화 수준 2(-OO) 모두에 동일하게 사용되어, 해당 파일이 어떤 최적화 수준으로 생성되었는지 명확히 알 수 없다는 점입니다. 이러한 모호성은 다음과 같은 문제를 야기합니다.

  • 최적화 수준 혼동: 사용자가 주의하지 않으면 인터프리터가 다른 최적화 수준으로 컴파일된 코드를 혼합하여 사용할 수 있습니다.
  • 불필요한 파일 재생성: 최적화 수준을 변경하거나 기존 .pyo 파일의 최적화 수준을 확신할 수 없을 때마다 모든 .pyo 파일을 삭제해야 하는 번거로움이 있습니다.
  • 사전 컴파일 제약: .pyo 확장자가 여러 최적화 수준에 재사용되면서 모든 최적화 수준에 대한 바이트코드 파일을 미리 컴파일하는 것이 불가능합니다.
  • 배포 비효율성: 바이트코드 전용 모듈을 배포할 때 .pyc.pyo 파일을 모두 배포하는 것은 비효율적입니다. 이 PEP에서는 비최적화 .pyc 파일 이름으로만 로드하도록 합니다.

제안 (Proposal)

이 PEP는 PYO 파일의 모호성을 제거하기 위해 .pyo 파일과 확장자 개념을 없앨 것을 제안합니다. 대신, 최적화 수준을 바이트코드 파일 이름에 포함시켜 명확성을 확보하고 __pycache__ 디렉터리에서 불필요한 파일 재생성을 피합니다.

최적화 수준이 지정되지 않은 경우, 기존의 .pyc 파일 이름 형식이 그대로 사용됩니다.

변경될 바이트코드 파일 이름 예시 (Python 3.5, foo.py 기준):

  • 0 (최적화 없음): foo.cpython-35.pyc (변경 없음)
  • 1 (-O): foo.cpython-35.opt-1.pyc
  • 2 (-OO): foo.cpython-35.opt-2.pyc

현재 바이트코드 파일 이름은 importlib.util.cache_from_source() 함수에 의해 '{name}.{cache_tag}.pyc' 형식으로 생성되는데, 이 PEP는 최적화 수준이 지정된 경우 다음 형식으로 변경할 것을 제안합니다.

'{name}.{cache_tag}.opt-{optimization}.pyc'

opt- 접두사는 캐시 태그와 시각적으로 구분되며, 최적화 수준은 캐시 태그 뒤에 배치되어 모듈 이름과 캐시 태그를 기준으로 한 사전식 정렬 순서를 유지합니다. 이 변경 사항은 import 성능에 영향을 미치지 않으며, __pycache__ 디렉터리 내 파일 수 증가로 인한 저장 공간 사용량 증가는 sys.dont_write_bytecode를 통해 제어할 수 있습니다.

구현 (Implementation)

importlib

importlib.util.cache_from_source() 함수의 시그니처가 Python 3.5에서 다음과 같이 변경됩니다.

importlib.util.cache_from_source(path, debug_override=None, *, optimization=None)

새로운 키워드 전용 매개변수 optimization은 파일 이름에 포함될 최적화 수준을 제어합니다. debug_override 매개변수는 더 이상 사용되지 않으며 Deprecation Warning이 발생할 것입니다. importlib.machineryDEBUG_BYTECODE_SUFFIXESOPTIMIZED_BYTECODE_SUFFIXESBYTECODE_SUFFIXES와 동일하게 설정되며 더 이상 사용되지 않음으로 문서화됩니다.

표준 라이브러리의 나머지 부분

py_compilecompileall 모듈의 함수들은 새로운 바이트코드 파일 이름 의미론을 따르도록 업데이트될 것입니다.

호환성 고려 사항 (Compatibility Considerations)

Python 3.2부터 바이트코드 파일을 직접 조작하는 모든 코드는 이 변경 사항의 영향을 고려해야 합니다. 특히 importlib.util.cache_from_source()debug_override 인수를 설정하던 코드는 최적화 수준 2의 바이트코드 파일 경로를 다룰 때 주의가 필요합니다.

바이트코드 전용 모듈을 배포하는 경우, .pyc 파일과 함께 .pyo 파일을 배포하는 것이 더 이상 유용하지 않으므로, 사용할 최적화 수준을 선택하여 단일 .pyc 파일만 배포해야 합니다.

기각된 아이디어 (Rejected Ideas)

CPython에서 최적화 수준을 완전히 제거하는 것

런타임 최적화가 더 효율적이라는 이유로 CPython의 최적화 수준을 완전히 제거하자는 제안이 있었으나, 기존 최적화 수준이 유용하다고 생각하는 사용자들이 존재하며 다른 Python 인터프리터에서도 이 PEP의 제안이 유용할 수 있다는 점을 들어 기각되었습니다.

파일 이름에서 최적화 수준의 대체 형식

opt- 접두사 및 최적화 수준 배치에 대한 다양한 대체 형식들이 고려되었으나, 파일 정렬 순서 변경, 캐시 태그와의 모호성, 자체 설명 부족 등의 이유로 현재 PEP가 제안하는 형식이 채택되었습니다.

바이트코드 메타데이터에 최적화 수준 포함

바이트코드의 최적화 수준을 파일 이름이 아닌 파일의 메타데이터에 포함하자는 제안도 있었으나, Python이 루트 수준 애플리케이션으로 설치되는 경우가 많아 표준 라이브러리 모듈의 바이트코드 파일을 수정할 때 통합자들이 적절한 최적화 수준을 추측해야 하는 문제가 발생할 수 있어 기각되었습니다. 여러 최적화 수준이 동시에 존재할 수 있도록 하여 사용자가 원하는 최적화 수준을 자유롭게 활용할 수 있도록 하는 것이 더 바람직하다고 판단되었습니다.

⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.

Comments