前言
Python以其簡單的語法而聞名。然而瀑焦,當(dāng)您第一次學(xué)習(xí)Python時(shí)腌且,或者當(dāng)您具有另一種編程語言的堅(jiān)實(shí)背景時(shí),您可能會(huì)遇到一些Python不允許的事情榛瓮。如果您在嘗試運(yùn)行Python代碼時(shí)收到過SyntaxError錯(cuò)誤铺董,那么本指南可以幫助您。在本教程中禀晓,您將看到Python中常見的無效語法示例精续,并學(xué)習(xí)如何解決這個(gè)問題。
在本教程結(jié)束時(shí)粹懒,您將能夠:
識(shí)別Python中的無效語法
理解SyntaxError回溯
解析無效語法或完全阻止它
Python中的無效語法
當(dāng)您運(yùn)行Python代碼時(shí)重付,解釋器將首先解析它,將其轉(zhuǎn)換成Python字節(jié)碼凫乖,然后執(zhí)行确垫。解釋器將在程序執(zhí)行的第一階段(也稱為解析階段)中發(fā)現(xiàn)Python中的任何無效語法。如果解釋器不能成功地解析您的Python代碼帽芽,那么這意味著您在代碼的某個(gè)地方使用了無效的語法删掀。解釋器將嘗試向您顯示錯(cuò)誤發(fā)生的位置。
當(dāng)您第一次學(xué)習(xí)Python時(shí)导街,得到一個(gè)SyntaxError可能會(huì)令人沮喪爬迟。Python將嘗試幫助您確定無效語法在代碼中的位置,但是它提供的回溯可能會(huì)讓您感到有些困惑菊匿。有時(shí),它所指向的代碼是完全正確的计福。
您不能像處理其他異常一樣處理Python中的無效語法跌捆。即使您嘗試將try和except塊封裝到帶有無效語法的代碼中,您仍然會(huì)看到解釋器拋出一個(gè)SyntaxError象颖。
SyntaxError異常和回溯
當(dāng)解釋器在Python代碼中遇到無效語法時(shí)佩厚,它將拋出一個(gè)SyntaxError異常,并提供一個(gè)帶有一些有用信息的回溯说订,以幫助您調(diào)試錯(cuò)誤抄瓦。下面是一些Python中包含無效語法的代碼:
您可以在第4行字典的文字中看到無效的語法。第二個(gè)詞條“jim”漏掉了一個(gè)逗號(hào)陶冷。如果你試著按原樣運(yùn)行這段代碼钙姊,你會(huì)得到以下回溯結(jié)果:
注意,traceback消息定位的錯(cuò)誤在第5行埂伦,而不是第4行煞额。Python解釋器試圖指出無效語法的位置。然而,它只能指出它最初注意到的問題膊毁。當(dāng)您獲得一個(gè)SyntaxError traceback胀莹,并且traceback所指向的代碼看起來很好,那么您將希望開始向后移動(dòng)代碼婚温,直到您能夠確定哪里出了問題描焰。
在上面的例子中,根據(jù)后面的內(nèi)容栅螟,省略逗號(hào)是沒有問題的荆秦。例如,第5行“michael”后面缺少逗號(hào)是沒有問題的嵌巷。但是一旦解釋器遇到不理解的東西萄凤,它只能指出它發(fā)現(xiàn)的第一件不理解的事情。
有幾個(gè)元素的SyntaxError回溯搪哪,可以幫助您確定無效的語法在您的代碼:
遇到無效語法的文件名
遇到問題的行號(hào)和代碼的復(fù)寫行
在復(fù)制代碼下面的行中有一個(gè)插入符號(hào)(^)靡努,它向您顯示代碼中有問題的那一點(diǎn)
異常類型SyntaxError之后的錯(cuò)誤消息,可以提供幫助您確定問題的信息
在上面的例子中晓折,給出的文件名是theofficefacts惑朦。行號(hào)為5,插入符號(hào)指向字典鍵michael的結(jié)束引用漓概。SyntaxError回溯可能不會(huì)指向真正的問題漾月,但它將指向解釋器無法理解語法的第一個(gè)地方。
您可能會(huì)看到Python引發(fā)另外兩個(gè)異常胃珍。它們等價(jià)于SyntaxError梁肿,但有不同的名稱:
IndentationError
TabError
這些異常都繼承自SyntaxError類,但它們是涉及縮進(jìn)的特殊情況觅彰。當(dāng)代碼的縮進(jìn)級(jí)別不匹配時(shí)吩蔑,將引發(fā)IndentationError。當(dāng)代碼在同一文件中同時(shí)使用制表符和空格時(shí)填抬,將引發(fā)一個(gè)制表符錯(cuò)誤烛芬。在后面的小節(jié)中,您將進(jìn)一步了解這些異常飒责。
常見的語法問題
當(dāng)您第一次遇到SyntaxError時(shí)赘娄,了解為什么會(huì)出現(xiàn)問題以及如何修復(fù)Python代碼中的無效語法是很有幫助的。在下面的小節(jié)中宏蛉,您將看到可能引發(fā)SyntaxError的一些更常見的原因遣臼,以及如何修復(fù)它們。
1.誤用賦值運(yùn)算符(=)
在Python中有幾種情況下拾并,您不能對對象進(jìn)行賦值暑诸。一些例子是分配文字和函數(shù)調(diào)用蚌讼。在下面的代碼塊中,您可以看到一些嘗試這樣做的示例和由此產(chǎn)生的SyntaxError回溯:
Python作為一門不斷發(fā)展與普及的語言个榕,還在不斷更新中篡石。在學(xué)習(xí)時(shí),建議找一些學(xué)習(xí)伙伴一起來學(xué)習(xí)和討論西采,效果更佳凰萨。如果想學(xué)習(xí)Python,歡迎加入Python學(xué)習(xí)交流群(627012464)械馆,一起督促胖眷,一起學(xué)習(xí)。里面有開發(fā)工具霹崎,很多干貨和技術(shù)資料分享珊搀!
第一個(gè)示例嘗試將值5分配給len()調(diào)用。在這種情況下尾菇,SyntaxError消息非常有用境析。它告訴你不能給函數(shù)調(diào)用賦值。
第二個(gè)和第三個(gè)示例嘗試將字符串和整數(shù)分配給文字派诬。同樣的規(guī)則也適用于其他文字值劳淆。同樣,回溯消息表明默赂,當(dāng)您試圖將一個(gè)值賦給一個(gè)文字時(shí)沛鸵,問題就會(huì)發(fā)生。
很可能你的目的不是給文字或函數(shù)調(diào)用賦值缆八。例如曲掰,如果您不小心省略了額外的等號(hào)(=),就會(huì)發(fā)生這種情況奈辰,這會(huì)將賦值轉(zhuǎn)換為比較栏妖。如下所示,比較是有效的:
大多數(shù)情況下冯挎,當(dāng)Python告訴您正在對無法賦值的東西進(jìn)行賦值時(shí),您首先可能需要檢查以確保語句不應(yīng)該是布爾表達(dá)式咙鞍。當(dāng)您試圖為Python關(guān)鍵字賦值時(shí)房官,也可能遇到這個(gè)問題,下一節(jié)將討論這個(gè)問題续滋。
2.拼寫錯(cuò)誤翰守、缺少或誤用Python關(guān)鍵字
Python關(guān)鍵字是一組在Python中具有特殊含義的受保護(hù)的單詞。這些詞在代碼中不能用作標(biāo)識(shí)符疲酌、變量或函數(shù)名蜡峰。它們是語言的一部分了袁,只能在Python允許的上下文中使用。
有三種常見的方式湿颅,你可以錯(cuò)誤地使用關(guān)鍵字:
1.拼錯(cuò)的關(guān)鍵字
2.缺少一個(gè)關(guān)鍵字
3.濫用關(guān)鍵字
如果您在Python代碼中拼錯(cuò)了關(guān)鍵字载绿,那么您將得到一個(gè)SyntaxError。例如油航,如果你把關(guān)鍵字拼錯(cuò)了崭庸,會(huì)發(fā)生以下情況:
消息將讀取SyntaxError:無效語法,但這沒有多大幫助谊囚∨孪恚回溯指向Python可以檢測到錯(cuò)誤的第一個(gè)地方。要修復(fù)這類錯(cuò)誤镰踏,請確保所有Python關(guān)鍵字拼寫正確函筋。
另一個(gè)關(guān)于關(guān)鍵字的常見問題是你完全忽略了它們:
同樣,異常消息也不是很有用奠伪,但是回溯確實(shí)試圖為您指出正確的方向跌帐。如果從插入符號(hào)返回,則可以看到for循環(huán)語法中缺少關(guān)鍵字in芳来。
您還可能誤用受保護(hù)的Python關(guān)鍵字含末。記住,關(guān)鍵字只允許在特定的情況下使用即舌。如果您不正確地使用它們佣盒,那么您的Python代碼中就會(huì)出現(xiàn)無效的語法。一個(gè)常見的例子是在循環(huán)外使用continue或break顽聂。這在開發(fā)過程中很容易發(fā)生肥惭,當(dāng)你在實(shí)現(xiàn)一些東西的時(shí)候,碰巧把邏輯移出了一個(gè)循環(huán):
在這里紊搪,Python很好地告訴了您到底哪里出了問題蜜葱。"'break' outside loop"和" continue' not exactly in loop"這兩個(gè)信息可以幫助你明確地知道該怎么做。如果這段代碼在一個(gè)文件中耀石,那么Python也會(huì)讓插入符號(hào)指向被誤用的關(guān)鍵字牵囤。
另一個(gè)例子是,如果你嘗試給一個(gè)變量分配一個(gè)Python關(guān)鍵字滞伟,或者使用一個(gè)關(guān)鍵字來定義一個(gè)函數(shù):
當(dāng)您試圖為pass分配一個(gè)值時(shí)揭鳞,或者當(dāng)您試圖定義一個(gè)名為pass的新函數(shù)時(shí),您將得到一個(gè)SyntaxError并再次看到“無效語法”消息梆奈。
在Python代碼中解決這種類型的無效語法可能會(huì)稍微困難一些野崇,因?yàn)榇a從外部看起來沒什么問題。如果您的代碼看起來不錯(cuò)亩钟,但是您仍然會(huì)得到一個(gè)SyntaxError乓梨,那么您可以考慮檢查您想要使用的變量名或函數(shù)名與您正在使用的Python版本的關(guān)鍵字列表鳖轰。
受保護(hù)的關(guān)鍵字列表隨著Python的每個(gè)新版本而改變。例如扶镀,在Python 3.6中蕴侣,您可以使用await作為變量名或函數(shù)名,但是在Python 3.7中狈惫,這個(gè)單詞已經(jīng)被添加到關(guān)鍵字列表中【χ耄現(xiàn)在,如果您嘗試使用await作為變量名或函數(shù)名胧谈,如果您的代碼是Python 3.7或更高版本忆肾,那么這將導(dǎo)致SyntaxError。
另一個(gè)例子是print菱肖,它在python2和python3中有所不同:
print是python2中的一個(gè)關(guān)鍵字客冈,所以你不能給它賦值。然而稳强,在python3中场仲,它是一個(gè)可以賦值的內(nèi)置函數(shù)。
你可以運(yùn)行以下代碼來查看關(guān)鍵字列表退疫,無論你運(yùn)行的Python版本是什么:
keyword還提供了有用的keyword.iskeyword()渠缕。如果你只是需要一個(gè)快速的方法來檢查通過變量,那么你可以使用以下一行:
這段代碼將快速告訴您要使用的標(biāo)識(shí)符是否是關(guān)鍵字褒繁。
3.缺少括號(hào)亦鳞、方括號(hào)和引號(hào)
通常,Python代碼中無效語法的原因是缺少或不匹配的右括號(hào)棒坏、方括號(hào)或引號(hào)燕差。在嵌套圓括號(hào)的很長行或更長的多行塊中很難發(fā)現(xiàn)這些充岛。你可以通過Python的回溯來發(fā)現(xiàn)不匹配或缺失的引用:
這里弓乙,回溯指向無效代碼棍现,其中在結(jié)束單引號(hào)后有一個(gè)t'敬矩。要解決這個(gè)問題,您可以進(jìn)行以下兩種更改之一:
1.用反斜杠轉(zhuǎn)義單引號(hào)('don\t')
2.將整個(gè)字符串用雙引號(hào)括起來(“don't”)
另一個(gè)常見的錯(cuò)誤是忘記關(guān)閉字符串拴念。對于雙引號(hào)和單引號(hào)字符串宠漩,情況和回溯是相同的:
這一次蚂踊,traceback中的插入符號(hào)指向問題代碼磨澡。SyntaxError消息“在掃描字符串文字時(shí)的EOL”更具體一些碗啄,有助于確定問題。這意味著Python解釋器在一個(gè)開放字符串關(guān)閉之前到達(dá)該行(EOL)的末尾钱贯。要解決這個(gè)問題挫掏,請使用與開始時(shí)匹配的引號(hào)關(guān)閉字符串侦另。在本例中秩命,將使用雙引號(hào)(")尉共。
在f-string語句中缺少引號(hào)也會(huì)導(dǎo)致Python中無效的語法:
這里,打印的f-string中對ages字典的引用缺少關(guān)鍵引用的雙引號(hào)弃锐。得到的回溯結(jié)果如下:
Python識(shí)別問題并告訴您它存在于f-string中袄友。消息“未終止字符串”也指出了問題所在。本例中的插入符號(hào)僅指向f-string的開頭霹菊。
當(dāng)插入符號(hào)指向f-string的問題區(qū)域時(shí)剧蚣,這可能沒有那么有用,但是它確實(shí)縮小了您需要查找的范圍旋廷。在那個(gè)f字串的某個(gè)地方有一個(gè)未終止的字符串鸠按。你只需要找到在哪里。要修復(fù)此問題饶碘,請確保所有內(nèi)部f-string引號(hào)和方括號(hào)都已存在目尖。
缺少括號(hào)和方括號(hào)的情況大致相同。例如扎运,如果您從列表中刪除了右方括號(hào)瑟曲,那么Python將會(huì)發(fā)現(xiàn)并指出它。然而豪治,這有一些變化洞拨。第一種是把列表中的右括號(hào)去掉:
當(dāng)你運(yùn)行這段代碼時(shí),你會(huì)被告知調(diào)用print()有一個(gè)問題:
這里發(fā)生的是Python認(rèn)為列表包含三個(gè)元素:1负拟、2和3 print(foo())烦衣。Python使用空格從邏輯上對事物進(jìn)行分組,因?yàn)閺膒rint(foo())中沒有逗號(hào)或括號(hào)分隔3齿椅,所以Python將它們集中在一起作為列表的第三個(gè)元素琉挖。
另一種變化是在列表的最后一個(gè)元素后面添加一個(gè)逗號(hào),同時(shí)仍然去掉右方括號(hào):
現(xiàn)在你得到了一個(gè)不同的回溯:
在前面的例子中涣脚,3和print(foo())被集中在一起作為一個(gè)元素示辈,但是在這里你可以看到一個(gè)逗號(hào)將兩者分開。現(xiàn)在遣蚀,print(foo())的調(diào)用被添加為列表的第四個(gè)元素矾麻,Python到達(dá)了文件的末尾,但沒有使用右括號(hào)芭梯∠找回溯告訴您,Python已經(jīng)到達(dá)了文件(EOF)的末尾玖喘,但是它還在期待其他內(nèi)容甩牺。
在本例中,Python希望有一個(gè)右括號(hào)(])累奈,但是重復(fù)的行和插入符號(hào)沒有多大幫助贬派。缺少括號(hào)和方括號(hào)是Python很難識(shí)別的急但。有時(shí),您唯一能做的就是從插入符號(hào)開始搞乏,然后向后移動(dòng)波桩,直到您能夠識(shí)別出缺失或錯(cuò)誤的地方。
結(jié)論
在本教程中请敦,您已經(jīng)看到了SyntaxError回溯所提供的信息镐躲。您還看到了Python中許多常見的無效語法示例,以及這些問題的解決方案侍筛。這不僅會(huì)加快你的工作流程萤皂,而且還會(huì)使你成為一個(gè)更有幫助的代碼審查者!
在編寫代碼時(shí),請嘗試使用能夠理解Python語法并提供反饋的IDE匣椰。如果您將本教程中的許多無效Python代碼示例放到一個(gè)良好的IDE中敌蚜,那么它們應(yīng)該在您執(zhí)行代碼之前突出顯示問題行。
在學(xué)習(xí)Python時(shí)獲得一個(gè)SyntaxError可能會(huì)令人沮喪窝爪,但是現(xiàn)在您知道了如何理解回溯消息以及在Python中可能遇到的無效語法形式弛车。下一次出現(xiàn)SyntaxError時(shí),您就可以更好地快速修復(fù)這個(gè)問題了!