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

Python 개선 제안 한국어 번역

PEP 741 – Python 구성 C API

Author:
Victor Stinner <vstinner at python.org>
Discussions-To:
Discourse thread
Status:
Final
Type:
Standards Track
Created:
18-Jan-2024
Python-Version:
3.14
Post-History:
19-Jan-2024, 08-Feb-2024
Resolution:
Discourse message

Table of Contents

번역·라이선스 안내

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

초록

C 구조체에 의존하지 않고 Python 초기화를 구성하며 향후 ABI 호환 변경을 수행할 수 있는 C API를 추가합니다.

내장 확장 모듈을 추가하는 데 사용할 수 있는 PyInitConfig_AddModule()를 추가하여 PEP 587 API를 완성합니다. 이 기능은 이전에 “inittab”이라고 불렸습니다.

현재 런타임 구성을 가져오고 설정하는 PyConfig_Get()PyConfig_Set() 함수를 추가합니다.

PEP 587 “Python 초기화 구성”은 Python 초기화를 구성하는 모든 방식을 통합했습니다. 이 PEP는 Python 사전 초기화와 Python 초기화의 구성도 단일 API로 통합합니다. 또한 이 PEP는 API를 더욱 단순화하기 위해 “Python”과 “Isolated”라는 두 가지 선택지(PEP 587) 대신 Python을 임베드하는 선택지를 하나만 제공합니다.

하위 수준의 PEP 587 PyConfig API는 CPython 구현 세부 사항과 의도적으로 더 높은 수준으로 결합해야 하는 사용 사례(구성 메커니즘을 포함하여 CPython CLI의 전체 기능을 에뮬레이션하는 경우 등)에 사용할 수 있도록 계속 제공됩니다.

근거

런타임 구성 가져오기

PEP 587에는 현재 런타임 구성을 가져오는 API는 없고, Python 초기화구성하는 API만 있습니다.

예를 들어 전역 구성 변수 Py_UnbufferedStdioFlag는 Python 3.12에서 더 이상 사용되지 않으며, 대신 PyConfig.buffered_stdio를 사용하는 것이 권장됩니다. 이는 Python을 구성하는 데만 사용할 수 있으며, PyConfig.buffered_stdio를 가져오는 공개 API는 없습니다.

제한된 C API 사용자는 현재 런타임 구성을 가져오는 공개 API를 요청하고 있습니다.

Cython은 optimization_level 구성 옵션을 가져와야 합니다: issue.

2022년에 전역 구성 변수가 더 이상 사용되지 않게 되었을 때, Marc-André Lemburg requested가 Python 초기화 중뿐만 아니라 런타임에도 이러한 구성 변수에 액세스할 수 있는 C API를 요청했습니다.

보안 수정

매우 큰 문자열을 정수(10진수 기준)로 변환할 때 발생하는 서비스 거부 공격인 CVE-2020-10735를 수정하기 위해 ABI에 영향을 주는 새 PyConfig 멤버를 안정화 브랜치에 추가하는 방안이 논의되었습니다.

Gregory P. Smith는 PyConfig 멤버에 제한되지 않도록 텍스트 기반 구성 파일을 사용하는 다른 API를 제안했습니다: FR: Allow private runtime config to enable extending without breaking the PyConfig ABI (2022년 8월).

결국 안정화 브랜치에는 새로운 PyConfig 멤버를 추가하지 않고, 개발 브랜치(Python 3.12가 됨)에만 새로운 PyConfig.int_max_str_digits 멤버를 추가하기로 결정했습니다. 안정화 브랜치에서는 전용 비공개 전역 변수(PyConfig와 무관함)를 사용합니다.

PyPreConfig와 PyConfig 간 중복

Python 사전 초기화에서는 PyPreConfig 구조체를 사용하고, Python 초기화에서는 PyConfig 구조체를 사용합니다. 두 구조체에는 중복되는 멤버가 네 개 있습니다: dev_mode, parse_argv, isolateduse_environment.

이러한 중복은 두 구조체가 분리되어 있기 때문에 발생하며, 일부 PyConfig 멤버는 사전 초기화에 필요합니다.

Python 임베딩

Python을 임베드하는 애플리케이션

예:

Linux, FreeBSD 및 macOS에서 애플리케이션은 일반적으로 libpython에 정적으로 링크되거나, libpython을 동적으로 로드합니다. libpython 공유 라이브러리는 버전이 지정되며, 예를 들어 Linux의 Python 3.12에서는 libpython3.12.so입니다.

vim 프로젝트는 안정적인 ABI를 대상으로 할 수 있습니다. 일반적으로 “시스템 Python” 버전이 사용됩니다. 현재는 사용할 Python 버전을 선택할 수 없습니다. 사용자는 필요할 때 더 최신 버전의 Python을 선택할 수 있기를 원합니다.

Linux에서 GIMP와 같이 Python을 임베드하는 애플리케이션을 배포하는 또 다른 방법은 Flatpack, AppImage 또는 Snap “컨테이너”에 Python을 포함하는 것입니다. 이 경우 애플리케이션은 컨테이너와 함께 자체 Python 버전 사본을 포함합니다.

Python을 임베드하는 라이브러리

예:

독립 실행형 애플리케이션을 생성하는 유틸리티

이러한 유틸리티는 독립 실행형 애플리케이션을 생성하며, libpython에 링크되지 않습니다.

런타임 구성 설정

Marc-André Lemburg requested는 런타임에 일부 구성 옵션의 값을 설정할 수 있는 C API를 요청했습니다:

  • optimization_level
  • verbose
  • parser_debug
  • inspect
  • write_bytecode

이전에는 전역 구성 변수를 직접 설정할 수 있었습니다:

  • Py_OptimizeFlag
  • Py_VerboseFlag
  • Py_DebugFlag
  • Py_InspectFlag
  • Py_DontWriteBytecodeFlag

하지만 이러한 구성 플래그는 Python 3.12에서 더 이상 사용되지 않으며 Python 3.14에서 제거될 예정입니다.

사양

Python 초기화를 구성하기 위한 C API 함수와 구조체를 추가합니다:

  • 구성 생성:
    • PyInitConfig는 불투명 구조체입니다.
    • PyInitConfig_Create().
    • PyInitConfig_Free(config).
  • 옵션 가져오기:
    • PyInitConfig_HasOption(config, name).
    • PyInitConfig_GetInt(config, name, &value).
    • PyInitConfig_GetStr(config, name, &value).
    • PyInitConfig_GetStrList(config, name, &length, &items).
    • PyInitConfig_FreeStrList().
  • 옵션 설정:
    • PyInitConfig_SetInt(config, name, value).
    • PyInitConfig_SetStr(config, name, value).
    • PyInitConfig_SetStrList(config, name, length, items).
    • PyInitConfig_AddModule(config, name, initfunc)
  • 초기화:
    • Py_InitializeFromInitConfig(config).
  • 오류 처리:
    • PyInitConfig_GetError(config, &err_msg).
    • PyInitConfig_GetExitcode(config, &exitcode).

현재 런타임 구성을 가져오고 설정하는 C API 함수를 추가합니다:

  • PyConfig_Get(name).
  • PyConfig_GetInt(name, &value).
  • PyConfig_Set(name).
  • PyConfig_Names()입니다.

C API는 구성 옵션 이름을 참조하기 위해 null로 끝나는 UTF-8 인코딩 문자열을 사용합니다.

이러한 C API 함수는 제한된 C API에서 제외됩니다.

PyInitConfig 구조

PyInitConfig구조는 PyConfig API의 세 구조체를 결합하여 구현되며, inittab 멤버도 포함합니다.

  • PyPreConfig preconfig
  • PyConfig config
  • PyStatus status
  • PyInitConfig_AddModule()struct _inittab *inittab

PyStatus상태는 더 이상 분리되지 않고 통합된 PyInitConfig구조의 일부가 되므로 API를 더 쉽게 사용할 수 있습니다.

구성 옵션

구성 옵션의 이름은 PyPreConfigPyConfig 구조 멤버를 따라 지정합니다. PyPreConfig 문서PyConfig 문서를 참조하십시오.

구성 옵션의 사용 중단 및 제거는 PEP의 범위에 포함되지 않으며, 사안별로 논의해야 합니다.

공개 구성 옵션

다음 옵션들은 PyConfig_Get()으로 가져오고 PyConfig_Set()으로 설정할 수 있습니다.

옵션 타입 설명
argv list[str] API: sys.argv.
base_exec_prefix str API: sys.base_exec_prefix.
base_executable str API: sys._base_executable.
base_prefix str API: sys.base_prefix.
bytes_warning int API: sys.flags.bytes_warning.
exec_prefix str API: sys.exec_prefix.
executable str API: sys.executable.
inspect bool API: sys.flags.inspect (int).
int_max_str_digits int API: sys.flags.int_max_str_digits, sys.get_int_max_str_digits()sys.set_int_max_str_digits().
interactive bool API: sys.flags.interactive.
module_search_paths list[str] API: sys.path.
optimization_level int API: sys.flags.optimize.
parser_debug bool API: sys.flags.debug (int).
platlibdir str API: sys.platlibdir.
prefix str API: sys.base_prefix.
pycache_prefix str API: sys.pycache_prefix.
quiet bool API: sys.flags.quiet (int).
stdlib_dir str API: sys._stdlib_dir.
use_environment bool API: sys.flags.ignore_environment (int).
verbose int API: sys.flags.verbose.
warnoptions list[str] API: sys.warnoptions입니다.
write_bytecode bool API: sys.flags.dont_write_bytecode (int)와 sys.dont_write_bytecode (bool)입니다.
xoptions dict[str, str] API: sys._xoptions입니다.

일부 옵션 이름은 optimization_level 옵션과 sys.flags.optimize 속성처럼 sys 속성과 다릅니다. PyConfig_Set()은 해당 sys 속성을 설정합니다.

xoptionsPyInitConfig에 있는 문자열 목록으로, 각 문자열의 형식은 key (value)은 암묵적으로 True임 또는 key=value입니다. 현재 런타임 구성에서는 이것이 딕셔너리(key: strvalue: str | True)가 됩니다.

읽기 전용 구성 옵션

다음 옵션들은 PyConfig_Get()으로 가져올 수 있지만 PyConfig_Set()으로 설정할 수는 없습니다.

옵션 형식 설명
allocator int
buffered_stdio bool
check_hash_pycs_mode str
code_debug_ranges bool
coerce_c_locale bool
coerce_c_locale_warn bool
configure_c_stdio bool
configure_locale bool
cpu_count int API: os.cpu_count() (int | None).
dev_mode bool API: sys.flags.dev_mode.
dump_refs bool
dump_refs_file str
faulthandler bool API: faulthandler.is_enabled().
filesystem_encoding str API: sys.getfilesystemencoding().
filesystem_errors str API: sys.getfilesystemencodeerrors().
hash_seed int
home str
import_time bool
install_signal_handlers bool
isolated bool API: sys.flags.isolated (int).
legacy_windows_fs_encoding bool Windows에서만 사용됩니다.
legacy_windows_stdio bool Windows 전용입니다.
malloc_stats bool
orig_argv list[str] API: sys.orig_argv.
parse_argv bool
pathconfig_warnings bool
perf_profiling bool API: sys.is_stack_trampoline_active().
program_name str
run_command str
run_filename str
run_module str
run_presite str 디버그 빌드가 필요합니다.
safe_path bool
show_ref_count bool
site_import bool API: sys.flags.no_site(int).
skip_source_first_line bool
stdio_encoding str API: sys.stdin.encoding, sys.stdout.encodingsys.stderr.encoding입니다.
stdio_errors str API: sys.stdin.errors, sys.stdout.errorssys.stderr.errors입니다.
tracemalloc int API: tracemalloc.is_tracing() (bool)입니다.
use_frozen_modules bool
use_hash_seed bool
user_site_directory bool API: sys.flags.no_user_site (int)입니다.
utf8_mode bool
warn_default_encoding bool
_pystats bool API: sys._stats_on(), sys._stats_off()입니다. Py_STATS 빌드가 필요합니다.

Config 생성

PyInitConfig 구조체:
Python 사전 초기화와 Python 초기화를 구성하는 불투명 구조체입니다.
PyInitConfig* PyInitConfig_Create(void):
Isolated Configuration의 기본값을 사용하여 새 초기화 구성을 생성합니다.

PyInitConfig_Free()로 해제해야 합니다.

메모리 할당에 실패하면 NULL을 반환합니다.

void PyInitConfig_Free(PyInitConfig *config):
초기화 구성의 메모리를 해제합니다.

옵션 가져오기

구성 옵션 name 매개변수는 NULL이 아니며 null로 끝나는 UTF-8 인코딩 문자열이어야 합니다.

int PyInitConfig_HasOption(PyInitConfig *config, const char *name):
구성에 name이라는 옵션이 있는지 테스트합니다.

옵션이 있으면 1을 반환하고, 그렇지 않으면 0을 반환합니다.

int PyInitConfig_GetInt(PyInitConfig *config, const char *name, int64_t *value):
정수 구성 옵션을 가져옵니다.
  • *value를 설정하고, 성공하면 0을 반환합니다.
  • 오류 발생 시 config에 오류를 설정하고 -1을 반환합니다.
int PyInitConfig_GetStr(PyInitConfig *config, const char *name, char **value):
구성 옵션을 널 종료 UTF-8 인코딩 문자열로 가져옵니다.
  • *value를 설정하고, 성공하면 0을 반환합니다.
  • 오류 발생 시 config에 오류를 설정하고 -1을 반환합니다.

성공하면 free(value)로 문자열을 해제해야 합니다.

int PyInitConfig_GetStrList(PyInitConfig *config, const char *name, size_t *length, char ***items):
문자열 목록 구성 옵션을 널 종료 UTF-8 인코딩 문자열 배열로 가져옵니다.
  • *length*value를 설정하고, 성공하면 0을 반환합니다.
  • 오류 발생 시 config에 오류를 설정하고 -1을 반환합니다.

성공하면 PyInitConfig_FreeStrList(length, items)를 사용하여 문자열 목록을 해제해야 합니다.

void PyInitConfig_FreeStrList(size_t length, char **items):
PyInitConfig_GetStrList()로 생성된 문자열 목록의 메모리를 해제합니다.

옵션 설정

구성 옵션 name 매개변수는 NULL이 아닌 널 종료 UTF-8 인코딩 문자열이어야 합니다.

일부 구성 옵션은 다른 옵션에 부수 효과를 줍니다. 이 로직은 Py_InitializeFromInitConfig()가 호출될 때만 구현되며, 아래의 “Set” 함수에서는 구현되지 않습니다. 예를 들어 dev_mode1로 설정해도 faulthandler1로 설정되지 않습니다.

int PyInitConfig_SetInt(PyInitConfig *config, const char *name, int64_t value):
정수 구성 옵션을 설정합니다.
  • 성공하면 0을 반환합니다.
  • 오류 발생 시 config에 오류를 설정하고 -1을 반환합니다.
int PyInitConfig_SetStr(PyInitConfig *config, const char *name, const char *value):
널 종료 UTF-8 인코딩 문자열에서 문자열 구성 옵션을 설정합니다. 문자열이 복사됩니다.
  • 성공하면 0을 반환합니다.
  • config에 오류를 설정하고 오류 발생 시 -1을 반환합니다.
int PyInitConfig_SetStrList(PyInitConfig *config, const char *name, size_t length, char * const *items):
널 문자로 끝나는 UTF-8 인코딩 문자열 배열에서 문자열 목록 구성 옵션을 설정합니다. 문자열 목록을 복사합니다.
  • 성공하면 0을 반환합니다.
  • config에 오류를 설정하고 오류 발생 시 -1을 반환합니다.
int PyInitConfig_AddModule(PyInitConfig *config, const char *name, PyObject* (*initfunc)(void)):
내장 확장 모듈을 내장 모듈 테이블에 추가합니다.

새 모듈은 name으로 가져올 수 있으며, 첫 번째 가져오기 시도 시 호출되는 초기화 함수로 initfunc를 사용합니다.

  • 성공하면 0을 반환합니다.
  • config에 오류를 설정하고 오류 발생 시 -1을 반환합니다.

Python이 여러 번 초기화되는 경우 각 Python 초기화 시 PyInitConfig_AddModule()를 호출해야 합니다.

PyImport_AppendInittab() 함수와 유사합니다.

Python을 초기화합니다.

int Py_InitializeFromInitConfig(PyInitConfig *config):
초기화 구성에서 Python을 초기화합니다.
  • 성공하면 0을 반환합니다.
  • config에 오류를 설정하고 오류 발생 시 -1을 반환합니다.
  • Python이 종료하려는 경우 config에 종료 코드를 설정하고 -1을 반환합니다.

종료 코드의 경우 PyInitConfig_GetExitcode()를 참조하십시오.

오류 처리

int PyInitConfig_GetError(PyInitConfig* config, const char **err_msg):
config의 오류 메시지를 가져옵니다.
  • 오류가 설정되어 있으면 *err_msg를 설정하고 1을 반환합니다.
  • 그렇지 않으면 *err_msgNULL로 설정하고 0을 반환합니다.

오류 메시지는 UTF-8로 인코딩된 문자열입니다.

config에 종료 코드가 있으면 종료 코드를 오류 메시지로 형식화합니다.

오류 메시지는 다른 PyInitConfig 함수가 config와 함께 호출될 때까지 유효합니다. 호출자는 오류 메시지를 해제할 필요가 없습니다.

int PyInitConfig_GetExitcode(PyInitConfig* config, int *exitcode):
config의 종료 코드를 가져옵니다.
  • Python이 종료하려는 경우 *exitcode를 설정하고 1을 반환합니다.
  • config에 종료 코드가 설정되어 있지 않으면 0을 반환합니다.

parse_argv 옵션이 0이 아닌 경우 Py_InitializeFromInitConfig() 함수만 종료 코드를 설정할 수 있습니다.

명령줄 구문 분석에 실패한 경우(종료 코드 2) 또는 명령줄 옵션에서 명령줄 도움말을 표시하도록 요청한 경우(종료 코드 0) 종료 코드를 설정할 수 있습니다.

런타임 구성 가져오기 및 설정

구성 옵션의 name 매개변수는 NULL이 아니며 null로 끝나는 UTF-8 인코딩 문자열이어야 합니다.

PyObject* PyConfig_Get(const char *name):
구성 옵션의 현재 런타임 값을 Python 객체로 가져옵니다.
  • 성공하면 새 참조를 반환합니다.
  • 오류가 발생하면 예외를 설정하고 NULL을 반환합니다.

객체 타입은 옵션에 따라 달라집니다. Configuration Options 표를 참조하십시오.

다른 옵션은 내부 PyPreConfigPyConfig 구조체에서 가져옵니다.

호출자는 GIL을 보유해야 합니다. Python 초기화 전이나 Python 종료 후에는 이 함수를 호출할 수 없습니다.

int PyConfig_GetInt(const char *name, int *value):
PyConfig_Get()와 유사하지만 값을 정수로 가져옵니다.
  • *value를 설정하고 성공 시 0을 반환합니다.
  • 오류가 발생하면 예외를 설정하고 -1을 반환합니다.
PyObject* PyConfig_Names(void):
모든 구성 옵션 이름을 frozenset으로 가져옵니다.

오류가 발생하면 예외를 설정하고 NULL을 반환합니다.

호출자는 GIL을 보유해야 합니다.

PyObject* PyConfig_Set(const char *name, PyObject *value):
구성 옵션의 현재 런타임 값을 설정합니다.
  • 옵션 name이 없으면 ValueError를 발생시킵니다.
  • value가 유효하지 않은 값이면 ValueError를 발생시킵니다.
  • 옵션이 읽기 전용이어서 설정할 수 없으면 ValueError를 발생시킵니다.
  • value가 올바른 타입이 아니면 TypeError를 발생시킵니다.

Read-only configuration options은 설정할 수 없습니다.

호출자는 GIL을 보유해야 합니다. Python 초기화 전이나 Python 종료 후에는 이 함수를 호출할 수 없습니다.

안정성

옵션의 동작, 기본 옵션 값 및 Python 동작은 Python 버전마다 변경될 수 있으므로 “안정적”이지 않습니다.

또한 일반적인 PEP 387 폐기 절차에 따라 구성 옵션을 추가하거나 폐기하거나 제거할 수 있습니다.

PyPreConfig 및 PyConfig API와의 상호 작용

하위 수준의 PEP 587 PyPreConfigPyConfig API는 계속 사용할 수 있으며 완전히 지원됩니다. 초록에서 언급한 바와 같이, 대규모 애플리케이션의 일부로 Python 런타임을 제공하는 데 그치기보다는 전체 CPython CLI의 동작을 면밀히 에뮬레이트하려는 임베딩 사용 사례에는 여전히 이러한 API가 선호되는 접근 방식입니다.

PyPreConfig API는 이 PEP의 초기화 API와 함께 사용할 수 있습니다. 이러한 경우 인터프리터가 사전 구성된 후에는 사전 구성 설정에 대한 읽기 전용 및 읽기/쓰기 제한이 PyInitConfig_SetInt에도 PyConfig_Set와 함께 적용됩니다(구체적으로 use_environment 변수만 업데이트할 수 있으며, 다른 사전 구성 변수 중 어느 것이라도 업데이트하려고 하면 오류가 보고됩니다).

예제

Python 초기화

다양한 유형의 구성 옵션을 설정하여 Python을 초기화하고, 오류가 발생하면 -1을 반환하는 예제입니다.

int init_python(void)
{
    PyInitConfig *config = PyInitConfig_Create();
    if (config == NULL) {
        printf("PYTHON INIT ERROR: memory allocation failed\n");
        return -1;
    }

    // Set an integer (dev mode)
    if (PyInitConfig_SetInt(config, "dev_mode", 1) < 0) {
        goto error;
    }

    // Set a list of UTF-8 strings (argv)
    char *argv[] = {"my_program", "-c", "pass"};
    if (PyInitConfig_SetStrList(config, "argv",
                                 Py_ARRAY_LENGTH(argv), argv) < 0) {
        goto error;
    }

    // Set a UTF-8 string (program name)
    if (PyInitConfig_SetStr(config, "program_name", L"my_program") < 0) {
        goto error;
    }

    // Initialize Python with the configuration
    if (Py_InitializeFromInitConfig(config) < 0) {
        goto error;
    }
    PyInitConfig_Free(config);
    return 0;

error:
    // Display the error message
    const char *err_msg;
    (void)PyInitConfig_GetError(config, &err_msg);
    printf("PYTHON INIT ERROR: %s\n", err_msg);
    PyInitConfig_Free(config);

    return -1;
}

초기화 bytes_warning 옵션 증가

초기화 구성의 bytes_warning 옵션을 증가시키는 예제입니다.

int config_bytes_warning(PyInitConfig *config)
{
    int64_t bytes_warning;
    if (PyInitConfig_GetInt(config, "bytes_warning", &bytes_warning)) {
        return -1;
    }
    bytes_warning += 1;
    if (PyInitConfig_SetInt(config, "bytes_warning", bytes_warning)) {
        return -1;
    }
    return 0;
}

런타임 verbose 옵션 가져오기

구성 옵션 verbose의 현재 런타임 값을 가져오는 예제입니다.

int get_verbose(void)
{
    int verbose;
    if (PyConfig_GetInt("verbose", &verbose) < 0) {
        // Silently ignore the error
        PyErr_Clear();
        return -1;
    }
    return verbose;
}

오류가 발생하면 함수는 오류를 조용히 무시하고 -1을 반환합니다. 실제로는 향후 Python 버전에서 verbose 옵션을 제거하지 않는 한 이 옵션을 가져오는 과정에서 실패할 수 없습니다.

구현

하위 호환성

변경 사항은 완전히 하위 호환됩니다. 새로운 API만 추가됩니다.

PyConfig C API(PEP 587)와 같은 기존 API는 변경되지 않습니다.

거부된 아이디어

텍스트로서의 구성

안정 ABI와 API를 호환시키고 사용자 지정 옵션을 허용하기 위해 구성을 텍스트로 제공하자는 제안이 있었습니다.

예제:

# integer
bytes_warning = 2

# string
filesystem_encoding = "utf8"   # comment

# list of strings
argv = ['python', '-c', 'code']

API는 구성 파일이 아니라 문자열로 구성을 받게 됩니다. 가상의 PyInit_SetConfig() 함수를 사용한 예제입니다.

void stable_abi_init_demo(int set_path)
{
    PyInit_SetConfig(
        "isolated = 1\n"
        "argv = ['python', '-c', 'code']\n"
        "filesystem_encoding = 'utf-8'\n"
    );
    if (set_path) {
        PyInit_SetConfig("pythonpath = '/my/path'");
    }
}

이 예제에서는 읽기 쉽게 만들기 위해 오류 처리를 생략합니다.

문제는 이러한 구성 텍스트를 생성하려면 문자열에 따옴표를 추가하고 문자열 내의 따옴표를 이스케이프해야 한다는 점입니다. 문자열 배열의 형식을 지정하는 일은 간단하지 않게 됩니다.

문자열 또는 문자열 배열을 형식화하는 API를 제공하는 것은 그다지 가치가 없지만, Python은 값을 문자열 또는 문자열 배열로 직접 전달하여 구성 옵션을 설정하는 API를 직접 제공할 수 있습니다. 이렇게 하면 이스케이프해야 하는 개행 문자와 같은 일부 문자에 특별한 의미를 부여하지 않아도 됩니다.

정수로 옵션 참조하기

구성 옵션을 참조하는 데 문자열을 사용하면 문자열을 비교해야 하므로, 정수를 비교하는 것보다 느릴 수 있습니다.

Py_tp_doc와 같은 타입 “슬롯”과 유사하게 정수를 사용하여 구성 옵션을 참조하십시오. const char *name 매개변수는 int option으로 대체됩니다.

정수를 사용할 때 사용자 정의 옵션을 허용하면 충돌이 발생할 가능성이 더 높습니다. 정수 옵션의 “네임스페이스”(범위)를 유지 관리하기가 더 어렵기 때문입니다. 문자열을 사용하면 콜론을 구분자로 하는 간단한 접두사를 사용할 수 있습니다.

정수는 정수 상수 목록도 유지 관리해야 하므로 C API와 Python API를 더 커지게 합니다.

Python 3.13에는 구성 옵션이 약 62개뿐이므로 성능은 실제로 차단 요인이 아닙니다. 나중에 더 나은 성능이 필요해지면 해시 테이블을 사용하여 이름으로 옵션을 가져올 수 있습니다.

구성 옵션 가져오기를 핫 코드에서 사용하는 경우 값을 한 번 읽어 캐시할 수 있습니다. 참고로 대부분의 구성 옵션은 런타임에 변경할 수 없습니다.

다단계 초기화(PEP 432와 유사)

Eric Snow expressed concerns는 이 제안이 임베더에게 초기화가 단일한 거대한 단계라는 생각을 강화할 수 있다는 우려를 표명했습니다. 그는 초기화가 서로 구별되는 5개의 단계를 포함한다고 주장했으며, API가 이를 명시적으로 반영해야 한다고 제안하기까지 했습니다. Eric은 최소한 초기화 구현이 코드 건전성 향상을 위해 부분적으로라도 해당 단계들을 반영해야 한다고 제안했습니다. 전반적으로 그의 설명은 PEP 432PEP 587과 일부 유사점이 있습니다.

이 PEP와 관련된 Eric의 또 다른 핵심 요점은 이상적으로는 Py_InitializeFromConfig()에 전달되는 구성이 해당 함수가 호출되기 전에 완성되어야 하지만, 현재는 초기화 과정에서 실제로 구성이 수정된다는 것이었습니다.

Eric이 반드시 PEP 741의 대안을 제안한 것은 아니지만, 단계를 중심으로 세분화된 초기화 API를 추가하자는 제안은 사실상 이 PEP가 달성하려는 것과 정반대입니다. 이러한 API는 더 복잡하며, 새로운 공개 구조체와 새로운 공개 함수를 추가해야 합니다. 이는 기존 API를 통합하고 더 단순하게 만들려는 이 PEP의 취지와 반대로 Python 초기화를 더 복잡하게 만듭니다. 유사한 목적을 위해 여러 구조체를 사용하면 중복 멤버가 생길 수 있으며, 이는 기존 PyPreConfigPyConfig 구조체 간에 중복 멤버가 있는 것과 유사한 문제입니다.

로캘 인코딩 및 와이드 문자열

로캘 인코딩으로 인코딩된 문자열과 와이드 문자열(wchar_t*)을 PyInitConfig API에서 허용하는 것은 PyInitConfig API를 단순하게 유지하고 Python 사전 초기화의 복잡성을 피하기 위해 연기되었습니다. 이러한 기능은 전체 CPython CLI 동작을 에뮬레이트할 때 주로 필요하므로, 하위 수준의 PEP 587 API를 사용하는 것이 더 적합합니다.

논의