CPython

CPython 구성과 입력

25G 2022. 12. 10. 14:04

Cpython에서는 다양한 방식으로 파이썬 코드를 실행할 수 있다.

1. python -c : 파이썬 문자열 실행

2. python -m :으로 모듈 실행

3. python : 파이썬 코드가 들어있는 파일 실행

4. cat | python 처럼 파이썬 코드를 stidn으로 python에 파이프 하기

5. REPL에서 한번에 하나씩 명령 실행하기

6. C API를 사용해파이썬을 임베디드 환경으로 사용

인터프리터가 파이썬 코드를 실행하려면 세 가지 요소가 필요하다.

1. 실행할 모듈

2. 변수 등을 저장할 상태

3. 활성화된 옵션 등의 구성

이 세가지 요소가 있어야 인터프리터가 코드를 실행하고 출력을 제공할 수 있다.

구성 상태

파이썬 코드를 실행하기 전에 Cpython 런타임은 먼저 사용자 옵션과 구성을 설정한다.
Cpython의 구성은 세 부분으로 나뉘어 있다.

  1. PyPreConfig 딕셔너리 초기화구성
  2. PyConfig 런타임 구성
  3. CPython 인터프리터에 같이 컴파일된 구성
  ./configure --help 

위 명령어를 실행해서 메모리 할당자에 대한 추가 정보를 얻을 수 있다.

명령줄로 런타임 구성 설정하기

파이썬은 다양한 명령줄 인터페이스 옵션을 제공한다. 예를 들면 CPython 디버깅용 기능인 상세 모드는 주로 개발자 대상이다.
-v 플래그로 상세 모드를 활성화하면 파이썬은 모듈을 로딩할 때마다 화면에 메시지를 출력한다.

위 사진과 같이 사용자 사이트 패키지와 시스템 환경의 모든 항목을 임포트 하면 수백 줄이 출력된다. 이에 우선 순이가 있는데 다음은 상세 모드 설정에 대한 우선순위이다

  1. config->verbose의 기본값은 -1로 소스코드에 하드 코딩되어 있다.
  2. PYTHONVERBBOSE 환경 변수를 config->vervose를 설정하는 데 사용한다.
  3. 환경 변수가 없으면 기본값인 -1을 사용한다.
  4. Python->initconfig.c의 config_parse_cmdline()은 명시된 명령줄 플래그를 사용해 모드를 설정한다.
  5. _Py_GetGlovbalVariablesAsDict()가 값을 전역 변수 Py_VerboseFlag로 복사한다. Cpython 인터프리터의 런타임 플래그는 

 

런타임 플래그 확인하기

Cpython의 동작들을 끄고 켜는 데 사용하는 고금 기능이다. 파이썬 세션 중에 sys.flags 네임드 튜플로 상세 모드나 메시지 없는 Quiet 모드 같은 런타임 플래그에 접근할 수 있다.
sys._xoptioins 딕셔너리에서 모든 -X플래그를 확인할 수 있다.

빌드 구성

빌드 구성은 최상위 폴더의 pyconfig.h에서 정의한다. 이 파일은 macOS나 리눅스용 빌드 과정 중./configure 단계나 윈도의 build.bat실행 중에 자동으로 생성된다. 다음 명령으로 빌드 구성을 확인할 수 있다.

빌드 구성 항목들은 컴파일 시에 결정되는 값으로 바이너리에 링크할 추가 모듈 선택에 사용된다. 예를 들어 디버거와 계측 라이브러리, 메모리할당자는 모두 컴파일시 결정된다.

 

입력에서 모듈 만들기

코드를 실행하려면 먼저 입력을 모듈로 컴파일해야 한다. 다음과 같이 입력방식에는 여러 가지가 있다.

- 로컬 파일과 패키지

- 메모리 파이프나 stdin 같은 I/O스트림

- 문자열

읽어 들인 입력은 파서를 거쳐 컴파일러로 전달된다.

 

명령줄 문자열 입력

 

 

먼저 Modules/main.c에서 pymain_run_command()가 실행되며 -c로 전달된 명령은 C의 wchar_t*타입 인자로 함수에 전달된다.

이때 UTF-8로 인코딩하려면 PyUnicode_FromWideChar()를 이용해서 유니코드를 문자열로 변환할 수 있다.

pymain_run_command()는  PyUnicode_FromWideChar()로 바이트 열 객채를 넘겨서 실행한다.

파이썬 모듈을 독립된 모듈로 실행하려면 __main__진입점이 필요하기 때문에 PyRun_SimpleStringFlags()가 진입점을 자동으로 추가한다.

PyRun_SimpleStringFlags()는 딕셔너리와 모듈을 만든 후 PyRun_StringFlags()를 호출한다. PyRun_SimpleStringFlags()는 가짜 파일 이름을 만들고 파이썬 파서를 실행해서, 문자열에서 추상 구문 트리를 생성해 모듈로 반환한다.

 

컴파일된 바이트 코드 입력

python을. pyc 파일 경로와 함께 실행하면 CPython은 파일을 텍스트 파일로 불러와 파싱 하는 대신. pyc 파일에서 디스크에 기록된 코드 객체를 찾는다 PyRun_SimpleFileExFlags()에는. pyc 파일 경로를 처리하는 부분이 있다. 

Python->pythonrun.c의 run_pyc_file()은 파일 핸들을 사용해. pyc 파일에서 코드 객체를 마셜링한다.

 

*마셜 링 = 한 객체의 메모리에서 표현방식을 저장 또는 전송에 적합한 다른 데이터 형식으로 변환하는 과정

 

 

Cpython 컴파일러는 스크립트가 호출될 때마다 파싱 하는 대신 디스크의 코드 객체 구조체에 컴파일한 코드를 캐시 한다.

메모리로 마셜링된 코드 객체는 Python->ceval.c를 호출하는 run_eval_code_obj()로 전달되어 실행된다.