?
SyntaxError的來(lái)源
當(dāng)您運(yùn)行 Python 代碼時(shí),解釋器將首先解析它以將其轉(zhuǎn)換為 Python 字節(jié)碼,然后執(zhí)行。解釋器將在程序執(zhí)行的第一階段(也稱為解析階段)中發(fā)現(xiàn) Python 中的任何無(wú)效語(yǔ)法。如果解釋器無(wú)法成功解析您的 Python 代碼,則意味著您在代碼中的某處使用了無(wú)效語(yǔ)法。解釋器將嘗試向您顯示該錯(cuò)誤發(fā)生的位置。
當(dāng)您第一次學(xué)習(xí) Python 時(shí),遇到 SyntaxError 可能會(huì)令人沮喪。Python 將嘗試幫助您確定代碼中無(wú)效語(yǔ)法的位置,但它提供的回溯可能有點(diǎn)令人困惑。有時(shí),它指向的代碼非常好。
注意:如果您的代碼在語(yǔ)法上是正確的,那么您可能會(huì)引發(fā)其他不是 SyntaxError 的異常。
今天,咱們就來(lái)看看Python中6個(gè)常見(jiàn)的語(yǔ)法問(wèn)題。
當(dāng)您第一次遇到 SyntaxError 時(shí),了解為什么會(huì)出現(xiàn)問(wèn)題,以及如何修復(fù) Python 代碼中的無(wú)效語(yǔ)法,會(huì)很有幫助。
在下面的部分中,您將看到可能引發(fā) SyntaxError 的一些更常見(jiàn)的原因,以及如何修復(fù)它們。
濫用賦值運(yùn)算符 (=)
在 Python 中有幾種情況,您無(wú)法對(duì)對(duì)象進(jìn)行賦值。一些示例分配給文字和函數(shù)調(diào)用。在下面的代碼塊中,您可以看到一些嘗試執(zhí)行此操作的示例,以及由此產(chǎn)生的SyntaxError 回溯:
?
?
>>>?len('hello')?=?5 ??File?"
第一個(gè)示例嘗試將值 5 分配給 len() 調(diào)用。SyntaxError 消息在這種情況下非常有用。它告訴你不能給函數(shù)調(diào)用賦值。
第二個(gè)和第三個(gè)示例嘗試為文字分配一個(gè)字符串和一個(gè)整數(shù)。相同的規(guī)則適用于其他文字值。回溯消息再次表明當(dāng)您嘗試為文字賦值時(shí)出現(xiàn)問(wèn)題。
您的意圖很可能不是為文字或函數(shù)調(diào)用分配值。例如,如果您不小心遺漏了額外的等號(hào) (=),就會(huì)發(fā)生這種情況,這會(huì)將賦值轉(zhuǎn)換為比較。如下所示,比較是有效的:
?
?
>>>?len('hello')?==?5 True
拼寫錯(cuò)誤、遺漏或誤用 Python 關(guān)鍵字
Python 關(guān)鍵字是一組受保護(hù)的詞,在 Python 中具有特殊含義。這些詞不能用作代碼中的標(biāo)識(shí)符、變量或函數(shù)名稱。它們是語(yǔ)言的一部分,只能在 Python 允許的上下文中使用。
錯(cuò)誤使用關(guān)鍵字的常見(jiàn)方式有以下三種:
① 關(guān)鍵字拼寫錯(cuò)誤;
② 缺少關(guān)鍵字;
③ 濫用關(guān)鍵字;
如果您在 Python 代碼中拼錯(cuò)了關(guān)鍵字,則會(huì)收到 SyntaxError。例如,如果關(guān)鍵字 for 拼寫錯(cuò)誤,會(huì)發(fā)生以下情況:
?
?
>>>?fro?i?in?range(10): ??File?"
該消息顯示 SyntaxError: invalid syntax ,但這不是很有幫助。回溯指向 Python 可以檢測(cè)到錯(cuò)誤的第一個(gè)位置。要修復(fù)此類錯(cuò)誤,請(qǐng)確保所有 Python 關(guān)鍵字拼寫正確。
關(guān)鍵字的另一個(gè)常見(jiàn)問(wèn)題是當(dāng)您完全忘記寫時(shí):
?
?
>>>?for?i?range(10): ??File?"
再一次,異常消息并沒(méi)有那么有用,但回溯確實(shí)會(huì)嘗試為您指明正確的方向。如果從插入符號(hào)中移回,則可以看到 for 循環(huán)語(yǔ)法中缺少 in 關(guān)鍵字。 您還可以濫用受保護(hù)的 Python 關(guān)鍵字。請(qǐng)記住,關(guān)鍵字只允許在特定情況下使用。如果您錯(cuò)誤地使用它們,那么您的 Python 代碼中將包含無(wú)效的語(yǔ)法。一個(gè)常見(jiàn)的例子是在循環(huán)外使用 continue 或 break。這很容易在開(kāi)發(fā)過(guò)程中發(fā)生,當(dāng)您正在實(shí)現(xiàn)事物并碰巧將邏輯移到循環(huán)之外時(shí):
?
>>>?names?=?['pam',?'jim',?'michael'] >>>?if?'jim'?in?names: ...?????print('jim?found') ...?????break ... ??File?"
在這里,Python 可以很好地告訴您究竟出了什么問(wèn)題。消息“'break' 外循環(huán)”和“'continue' 未正確循環(huán)”可幫助您確定要做什么。如果這段代碼在一個(gè)文件中,那么 Python 也會(huì)有指向誤用關(guān)鍵字的插入符號(hào)。 另一個(gè)示例是,如果您嘗試將 Python 關(guān)鍵字分配給變量或使用關(guān)鍵字來(lái)定義函數(shù):
?
>>>?pass?=?True ??File?"
缺少括號(hào)、方括號(hào)和引號(hào)
通常,Python 代碼中無(wú)效語(yǔ)法的原因是缺少或不匹配的右括號(hào)、方括號(hào)或引號(hào)。這些在很長(zhǎng)的嵌套括號(hào)行或更長(zhǎng)的多行塊中很難發(fā)現(xiàn)。借助 Python 的回溯,您可以發(fā)現(xiàn)不匹配或丟失的引號(hào):
?
?
>>?message?=?'don't' ??File?"
在這里,回溯指向無(wú)效代碼,其中在結(jié)束單引號(hào)之后有一個(gè) t'。要解決此問(wèn)題,您可以進(jìn)行以下兩項(xiàng)更改之一:
① 用反斜杠轉(zhuǎn)義單引號(hào) ('don't');
② 用雙引號(hào)將整個(gè)字符串括起來(lái)("don't");
另一個(gè)常見(jiàn)的錯(cuò)誤是忘記關(guān)閉字符串。對(duì)于雙引號(hào)和單引號(hào)字符串,情況和回溯是相同的:
?
?
>>>?message?=?"This?is?an?unclosed?string ??File?"
錯(cuò)誤的字典語(yǔ)法
您之前看到,如果您將逗號(hào)放在字典元素之外,您可能會(huì)得到 SyntaxError。Python 字典的另一種無(wú)效語(yǔ)法形式是使用等號(hào) (=) 來(lái)分隔鍵和值,而不是使用冒號(hào):
?
?
>>>?ages?=?{'pam'=24} ??File?"
同樣,此錯(cuò)誤消息不是很有幫助。然而,重復(fù)的行和插入符號(hào)非常有幫助!他們直指問(wèn)題人物。
如果您將 Python 語(yǔ)法與其他編程語(yǔ)言的語(yǔ)法混淆,則此類問(wèn)題很常見(jiàn)。如果您將定義字典的行為與 dict() 調(diào)用混淆,您也會(huì)看到這一點(diǎn)。要解決此問(wèn)題,您可以用冒號(hào)替換等號(hào)。您還可以切換到使用 dict():
?
?
>>>?ages?=?dict(pam=24) >>>?ages {'pam':?24}
使用錯(cuò)誤的縮進(jìn)
其他編程語(yǔ)言使用花括號(hào)表示代碼塊,而 Python 使用空格。這意味著 Python 期望代碼中的空白行為可預(yù)測(cè)。如果代碼塊中的一行包含錯(cuò)誤的空格數(shù),它將引發(fā) IndentationError:
?
?
def?foo(): ????for?i?in?range(10): ????????print(i) ??print('done') foo()
這可能很難看到,但第 5 行僅縮進(jìn)了 2 個(gè)空格。應(yīng)該和for循環(huán)語(yǔ)句一致,多4個(gè)空格。值得慶幸的是,Python 可以很容易地發(fā)現(xiàn)這一點(diǎn),并會(huì)很快告訴您問(wèn)題所在。
不過(guò),這里也有一些歧義。print('done') 行是在 for 循環(huán)之后還是在 for 循環(huán)塊內(nèi)?當(dāng)你運(yùn)行上面的代碼時(shí),你會(huì)看到以下錯(cuò)誤:
?
?
File?"indentation.py",?line?5 ????print('done') ????????????????^ IndentationError:?unindent?does?not?match?any?outer?indentation?level
盡管回溯看起來(lái)很像 SyntaxError 回溯,但它實(shí)際上是一個(gè) IndentationError。錯(cuò)誤信息也很有幫助。它告訴您該行的縮進(jìn)級(jí)別與任何其他縮進(jìn)級(jí)別都不匹配。換句話說(shuō),print('done') 被縮進(jìn)了 2 個(gè)空格,但是 Python 找不到任何其他符合這種縮進(jìn)級(jí)別的代碼行。您可以通過(guò)確保代碼與預(yù)期的縮進(jìn)級(jí)別對(duì)齊來(lái)快速解決此問(wèn)題。
定義和調(diào)用函數(shù)
在定義或調(diào)用函數(shù)時(shí),您可能會(huì)在 Python 中遇到無(wú)效語(yǔ)法。例如,如果在函數(shù)定義的末尾使用分號(hào)而不是冒號(hào),則會(huì)看到 SyntaxError:
?
?
>>>?def?fun(); ??File?"
這里的回溯非常有用,插入符號(hào)直接指向問(wèn)題字符。您可以通過(guò)將分號(hào)替換為冒號(hào)來(lái)清除 Python 中的這種無(wú)效語(yǔ)法。
此外,函數(shù)定義和函數(shù)調(diào)用中的關(guān)鍵字參數(shù)都需要按正確的順序排列。關(guān)鍵字參數(shù)總是在位置參數(shù)之后。不使用此順序?qū)?dǎo)致 SyntaxError:
?
?
>>>?def?fun(a,?b): ...?????print(a,?b) ... >>>?fun(a=1,?2) ??File?"
評(píng)論
查看更多