我可以使用以下语法创建多行字符串:
string = str("Some chars " "Some more chars")
这将产生以下字符串:
"Some chars Some more chars"
Python是加入这两个单独的字符串还是编辑器/编译器将它们视为单个字符串?
Ps:我只想了解内部情况.我知道还有其他方法来声明或创建多行字符串.
阅读参考手册,它就在那里.特别:
允许使用多个相邻的字符串或字节文字(由空格分隔),可能使用不同的引用约定,并且它们的含义与它们的串联相同.因此,"你好"'世界'相当于"helloworld".此功能可用于减少所需的反斜杠数量,方便地跨长行分割长字符串,甚至可以为字符串的某些部分添加注释,
(强调我的)
这就是为什么:
string = str("Some chars " "Some more chars")
与...完全相同:str("Some chars Some more chars")
.
此操作在字符串文字可能出现的任何地方执行,列出initiliazations,函数调用(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的编译器如何工作中提供一个很好的温和介绍.