△ △ 請給「 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 語法進行對比。
如果你覺得本文有幫助
請慷慨 分享 和 點贊 ,感謝啦 !