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

Выводы    85

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

Если пользователь выполняет python с путем к файлу .pyc, то вместо того, чтобы загрузить его как простой текстовый файл и распарсить, CPython предполагает, что файл .pyc содержит программный объект, записанный на диск.

В PyRun_SimpleFileExFlags() есть условие для передачи пользователем пути к файлу .pyc.

Функция run_pyc_file() из файла Python pythonrun.c осуществляет маршалинг объектного кода из файла .pyc с использованием дескриптора файла.

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

ПРИМЕЧАНИЕ

Термином«маршалинг»обозначается копирование содержимого файла в память и преобразование его в конкретную структуру данных.

Когда объектный код маршализован в память, он передается функции run_ eval_code_obj(), которая вызывает Python ceval.c для выполнения.

ВЫВОДЫ

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

Благодаря возможности выбора ввода Python отлично подходит для разно­ образных приложений, например:

zz утилит командной строки;

zz постоянно работающих сетевых приложений (например, веб-серверов); zz коротких скриптов компоновки.

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

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

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

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

Свойства времени компиляции, находящиеся в системной конфигурации, могут различаться между дистрибутивами Python. Например, дистрибутив Python 3.8 для macOS, загруженный с Python.org, по умолчанию использует значения, отличные от тех, которые использует Python 3.8 из Homebrew или Anaconda.

При любом способе ввода на выходе вы получаете модуль Python. В следующей главе вы увидите, как это происходит.

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

Лексический анализ и парсинг с использованием

синтаксических деревьев

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

Эта стадия называется парсингом (parsing):

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

При парсинге кода в CPython используются две структуры: конкретное синтаксическое дерево (CST) и абстрактное синтаксическое дерево (AST):

 

 

 

CST

 

AST

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

88    Лексический анализ и парсинг с использованием синтаксических деревьев

Процесс парсинга состоит из двух частей:

1.Создание конкретного синтаксического дерева (CST, concrete syntax tree) c использованием парсера/токенизатора (parser-tokenizer) или лексического анализатора (lexer).

2.Создание абстрактного синтаксического дерева (AST, abstract syntax tree) из конкретного синтаксического дерева с использованием парсера.

Эти два шага — распространенные парадигмы, используемые во многих языках программирования.

ГЕНЕРИРОВАНИЕ КОНКРЕТНОГО СИНТАКСИЧЕСКОГО ДЕРЕВА

CST, иногда называемое деревом разбора, — упорядоченная древовидная структура с корнем, представляющая код в контекстно-свободной грамматике.

CST строится токенизатором и парсером. Парсер рассматривался в главе «Язык Python и грамматика». Вывод парсера представляет собой таблицу разбора в форме детерминированного конечного автомата (ДКА), описывающую возможные состояния контекстно-свободной грамматики.

СМ. ТАКЖЕ

Создатель Python Гвидо ван Россум разработал контекстную грамматику для использования в CPython 3.9 как альтернативу для LL(1) — граммати­ ки, использованной в предыдущих версиях CPython. Новая грамматика называется PEG (Parser Expression Grammar).

Парсер PEG стал доступным вPython 3.9.ВPython 3.10 старая грамматика LL(1) была полностью исключена.

В главе «Язык Python и грамматика» рассматривались некоторые типы выражений, такие как if_stmt и with_stmt. CST представляет грамматические обозначения вида if_stmt как ветви, а лексемы и терминалы — как листовые узлы.

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

Генерирование конкретного синтаксического дерева    89

Например, арифметическое выражение a+1 преобразуется в следующее дерево CST:

 

 

arith_expr

 

 

 

 

term

 

 

 

 

 

 

 

PLUS

 

term

 

factor

 

 

 

 

 

 

 

 

 

 

 

 

'+'

 

 

factor

 

power

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

power

 

atom_expr

 

 

 

 

 

 

 

 

 

 

atom_expr

 

atom

 

 

 

 

 

 

 

 

 

 

atom

NAME

'a'

 

 

 

1

 

NUMBER

 

Арифметическое выражение представляется тремя основными ветвями: левой ветвью, ветвью оператора и правой ветвью. Парсер перебирает лексемы из входного потока и сопоставляет их с возможными состояниями и лексемами в грамматике для построения CST.

Все символические имена в CST определяются в Grammar Grammar:

arith_expr: term (('+'|'-') term)*

term: factor (('*'|'@'|'/'|'%'|'//') factor)* factor: ('+'|'-'|'~') factor | power

power: atom_expr ['**' factor] atom_expr: [AWAIT] atom trailer*

atom: ('(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' |

'{' [dictorsetmaker] '}' |

NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')

Лексемы определяются в Grammar Tokens:

ENDMARKER

NAME

NUMBER

STRING

NEWLINE

INDENT

DEDENT

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

90    Лексический анализ и парсинг с использованием синтаксических деревьев

LPAR

'('

RPAR

')'

LSQB

'['

RSQB

']'

COLON

':'

COMMA

','

SEMI

';'

PLUS

'+'

MINUS

'-'

STAR

'*'

...

 

Лексема NAME представляет имя переменной, функции, класса или модуля. Синтаксис Python не допускает, чтобы NAME было одним из зарезервированных ключевых слов (например, await или async), а также числовым или другим литеральным типом. Например, если вы попытаетесь определить функцию с именем 1, Python выдаст ошибку синтаксиса (SyntaxError):

>>> def 1():

File "<stdin>", line 1 def 1():

^

SyntaxError: invalid syntax

NUMBER — особая разновидность лексем для представления одного из числовых значений Python. В Python существует специальная грамматика для чисел:

zz Восьмеричные значения, например 0o20

zz Шестнадцатеричные значения, например 0x10 zz Двоичные значения, например 0b10000

zz Комплексные числа, например 10j

zz Числа с плавающей точкой, например 1.01

zz Подчеркивания в качестве разделителя разрядов, например 1_000_000

Для просмотра скомпилированных символических имен и лексем в Python можно воспользоваться модулями symbol и token:

$ ./python

>>>import symbol

>>>dir(symbol)

['__builtins__', '__cached__', '__doc__', '__file__', '__loader__',

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