當前位置: 妍妍網 > 碼農

BNF 語法:揭開 Python 語法規則的秘密

2024-05-08碼農

請給「 Python貓 」加星標 ,以免錯過文章推播

大家好,我是貓哥。先打個小廣告:Python潮流周刊從本周末起轉為付費專欄,現在是漲價前的最優惠價,歡迎掃碼訂閱:

下面是今天的分享,來源:一只大鴿子(公號)

原文:【BNF Notation: Dive Deeper Into Python's Grammar】 https://realpython.com/python-bnf-notation/

在閱讀Python文件的時候,你可能已經遇到過BNF(Backus–Naur form)表示法:

文件中的BNF

下面我們將了解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 網站中測試這個規則。

    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([123]))
    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. 1. 熟悉BNF表示法。可以編寫BNF規則並在 BNF Playground 網站中測試。

    2. 2. 了解Python的BNF變體。

    3. 3. 分解規則。將規則分成多個部份來閱讀。

    4. 4. 辨識非終止符。非終止符可能需要進一步閱讀。

    5. 5. 了解終止符。尋找表示語言中特定元素的終止符,例如關鍵字、運算子、文本或識別元。這些符號被引號括起來。

    6. 6. 結合例項:研究與您試圖理解的 BNF 規則相對應的實際範例。分析 BNF 規則如何套用於這些範例。將規則與實際的 Python 語法進行對比。

    如果你覺得本文有幫助

    請慷慨 分享 點贊 ,感謝啦