코드가 실행 가능한 단계 까지 도달하기의 과정 중 인터프리터가 파이썬을 실행 하는 명령어를 살펴 보자면, 이렇게 처리 할 수 있다
이렇게 실행 하는 인터프리터는 아래와 같은 세 가지 요소가 필요하다.
1. 실행 할 모듈
2. 변수 등을 저장할 상태
3. 활성화 된 옵션의 구성
CPython code guide: PEP7
- 공개 된 함수가 정적 함수가 아니라면
Py
접두사를 붙힌다Py_FatalError
처럼 전역 서비스루틴에는Py_
접두사를 붙힌다
등, ...
이렇게 위와 같은 코드 컨밴션이 존재 하지만 PEP7은 8과 달리 검사 도구가 많지 않다. 그렇기 때문에 코어 개발자가 PEP7을 준수 하는지 매번 확인 해야 한다. 그 중 유일한 자동화 검사 도구 중 smell
을 사용 하여 위에 명시 된 또는, 더 많은 코드 가이드를 검사 할 수 있다.
코드를 실행 하기 전 CPython 런타임은 사용자 옵션과 구성을 설정한다.
PyPreConfig
딕셔너리 초기화 구성PyConfig
런타임 구성CPython
인터프리터에 같이 컴파일된 구성
👉 PyPreConfig
, PyConfig
구조체는 Include > cpython > initcofig.h 에서 정의함
딕셔너리 초기화 구성은 사용자 환경 또는 운영체제와 관련된 구성이기 때문
에 런타임 구성과 구분된다.
PyPreConfig
의 주요 세 가지 기능
PyPreConfig
구조체
- allocator: PYMEM_ALLOCATOR_MALLOC 같은 값을 사용 해서 메모리 할당자를 선택한다.
- configure_locale: LC_CTYPE 로켈을 사용자 선호 로켈로 설정한다. 0으로 설정 하면
coerce_c_locale
과coerce_c_locale_warn
을 0으로 설정한다.- coerce_c_locale: 2로 설정하면 C 로케일을 강제로 적용한다. 1로 설정하면
LC_CTYPE
을 읽은 후 강제로 적용할지 결정한다.- coerce_c_locale_warn: 0이 아니면 C 로케일이 강제로 적용 될 때 경고 발생
- dev_mode: 개발 모드 활성화
- isolated: 격리 모드 활성화,
sys.path
에 스크립트 디렉터리와 사용자의 사이트 패키지 디렉터리는 포함 되지 않음- legacy_windows_fs_encoding: 0이 아니면 UTF-8 모드 비활성화, 파이썬 파일 시스템 인코딩을 mbcs로 설정(윈도우 전용)
- parse_argv: 0이 아니면 CLI args 사용
- use_environment: 0보다 큰 값이면 환경 변수 사용
- utf8_mode: 0이 아니면 UTF-8 모드 활성화
PyPreConfig
와 연관된 소스 파일 목록
딕셔너리 초기화 구성 다음 단계로 PyConfig
런타임 구성 구조체는 다음과 같은 값들을 포함한다.
-X <option>
으로 설정 가능한 확장 옵션런타임 구성 데이터는 CPython 런타임 기능의 활성화 여부를 결정한다.
./python.exe -v -c "print('hello world')"
import _frozen_importlib # frozen
import _imp # builtin
import '_thread' # <class '_frozen_importlib.BuiltinImporter'>
import '_warnings' # <class '_frozen_importlib.BuiltinImporter'>
import '_weakref' # <class '_frozen_importlib.BuiltinImporter'>
import '_io' # <class '_frozen_importlib.BuiltinImporter'>
import 'marshal' # <class '_frozen_importlib.BuiltinImporter'>
import 'posix' # <class '_frozen_importlib.BuiltinImporter'>
import '_frozen_importlib_external' # <class '_frozen_importlib.FrozenImporter'>
# installing zipimport hook
...
Python 3.9.17+ (heads/3.9-dirty:38b489bae8, Aug 12 2023, 17:34:53)
[Clang 14.0.3 (clang-1403.0.22.14.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
hello world
상세모드 설정에 대한 우선순위
이렇게, 모든 PyConfig
값에는 같은 순서와 우선순위가 적용된다.
CPython 인터프리터의 런타임 플래그는 CPython의 동작들을 끄고 켜는 데 사용하는 고급 기능이다.
파이썬 세션 중에 sys.flags
네임드 튜플로 상세 모드나 메시지 없는 모드 같은 런타임 플래그에 접근이 가능하다.
빌드 구성은 최상위 폴더인 pyconfig.h
에 정의한다. 이 파일은 macOS, Linux용 빌드 과정 중 ./configure
단계나 왼도우의 build.bat
실행 중에 자동으로 생성 된다.
빌드 구성 확인
./python.exe -m sysconfig
빌드 구성 항목들은 컴파일 시에 결정 되는 값들로 바이너리에 링크 할 추가 모듈 선택에 사용됨.
예를 들어, 디버거와 계측(instrucmentation) 라이브러리, 메모리 할당자는 모두 컴파일 시 결정된다.
코드를 실행하려면 먼저 입력을 모듈로 컴파일 해야 한다.
입력 방식
이렇게 읽어 들인 입력은 파서를 거쳐 컴파일러로 전달된다.
이렇게 유연한 입력 방식을 제공하기 위해 CPython은 CPython 소스 코드의 상당 분량을
파서의 입력 처리에 사용한다.
연관된 소스 파일 목록
main.c
를 감싸는 역할만 맡음.입력과 파일 읽기
Modules > main.c > python_main()
이 실행된다.Py?Config
인스턴스에 설정된 옵션들과 함께 실행된다.명령줄 문자열 입력
CPython은 -c 옵션을 사용 해 명령줄에서 작은 파이썬 어플리케이션을 실행 할 수 있다.
마치 이렇게 ./python.exe -c "print(2 ** 2)"
Modules>main.c>pymain_run_command()
가 실행 되며 -c로 전달 된 명령은 C의 wchar_t*
타입 인자로 함수에 전달된다.
wchar_t*
타입은 UTF-8 문자를 저장 할 수 있기 때문에 CPython에서 저수준 유니코드 데이터를 저장하는 타입으로 사용된다.pymain_run_command()
는 파이썬 바이트열 객체를 PyRun_SimpleStringFlags()
로 넘겨 실행
PyRun_SimpleStringFlags()
는문자열을 파이썬 모듈로 변환 하고 실행__main__
진입점이 필요하기 때문에 PyRun_SimpleStringFlags()
가 진입점을 자동으로 추가함PyRun_SimpleStringFlags()
는 딕셔너리와 모듈을 만든 후 PyRun_StringFlags()
를 호출 함PyRun_SimpleStringFlags()
는 가짜 파일 이름을 만들고 파이썬 파서를 실행 하여 문자열에서 추상 구문 트리(abstract syntax tree, AST)를 생성 해 모듈로 반환함.-m 플래그는 모듈 패키지의 진입점(__main__
)을 실행한다. 이 때 해당 모듈은 sys.path
에서 검색 하는데 이 때 임포트 라이브러리의 검색 매너키즘 덕분에 특정 모듈의 파일 시스템 위치를 기억 할 필요는 없다.
runpy
모듈은 Lib > runpy.py 에 위치한 순수한 파이썬 모듈이다.
python -m <module>
을 실행 하는 것은 python -m runpy <module>
을 실행 하는 것과 같다. 이렇게, runpy
모듈은 운영체제에서 모듈을 찾아 실행하는 프로세스를 추상화 한다.
runpy
의 모듈 실행 과정
1. 제공된 모듈 이름을 __import__()
로 임포트한다.
2. __name__
(모듈 이름)을 __main__
이름 공간에 설정한다.
3. __main__
이름 공간에서 모듈을 실행한다.
if __name__ == "__main__":
pass
python test.py 처럼 첫 번째 인자가 파일명이라면 CPython은 파일 핸들을 열어 Python > pythonrun.c 의 PyRun_SimpleFileExFlags()
로 핸들을 넘긴다.
이 함수는 세 종류의 파일 경로를 처리 할 수 있다.
1. .pyc
파일 경로면 run_pyc_file()
을 호출한다.
2. 스크립트 파일(.py
) 경로면 PyRun_FileExFlags()
를 호출한다.
3. command | python
처럼 파일 경로가 stdin이면 stdin을 파일 핸들로 취급 하고 PyRun_FileExFlags()
를 호출한다.
PyRun_FileExFlags()
는 파일에서 파이썬 모듈을 생성 하고 run_mod()
로 보내 실행한다.
CPython 컴파일러는 스크립트가 호출 될 때 마다 파싱하는 대신, 디스크의 코드 객체 구조체에 컴파일 한 코드를 캐시한다.
그렇기 때문에, .pyc
라는 파일이 컴파일러에 의해 생성 되었다면 파이썬 코드가 수정 되지 않는 이상 빠르게 실행 시킬 수 있는 것이다.
파이썬이 다양한 구성 옵션을 로딩 하는 방식과 코드를 인터프리터에 입력하는 방식들에 대해 공부했다.
파이썬은 이렇게 유연한 입력 방식 덕분에 다양한 어플리케이션에 적합한 언어이다.