Python字符串字面量的拼接

16

我可以使用以下语法创建多行字符串:

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

这将会产生以下字符串:

"Some chars Some more chars"

Python是将这两个独立的字符串连接起来,还是编辑器/编译器将它们视为单个字符串?

附注:我只是想了解内部机制。我知道还有其他方法来声明或创建多行字符串。


3
Python会将这两个独立的字符串连接起来 - 是的,它会这样做。这种行为甚至有文档记录。 - vaultah
1
这不是一个多行字符串。这个特性与换行无关。Python会忽略括号中的换行符。顺便说一下,可以使用三引号("""''')来创建多行字符串。 - zvone
1个回答

35
阅读参考手册里面有这个内容。 具体来说:

允许使用多个相邻的字符串或字节文字(由空格分隔),可能使用不同的引号约定,它们的含义与它们的连接相同。因此,“hello” 'world'等同于“helloworld”。这个特性可以用于减少需要的反斜杠数量,方便地跨越长行拆分长字符串,甚至可以向字符串的部分添加注释。

我强调了这一点

这就是为什么:

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

str("一些字符更多的字符") 完全相同。

在任何字符串字面值可能出现的地方都执行此操作,如列表初始化、函数调用(如上述的 str)等。

唯一的注意事项是当一个字符串字面值包含在 分组定界符 (), {}[] 中,而是在两个单独的 物理行 之间扩展时。在这种情况下,我们可以 使用 反斜杠字符来连接这些行并获得相同的结果:

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

当然,在同一物理行上连接字符串不需要反斜杠。(string = "Hello " "World" 就可以了)

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.pyLib/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的输出像这样可视化:

                                           expression tree for the given expression

图片被裁剪以仅显示表达式的相关部分。

正如您所看到的,在终端叶节点中,我们有一个单独的str对象,即连接"Hello ""World"的字符串,即"Hello World"


如果你感觉足够勇敢,可以深入源代码。将表达式转换为解析树的源代码位于Parser/pgen.c,而将解析树转换为抽象语法树的代码位于Python/ast.c
此信息适用于Python 3.5,我非常确定除非你使用一些非常旧的版本(< 2.5),否则功能和位置应该是类似的。
此外,如果您对Python遵循的整个编译步骤感兴趣,核心贡献者之一Brett Cannon在视频From Source to Code: How CPython's Compiler Works中提供了一个良好的简介。

谢谢你的回答,解决了我的疑惑。另外,我想问一下,当我说“一些字符”并在下一行说“一些更多的字符”,而不用括号括起来时,它不会产生相同的输出。所以,当他们说空格时,他们并不是指换行,对吗? - Ganesh Satpute
@falsetru 如果没有括号,它就无法工作。这只是为了满足 Python 的占位符 :) - Ganesh Satpute
@GaneshSatpute,我的意思是只省略 str,而不是括号:("一些字符" "更多字符") - falsetru
@GaneshSatpute 我更新了我的回答,包括更多关于何时执行此操作的信息。至于如何执行它,我无法提供帮助,因为浏览和理解Pythonc源代码是我目前还没有完全掌握技能的事情(很快就会了!)。 - Dimitris Fasarakis Hilliard
1
@Jim,感谢您详细的回答。我花了一些时间来阅读和理解。 :) 我可能会去检查源代码。再次感谢您的建议。 - Ganesh Satpute
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接