
Python程序員開發(fā)中常犯的10個(gè)錯(cuò)誤
Python是一門簡單易學(xué)的編程語言,語法簡潔而清晰,并且擁有豐富和強(qiáng)大的類庫。與其它大多數(shù)程序設(shè)計(jì)語言使用大括號不一樣 ,它使用縮進(jìn)來定義語句塊。
在平時(shí)的工作中,Python開發(fā)者很容易犯一些小錯(cuò)誤,這些錯(cuò)誤都很容易避免,本文總結(jié)了Python開發(fā)者最常犯的10個(gè)錯(cuò)誤,一起來看下,不知你中槍了沒有。
1.濫用表達(dá)式作為函數(shù)參數(shù)默認(rèn)值
Python允許開發(fā)者指定一個(gè)默認(rèn)值給函數(shù)參數(shù),雖然這是該語言的一個(gè)特征,但當(dāng)參數(shù)可變時(shí),很容易導(dǎo)致混亂,例如,下面這段函數(shù)定義:
在上面這段代碼里,一旦重復(fù)調(diào)用foo()函數(shù)(沒有指定一個(gè)bar參數(shù)),那么將一直返回'bar',因?yàn)闆]有指定參數(shù),那么foo()每次被調(diào)用的時(shí)候,都會賦予[]。下面來看看,這樣做的結(jié)果:
解決方案:
2.錯(cuò)誤地使用類變量
先看下面這個(gè)例子:
這樣是有意義的:
再來一遍:
僅僅是改變了A.x,為什么C.x也跟著改變了。
在Python中,類變量都是作為字典進(jìn)行內(nèi)部處理的,并且遵循方法解析順序(MRO)。在上面這段代碼中,因?yàn)閷傩詘沒有在類C中發(fā)現(xiàn),它會查找它的基類(在上面例子中只有A,盡管Python支持多繼承)。換句話說,就是C自己沒有x屬性,獨(dú)立于A,因此,引用 C.x其實(shí)就是引用A.x。
3.為異常指定不正確的參數(shù)
假設(shè)代碼中有如下代碼:
問題在這里,except語句并不需要這種方式來指定異常列表。然而,在Python 2.x中,except Exception,e通常是用來綁定異常里的 第二參數(shù),好讓其進(jìn)行更進(jìn)一步的檢查。因此,在上面這段代碼里,IndexError異常并沒有被except語句捕獲,異常最后被綁定 到了一個(gè)名叫IndexError的參數(shù)上。
在一個(gè)異常語句里捕獲多個(gè)異常的正確方法是指定第一個(gè)參數(shù)作為一個(gè)元組,該元組包含所有被捕獲的異常。與此同時(shí),使用as關(guān)鍵字來保證最大的可移植性,Python 2和Python 3都支持該語法。
4.誤解Python規(guī)則范圍
Python的作用域解析是基于LEGB規(guī)則,分別是Local、Enclosing、Global、Built-in。實(shí)際上,這種解析方法也有一些玄機(jī),看下面這個(gè)例子:
許多人會感動(dòng)驚訝,當(dāng)他們在工作的函數(shù)體里添加一個(gè)參數(shù)語句,會在先前工作的代碼里報(bào)UnboundLocalError錯(cuò)誤( 點(diǎn)擊這里查看更詳細(xì)描述)。
在使用列表時(shí),開發(fā)者是很容易犯這種錯(cuò)誤的,看看下面這個(gè)例子:
>>> lst = [1, 2, 3]
>>> def foo2():
... lst += [5] # ... but this bombs!
...
>>> foo2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'lst' referenced before assignment
為什么foo2失敗而foo1運(yùn)行正常?
答案與前面那個(gè)例子是一樣的,但又有一些微妙之處。foo1沒有賦值給lst,而foo2賦值了。lst += [5]實(shí)際上就是lst = lst + [5],試圖給lst賦值(因此,假設(shè)Python是在局部作用域里)。然而,我們正在尋找指定給lst的值是基于lst本身,其實(shí)尚未確定。
5.修改遍歷列表
下面這段代碼很明顯是錯(cuò)誤的:
在遍歷的時(shí)候,對列表進(jìn)行刪除操作,這是很低級的錯(cuò)誤。稍微有點(diǎn)經(jīng)驗(yàn)的人都不會犯。
對上面的代碼進(jìn)行修改,正確地執(zhí)行:
6.如何在閉包中綁定變量
看下面這個(gè)例子:
你期望的結(jié)果是:
實(shí)際上:
是不是非常吃驚!出現(xiàn)這種情況主要是因?yàn)镻ython的后期綁定行為,該變量在閉包中使用的同時(shí),內(nèi)部函數(shù)又在調(diào)用它。
解決方案:
7.創(chuàng)建循環(huán)模塊依賴關(guān)系
假設(shè)有兩個(gè)文件,a.py和b.py,然后各自導(dǎo)入,如下:
在a.py中:
def f():
return b.x
print f()
在b.py中
x = 1
def g():
print a.f()
首先,讓我們試著導(dǎo)入a.py
可以很好地工作,也許你會感到驚訝。畢竟,我們確實(shí)在這里做了一個(gè)循環(huán)導(dǎo)入,難道不應(yīng)該有點(diǎn)問題嗎?
僅僅存在一個(gè)循環(huán)導(dǎo)入并不是Python本身問題,如果一個(gè)模塊被導(dǎo)入,Python就不會試圖重新導(dǎo)入。根據(jù)這一點(diǎn),每個(gè)模塊在試圖訪問函數(shù)或變量時(shí),可能會在運(yùn)行時(shí)遇到些問題。
當(dāng)我們試圖導(dǎo)入b.py會發(fā)生什么(先前沒有導(dǎo)入a.py):
出錯(cuò)了,這里的問題是,在導(dǎo)入b.py的過程中還要試圖導(dǎo)入a.py,這樣就要調(diào)用f(),并且試圖訪問b.x。但是b.x并未被定義。
可以這樣解決,僅僅修改b.py導(dǎo)入到a.py中的g()函數(shù):
無論何時(shí)導(dǎo)入,一切都可以正常運(yùn)行:
8.與Python標(biāo)準(zhǔn)庫模塊名稱沖突
Python擁有非常豐富的模塊庫,并且支持“開箱即用”。因此,如果不刻意避免,很容易發(fā)生命名沖突事件。例如,在你的代碼中可能有一個(gè)email.py的模塊,由于名稱一致,它很有可能與Python自帶的標(biāo)準(zhǔn)庫模塊發(fā)生沖突。
9.未按規(guī)定處理Python2.x和Python3.x之間的區(qū)別
看一下foo.py:
def bar(i):
if i == 1:
raise KeyError(1)
if i == 2:
raise ValueError(2)
def bad():
e = None
try:
bar(int(sys.argv[1]))
except KeyError as e:
print('key error')
except ValueError as e:
print('value error')
print(e)
bad()
在Python 2里面可以很好地運(yùn)行:
但是在Python 3里:
解決方案:
def bar(i):
if i == 1:
raise KeyError(1)
if i == 2:
raise ValueError(2)
def good():
exception = None
try:
bar(int(sys.argv[1]))
except KeyError as e:
exception = e
print('key error')
except ValueError as e:
exception = e
print('value error')
print(exception)
good()
在Py3k中運(yùn)行結(jié)果:
在 Python招聘指南里有許多關(guān)于Python 2與Python 3在移植代碼時(shí)需要關(guān)注的注意事項(xiàng)與討論,大家可以前往看看。
10.濫用__del__方法
比如這里有一個(gè)叫mod.py的文件:
下面,你在another_mod.py文件里執(zhí)行如下操作:
你會獲得一個(gè)AttributeError異常。
至于為什么會出現(xiàn)該異常,點(diǎn)擊這里查看詳情。當(dāng)解釋器關(guān)閉時(shí),該模塊的全局變量全部設(shè)置為None。因此,在上面這個(gè)例子里,當(dāng)__del__被調(diào)用時(shí),foo已經(jīng)全部被設(shè)置為None。
一個(gè)很好的解決辦法是使用atexit.register()代替。順便說一句,當(dāng)程序執(zhí)行完成后,您注冊的處理程序會在解釋器關(guān)閉之前停止 工作。
修復(fù)上面問題的代碼:
def cleanup(handle):
foo.cleanup(handle)
class Bar(object):
def __init__(self):
...
atexit.register(cleanup, self.myhandle)
在程序的正常終止的前提下,這個(gè)實(shí)現(xiàn)提供了一個(gè)整潔可靠的方式調(diào)用任何需要清理的功能。
總結(jié)
Python是一款強(qiáng)大而靈活的編程語言,并且?guī)в性S多機(jī)制和模式來大大提高工作效率。正如任何一門語言或軟件工具一樣,人們對其能力都會存在一個(gè)限制性地理解或欣賞,有些是弊大于利,有些時(shí)候反而會帶來一些陷進(jìn)。 體會一名語言的細(xì)微之處,理解一些常見的陷阱,有助于你在開發(fā)者的道路上走的更遠(yuǎn)。
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
用 SQL 生成逆向回滾 SQL:數(shù)據(jù)操作的 “后悔藥” 指南? 在數(shù)據(jù)庫操作中,誤刪數(shù)據(jù)、錯(cuò)改字段或誤執(zhí)行批量更新等問題時(shí)有發(fā)生。 ...
2025-07-14如何考取數(shù)據(jù)分析師證書:以 CDA 為例? ? 在數(shù)字化浪潮席卷各行各業(yè)的當(dāng)下,數(shù)據(jù)分析師已然成為企業(yè)挖掘數(shù)據(jù)價(jià)值、驅(qū)動(dòng)決策的 ...
2025-07-14t檢驗(yàn)與Wilcoxon檢驗(yàn)的選擇:何時(shí)用t.test,何時(shí)用wilcox.test? t 檢驗(yàn)與 Wilcoxon 檢驗(yàn)的選擇:何時(shí)用 t.test,何時(shí)用 wilcox. ...
2025-07-14AI 浪潮下的生存與進(jìn)階: CDA數(shù)據(jù)分析師—開啟新時(shí)代職業(yè)生涯的鑰匙(深度研究報(bào)告、發(fā)展指導(dǎo)白皮書) 發(fā)布機(jī)構(gòu):CDA數(shù)據(jù)科 ...
2025-07-13LSTM 模型輸入長度選擇技巧:提升序列建模效能的關(guān)鍵? 在循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)家族中,長短期記憶網(wǎng)絡(luò)(LSTM)憑借其解決長序列 ...
2025-07-11CDA 數(shù)據(jù)分析師報(bào)考條件詳解與準(zhǔn)備指南? ? 在數(shù)據(jù)驅(qū)動(dòng)決策的時(shí)代浪潮下,CDA 數(shù)據(jù)分析師認(rèn)證愈發(fā)受到矚目,成為眾多有志投身數(shù) ...
2025-07-11數(shù)據(jù)透視表中兩列相乘合計(jì)的實(shí)用指南? 在數(shù)據(jù)分析的日常工作中,數(shù)據(jù)透視表憑借其強(qiáng)大的數(shù)據(jù)匯總和分析功能,成為了 Excel 用戶 ...
2025-07-11尊敬的考生: 您好! 我們誠摯通知您,CDA Level I和 Level II考試大綱將于 2025年7月25日 實(shí)施重大更新。 此次更新旨在確保認(rèn) ...
2025-07-10BI 大數(shù)據(jù)分析師:連接數(shù)據(jù)與業(yè)務(wù)的價(jià)值轉(zhuǎn)化者? ? 在大數(shù)據(jù)與商業(yè)智能(Business Intelligence,簡稱 BI)深度融合的時(shí)代,BI ...
2025-07-10SQL 在預(yù)測分析中的應(yīng)用:從數(shù)據(jù)查詢到趨勢預(yù)判? ? 在數(shù)據(jù)驅(qū)動(dòng)決策的時(shí)代,預(yù)測分析作為挖掘數(shù)據(jù)潛在價(jià)值的核心手段,正被廣泛 ...
2025-07-10數(shù)據(jù)查詢結(jié)束后:分析師的收尾工作與價(jià)值深化? ? 在數(shù)據(jù)分析的全流程中,“query end”(查詢結(jié)束)并非工作的終點(diǎn),而是將數(shù) ...
2025-07-10CDA 數(shù)據(jù)分析師考試:從報(bào)考到取證的全攻略? 在數(shù)字經(jīng)濟(jì)蓬勃發(fā)展的今天,數(shù)據(jù)分析師已成為各行業(yè)爭搶的核心人才,而 CDA(Certi ...
2025-07-09【CDA干貨】單樣本趨勢性檢驗(yàn):捕捉數(shù)據(jù)背后的時(shí)間軌跡? 在數(shù)據(jù)分析的版圖中,單樣本趨勢性檢驗(yàn)如同一位耐心的偵探,專注于從單 ...
2025-07-09year_month數(shù)據(jù)類型:時(shí)間維度的精準(zhǔn)切片? ? 在數(shù)據(jù)的世界里,時(shí)間是最不可或缺的維度之一,而year_month數(shù)據(jù)類型就像一把精準(zhǔn) ...
2025-07-09CDA 備考干貨:Python 在數(shù)據(jù)分析中的核心應(yīng)用與實(shí)戰(zhàn)技巧? ? 在 CDA 數(shù)據(jù)分析師認(rèn)證考試中,Python 作為數(shù)據(jù)處理與分析的核心 ...
2025-07-08SPSS 中的 Mann-Kendall 檢驗(yàn):數(shù)據(jù)趨勢與突變分析的有力工具? ? ? 在數(shù)據(jù)分析的廣袤領(lǐng)域中,準(zhǔn)確捕捉數(shù)據(jù)的趨勢變化以及識別 ...
2025-07-08備戰(zhàn) CDA 數(shù)據(jù)分析師考試:需要多久?如何規(guī)劃? CDA(Certified Data Analyst)數(shù)據(jù)分析師認(rèn)證作為國內(nèi)權(quán)威的數(shù)據(jù)分析能力認(rèn)證 ...
2025-07-08LSTM 輸出不確定的成因、影響與應(yīng)對策略? 長短期記憶網(wǎng)絡(luò)(LSTM)作為循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)的一種變體,憑借獨(dú)特的門控機(jī)制,在 ...
2025-07-07統(tǒng)計(jì)學(xué)方法在市場調(diào)研數(shù)據(jù)中的深度應(yīng)用? 市場調(diào)研是企業(yè)洞察市場動(dòng)態(tài)、了解消費(fèi)者需求的重要途徑,而統(tǒng)計(jì)學(xué)方法則是市場調(diào)研數(shù) ...
2025-07-07CDA數(shù)據(jù)分析師證書考試全攻略? 在數(shù)字化浪潮席卷全球的當(dāng)下,數(shù)據(jù)已成為企業(yè)決策、行業(yè)發(fā)展的核心驅(qū)動(dòng)力,數(shù)據(jù)分析師也因此成為 ...
2025-07-07