2. 词法分析
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, # 这些是 April, Mei, Juni, # 一年之中 Juli, Augustus, September, # 各个月份的 Oktober, November, December] # 荷兰语名称含注释是能够有隐式行拼接的, 后续行的缩进情况是不重要的, 空的后续行也是被支持的。在隐式拼接行相互之间不会存在形符。三引号字符串针对隐式拼接行是起到支持作用的, 可以见下文那儿, 在三引号字符串中注释并不会被支持。2.1.7. 空白行仅含有空格符、制表符、换页符、注释的逻辑行, 会被予以忽略, 也就是不会生成形符。在交互模式输入语句之际, 空白行的处理办法, 或许会由于读取 - 求值 - 打印循环, 也就是REPL的具体实现形式存在差异而有所不同。在标准交互模式解释器里面, 完全空白的逻辑行, 也就是既没有空格, 也没有注释的那种, 会致使多行复合语句终结。2.1.8. 缩进用于计算该行缩进层级的, 是放置在逻辑行开头的空白符, 也就是空格符和制表符它们决定语句组块。从左至右的制表符, 被替换成一到八个空格, 缩进空格的总数, 是八的倍数, 这与 Unix 的规则是保持一致的。首个非空字符前面的空格数目, 决定了该行的缩进层次。借助反斜杠进行多行拼接是不可以的首个反斜杠之前的空白符, 决定了缩进的层次。源文件在混用制表符以及空格符进行缩进时, 由于空格数量跟制表符有关系 , 这样产生的不一致, 会致使不能正常识别缩进层次 , 进而触发。关于跨平台兼容性的说明是, 因为非UNIX平台文本编辑器自身的特性, 所以不要在源文件里同时使用制表符和空格符。此外也需留意, 不同的平台可能会明确限制最大缩进层级。当行首包含换页符之际, 缩进计算会把该换页符忽略掉。换页符处于行首空白符内别的位置时其效果是未定义的, 比如, 那有可能致使空格计数被重置为零。连续行的缩进层级以堆栈形式生成 和 形符说明如下。在读取文件第一行之前, 要先往栈里推入一个零值, 此零值不会被拿掉。向栈推入的层级值从底部到顶部会一直增加。每一个逻辑行开头的行缩进层级会跟栈顶行作比较。要是相等, 那就不进行处理。若是新行层级更高, 就会被推到栈顶, 而且生成一个 形符。倘若新行层级更低, 那么应该 属于栈中的某项层级数值栈中高于此项层级的所有数值都会被移除, 每移除一级数值就生成一个 形符。到了文件末尾, 栈里剩下的每个大于零的数值都会生成一个 形符。下面的 代码缩进示例虽然正确但含混不清def perm(l): # 计算由 l 的所有排列组成的列表 if len(l) 1: return [l] r [] for i in range(len(l)): s l[:i] l[i1:] p perm(s) for x in p: r.append(l[i:i1] x) return r下例展示了多种缩进错误def perm(l): # 错误第一行有缩进 for i in range(len(l)): # 错误没有缩进 s l[:i] l[i1:] p perm(l[:i] l[i1:]) # 错误非预期的缩进 for x in p: r.append(l[i:i1] x) return r # 错误不一致的缩进事实上, 解析器能够识别前面的三个错误, 唯有最后一个错误是由词法分析器识别的, 这个错误是, r的缩进不存在办法去匹配从栈里移除掉的缩进层级。2.1.9. 形符间的空白字符可以分隔形符的是空格符、制表符、换页符等空白符, 不过它们仅限于在逻辑行开头或者字符串内, 除此之外都行不通。若要把两个相连形符解读成不同形符, 那就得用空白符来分隔才行, 像这样举例说明, ab算是一个形符, 而a b却是两个形符。2.2. 其他形符除了特定情况外, 还有标识符, 关键字, 字面值, 运算符, 分隔符等这样的形符。除了前述的行终止符之外的空白符, 不是形符, 它可用于分隔形符。当存在二义性时, 将要从左至右的方向, 读取尽量长的字符串来组成合法形符。2.3. 标识符和关键字标识符也称为 名称的词法定义说明如下。标识符的句法是以标准附件UAX - 31为依据的, 并且添加了下文所定义的细化内容以及修改, 详细内容可查看PEP 3131。在ASCII范围之内, 也就是U0001到U007F的区间里, 能够用来作为标识符的字符涵盖了大小写形式各个不同情况的字母A到Z, 还有下划线_, 以及数字0到9, 然而数字是不可以作为第一个字符的。3.0这个版本引入了落在ASCII范围以外的额外字符, 这部分内容可参见PEP 3131。针对这些字符, 会使用具体包含在模块中的字符数据库的版本来进行分类。标识符的长度没有限制但区分大小写。identifier::xid_startxid_continue*id_start::id_continue::id_start, plus characters in the categories Mn, Mc, Nd, Pc and others with the Other_ID_Continue propertyxid_start::id_startwhose NFKC normalization is in id_start xid_continue*xid_continue::id_continuewhose NFKC normalization is in id_continue*上述 类别码的含义:析取操作开展之际, 全部标识符均会转变为规范样式NFKC, 标识符之间的比对一概依据NFKC。15.0.0里, 所含有的用来表示的、能够被使用的标识符字符, 详细情况, 查看这个HTML文件。2.3.1. 关键字下述标识符属于保留字, 也就是所谓的关键字, 是不能够被用于普通标识符的。关键字进行拼写的时候, 必须得和在此处罗列的完全保持一致呀:False await else import pass None break except in raise True class finally is return and continue for lambda try as def from nonlocal while assert del global not with async elif if or yield2.3.2. 软关键字仅在特定上下文里被保留的标识符。某些具备这些特征的被称作软关键字。像match、case、type 和 _ 这类标识符, 在特定上下文中有着关键字的语义, 可这种区分是于解析器层级实现完成的, 并非在分词时分。可以作为软关键字, 它们在被用于相应语法的时候, 还能够始终维持着与当作标识符名称的现存代码的兼容性。针对, 情形与下划线是于, 语句里运用。类型是于, 语句里运用。于3.12版本出现了变更, type如今成为了一个软关键字。2.3.3. 保留的标识符类存在一些标识符类, 它们并非关键字, 而是有着特殊的含义, 这些类的命名模式呈现为, 以一个下划线字符作为起始, 并且以一个下划线字符作为结束。_*不会被 from * 所导入。在内容里的case样式里面, _是一个, 其意味着。除此之外, 交互式解释器会把最后一次求值得出的结果放置到变量 _ 当中。它跟print等内置函数一同被存储于模块于别的地点, _ 属于一个常规标识符, 此标识符常常被用于给 “特殊” 条目命名, 可是对于自身来讲没有任何特殊的地方。备注_ 常用于连接国际化文本详见 模块文档。它还经常被用来命名无需使用的变量。__*__存在着由系统所定义的名称, 一般情况下会被简称为 , 这些名称是经由解释器与其特定的种种实现涵盖标准库从而进行定义的, 现针对系统已然定义的名称有着相关论述, 可详细查看 等章节之处, 在未来版本里还会去定义更多这样的名称, 在所有情形之下, 任意一种没有显式遵从 __*__ 名称文档所用方式, 全都会去造成不存在警告提示状况的错误。__*关于类的私有名称, 在类进行定义的时候, 此类的名称会得以一种混合的形式去进行重写, 进而避免基类以及派生类的“私有”属性之间出现名称冲突, 具体可见于。2.4. 字面值字面值是内置类型常量值的表示法。2.4.1. 字符串与字节串字面值字符串字面值的词法定义如下stringliteral:: [stringprefix](shortstring|longstring)stringprefix:: r | u | R | U | f | F | fr | Fr | fR | FR | rf | rF | Rf | RFshortstring:: shortstringitem* | shortstringitem* longstring:: longstringitem* | longstringitem* shortstringitem::shortstringchar|stringescapeseqlongstringitem::longstringchar|stringescapeseqshortstringchar::longstringchar::stringescapeseq:: \bytesliteral::bytesprefix(shortbytes|longbytes)bytesprefix:: b | B | br | Br | bR | BR | rb | rB | Rb | RBshortbytes:: shortbytesitem* | shortbytesitem* longbytes:: longbytesitem* | longbytesitem* shortbytesitem::shortbyteschar|bytesescapeseqlongbytesitem::longbyteschar|bytesescapeseqshortbyteschar::longbyteschar::bytesescapeseq:: \一个句法限制, 且是这些产生式未指明的, 那就是空白符不被允许, 在“或”与字面值的其余部分之间去出现。源字符集借助编码格式声明予以定义, 要是源文件未给出编码格式声明, 那就默认UTF - 8, 参见“”一节。简单来讲, 有这样两种情况: 其一, 两种类型的字面值能够用成对的单引号 () 括起来。其二, 它们也能用成对的双引号 () 括起来。其三, 它们还能够用成对的连续三个单引号括起来。其四, 它们同样能用成对的连续三个双引号括起来。这通常叫做三重引号字符串。另外, 反斜杠 (\) 字符用于给普通字符赋予特殊含义。比如 n, 当用斜杠转义时 (\n) 表示 换行。而且, 它还可以用来对具有特殊含义的字符进行转义。像换行符、反斜杠本身、引号等。若想查看示例内容, 需请参阅下面的 查看示例处。向字节串字面值里加 b 或者 B作为前缀生成的是那种类型的实例, 可不是那种类型的实例字节串仅仅能够包含ASCII字符当字节串数值大于等于128的时候, 必须得用转义来进行表示。字符串字面值的话, 可选择加上前缀字母 r 或者 R, 这被称作原始字符串字面值, 字节串字面值同样如此, 也可选择加 r 或 R, 这被叫做原始字节串字面值, 并且它们都会把反斜杠看作原本的字符字面值。从而使得, 在原始字符串字面值当中, \U 和 \u 转义符号不会被特殊对待。于3.3 中添加, 新增了原始字节串, 其带有 rb 前缀, 它与 br 是同义词。认可字面值uvalue这种遗留代码, 使得 2.x 和 3.x 并行代码库的维护工作得以简化, 具体内容可查看 PEP 414。字符串当中, 前缀是 f 或者 F 的那些, 被称作 格式字符串, 详细情况可见接下来的内容。f 在使用时能够和 r 一起用, 然而却不可以跟 b 或者 u 连用, 所以呢, 可以选用原始格式字符串, 但是格式字节串字面值是不能使用的。处于三引号字面值里的内容, 能够涵盖未进行转义处理的换行与引号这些会被原样留存下来, 但不包括连在一起的、用以终止该字面值的、未经过转义处理的三个引号本身。“引号”乃是启用此字面值的字符, 它既可以是单引号‘, 也能够是双引号”2.4.1.1. 转义序列要是没有标注 r 或者 R 前缀, 在字符串以及字节串字面值里头, 转义序列依据跟 C 标准相似的规则去进行解释。可供使用的转义序列是下面这些:转义序列含意备注忽略反斜杠与换行符(1)\\反斜杠\\单引号\双引号\aASCII 响铃BEL\bASCII 退格符BS\fASCII 换页符FF\nASCII 换行符LF\rASCII 回车符CR\tASCII 水平制表符TAB\vASCII 垂直制表符VT\ooo八进制数 ooo 字符(2,4)\xhh十六进制数 hh 字符(3,4)字符串字面值专用的转义序列转义序列含意备注\N{name}数据库中名为 name 的字符(5)\uxxxx16 位十六进制数 xxxx 码位的字符(6)\32 位 16 进制数 码位的字符(7)注释可以在行尾添加一个反斜杠来忽略换行符: This string will not include \ ... backslashes or newline characters. This string will not include backslashes or newline characters.同样的效果也可以使用 或者圆括号和 来达成。与 C 标准一致接受最多三个八进制数字。于3.11版本出现变更, 取值比0o377大的八进制数转义序列将会产生。在3.12这个版本出现了变更, 数值比0o377大的八进制转义符会产生, 在往后的版本里最终会改成。与 C 标准不同必须为两个十六进制数字。在字节串字面值里头, 十六进制数以及八进制数的转义码, 是以相应的数值去代表每一个字节。在字符串字面值里头, 这些转义码是以相应的数值去代表每一个字符。在 3.3 版本发生变更: 加入了对别名 的支持。必须为 4 个十六进制数码。表示任意 字符。必须为 8 个十六进制数码。同C标准不一样, 在字符串当中, 无法被识别的转义序列会原样留存, 也就是说, 输出的结果会保留反斜杠。在调试时, 这样的方式极具作用: 当转义序列输错的时候, 在输出结果里更易于辨别错误留意, 在字节串字面值中间, 字符串字面值专门使用的转义序列是属于无法被识别的转义序列。在 3.6 版本发生变更: 不可识别的转义序列会产生 。于3.12版本出现变更, 不可识别的转义序列会产生, 在未来的一系列版本里将终归施行改变。哪怕是在初始字面值里, 引号能够借助反斜杠来进行转义, 然而反斜杠会在输出结果当中予以保留举例说明, r\是由两个字符构成的有效的字符串字面值: 反斜杠以及双引号r\却并非有效的字符串字面值原始字符串亦不可以以奇数个反斜杠作为结尾。特别是, 原始字面值不可以以单个反斜杠作为结尾 反斜杠会对其后的引号进行转义)。还要留意, 反斜杠加上换行在字面值里会被理解为两个字符, 而不是连续行。2.4.2. 字符串字面值合并针对以空白符分隔的多个相邻的字符串或者字节串字面值, 能够用不同引号进行标注, 这可等同于合并操作, 所以hello world等同于 , 此功能不需要反斜杠, 就能够将长字符串分成多个物理行, 并且还能够为不同部分的字符串添加注释, 比如:re.compile([A-Za-z_] # 字母或下划线 [A-Za-z0-9_]* # 字母、数字或下划线 )注意, 此功能于句法层面进行定义, 于编译的时候予以实现。于运行的时候, 合并那些字符串表达式必须要使用‘’运算符。并且, 还要注意的是, 字面值合并能够针对每个部分去应用不一样的引号风格, 要注意, 甚至能够混用原始字符串以及三引号字符串, 格式字符串字面值也是能够和纯字符串字面值进行合并的。2.4.3. f 字符串有一种字符串字面值, 被称作格式字符串字面值, 或者 f -, 它是那种标注了 f 或 F 前缀的字符串字面值, 这种字符串字面值当中可以包含替换字段, 也就是用 {} 标注起来的表达式, 其他的字符串字面值仅仅是常量, 然而格式字符串字面值却是能够在运行的时候进行求值的表达式。要是字面值没被标记成原始字符串的话, 那么呢, 就跟在普通字符串字面值里的情况相符, 转义序列同样会被解码。解码完成之后, 拿来用于字符串内容的那个语法是这样的:f_string:: (literal_char| {{ | }} |replacement_field)*replacement_field:: {f_expression[] [!conversion] [:format_spec] }f_expression:: (conditional_expression| *or_expr) (,conditional_expression| , *or_expr)* [,] |yield_expressionconversion:: s | r | aformat_spec:: (literal_char|replacement_field)*literal_char::单花括号替换了双花括号 {{ 或者 }}, 对于花括号外之字符串, 依旧按字面值来处理。单左花括号 { 标记着以表达式作为开头的替换字段。于表达式之后加上等于号 , 这在求值之后, 能够同时显示表达式文本及其结果, 供调用的参数使用, 也就是用于对程序错误的调试。接下来是用叹号 ! 所标记的转换字段。还能够在冒号 : 之后额外设置格式的说明符。替换字段以右花括号 } 作为结束。采用圆括号包围的常规表达式那样的方式来处理格式化字符串字面值里的表达式, 不过存在细微差别, 空表达式是不被允许的, 而且赋值表达式 : 都必须要显式地使用括号进行包围, 每个表达式在格式化字符串字面值出现的那个上下文里, 会依照从左到右这个顺序去求值, 替换表达式在包含换行符能够囊括单引号和三引号的 f-字符串里, 并且可以涵盖注释事项, 替换字段内 # 后面的全部内容都是注释范畴即便结尾的花括号以及引号也这样。 在这种情况下替换字段必须在另一行中结束。 fabc{a # This is a comment } ... 3} abc5于3.7版本出现变更, 在3.7以前, 鉴于实现方面的问题, 格式字符串字面值表达式内不被允许使用表达式跟包含子句的推导式。变更发生在3.12版本 , 在3.12之前, 用于f-字符串替换字段的注释使用并不被允许。当表达式之中含有等号‘’的时候, 输出相应内容覆盖含有表达式文字版本、‘’以及求值最终结果。输出涵盖的内容能够保留表达式里左花括号‘{’之后的部分, 以及‘’之后的空白格。在没有对格式做出指定的情况下, ‘’默认调用相应表达式的。当指定具体格式时此情形下默认优先调用表达式的 , 除非明确声明了转换字段‘!r’。当指定了转换符的状况下, 表达式求值所获取的结果, 会先进行转换操作 之后才会开展格式化处理。转换符 !s 会去调用转换求值之后得出的那个结果 , !r会进行调用 , !a同样会进行调用。之后运用协议去对结果开展格式化, 格式说明符会传送至表达式或者用于转换结果的方法处, 要是省略格式说明符, 那么将传入空字符串, 格式化好的结果会被包含于整个字符串的最终值里。能够包含嵌套替换字段的是最高层级的格式说明符, 这些嵌套字段同样能够包含自身的转换字段, 然而却不可以再次包含更深层嵌套的替换字段, 此处所使用的和方法所运用的是相同的。格式化字符串字面值能够进行拼接, 然而, 一个替换字段是不可以被拆分到多个字面值当中去的。格式字符串字面值示例如下 name Fred fHe said his name is {name!r}. He said his name is Fred. fHe said his name is {repr(name)}. # repr() is equivalent to !r He said his name is Fred. width 10 precision 4 value decimal.Decimal(12.34567) fresult: {value:{width}.{precision}} # nested fields result: 12.35 today datetime(year2017, month1, day27) f{today:%B %d, %Y} # using date format specifier January 27, 2017 f{today:%B %d, %Y} # using date format specifier and debugging todayJanuary 27, 2017 number 1024 f{number:#0x} # using integer format specifier 0x400 foo bar f{ foo } # preserves whitespace foo bar line The mills closed f{line } line The mill\s closed f{line :20} line The mills closed f{line !r:20} line The mill\s closed 允许在替换字段中重用外层 f-字符串的引号类型: a dict(x2) fabc {a[x]} def abc 2 def于3.12版本出现变更, 在3.12以前, 不许可在替换字段里, 再度使用和外层f - 字符串一样的引号类型。替换字段, 之中也是允许去运用反斜杠的而且还会以跟在其他场景之下同样的方式来进行求值。 a [a, b, c] print(fList a contains:\n{\n.join(a)}) List a contains: a b c在3.12版本出现了变更, 在3.12以前, f - 字符串的替换字段里头, 是不允许使用反斜杠的。即便未包含表达式格式字符串字面值也不能用作文档字符串。 def foo(): ... fNot a docstring ... foo.__doc__ is None True查阅PEP 498, 知晓关于格式字符串字面值的提议, 还有和格式字符串机制有联系的东西。2.4.4. 数值字面值有三种类型属于数值字面值, 分别是整数, 浮点数, 虚数。并不会存在复数字面值, 因为它是由加了虚数的实数所构成的。留意, 数值字面值不包含正负号实际上, 像 -1 这样的负数, 是通过一元运算符 - 以及字面值 1 组合而成的。2.4.5. 整数字面值整数字面值词法定义如下integer::decinteger|bininteger|octinteger|hexintegerdecinteger::nonzerodigit([_]digit)* | 0 ([_] 0)*bininteger:: 0 (b | B) ([_]bindigit)octinteger:: 0 (o | O) ([_]octdigit)hexinteger:: 0 (x | X) ([_]hexdigit)nonzerodigit:: 1...9digit:: 0...9bindigit:: 0 | 1octdigit:: 0...7hexdigit::digit| a...f | A...F整数字面值的长度没有限制能一直大到占满可用内存。要确定数值的时候, 字面值里的下划线是会被忽略掉的。下划线仅仅是用来对数字进行分组的, 目的是让数字能够更便于阅读。下划线既可以处在数字之间, 也能够在诸如 0x 这类基数说明符的后面。留意, 除去零之外, 十进制数字的起始部位不被允许存在零。以此避免和3.0版之前所运用的C样式八进制字面值产生混淆。整数字面值示例如下7 2147483647 0o177 0b100110111 3 79228162514264337593543950336 0o377 0xdeadbeef 100_000_000_000 0b_1110_0101在 3.6 版本出现了变更, 现今已经支持在字面值里, 通过下划线来对数字进行分组。2.4.6. 浮点数字面值浮点数字面值的词法定义如下所述floatnumber::pointfloat|exponentfloatpointfloat:: [digitpart]fraction|digitpart.exponentfloat:: (digitpart|pointfloat)exponentdigitpart::digit([_]digit)*fraction:: .digitpartexponent:: (e | E) [ | -]digitpart留意, 在进行解析之际整数以及指数部分始终是以 10 作为基数的。举例来说, 它是合乎规范的, 所呈现的数值跟 77e10 是一样的。浮点数字面值的支持范畴是由具体的实现情况来决定的。整数字面值支持运用下划线对数字进行分组。一些浮点数字面值的示例如下:3.14 10. .001 1e100 3.14e-10 0e0 3.14_15_93在 3.6 版本发生变更: 现已支持在字面值中用下划线分组数字。2.4.7. 虚数字面值虚数字面值词法定义如下imagnumber:: (floatnumber|digitpart) (j | J)由如下虚数字面值示例可知, 复数用一对取值范围相同的浮点数表示, 虚数字面值生成实部是 0.0 的复数, 若要创建实部不为零的复数, 则需添加浮点数, 比如 (34j)。3.14j 10.j 10j .001j 1e100j 3.14e-10j 3.14_15_93j2.5. 运算符运算符如下所示 - * ** / // % | ^ ~ : !2.6. 分隔符以下形符在语法中为分隔符( ) [ ] { } , : ! . ; - - * / // % | ^ **用于浮点数以及虚数字面值的, 是句点。表示省略符的, 是三个连续的句点。列表后半部分属于增强赋值操作符, 它能用来当作词法分隔符, 然而, 它也是能够去执行运算的。在下述的 ASCII 字符当中, 具备着特殊的含义, 对于词法分析器而言存在重要的意义: # \用于字符串字面值或者注释之外, 以下 ASCII 字符不被使用, 一旦使用将会直接报错。$ ? 备注