△ △ 请给「 Python猫 」加星标 ,以免错过文章推送
大家好,我是猫哥。先打个小广告:Python潮流周刊从本周末起转为付费专栏,现在是涨价前的最优惠价,欢迎扫码订阅:
下面是今天的分享,来源:一只大鸽子(公号)
原文:【BNF Notation: Dive Deeper Into Python's Grammar】 https://realpython.com/python-bnf-notation/
在阅读Python文档的时候,你可能已经遇到过BNF(Backus–Naur form)表示法:
下面我们将了解BNF表示法,并使用它来理解Python的语法。
理解BNF表示法
BNF是上下文无关语法的元语法 符号 。计算机科学家经常使用这种符号来描述编程语言的语法,因为BNF可以精确描述编程语言。
BNF 符号由三个核心部分组成:
• Terminals(终止符):必须与输入中的特定项完全匹配的
字符串
。例:
"def"
,
"return
,
":"
。
• Nonterminals(非终止符):会被替换为具体值的符号。也可称为句法变量(syntactic variables)。例:
<letter>
,
<digit>
。
• Rules(规则):定义
terminals
和
Nonterminals
的联系。如:
<letter> ::= "a"
。
通过组合 终止符 和 非终止符 ,可以创建出BNF 规则 。
通过定义一组
规则
,可以构建出一个语言的语法(
grammar
)。
BNF具有一些变体,如EBNF和ABNF。
BNF规则及其组成部分
BNF规则的格式通常如下:
<symbol> ::= expression
其中
•
<symbol>
:符号是一个非终止符变量,通常用
<>
括起来。
•
::=
:表示左边的非终止符会被右边的表达式替换。
•
expression
:表达式由一系列终止符、非终止符和其它符号组成。
在构建BNF规则时,你可以定义一些符号表示不同含义,例如:
符号 | 含义 |
""
| 将终止符括起来 |
<>
| 表示非终止符 |
()
| 表示一组有效选项 |
+
| 指定上一个元素中的一个或多个 |
*
| ...零个或多个 |
?
| ...零个或一个 |
| | 选择其中一个 |
[x-z]
| 字母或数字区间 |
下面我们尝试自定义一些BNF规则。
一般示例:全名的语法
现在我们尝试定义一个人的全名的语法,一个人的全名包含3部分:
first name
,
middle name
,
family name
。每个部分之间应该用空格分隔,
middle name
是可选的。
<full_name> ::= <first_name> " " (<middle_name> " ")? <family_name>
规则的左侧部分是一个非终止符变量,用于标识人员的全名。
::=
符号表示
<full_name>
将替换为规则的右侧部分。
规则的右侧部分有几个组成部分。首先是first name,使用
<first_name>
非终止符定义。接下来是一个空格。为了定义空格,要使用一个终止符,即
" "
。接下来,我们有一个可选的middle_name,使用
(<middle_name> " ")?
定义。最后,我们有一个家庭名,使用
<family_name>
定义。
我们还需要定义
<first_name>
,
<middle_name>
,
<family_name>
的规则。
• 只接受字母
• 首字母大写,其余小写
我们又引入了大写字母和小写字母两个非终止符,需要进一步定义:
<uppercase_letter> ::= [A-Z]
<lowercase_letter> ::= [a-z]
接着,我们可以定义
<first_name>
,
<middle_name>
,
<family_name>
的规则:
<first_name> ::= <uppercase_letter> <lowercase_letter>*
您可以按照相同的模式来构建
<middle_name>
和
<family_name>
规则。
我们构建完了一个full name的BNF规则。下面我们在
BNF Playground
网站中测试这个规则。
与编程相关的示例:标识符
在学习编程语言时,我们很早就会接触到标识符(Identifiers)的概念。标识符是用来标识变量、函数、类等的名称。在Python中,标识符的命名规则如下:
• 第一个字符是字母、下划线。
• 其余字符可以是字母、下划线或数字。
可以写出相应的BNF规则:
<identifier> ::= <char> (<char> | <digit>)*
其中
<char>
和
<digit>
进一步定义:
<char> ::= [A-Z] | [a-z] | "_"
<digit> ::= [0-9]
我们可以在
BNF Playground
网站中测试这个规则。
Python的BNF变体
Python 使用 BNF 表示法的自定义变体来定义语言的语法。
Python 的 BNF 变体使用以下样式:
符号 | 含义 |
name
| 规则或非终止符的名称 |
::=
| 意味着 |
` | ` |
*
| 零个或多个 |
+
| 一个或多个 |
[]
| 零个或一个,即可选项 |
()
| 分组 |
| | 文本字符串 |
space
| 仅对分隔令牌有意义 |
这些符号定义了 Python 的 BNF 变体。与常规 BNF 规则的一个显着区别是Python不使用尖括号(
<>
)来括起非终端符号。它仅使用非终端标识符或名称。这使得规则更简洁易读。另外,
[]
的含义不再是字符集,而是可选项。要定义类似于BNF的
[a-z]
,需要使用
"a"..."z"
。
在Python文档经常会遇到BNF代码片段,有必要学习如何阅读它们。
从 Python 的文档中读取 BNF 规则:示例
pass 和 return 语句
这是Python的
pass
语句
pass_stmt ::= "pass"
这里,
pass_stmt
是一个规则的名称,使用
::=
指示规则扩展为
"pass"
。
"pass"
是一个终止符,意味着语句本身由单词
pass
组成。因此,
pass
语句只是一个单词
pass
另一个常见的语句是
return
语句:
return_stmt ::= "return" [expression_list]
return
语句由
"return"
和
[expression_list]
组成。
expression_list
是一个非终止符,
[]
表示它是可选的。
因此你可以这样使用return语句
deffunc():
return
如果你进入expression_list的定义,你会看到
expression_list ::= expression ("," expression)* [","]
又出现了一个非终止符expression,你可以继续查看expression的定义。
通过该定义,你可以了解到
return
语句可以返回一个或多个(用,隔开)表达式。
deffunc():
return"Hello!", "Pythonista!"
赋值表达式
Python 3.8 引入了赋值表达式
:=
(称为walrus运算符/象牙运算符)。作用是给变量赋值并返回表达式的值。
assignment_expression ::= [identifier ":="] expression
规则的右侧先是一个可选的组件,由一个标识符和一个终止符
:=
组成。然后是一个表达式。
我们可以在python中使用赋值表达式:
identifier := expression
例如
>>> (length := len([1, 2, 3]))
3
>>> length
3
条件语句
我们现在进阶到 复合语句 了。if语句的BNF规则如下:
if_stmt ::= "if" assignment_expression ":" suite
("elif" assignment_expression ":" suite)*
["else" ":" suite]
首先是终止符
if
,然后是assignment_expression(上一节已经讨论过)。然后是终止符
:
, 非终止符
suite
。安装刚刚读的定义,我们可以写出下面的if语句:
if assignment_expression:
suite
继续看定义,我们有了可选的elif:
if assignment_expression:
suite
elif assignment_expression:
suite
最后是可选的else:
if assignment_expression:
suite
elif assignment_expression:
suite
else:
suite
循环语句
循环是 Python 中另一个常用的复合语句。Python中有两种循环:
•
for
循环
•
while
循环
for 循环的 BNF 语法如下:
for_stmt ::= "for" target_list "in" starred_list ":" suite
["else"":" suite]
于是我们可以写出for语句:
for target_list in starred_list:
suite
else:
suite
例如:
high = 5
for number inrange(high):
if number > 5:
break
print(number)
else:
print("range covered")
while 循环的 BNF 语法如下:
while_stmt ::= "while" assignment_expression ":" suite
["else"":" suite]
可以写出while语句:
while assignment_expression:
suite
else:
suite
读取 Python BNF 的最佳实践
当您阅读文档中的 Python 的 BNF 规则时,您可以遵循一些最佳实践来提高您的理解。以下是一些建议:
1. 熟悉BNF表示法。可以编写BNF规则并在
BNF Playground
网站中测试。2. 了解Python的BNF变体。
3. 分解规则。将规则分成多个部分来阅读。
4. 识别非终止符。非终止符可能需要进一步阅读。
5. 了解终止符。查找表示语言中特定元素的终止符,例如关键字、运算符、文本或标识符。这些符号被引号括起来。
6. 结合实例:研究与您试图理解的 BNF 规则相对应的实际示例。分析 BNF 规则如何应用于这些示例。将规则与实际的 Python 语法进行对比。
如果你觉得本文有帮助
请慷慨 分享 和 点赞 ,感谢啦 !