Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Внутри CPython гид по интерпретатору Python.pdf
Скачиваний:
2
Добавлен:
07.04.2024
Размер:
8.59 Mб
Скачать

Структура данных конфигурации среды выполнения    77

Исходные файлы

Ниже перечислены исходные файлы, относящиеся к PyPreConfig.

ФАЙЛ

НАЗНАЧЕНИЕ

Python initconfig.c

Загружает данные конфигурации из системных

 

параметров среды и объединяет их с флагами

 

командной строки

Include cpython initconfig.h

Определяет структуру данных конфигурации ини-

 

циализации

СТРУКТУРА ДАННЫХ КОНФИГУРАЦИИ СРЕДЫ ВЫПОЛНЕНИЯ

Вторая фаза конфигурации — конфигурация среды выполнения. Структура данных конфигурации среды выполнения в PyConfig содержит несколько значений, включая следующие:

zz Флаги среды выполнения для таких режимов, как отладка и оптимизация.

zz Режим выполнения (например, файл сценария, stdin или модуль). zz Расширенные параметры, задаваемые с ключом -X <параметр>. zz Переменные среды для настроек среды выполнения.

Данные конфигурации используются средой выполнения CPython для включения и отключения отдельных возможностей.

Настройка конфигурации среды выполнения в командной строке

Python также включает ряд параметров интерфейса командной строки1. Например, в CPython существует режим подробного вывода, предназначенный прежде всего для отладки CPython разработчиками.

Режим подробного вывода включается флагом -v. Python выводит сообщения на экран при загрузке модулей:

1 https://docs.python.org/3/using/cmdline.html.

Книги для программистов: https://t.me/booksforits

78    Конфигурация и ввод

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

#installing zipimport hook import zipimport # builtin

#installed zipimport hook

...

Вы увидите сотню и более строк с сообщениями об импортировании веб-пакетов пользователя и всех остальных событий, происходящих в системной среде.

Так как конфигурацию среды выполнения можно задать несколькими способами, у настроек конфигурации существуют разные приоритеты. Порядок приоритетов для режима подробного вывода:

1.Для config->verbose в исходном коде жестко фиксируется значение -1.

2.Переменная среды PYTHONVERBOSE используется для задания значения

config->verbose.

3.Если переменная среды не существует, используется значение по умолчанию -1.

4.В функции config_parse_cmdlin() из файла Python initconfig.c флаг командной строки (если он указан) используется для присваивания значения.

5.Значение копируется в глобальную переменную Py_VerboseFlag при вызове _Py_GetGlobalVariablesAsDict().

Для всех значений PyConfig существует один порядок действий и последовательность приоритетов:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

PyPreCon•g

 

 

 

 

 

 

 

 

 

 

 

 

 

 

PyCon•g

 

 

 

 

 

 

 

Книги для программистов: https://t.me/booksforits

Конфигурация сборки    79

Просмотр флагов времени выполнения

У интерпретаторов CPython имеется набор флагов времени выполнения. Эти флаги управляют расширенными возможностями по включению/отключению поведения, специфического для CPython. В сеансе Python можно обращаться к флагам времени выполнения (например, режиму подробного вывода и тихому режиму) через кортеж с именем sys.flags.

Все флаги -X доступны в словаре sys._xoptions:

$ ./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}

КОНФИГУРАЦИЯ СБОРКИ

Наряду с конфигурацией среды выполнения вфайле Include cpython initconfig.h также существует конфигурация сборки в файле pyconfig.h корневой папки. Этот файл создается динамически на шаге ./configure процесса сборки в macOS и Linux либо build.bat в Windows.

Чтобы просмотреть конфигурацию сборки, выполните следующую команду:

$ ./python -m sysconfig

Platform: "macosx-10.15-x86_64"

Python version: "3.9"

Current installation scheme: "posix_prefix"

Paths:

data = "/usr/local"

include = "/Users/anthonyshaw/CLionProjects/cpython/Include" platinclude = "/Users/anthonyshaw/CLionProjects/cpython"

...

Книги для программистов: https://t.me/booksforits

80    Конфигурация и ввод

Свойства конфигурации сборки представляют собой значения времени компиляции, используемые для выбора дополнительных модулей, которые компонуются с двоичным файлом. Например, отладчики, инструментальные библиотеки и распределители памяти задаются во время компиляции.

Когда вы выполните три этапа конфигурации, интерпретатор CPython сможет получить входные данные и преобразовать текст в исполняемый код.

СБОРКА МОДУЛЯ ИЗ ВХОДНЫХ ДАННЫХ

Любой код перед выполнением необходимо скомпилировать в модуль из входных данных. Как упоминалось ранее, входные данные могут существовать в разных формах:

zz локальные файлы и пакеты;

zz потоки ввода/вывода (например, stdin или канал в памяти); zz строки.

Входные данные читаются, передаются парсеру, а затем компилятору:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Из-за этой гибкости большая часть исходного кода CPython относится к обработке входных данных парсера CPython.

Исходные файлы

Существуют четыре основных файла для взаимодействия с интерфейсом командной строки.

Книги для программистов: https://t.me/booksforits

 

Сборка модуля из входных данных    81

 

 

ФАЙЛ

НАЗНАЧЕНИЕ

Lib runpy.py

Модуль стандартной библиотеки для импортирования

 

и выполнения модулей Python

Modules main.c

Функции-обертки для выполнения внешнего кода (на-

 

пример, из файла, модуля или входного потока)

Programs python.c

Точка входа для исполняемого файла python в Windows,

 

Linux и macOS. Служит оберткой для Modules/main.c

Python pythonrun.c

Функции-обертки внутренних API, написанные на C

 

и предназначенные для обработки ввода из командной

 

строки

Чтение файлов и ввод

Как только для CPython настроены среда выполнения и аргументы командной строки, он может загрузить код, который требуется выполнить. Эту задачу решает функция pymain_main() из Modules main.c.

Теперь CPython выполняет заданный код с любыми параметрами, указанными во вновь созданном экземпляре PyConfig.

Получение входных данных из командной строки

CPython может запустить небольшое приложение Python из командной строки с ключом -c. Например, рассмотрим, что произойдет при выполнении print(2 ** 2):

$ ./python -c "print(2 ** 2)"

4

Сначала pymain_run_command() выполняется внутри Modules main.c; при этом команда из -c передается в аргументе с типом C wchar_t*.

Затем pymain_run_command() передает объект Python с набором байтов функции PyRun_SimpleStringFlags() для выполнения.

PyRun_SimpleStringFlags() является частью файла Python pythonrun.c. Его цель — преобразование строки в модуль Python и его последующая передача для выполнения.

Книги для программистов: https://t.me/booksforits

PyRun_SimpleStringFlags()

82    Конфигурация и ввод

ПРИМЕЧАНИЕ

Тип wchar_t* часто используется в CPython как низкоуровневый тип для хранения данных в Юникоде, так как размер типа позволяет хранить символы UTF-8.

Припреобразованииwchar_t*встрокуPythonфайлObjects unicodeobject.c

содержит вспомогательную функцию PyUnicode_FromWideChar(),которая возвращает строку в Юникоде.Затем она кодируется в UTF-8 функцией

PyUnicode_AsUTF8String().

Строки в кодировке Юникод в Python подробно рассматриваются в раз­ деле «Тип строк в Юникоде» главы «Объекты и типы».

Модуль Python должен иметь точку входа __main__ для возможности его автономного выполнения, и неявно создает эту точку входа.

После того как функция PyRun_SimpleStringFlags() создаст модуль и словарь, она вызывает PyRun_StringFlags(). PyRun_SimpleStringFlags() создает фиктивное имя файла, после чего вызывает парсер Python для создания дерева абстрактного синтаксиса1 (AST, abstract syntax tree) из строки и возвращает модуль. Вы узнаете больше об AST в следующей главе.

ПРИМЕЧАНИЕ

Модули Python — структуры данных, используемые для передачи син­ таксически разобранного кода компилятору. Структура данных C для модулей Python — mod_ty — определяется в Include Python-ast.h.

Получение входных данных из локального модуля

Другой способ выполнения команд Python основан на использовании параметра -m с именем модуля. Типичный пример — команда python -m unittest, которая выполняет модуль unittest из стандартной библиотеки.

1 Иначе — абстрактное синтаксическое дерево. — Примеч. ред.

Книги для программистов: https://t.me/booksforits

Сборка модуля из входных данных    83

Возможность выполнения модулей как скриптов была изначально предложена в PEP 338, а стандарт явного относительного импортирования был определен в PEP 366.

Флаг -m означает, что внутри пакета модуля должно быть выполнено все, что находится внутри точки входа (__main__)1. Он также подразумевает, что вы хотите найти sys.path для модуля с заданным именем.

Именно благодаря механизму поиска в библиотеке импортирования (importlib) вам не приходится запоминать, где в вашей файловой системе хранится модуль unittest.

CPython импортирует модуль стандартной библиотеки runpy и выполняет его с использованием PyObject_Call(). Импортирование осуществляется с использованием API-функции языка C — PyImport_ImportModule(), находящейся в файле Python import.c.

ПРИМЕЧАНИЕ

Если в Python вы захотите получить атрибут для имеющегося объекта, следует вызвать функцию getattr(). В C API этому вызову соответствует функция PyObject_GetAttrString(),находящаяся вфайле Objects object.c.

Если вы захотите использовать вызываемый (callable) объект, поставь­ те круглые­ скобки либо вызовите свойство __call__() объекта Python. __call__() реализуется внутри Objects object.c:

>>>my_str = "hello, world"

>>>my_str.upper()

'HELLO, WORLD'

>>> my_str.upper.__call__()

'HELLO, WORLD'

Модуль runpy написан на чистом Python и находится в файле Lib runpy.py.

Выполнение команды python -m <модуль> эквивалентно выполнению команды python -m runpy <модуль>. Модуль runpy был создан для абстрагирования процесса поиска и выполнения модулей в операционной системе.

1 https://realpython.com/python-main-function/.

Книги для программистов: https://t.me/booksforits

84    Конфигурация и ввод

Для запуска целевого модуля runpy выполняет три операции:

1.Для предоставленного имени модуля вызывается __import__().

2.Переменной __name__ (имя модуля) присваивается пространство имен

__main__.

3. Модуль выполняется в пространстве имен __main__.

Модуль runpy также поддерживает выполнение каталогов и ZIP-файлов.

Входные данные из скрипта или стандартного ввода

Если первым аргументом python является имя файла (например, python test.py), то CPython открывает дескриптор файла и передает его функции

PyRun_SimpleFileExFlags() из Python pythonrun.c.

Существуют три разных способа выполнения этой функции в зависимости от пути:

1.Если указан путь до файла .pyc, вызывается run_pyc_file().

2.Если указан путь до файла со скриптом (.py), выполняется PyRun_

FileExFlags().

3.Если указан путь до потока ввода stdin (потому что пользователь выполнил перенаправление <команда> | python), то stdin рассматривается как дескриптор файла и выполняется PyRun_FileExFlags().

Для stdin и базовых файлов со скриптами CPython передает дескриптор файла функции PyRun_FileExFlags(), находящейся в файле Python pythonrun.c file.

Функция PyRun_FileExFlags() делает примерно то же, что и PyRun_ SimpleStringFlags(). CPython загружает дескриптор файла в PyParser_ ASTFromFileObject().

Как и в случае с PyRun_SimpleStringFlags(), после того как PyRun_ FileExFlags() создает модуль Python из файла, он передает его в run_mod() для выполнения.

Книги для программистов: https://t.me/booksforits