Python 初始化配置

3.8 版的新Function。

Structures:

Functions:

预先配置(PyPreConfig类型)存储在_PyRuntime.preconfig中,而配置(PyConfig类型)存储在PyInterpreterState.config中。

另请参见初始化,完成和线程

See also

PEP 587“ Python 初始化配置”。

PyWideStringList

  • PyWideStringList
    • wchar_t*个字符串的列表。

如果* length 不为零,则 items *必须为非NULL,并且所有字符串都必须为非NULL

Methods:

必须预先初始化 Python 才能调用此函数。

  • PyStatus PyWideStringList_Insert(PyWideStringList **list ,Py_ssize_t * index ,const wchar_t item *)
    • 将* item 插入 index list *中。

如果* index 大于或等于 list 长度,则将 item 附加到 list *。

  • index *必须大于或等于 0.

必须预先初始化 Python 才能调用此函数。

Structure fields:

  • Py_ssize_t length

    • List length.
  • wchar_t ** items

    • List items.

PyStatus

  • PyStatus
    • 用于存储初始化Function状态的结构:成功,错误或退出。

对于错误,它可以存储创建错误的 C 函数名称。

Structure fields:

  • int exitcode

    • 退出代码。参数传递给exit()
  • const char * err_msg

    • Error message.
  • const char * func

    • 产生错误的函数的名称可以为NULL

创建状态的Function:

  • PyStatus PyStatus_Ok(无效)

    • Success.
  • PyStatus PyStatus_Error(const char ** err_msg *)

    • 带有消息的初始化错误。
  • PyStatus PyStatus_NoMemory(无效)

    • 内存分配失败(内存不足)。
  • PyStatus PyStatus_Exit(int 退出代码)

    • 使用指定的退出代码退出 Python。

处理状态的Function:

  • int PyStatus_Exception(PyStatus 状态)

    • 状态是错误还是退出?如果为 true,则必须处理异常;否则为 false。例如致电Py_ExitStatusException()
  • int PyStatus_IsError(PyStatus 状态)

    • 结果是错误的吗?
  • int PyStatus_IsExit(PyStatus 状态)

    • 结果是否退出?
  • 无效Py_ExitStatusException(PyStatus 状态)

    • 如果* status 是 Export,请致电exit(exitcode)。打印错误消息,如果 status *是错误,则使用非零退出代码退出。仅当PyStatus_Exception(status)不为零时才必须调用。

Note

在内部,Python 使用设置PyStatus.func的宏,而使用函数将状态func设置为NULL

Example:

PyStatus alloc(void **ptr, size_t size)
{
    *ptr = PyMem_RawMalloc(size);
    if (*ptr == NULL) {
        return PyStatus_NoMemory();
    }
    return PyStatus_Ok();
}

int main(int argc, char **argv)
{
    void *ptr;
    PyStatus status = alloc(&ptr, 16);
    if (PyStatus_Exception(status)) {
        Py_ExitStatusException(status);
    }
    PyMem_Free(ptr);
    return 0;
}

PyPreConfig

  • PyPreConfig

    • 用于预初始化 Python 的结构:
  • 设置 Python 内存分配器

  • 配置 LC_CTYPE 语言环境

  • 设置 UTF-8 模式

初始化预配置的Function:

Structure fields:

  • int allocator

    • 内存分配器的名称:
  • PYMEM_ALLOCATOR_NOT_SET(0):不要更改内存分配器(使用默认值)

  • PYMEM_ALLOCATOR_DEFAULT(1):默认内存分配器

  • PYMEM_ALLOCATOR_DEBUG(2):具有调试钩子的默认内存分配器

  • PYMEM_ALLOCATOR_MALLOC(3):强制使用malloc()

  • PYMEM_ALLOCATOR_MALLOC_DEBUG(4):pass调试钩子强制使用malloc()

  • PYMEM_ALLOCATOR_PYMALLOC ( 5 ): Python Pymalloc 内存分配器

  • PYMEM_ALLOCATOR_PYMALLOC_DEBUG(6):Python Pymalloc 内存分配器带有调试钩子

如果使用--without-pymalloc配置了 Python,则不支持PYMEM_ALLOCATOR_PYMALLOCPYMEM_ALLOCATOR_PYMALLOC_DEBUG

See Memory Management.

  • int configure_locale

    • 将 LC_CTYPE 语言环境设置为用户首选语言环境?如果等于 0,则将coerce_c_localecoerce_c_locale_warn设置为 0.
  • int coerce_c_locale

    • 如果等于 2,则强制 C 语言环境;否则为 0.如果等于 1,则读取 LC_CTYPE 语言环境以决定是否应强制使用该语言环境。
  • int coerce_c_locale_warn

    • 如果非零,则在强制 C 语言环境的情况下发出警告。
  • int dev_mode

  • int isolated

  • int legacy_windows_fs_encoding(仅适用于 Windows *)

    • 如果非零,请禁用 UTF-8 模式,将 Python 文件系统编码设置为mbcs,将文件系统错误处理程序设置为replace

仅在 Windows 上可用。 #ifdef MS_WINDOWS宏可用于 Windows 特定代码。

使用 PyPreConfig 进行预初始化

用于预初始化 Python 的函数:

  • PyStatus Py_PreInitialize(const PyPreConfig ** preconfig *)

    • 从* preconfig *预配置中预初始化 Python。
  • PyStatus Py_PreInitializeFromBytesArgs(const PyPreConfig **preconfig ,int * argc ,char * const argv *)

    • 从* preconfig *预配置和命令行参数(字节字符串)预初始化 Python。
  • PyStatus Py_PreInitializeFromArgs(const PyPreConfig ** preconfig *,int * argc *,wchar_t * const * * argv *)

    • 从* preconfig *预配置和命令行参数(宽字符串)预初始化 Python。

调用方负责使用PyStatus_Exception()Py_ExitStatusException()处理异常(错误或退出)。

对于Python Configuration(PyPreConfig_InitPythonConfig()),如果 Python 是使用命令行参数初始化的,则也必须传递命令行参数以对 Python 进行预初始化,因为它们会影响诸如编码之类的预配置。例如,-X utf8命令行选项启用 UTF-8 模式。

可以在Py_PreInitialize()之后和Py_InitializeFromConfig()之前调用PyMem_SetAllocator()以安装自定义内存分配器。如果PyPreConfig.allocator设置为PYMEM_ALLOCATOR_NOT_SET,则可以在Py_PreInitialize()之前调用它。

请勿在 Python 预初始化之前使用PyMem_RawMalloc()之类的 Python 内存分配函数,而直接调用malloc()free()始终是安全的。不得在预初始化之前调用Py_DecodeLocale()

使用预初始化启用 UTF-8 模式的示例:

PyStatus status;
PyPreConfig preconfig;
PyPreConfig_InitPythonConfig(&preconfig);

preconfig.utf8_mode = 1;

status = Py_PreInitialize(&preconfig);
if (PyStatus_Exception(status)) {
    Py_ExitStatusException(status);
}

/* at this point, Python will speak UTF-8 */

Py_Initialize();
/* ... use Python API here ... */
Py_Finalize();

PyConfig

  • PyConfig
    • 包含用于配置 Python 的大多数参数的结构。

Structure methods:

如果需要,请预先初始化 Python。

  • PyStatus PyConfig_SetBytesString(PyConfig *config ,wchar_t * const config_str *,const char ** str *)
    • 使用Py_DecodeLocale()解码* str *并将结果设置为*config_str

如果需要,请预先初始化 Python。

  • PyStatus PyConfig_SetArgv(PyConfig **config ,int * argc ,wchar_t * const argv *)
    • 从宽字符串设置命令行参数。

如果需要,请预先初始化 Python。

如果需要,请预先初始化 Python。

  • PyStatus PyConfig_SetWideStringList(PyConfig *config PyWideStringList list *,Py_ssize_t * length *,wchar_t *** items *)
    • 将宽字符串列表* list 设置为 length items *。

如果需要,请预先初始化 Python。

已经初始化的字段保持不变。

如果需要,请预先初始化 Python。

  • 无效PyConfig_Clear(PyConfig ** config *)
    • 释放配置内存。

如果需要,大多数PyConfig方法会预先初始化 Python。在这种情况下,Python 的预初始化配置基于PyConfig。如果调整了与PyPreConfig相同的配置字段,则必须在调用PyConfig方法之前设置它们:

此外,如果使用PyConfig_SetArgv()PyConfig_SetBytesArgv(),则必须先调用此方法,然后再调用其他方法,因为预初始化配置取决于命令行参数(如果parse_argv为非零)。

这些方法的调用者负责使用PyStatus_Exception()Py_ExitStatusException()处理异常(错误或退出)。

Structure fields:

  • PyWideStringList argv

    • 命令行参数sys.argv。参见parse_argv来解析argv,就像常规 Python 解析 Python 命令行参数一样。如果argv为空,则添加一个空字符串以确保sys.argv始终存在且永不为空。
  • wchar_t * base_exec_prefix

  • wchar_t * base_executable

    • sys._base_executable__PYVENV_LAUNCHER__环境变量值,或PyConfig.executable的副本。
  • wchar_t * base_prefix

  • int buffered_stdio

    • 如果等于 0,则启用非缓冲模式,使 stdout 和 stderr 流变为非缓冲状态。

stdin 始终以缓冲模式打开。

有效值:alwaysneverdefault

默认值为:default

  • int configure_c_stdio

    • 如果非零,请配置 C 个标准流(stdiostdoutstdout)。例如,在 Windows 上将其模式设置为O_BINARY
  • int dev_mode

    • 开发模式:请参见-X dev
  • int dump_refs

    • 如果非零,则转储所有在退出时仍然有效的对象。

需要 Python 的调试版本(必须定义Py_REF_DEBUG宏)。

如果use_hash_seed为零,则在 Pythonstartup 上随机选择一个种子,而hash_seed被忽略。

  • wchar_t * home
    • Python 主目录。

默认情况下从 PYTHONHOME环境变量值初始化。

  • int import_time

    • 如果不为零,则配置文件导入时间。
  • int inspect

    • 执行脚本或命令后进入交互模式。
  • int install_signal_handlers

    • 安装 signal 处理程序?
  • int interactive

    • Interactive mode.
  • int isolated

    • 如果大于 0,则启用隔离模式:
  • sys.path既不包含脚本的目录(从argv[0]或当前目录计算得出),也不包含用户的 site-packages 目录。

  • Python REPL 不会导入readline,也不会在交互式提示上启用默认的 readline 配置。

  • use_environmentuser_site_directory设置为 0.

  • int legacy_windows_stdio

仅在 Windows 上可用。 #ifdef MS_WINDOWS宏可用于 Windows 特定代码。

如果 Python 是使用--without-pymalloc构建的,则忽略该选项。

  • wchar_t * pythonpath_env
    • 模块搜索路径以用DELIM(os.path.pathsep)分隔的字符串表示。

默认情况下从 PYTHONPATH环境变量值初始化。

  • PyWideStringList module_search_paths

  • int module_search_paths_set

  • int optimization_level

    • 编译优化级别:
  • 0:窥孔优化器(并且__debug__设置为True)

  • 1:删除 assert,将__debug__设置为False

  • 2:删除文档字符串

  • int parse_argv

    • 如果非零,则以与常规 Python 命令行参数相同的方式解析argv,并从argv剥离 Python 参数:请参见命令行参数
  • int parser_debug

    • 如果非零,请打开解析器调试输出(仅针对 maven,取决于编译选项)。
  • int pathconfig_warnings

    • 如果等于 0,则在计算Path Configuration时禁止显示警告(仅限 Unix,Windows 不记录任何警告)。否则,警告将写入stderr
  • wchar_t * prefix

  • wchar_t * program_name

    • 程序名称。用于初始化executable,并用于早期错误消息。
  • wchar_t * pycache_prefix

如果NULL,则sys.pycache_prefix设置为None

  • int quiet

    • 静音模式。例如,不要以交互方式显示版权和版本消息。
  • wchar_t * run_command

  • wchar_t * run_filename

  • wchar_t * run_module

  • int show_alloc_count

    • 在 Export 处显示分配计数?

pass-X showalloccount命令行选项设置为 1.

需要定义COUNT_ALLOCS宏的特殊 Python 构建。

  • int show_ref_count
    • 显示退出时的总参考计数?

pass-X showrefcount命令行选项设置为 1.

需要 Python 的调试版本(必须定义Py_REF_DEBUG宏)。

  • int site_import

    • 在启动时要导入site模块吗?
  • int skip_source_first_line

    • 跳过源代码的第一行?
  • wchar_t * stdio_encoding

  • wchar_t * stdio_errors

  • int tracemalloc

  • int use_environment

  • int user_site_directory

    • 如果非零,则将用户站点目录添加到sys.path
  • int verbose

    • 如果非零,请启用详细模式。
  • PyWideStringList warnoptions

warnings模块以相反的 Sequences 添加sys.warnoptions:最后的PyConfig.warnoptions项成为warnings.filters的第一个项,第一个被检查(最高优先级)。

  • int write_bytecode
    • 如果非零,则写入.pyc个文件。

sys.dont_write_bytecode初始化为write_bytecode的取反值。

如果parse_argv为非零值,则以与常规 Python 解析命令行参数相同的方式解析argv参数,并从argv中剥离 Python 参数:参见命令行参数

可以解析xoptions选项以设置其他选项:请参见-X选项。

使用 PyConfig 初始化

初始化 Python 的函数:

  • PyStatus Py_InitializeFromConfig(const PyConfig ** config *)
    • 从* config *配置初始化 Python。

调用方负责使用PyStatus_Exception()Py_ExitStatusException()处理异常(错误或退出)。

如果使用PyImport_FrozenModulesPyImport_AppendInittab()PyImport_ExtendInittab(),则必须在 Python 预初始化之后和 Python 初始化之前设置或调用它们。

设置程序名称的示例:

void init_python(void)
{
    PyStatus status;

    PyConfig config;
    PyConfig_InitPythonConfig(&config);

    /* Set the program name. Implicitly preinitialize Python. */
    status = PyConfig_SetString(&config, &config.program_name,
                                L"/path/to/my_program");
    if (PyStatus_Exception(status)) {
        goto fail;
    }

    status = Py_InitializeFromConfig(&config);
    if (PyStatus_Exception(status)) {
        goto fail;
    }
    PyConfig_Clear(&config);
    return;

fail:
    PyConfig_Clear(&config);
    Py_ExitStatusException(status);
}

更完整的示例,修改默认配置,读取配置,然后覆盖一些参数:

PyStatus init_python(const char *program_name)
{
    PyStatus status;

    PyConfig config;
    PyConfig_InitPythonConfig(&config);

    /* Set the program name before reading the configuration
       (decode byte string from the locale encoding).

       Implicitly preinitialize Python. */
    status = PyConfig_SetBytesString(&config, &config.program_name,
                                  program_name);
    if (PyStatus_Exception(status)) {
        goto done;
    }

    /* Read all configuration at once */
    status = PyConfig_Read(&config);
    if (PyStatus_Exception(status)) {
        goto done;
    }

    /* Append our custom search path to sys.path */
    status = PyWideStringList_Append(&config.module_search_paths,
                                     L"/path/to/more/modules");
    if (PyStatus_Exception(status)) {
        goto done;
    }

    /* Override executable computed by PyConfig_Read() */
    status = PyConfig_SetString(&config, &config.executable,
                                L"/path/to/my_executable");
    if (PyStatus_Exception(status)) {
        goto done;
    }

    status = Py_InitializeFromConfig(&config);

done:
    PyConfig_Clear(&config);
    return status;
}

Isolated Configuration

PyPreConfig_InitIsolatedConfig()PyConfig_InitIsolatedConfig()函数创建一个配置以将 Python 与系统隔离。例如,将 Python 嵌入到应用程序中。

此配置将忽略全局配置变量,环境变量,命令行参数(未解析PyConfig.argv)和用户站点目录。 C 标准流(例如:stdout)和 LC_CTYPE 语言环境保持不变。未安装 signal 处理程序。

配置文件仍与此配置一起使用。设置Path Configuration(“输出字段”)以忽略这些配置文件,并避免函数计算默认路径配置。

Python Configuration

PyPreConfig_InitPythonConfig()PyConfig_InitPythonConfig()函数创建配置以构建自定义的 Python,其行为与常规 Python 相同。

环境变量和命令行参数用于配置 Python,而全局配置变量则被忽略。

此Function根据 LC_CTYPE 语言环境, PYTHONUTF8 PYTHONCOERCECLOCALE环境变量启用 C 语言环境强制( PEP 538)和 UTF-8 模式( PEP 540)。

始终以隔离模式运行的定制 Python 的示例:

int main(int argc, char **argv)
{
    PyStatus status;

    PyConfig config;
    PyConfig_InitPythonConfig(&config);
    config.isolated = 1;

    /* Decode command line arguments.
       Implicitly preinitialize Python (in isolated mode). */
    status = PyConfig_SetBytesArgv(&config, argc, argv);
    if (PyStatus_Exception(status)) {
        goto fail;
    }

    status = Py_InitializeFromConfig(&config);
    if (PyStatus_Exception(status)) {
        goto fail;
    }
    PyConfig_Clear(&config);

    return Py_RunMain();

fail:
    PyConfig_Clear(&config);
    if (PyStatus_IsExit(status)) {
        return status.exitcode;
    }
    /* Display the error message and exit the process with
       non-zero exit code */
    Py_ExitStatusException(status);
}

Path Configuration

PyConfig包含用于路径配置的多个字段:

如果未设置至少一个“输出字段”,Python 将计算路径配置以填充未设置的字段。如果module_search_paths_set等于 0,则module_search_paths被覆盖并且module_search_paths_set设置为 1.

pass显式设置上面列出的所有路径配置输出字段,可以完全忽略计算默认路径配置的Function。即使字符串不是空的,它也被视为已设置。如果将module_search_paths_set设置为 1,则将module_search_paths视为已设置。在这种情况下,路径配置 Importing 字段也将被忽略。

pathconfig_warnings设置为 0 可在计算路径配置时禁止显示警告(仅 Unix,Windows 不记录任何警告)。

如果未设置base_prefixbase_exec_prefix字段,则它们分别从prefixexec_prefix继承其值。

Py_RunMain()Py_Main()修改sys.path

如果site_import非零,则site模块可以修改sys.path。如果user_site_directory非零并且用户的站点包目录存在,则site模块将用户的站点包目录追加到sys.path

路径配置使用以下配置文件:

  • pyvenv.cfg

  • python._pth(仅 Windows)

  • pybuilddir.txt(仅适用于 Unix)

__PYVENV_LAUNCHER__环境变量用于设置PyConfig.base_executable

Py_RunMain()

默认情况下,并且如果使用-i选项,请运行 REPL。

最后,完成 Python 处理并返回退出状态,该状态可以传递给exit()函数。

有关始终使用Py_RunMain()在隔离模式下运行的定制 Python 的示例,请参见Python Configuration

多阶段初始化专用临时 API

本部分是私有的临时 API,介绍了多阶段初始化,这是 PEP 432的核心Function:

  • “核心”初始化阶段,“裸机最低 Python”:

  • Builtin types;

    • Builtin exceptions;

    • 内置和冻结模块;

    • sys模块仅被部分初始化(例如:sys.path尚不存在)。

  • 在“主”初始化阶段,Python 已完全初始化:

  • 安装并配置importlib;

私有临时 API:

  • PyConfig._init_main:如果设置为 0,则Py_InitializeFromConfig()停止在“ Core”初始化阶段。

  • PyStatus _Py_InitializeMain(无效)

    • 转到“主要”初始化阶段,完成 Python 初始化。

在“核心”阶段未导入任何模块,并且未配置importlib模块:Path Configuration仅在“主”阶段适用。它可能允许在 Python 中自定义 Python 以覆盖或调整Path Configuration,可能安装自定义sys.meta_path导入程序或导入钩子等。

在 Core 阶段之后和 Main 阶段之前,可以计算 Python 中的Path Configuration,这是 PEP 432动机之一。

“核心”阶段定义不正确:在此阶段应该指定什么和不应该指定什么。该 API 被标记为私有和临时的:可以在设计适当的公共 API 之前随时修改甚至删除该 API。

在“ Core”和“ Main”初始化阶段之间运行 Python 代码的示例:

void init_python(void)
{
    PyStatus status;

    PyConfig config;
    PyConfig_InitPythonConfig(&config);
    config._init_main = 0;

    /* ... customize 'config' configuration ... */

    status = Py_InitializeFromConfig(&config);
    PyConfig_Clear(&config);
    if (PyStatus_Exception(status)) {
        Py_ExitStatusException(status);
    }

    /* Use sys.stderr because sys.stdout is only created
       by _Py_InitializeMain() */
    int res = PyRun_SimpleString(
        "import sys; "
        "print('Run Python code before _Py_InitializeMain', "
               "file=sys.stderr)");
    if (res < 0) {
        exit(1);
    }

    /* ... put more configuration code here ... */

    status = _Py_InitializeMain();
    if (PyStatus_Exception(status)) {
        Py_ExitStatusException(status);
    }
}