Конкретная конкатенация строк Python

Я могу создать многострочную строку, используя этот синтаксис:

string = str("Some chars "
         "Some more chars")

Это создаст следующую строку:

"Some chars Some more chars"

Python соединяет эти две отдельные строки или редактор / компилятор рассматривает их как одну строку?

Ps: я просто хочу понять внутренности. Я знаю, что есть и другие способы объявления или создания многострочных строк.

1 ответ

Решение

Прочитайте справочное руководство, оно там. В частности:

Допускается использование нескольких смежных строковых или байтовых литералов (разделенных пробелами), возможно, с использованием различных соглашений о цитировании, и их значение совпадает с их конкатенацией. Таким образом, "привет" "мир" эквивалентен "helloworld". Эта функция может быть использована для уменьшения необходимого количества обратных слэшей, для удобного разделения длинных строк на длинные или даже для добавления комментариев к частям строк.

(акцент мой)

Вот почему:

string = str("Some chars "
         "Some more chars")

точно так же, как: str("Some chars Some more chars"),

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

Единственное предостережение - когда строковый литерал не содержится между одним из разделителей группировки. () , {} или же [] но вместо этого распространяется между двумя отдельными физическими линиями. В этом случае мы можем альтернативно использовать символ обратной косой черты, чтобы соединить эти строки и получить тот же результат:

string = "Some chars " \
         "Some more chars"

Конечно, объединение строк в одной физической строке не требует обратной косой черты. (string = "Hello " "World" просто отлично)


Python соединяет эти две отдельные строки или редактор / компилятор рассматривает их как одну строку?

Python, теперь, когда именно Python делает это, все становится интересным.

Из того, что я мог бы собрать (взять это с щепоткой соли, я не эксперт разбора), это происходит, когда Python преобразует дерево разбора (LL(1) Parser) для данного выражения к соответствующему AST ( абстрактному синтаксическому дереву).

Вы можете получить представление о разобранном дереве через parser модуль:

import parser

expr = """
       str("Hello "
           "World")
"""
pexpr = parser.expr(expr)
parser.st2list(pexpr)

Это выводит довольно большой и запутанный список, который представляет конкретное синтаксическое дерево, проанализированное из выражения в expr:

-- rest snipped for brevity --

          [322,
             [323,
                [3, '"hello"'],
                [3, '"world"']]]]]]]]]]]]]]]]]],

-- rest snipped for brevity --

Числа соответствуют либо символам, либо токенам в дереве разбора, а сопоставления от символа к правилу грамматики и токена к константе находятся в Lib/symbol.py а также Lib/token.py соответственно.

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

Далее мы можем просмотреть вывод дерева AST, созданного предыдущим выражением, через ast Модуль предоставлен в стандартной библиотеке:

p = ast.parse(expr)
ast.dump(p)

# this prints out the following:
"Module(body = [Expr(value = Call(func = Name(id = 'str', ctx = Load()), args = [Str(s = 'hello world')], keywords = []))])"

В этом случае вывод более удобен для пользователя; Вы можете видеть, что args для вызова функции - единственная каскадная строка Hello World,

Кроме того, я также наткнулся на классный модуль, который генерирует визуализацию дерева для ast узлы. Используя его, вывод выражения expr визуализируется так:

дерево выражений для данного выражения

Изображение обрезано, чтобы показать только соответствующую часть для выражения.

Как вы можете видеть, в терминальном конечном узле у нас есть один str объект, объединенная строка для "Hello " а также "World" т.е. "Hello World",


Если вы чувствуете себя достаточно смелым, покопайтесь в исходном коде, исходный код для преобразования выражений в дерево разбора находится по адресу Parser/pgen.c в то время как код, преобразующий дерево синтаксического анализа в абстрактное синтаксическое дерево, находится в Python/ast.c,

Эта информация для Python 3.5 и я уверен, что если вы не используете действительно старую версию (< 2.5) функциональность и расположение должны быть одинаковыми.

Кроме того, если вас интересует весь этап компиляции, за которым следует python, то один из основных участников, Бретт Кэннон (Brett Cannon), предоставит хорошее мягкое введение в видео " Из исходного кода в код: как работает компилятор CPython".

Другие вопросы по тегам