2. Лексический анализ

Программа на Python читается синтаксическим анализатором (parser). В парсер вводится поток символов (tokens), генерируемых лексическим анализатором (lexical analyzer). В этой главе описывается, как лексический анализатор разбивает файл на токены.

Python читает текст программы как элементы кода Unicode; кодировка исходного файла может быть задана объявлением кодировки и по-умолчанию является UTF-8, детали см. PEP 3120 (www.python.org/dev/peps/pep-3120). Если файл исходного кода не может быть декодирован возникает ошибка SyntaxError (docs.python.org/3/library/exceptions.html#SyntaxError).

2.1. Структура строки (линии)

Программа на Python разделена на ряд логических строк (logical lines).

2.1.1. Логические строки (линии)

Конец логической строки представлен символом NEWLINE. Выражения не могут пересекать границы логической линии, за исключением случаев, когда NEWLINE допускается синтаксисом (например, между выражениями в составных операторах). Логическая линия состоит из одной или более физических линий в соответствии с явными или неявными правилами объединения строк.

2.1.2. Физические линии

Физическая линия есть последовательность символов, ограниченная последовательностью конца строки. В файлах исходников может использоваться любой прерыватель для строки, стандартный для платформы, - в Unix обрабатывается с помощью ASCII LF (linefeed - символ новой строки), в Windows - с помощью ASCII-последовательности CR LF (возврат, за которым следует новая строка), на старом Macintosh - символ возврата (ASCII CR). Все эти формы могут одинаково быть использованы, независимо от платформы.

При встраивании Python, строки исходного кода следует передавать API Питона с помощью стандартных соглашений C для символа новой строки (это символ \n, представляющий ASCII LF, который является завершителем линии).

2.1.3. Комментарии

Комментарий начинается с символа хэша (#), который не является частью строкового литерала и заканчивается концом физической строки. Комментарий обозначает конец логической линии, если не задействованы неявные правила присоединения строки. Комментарии игнорируются синтаксисом; они не являются символами.

2.1.4. Объявления кодировки

Если комментарий в первой или второй строке скрипта Python соответствует регулярному выражению coding[=:]\s*([-\w.]+), такой комментарий обрабатывается как объявление кодировки; первая группа этого выражения называется кодировкой файла с исходным кодом. Объявление кодировки должно появляться в отдельной строке. Если это вторая строка, первая должна также быть только комментарием. Рекомендуемая форма выражения с кодировкой

# -*- coding: <encoding-name> -*-

которая также распознается GNU Emacs, и 

# vim:fileencoding=<encoding-name>

которая распознается VIM Bram Moolenaar'а.

Если объявления кодировки не обнаружено, по-умолчанию будет UTF-8. Кроме того, если первыми байтами файла является последовательность байтов-знаков UTF-8 (b'\xef\xbb\xbf'), объявленной кодировкой файла является UTF-8 (среди других она поддерживается блокнотом Майкрософта).

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

2.1.5. Явное объединение линий

Две и более физических линии могут быть объединены в логические линии с помощью символов обратного слэша (\) следующим образом: когда физическая линия заканчивается обратным слэшем, который не является частью строкового литерала или комментария, она объединяется со следующей одиночной логической линией, удаляя бэкслэш и последующий символ конца стоки. Например:

if 1900 < year < 2100 and 1 <= month <= 12 \
   and 1 <= day <= 31 and 0 <= hour < 24 \
   and 0 <= minute < 60 and 0 <= second < 60:   # Выглядит как нормальная дата
        return 1

Линия, заканчивающаяся бэкслэшем, не может включать комментарий. Бэкслэш не продолжает комментарий. Обратная косая черта не продолжает токен, за исключением строковых литералов (напр., токены нестроковых литералов не могут быть разделены на физичекие линии с помощью бэкслеша). Бэкслэш недопустим еще где-либо в строке вне строкового литерала.

2.1.6. Неявное объединение линий

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

month_names = ['Januari', 'Februari', 'Maart',      # These are the
               'April',   'Mei',      'Juni',       # Dutch names
               'Juli',    'Augustus', 'September',  # for the months
               'Oktober', 'November', 'December']   # of the year

Неявно продолженные линии могут содержать комментарии. Отступ продолжения линии не важен. Позволены пустые продолжения линий. Символа NEWLINE нет между неявными продолжениями линий. Неявно продолженные линии могут также случаться внутри заключенных в тройные кавычки строк (см. ниже); в этом случае они не могут содержать комментарии.

2.1.7. Пустые линии

Логические линии, которые содержат только пробелы, табуляции, перевод строки и возможно комментарий, игнорируются (напр., не образуется символ новой строки). Во время интерактивного ввода выражений, обработка пустой линии может отличаться в зависимости от реализации цикла чтение-вычисление-вывод. В стандартном интерактивном интерпретаторе, полностью пустая логическая строка (например, не содержащая даже пробела и комментария) заканчивает многострочный оператор.

2.1.8. Отступ

Лидирующие пробелы (пробелы и табуляции) в начале логической линии используются для определения уровня отступа линии, который, в свою очередь, используется для определения сгруппированных выражений.

Табуляции заменяются (слева направо) от одного до восьми пробелами, так что общее количество символов до замены включает в себя кратность восьми (это должно быть то же правило, которое используется в Unix). Общее количество пробелов, предшествующих общему непробельному символу, затем определяет отступ строки. Отступ не может быть разделен на несколько физических линий бэкслэшем; пробелы вплоть до первого бэкслэша определяют отступ.

Отступ отвергается как противоречивый, если в фале исходного кода смешаны табуляции и пробелы таким способом, что значение зависит от оценки табуляции в пробелы; в этом случае возбуждается TabError (https://docs.python.org/3/library/exceptions.html#TabError).

Заметка о кросс-платформенной совместимости: из-за характера текстовых редакторов на платформах, отличных от UNIX, нецелесообразно использовать смесь пробелов и табуляций для отступов в одном исходном файле. Также следует отметить, что различные платформы могут явно ограничивать максимальный уровень отступа.

Символ formfeed может присутствовать в начале линии; он будет проигнорирован для расчета отступов выше. Эти символы, случающиеся где-либо в лидирующих пробелах, имеют неопределенный эффект (например, они могут сбросить счетчик пробелов в ноль).

Уровни отступов последовательных линий используются для генерации токенов INDENT (отступить) и DEDENT (выровнять), использующим стек, согласно следующему.

Перед первой линией читаемого файла одиночный ноль заталкивается в стек; он никогда не будет вытолкнут опять. Количество заталкиваний в стек будет всегда строго увеличивающимся снизу вверх. В начале каждой логической линии ее уровень отступа сравнивается с верхушкой стека. Если он равен, ничего не происходит. Если больше, то помещается в стек, и генерируется токен INDENT. Если меньше, то он должен быть одним из чисел, содержащихся в стеке; все числа в стеке, которые больше, извлекаются, и для каждого вытолкнутого числа генерируется токен DEDENT. В конце файла токен DEDENT генерируется для каждого числа, оставшегося в стеке, которое больше нуля.

Вот пример корректного (хотя сбивающего с толку) куска кода Python с отступами:

def perm(l):
        # Compute the list of all permutations of l
    if len(l) <= 1:
                  return [l]
    r = []
    for i in range(len(l)):
             s = l[:i] + l[i+1:]
             p = perm(s)
             for x in p:
              r.append(l[i:i+1] + x)
    return r

Следующий пример показывает различные ошибки отступа:

 def perm(l):                       # ошибка: отступ в первой строке
for i in range(len(l)):             # ошибка: нет отступа
    s = l[:i] + l[i+1:]
        p = perm(l[:i] + l[i+1:])   # ошибка: неожиданный отступ
        for x in p:
                r.append(l[i:i+1] + x)
            return r                # ошибка: противоречивое выравнивание

(В действительности, первые три ошибки обнаруживаются парсером; только последняя ошибка находится лексическим анализатором - отступ в return r не соответствует уровню выталкивания стека.)

2.1.9. Пробельные символы между токенами

За исключением начала логической линии или в строковом литерале, символы пробела, табуляции и formfeed могут быть использованы взаимозаменяемо для разделения токенов. Пробельные символы нужны между двумя токенами, только если в противном случае их соединение могло бы быть интерпретировано как другой токен (например, ab - это один токен, но a b - два токена).

2.2. Другие токены

Кроме NEWLINE, INDENT и DEDENT, существуют следующие категории токенов: идентификаторы, ключевые слова, литералы, операторы и разделители. Пробельные символы (другие, чем терминаторы линии, обсуждаемые ранее) не являются токенами, но служат их разграничителями. Где существует двусмысленность, токен заключает в себе самую длинную возможную строку, которая создает правильный токен, когда чтение идет слева направо.

2.3. Идентификаторы и ключевые слова

Идентификаторы (также называемые именами) описываются следующими лексическими определениями.

Синтаксис идентификаторов в Python основывается на приложении UAX-31 к стандарту Unicode с разработкой и изменениями как определено ниже; см. также PEP 3131 (python.org/dev/peps/pep-3131) для более детальной информации.

В диапазоне ASCII (U+0001..U+007F) валидными символами для идентификаторов являются те же самые, что и для Python 2.x: буквы в верхнем и нижнем регистре от A до Z, символ подчеркивания _ и за исключением первого символа цифры от 0 до 9

Python 3.0 вводит дополнительные символы за пределами диапазона ASCII (см. PEP 3131). Для этих символов классификация использует версию Unicode Character Database (база данных символов Юникод) как включенную в модуль unicodedata (docs.python.org/3/library/unicodedata.html#module-unicodedata).

Идентификаторы не ограничены по длине. Регистр имеет значение.

identifier   ::=  xid_start xid_continue*
id_start     ::=  <all characters in general categories Lu, Ll, Lt, Lm, Lo, Nl, the underscore, and characters with the Other_ID_Start property>
id_continue  ::=  <all characters in id_start, plus characters in the categories Mn, Mc, Nd, Pc and others with the Other_ID_Continue property>
xid_start    ::=  <all characters in id_start whose NFKC normalization is in "id_start xid_continue*">
xid_continue ::=  <all characters in id_continue whose NFKC normalization is in "id_continue*">

Коды категорий Unicode, упомянутые выше, означают:

  • Lu - буквы в верхнем регистре
  • Ll - буквы в нижнем регистре
  • Lt - буквы в стиле заголовка
  • Lm - буквы-модификаторы
  • Lo - другие буквы
  • Nl - номера букв
  • Mn - неинтервальные метки
  • Mc - интервальные сочетания меток
  • Nd - десятичные числа
  • Pc - пунктуация соединения
  • Other_ID_Start - явный список символов в PropList.txt для поддержки обратной совместимости
  • Other_ID_Continue - аналогично

Во время парсинга все идентификаторы преобразуются к обычной форме NFKC; сравнение идентификаторов основано на NFKC. 

Ненормативный HTML файл, перечисляющий все валидные идентификаторные символы для Unicode 4.1 может быть найден на https://www.dcl.hpi.uni-potsdam.de/home/loewis/table-3131.html.

2.3.1. Ключевые слова

Следующие идентификаторы используются как зарезервированные слова, или ключевые слова языка, они не могут быть использованы в качестве обычных идентификаторов и должны писаться точно так как здесь:

False      class      finally    is         return
None       continue   for        lambda     try
True       def        from       nonlocal   while
and        del        global     not        with
as         elif       if         or         yield
assert     else       import     pass
break      except     in         raise

 2.3.2. Зарезервированные классы идентификаторов

Определенные классы идентификаторов (за исключение ключевых слов) имеют специальные значения. Эти классы идентифицируются шаблонами лидирующих и заканчивающих символов подчеркивания:

_*

Неимпортированные посредством from module import *. Специальный идентификатор _ используется в интерактивном интерпретаторе для хранения результата последнего вычисления; он сохранен в модуле builtins (docs.python.org/3/library/builtins.html#module-builtins). Когда нет интерактивного режима, _ не имеет специального значения и не определен. См. Оператор import (docs.python.org/3/reference/simple_stmts.html#import).

Примечание: Имя _ часто используется в сочетании с интернационализацией; обратитесь к документации для модуля gettext (docs.python.org/3/library/gettext.html#module-gettext) для получения дополнительной информации об этом соглашении.

__*__

Системно-зависимые имена. Эти имена определены интерпретатором и его реализацией (включая стандартную библиотеку). Текущие системные имена обсуждаются в разделе Специальные имена методов (docs.python.org/3/reference/datamodel.html#specialnames) и где-нибудь еще. Более вероятно, будет определено в будущих версиях Python. Любое использование имен __*__ в любом контексте, который не следует явно документированному использованию, подвержен поломке без предупреждения.

__*

Приватные имена классов. Имена данной категории, когда используются в контексте определения класса, переписываются, чтобы использовать искаженную форму для избегания конфликта имен между "private" атрибутами базового и производного классов. См. раздел Идентификаторы (Имена) (docs.python.org/3/reference/expressions.html#atom-identifiers).

2.4. Литералы

Литералы есть обозначения для константных значений некоторых встроенных типов.

2.4.1. Строковые и байтовые литералы

Строковые литералы описываются следующими лексическими определениями:

stringliteral   ::=  [stringprefix](shortstring | longstring)
stringprefix    ::=  "r" | "u" | "R" | "U" | "f" | "F"
                     | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF"
shortstring     ::=  "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring      ::=  "'''" longstringitem* "'''" | '"""' longstringitem* '"""'
shortstringitem ::=  shortstringchar | stringescapeseq
longstringitem  ::=  longstringchar | stringescapeseq
shortstringchar ::=  <any source character except "\" or newline or the quote>
longstringchar  ::=  <any source character except "\">
stringescapeseq ::=  "\" <any source character>
bytesliteral   ::=  bytesprefix(shortbytes | longbytes)
bytesprefix    ::=  "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"
shortbytes     ::=  "'" shortbytesitem* "'" | '"' shortbytesitem* '"'
longbytes      ::=  "'''" longbytesitem* "'''" | '"""' longbytesitem* '"""'
shortbytesitem ::=  shortbyteschar | bytesescapeseq
longbytesitem  ::=  longbyteschar | bytesescapeseq
shortbyteschar ::=  <any ASCII character except "\" or newline or the quote>
longbyteschar  ::=  <any ASCII character except "\">
bytesescapeseq ::=  "\" <any ASCII character>

Одно синтаксическое ограничение, не указанное этими представлениями, это то, что символы пустоты не допускаются между stringprefix или bytesprefix и остальным литералом. Набор исходных символов определен объявлением кодировки; это UTF-8 при отсутствии объявления кодировки в исходном файле; см. раздел Объявления кодировки.

В плоском английском: Оба типа литералов могут быть заключены в соответствующие одиночные кавычки (') или двойные ("). Они также могут быть заключены в соответствующие группы из трех одиночных или двойных кавычек (они обычно называются тройными кавычками). Символ обратного слэша (\) используется для исключения (экранирования) символа, который иначе имел бы специальное значение, такое как новая строка, сам бэкслэш или символ кавычки).

Байтовые литералы всегда имеют префикс 'b' или 'B'; они создают экземпляр типа bytes вместо типа str. Они могут содержать только символы ASCII; байты с числовым значением 128 или больше должны быть с экранированием.

Как строковые, так и байтовые литералы могут опционально иметь префикс из букв 'r' или 'R'; такие строки называются сырыми и обрабатывают обратные слэши как литеральные символы. В резульатте в строковых литералах эскейпы '\U' и '\u' специально не обрабатываются. Учитывая, что сырые литералы юникода в Python 2.x ведут себя иначе, чем в Python 3.x, где 'ur' синтаксис не поддерживается.

 

 

 

 

 

 

 

 

 

 

 

Создано