# 6.1 配置状态

在执行 Python 代码之前，CPython 首先会对运行时及用户选项进行配置。

运行时的配置存位于三个位置，数据结构在 [PEP 587](https://peps.python.org/pep-0587/) 中定义：

1. [PyPreConfig](https://github.com/python/cpython/blob/v3.9.0b1/Include/cpython/initconfig.h#L125)，用于预初始化配置；
2. [PyConfig](https://github.com/python/cpython/blob/v3.9.0b1/Include/cpython/initconfig.h#L416)，用于运行时配置；
3. CPython 解释器编译选项的配置。

`PyPreConfig` 和`PyConfig` 数据结构都定义在 `Include/cpython/initconfig.h` 文件中。

## 预初始化配置

预初始化配置与运行时配置是分开的，因为它的属性与操作系统或用户环境相关。

`PyPreConfig` 有三个主要功能：

* 设置 Python 内存分配器；
* 配置 `LC_CTYPE` 语言环境；
* 将 LC\_CTYPE 区域配置为系统或用户首选的区域配置；
* 设置 UTF-8 模式（[PEP 540](https://www.python.org/dev/peps/pep-0540/)）。

`PyPreConfig` 结构体包含以下属性，都是 `int` 类型：

* allocator：选择一个内存分配器，如：`PYMEM_ALLOCATOR_MALLOC`。运行 `./configure --help` 可获取有关内存分配器的详细信息；
* configure\_locale：将 `LC_CTYPE` 区域设置为用户首选的区域配置。如果等于 0，则将 `coerce_c_locale` 和 `coerce_c_locale_warn` 设置为 0；
* coerce\_c\_locale：如果等于 2，则强制使用 C 语言区域配置； 如果等于 1，则读取 `LC_CTYPE` 的区域设置来决定是否强制使用 C 语言区域配置；
* coerce\_c\_locale\_warn：如果非零，在强制使用 C 语言区域配置时会发出告警；
* dev\_mode：开启开发模式；
* isolated：启用隔离模式：`sys.path` 不包含脚本的目录，也不包含用户的 site-packages 目录；
* legacy\_windows\_fs\_encoding：（只在 windows 下使用）如果非零禁用 UTF-8 模式并设置 Python 文件系统编码模式为 `mbcs`；
* parse\_argv：如果非零，则使用命令行参数；
* use\_environment：如果大于零，则使用环境变量；
* utf8\_mode：如果非零，则启用 UTF-8 模式。

## 相关的源文件

以下是与 `PyPreConfig` 相关的源文件：

| 文件目录                         | 作用                           |
| ---------------------------- | ---------------------------- |
| Python/initconfig.c          | 从系统环境加载配置，并将其与命令行中输入的信息进行合并。 |
| Include/cpython/initconfig.h | 定义了初始化配置的数据结构。               |

## 运行时配置数据结构

第二阶段配置是运行时配置。[PyConfig](https://github.com/python/cpython/blob/v3.9.0b1/Include/cpython/initconfig.h#L416) 中的运行时配置数据结构包含一些值：

* 调试和优化等模式的运行时标志；
* 执行模式，如：脚本文件，标准输入或者一个模块；
* 扩展选项，通过 `-X <选项值>` 的方式来指定；
* 运行时设置的环境变量。

CPython 运行时使用配置数据来启用和禁用某项功能。

## 通过命令行设置运行时配置

Python 还附带了几个[命令行接口选项](https://docs.python.org/3/using/cmdline.html)。 如，CPython 有个名为 **verbose** 的模式，这个模式主要面向开发者，用于调试 CPython。

你可以通过 `-v` 标志启用 verbose 模式，当模块被加载时，Python 会将信息打印在屏幕上：

```bash
$ ./python -v -c "print('hello world')"

# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
...
```

可以看到在屏幕上会打印出上百条甚至更多的模块加载信息，包含用户 site-packages 和其他在系统环境中的模块。 由于运行时配置可以通过多种方式进行设置，因此各个配置设置之间是有优先顺序的。verbose 模式的优先顺序如下：

1. `config->verbose` 的默认值是 -1，硬编码在源码中；
2. 环境变量 PYTHONVERBOSE 用来设置 `config->verbose` 的值；
3. 如果环境变量不存在，将会保留默认值 -1；
4. 在 Python/initconfig.c 文件的 [config\_parse\_cmdline()](https://github.com/python/cpython/blob/v3.9.0b1/Python/initconfig.c#L1875) 方法中，如果有提供命令行标志的话也会被用来设置值；
5. 该值将会被 [\_Py\_GetGlobalVariablesAsDict()](https://github.com/python/cpython/blob/v3.9.0b1/Python/initconfig.c#L167) 方法拷贝到一个全局变量 `Py_VerboseFlag` 中。

所有的 `PyConfig` 值都遵循相同的排列和优先顺序：

![图6.1.1 运行时配置顺序](https://1029588898-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FJhewUmzI3BNeGgeFH9Rv%2Fuploads%2Fgit-blob-f1b4c5a2f83d71728f53bb01f692e0f3da00df54%2F%E5%9B%BE6.1.1%20%E8%BF%90%E8%A1%8C%E6%97%B6%E9%85%8D%E7%BD%AE%E9%A1%BA%E5%BA%8F.png?alt=media)

## 查看运行时配置

CPython 解释器有一组运行时标志，这些标志是用于切换 CPython 相关行为的高级功能。 在 Python 会话中，你可以使用 `sys.flags` 命名元组访问运行时标志，例如 verbose 模式和 quiet 模式。所有通过 `-X` 指定的标志都会存储在 `sys._xoptions` 字典中：

```bash
$ ./python -X dev -q

>>> import sys
>>> sys.flags
sys.flags(debug=0, inspect=0, interactive=0, optimize=0,
dont_write_bytecode=0, no_user_site=0, no_site=0,
ignore_environment=0, verbose=0, bytes_warning=0,
quiet=1, hash_randomization=1, isolated=0,
dev_mode=True, utf8_mode=0)
>>> sys._xoptions
{'dev': True}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hai-shi.gitbook.io/cpython-internals/6-configuration-and-input/6.1-configuration-state.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
