python语言的语法由backus-naur form (bnf) 或其扩展形式(如ebnf)精确定义,这为我们理解语言的结构提供了基础。对于赋值语句,python官方文档给出了如下核心bnf规则:
assignment_stmt ::= (target_list "=")+ (starred_expression | yield_expression) target_list ::= target ("," target)* [","] target ::= identifier | "(" [target_list] ")" | "[" [target_list] "]" | attributeref | subscription | slicing | "*" target
其中,赋值语句的右侧(RHS)必须是starred_expression或yield_expression。它们的定义如下:
starred_expression ::= expression | (starred_item ",")* [starred_item] starred_item ::= assignment_expression | "*" or_expr yield_atom ::= "(" yield_expression ")" yield_expression ::= "yield" [expression_list | "from" expression]
初次接触时,我们可能会对一个看似简单的赋值语句,例如a = 9,感到困惑。问题在于,赋值操作符=右侧的字面量9,如何能够匹配到starred_expression或yield_expression这些更复杂的语法结构中?尤其是yield_expression明显与生成器相关,而starred_expression中的*通常用于解包操作。
核心解析:starred_expression与expression的关联解答这个困惑的关键在于starred_expression的第一个产生式:
starred_expression ::= expression | (starred_item ",")* [starred_item]
这表明,一个starred_expression可以仅仅是一个expression。换句话说,任何被Python语法定义为“表达式”的内容,都可以合法地出现在赋值语句的右侧,作为starred_expression的一种简单形式。因此,问题现在转化为:数字字面量9是如何被归类为expression的?
9的BNF追溯路径:从expression到integer要理解9如何成为一个expression,我们需要沿着BNF规则从expression向下追溯,直到找到能够匹配9的终结符。这个追溯路径非常长,但每一步都是逻辑自洽的:
starred_expression ::= expression | (starred_item ",")* [starred_item] expression ::= conditional_expression | lambda_expr conditional_expression ::= or_test ["if" or_test "else" expression] or_test ::= and_test | or_test "or" and_test and_test ::= not_test | and_test "and" not_test not_test ::= comparison | "not" not_test comparison ::= or_expr (comp_operator or_expr)* or_expr ::= xor_expr | or_expr "|" xor_expr xor_expr ::= and_expr | xor_expr "^" and_expr and_expr ::= shift_expr | and_expr "&" shift_expr shift_expr ::= a_expr | shift_expr ("<<" | ">>") a_expr a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr | m_expr "//" u_expr | m_expr "/" u_expr | m_expr "%" u_expr u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr power ::= (await_expr | primary) ["**" u_expr] primary ::= atom | attributeref | subscription | slicing | call atom ::= identifier | literal | enclosure literal ::= stringliteral | bytesliteral | integer | floatnumber | imagnumber integer ::= decinteger | bininteger | octinteger | hexinteger decinteger ::= nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")* nonzerodigit ::= "1"..."9"
从上述BNF链条中我们可以清晰地看到:
- starred_expression 可以是 expression。
- expression 可以是 conditional_expression (条件表达式)。
- conditional_expression 可以是 or_test (或测试)。
- 这个链条一直向下延伸,经过各种运算符优先级和结合性的定义,直到 u_expr (一元表达式)。
- u_expr 可以是 power (幂运算)。
- power 可以是 primary (主要表达式)。
- primary 可以是 atom (原子)。
- atom 可以是 literal (字面量)。
- literal 可以是 integer (整数)。
- integer 可以是 decinteger (十进制整数)。
- decinteger 可以是 nonzerodigit (非零数字),而9正是一个nonzerodigit。
因此,9通过这一系列递归的BNF规则,最终被成功地归类为expression,进而满足了starred_expression的要求。
理解BNF规则中的“可选性”这个追溯过程之所以能够成立,一个非常重要的原因在于BNF规则中广泛存在的“可选性”。在BNF中,方括号[]表示其内部的元素是可选的。这意味着许多非终结符(non-terminal)的定义,即使看起来描述的是带有操作符或特定结构的复杂表达式,也允许其以最简单的形式存在。
例如:
- power ::= (await_expr | primary) ["**" u_expr]:这里的"**" u_expr是可选的。这意味着一个primary本身就可以是一个power,而不需要包含幂运算符**。因此,9作为一个primary,也自然是一个power。
- or_test ::= and_test | or_test "or" and_test:这里的or_test "or" and_test是可选的。这意味着一个and_test本身就可以被视为一个or_test,而不需要包含逻辑或运算符or。
- conditional_expression ::= or_test ["if" or_test "else" expression]:条件表达式的if ... else ...部分是可选的,所以一个or_test本身就可以是一个conditional_expression。
正是这种“可选性”的机制,使得一个简单的字面量9能够向上层层匹配,满足所有中间非终结符的最低要求,最终被识别为一个完整的expression。
示例与注意事项理解BNF的这种结构对于深入掌握Python语法至关重要。例如:
# 9 是一个 expression,也是一个 starred_expression a = 9 # 9 + 5 也是一个 expression,因为它符合 a_expr 规则 b = 9 + 5 # "hello" 字符串字面量也是一个 expression c = "hello" # 一个函数调用也是一个 primary,因此也是一个 expression def greet(): return "Hi" d = greet() # 即使是更复杂的条件表达式,如果没有 if/else 部分,也仍然是 expression # 例如,这里的 `True` 本身就是一个 expression (通过 atom -> literal -> identifier) e = True
注意事项:
- 非终结符的层级性: BNF规则的层级设计通常反映了运算符的优先级。例如,m_expr(乘除模)在a_expr(加减)之下,表示乘除运算优先于加减运算。
- 递归定义: 许多规则是递归定义的,例如or_test可以包含另一个or_test。这使得可以构建任意复杂的表达式。
- 解析树: 编译器或解释器在处理代码时,会根据这些BNF规则构建一个抽象语法树(AST)或解析树,将源代码分解成符合这些规则的结构。
通过对Python赋值语句及其相关BNF规则的深入分析,我们明白了a=9中数字字面量9之所以能够作为赋值语句右侧的合法内容,是因为它通过starred_expression可作为expression的规则,并沿着expression到literal的完整BNF推导链,最终被识别为一个整数integer。这个过程的关键在于BNF规则中广泛存在的可选性,它允许简单的元素通过满足最低要求来匹配更复杂的语法结构。理解这些BNF规则不仅能帮助我们更透彻地理解Python的语法结构,也为我们分析和构建更复杂的语言工具提供了基础。
以上就是深入理解Python赋值语句的BNF语法结构的详细内容,更多请关注知识资源分享宝库其它相关文章!
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。