這些常見(jiàn)的坑供搀,90%的程序猿都踩過(guò),來(lái)看看里面有沒(méi)有你的腳幽浦痢葛虐?

在學(xué)習(xí)python的過(guò)程中,相信大家都有踩過(guò)不少的坑棉钧,有些坑可能踩了不止一次屿脐,感覺(jué)就像是在坑與坑之間反復(fù)橫跳。那么如何避免這些坑呢宪卿?看完這篇文章的诵,你就知道了。我們來(lái)談?wù)勎覀?b>學(xué)習(xí)python的過(guò)程中佑钾,最常見(jiàn)的七大坑:

1. 縮進(jìn)奢驯,符號(hào)和空格不正確

寫(xiě)代碼時(shí)大家會(huì)使用縮進(jìn)、對(duì)齊次绘、空格等瘪阁,這些是為了提高代碼的可讀性

在python語(yǔ)言中撒遣,縮進(jìn)是十分重要的

比如在創(chuàng)建一個(gè)新類(lèi)時(shí),該類(lèi)中的所有內(nèi)容都在聲明下縮進(jìn)管跺,決策义黎、循環(huán)還有其它結(jié)構(gòu)語(yǔ)句也會(huì)出現(xiàn)類(lèi)似的情況,

代碼執(zhí)行時(shí)如果存在問(wèn)題豁跑,可以先查看一下縮進(jìn)是否正確廉涕。

這邊有個(gè)例子,在使用IF語(yǔ)句時(shí)艇拍,請(qǐng)確保使用正確且合適的冒號(hào)和縮進(jìn)狐蜕,因?yàn)樗鼈儠?huì)導(dǎo)致語(yǔ)法和縮進(jìn)錯(cuò)誤。

val = 500

if val > 100

print(“value is grater then 100”)

File “”, line 2

if val > 100

^

SyntaxError: invalid syntax

在上面的代碼當(dāng)中卸夕,出現(xiàn)了兩處錯(cuò)誤:if語(yǔ)句后面的:缺失层释;下一行沒(méi)有進(jìn)行正確的縮進(jìn),執(zhí)行代碼出錯(cuò)快集。

val = 500

if val > 100:

print(“value is grater then 100”)

value is grater then 100

更正這兩個(gè)問(wèn)題之后贡羔,代碼可以很好的運(yùn)行

2. 變量使用不正確

class A(object):x = 1

class B(A):pass

class C(A):pass

print( A.x, B.x, C.x)

1 1 1

這里輸出的值都是1,然后我們?cè)囍鴣?lái)改變一下A.x和B.x的值看看有什么變化个初。

B.x = 2

print (A.x, B.x, C.x)

A.x = 3

print (A.x, B.x, C.x)

1 2 1

3 2 3

我們只改變了A.x,為什么C.x改變呢乖寒?

這里需要了解到python的命名空間。

python中院溺,命名空間是名字到對(duì)象映射的結(jié)合楣嘁,不同命名空間中的名字是沒(méi)有關(guān)聯(lián)的,這種映射的實(shí)現(xiàn)有點(diǎn)類(lèi)似于python中的字典珍逸。

當(dāng)你名字訪問(wèn)一個(gè)對(duì)象的屬性時(shí)马澈,先從對(duì)象的命名空間尋找。如果找到了這個(gè)屬性弄息,就返回這個(gè)屬性的值痊班;如果沒(méi)有找到的話,則從類(lèi)的命名空間中尋找摹量,找到了就返回這個(gè)屬性的值涤伐,找不到則拋出異常。

在Python中缨称,類(lèi)變量在內(nèi)部作為字典處理凝果,并遵循通常稱(chēng)為方法解析順序(MRO)的方法。

MRO:Method Resolution Order方法解析順序睦尽,Python支持多繼承器净,該方法用于解決父類(lèi)存在同名函數(shù)的時(shí)存在的二義性問(wèn)題。

因此在上面的代碼中当凡,由于x在對(duì)象的命名空間中找不到該屬性C山害,因此將在類(lèi)中查找它纠俭。換句話說(shuō),C沒(méi)有自己的x屬性浪慌,獨(dú)立于A冤荆。因此,引用C.x實(shí)際上是指A.x权纤。

3.不了解python范圍規(guī)則

倘若不知道python的范圍規(guī)則钓简,那么犯錯(cuò)誤的可能性會(huì)大大增加,這是因?yàn)镻ython使用一種獨(dú)有的范圍規(guī)則來(lái)確定變量范圍汹想。

python范圍解析是基于LEGB規(guī)則外邓,以下是Python范圍規(guī)則的概述:

·L -代表Local。它包含在函數(shù)內(nèi)指定的(標(biāo)識(shí)符/變量)名稱(chēng)(使用def或lambda)古掏,而不是使用global關(guān)鍵字聲明损话。

·E -代表Enclosing function locals。它包含來(lái)自任何/所有封閉函數(shù)的本地范圍的名稱(chēng)(例如冗茸,使用def或lambda)。

·G -指全球?qū)嶓w匹中。它包括在模塊文件的頂層運(yùn)行或使用global關(guān)鍵字定義的名稱(chēng)夏漱。

·B -指內(nèi)置插件。它跨越預(yù)先指定為內(nèi)置名稱(chēng)的名稱(chēng)顶捷,如打印挂绰,輸入,打開(kāi)等服赎。

LEGB規(guī)則指定名稱(chēng)空間的以下順序葵蒂,用于搜索名稱(chēng):

Local - > Enclosed - > Global - > Built-in

考慮以下的例子:

x = 10

def foo():

x += 1

print(x)

foo()

UnboundLocalError Traceback (most recent call last):

in

in foo()

UnboundLocalError: local variable xreferenced before assignment

發(fā)生上述錯(cuò)誤的原因是,對(duì)作用域中的變量進(jìn)行賦值時(shí)重虑,Python會(huì)自動(dòng)將該變量視為該作用域的本地變量践付,并在外部作用域中隱藏任何類(lèi)似命名的變量。

因此缺厉,許多人在代碼提示出錯(cuò)并顯示需要在函數(shù)中添加賦值語(yǔ)句而感到不解永高。

考慮一個(gè)在使用列表時(shí)遇到的例子:

lst = [1, 2, 3]

def foo1():

lst.append(5)

foo1()

lst

[1, 2, 3, 5]

lst = [1, 2, 3]

def foo2():

lst += [5]

foo2()

UnboundLocalError ?Traceback (most recent call last):

in

in foo2()

UnboundLocalError: local variable lstreferenced before assignment

為什么foo2出錯(cuò)了但是foo1運(yùn)行良好?

答案在前面就已經(jīng)有所提示提针,在這個(gè)例子當(dāng)中foo1()做一個(gè)分配到lst命爬,而在foo2()當(dāng)中l(wèi)st += [5]其實(shí)只是lst = lst + [5]的簡(jiǎn)寫(xiě),我們希望分配一個(gè)值給lst辐脖,但是分配的值lst是基于lst自身饲宛,但其尚未定義。

4. python閉包變量綁定

python的閉包變量問(wèn)題也是新手們?nèi)菀谆煜囊粋€(gè)點(diǎn)嗜价,來(lái)看看下面的例子:

def create_multipliers():

return [lambda x : i * x for i in range(5)]

for multiplier in create_multipliers():

print (multiplier(2))

8

8

8

8

8

為什么結(jié)果是88888艇抠,和我所想的02468不一樣呢幕庐?

這是由于Python的遲綁定(late binding)機(jī)制,閉包中內(nèi)部函數(shù)的值只有在被調(diào)用時(shí)才會(huì)進(jìn)行查詢练链。

因此create_multipliers函數(shù)返回的lambda函數(shù)被調(diào)用時(shí)翔脱,會(huì)在附近的作用域中查詢變量i的值,而在create_multipliers生成返回?cái)?shù)組之后媒鼓,整數(shù)i的值是4届吁,不會(huì)再改變,因此返回?cái)?shù)組中每個(gè)匿名函數(shù)實(shí)際上都是:lambda x: 4*x绿鸣。疚沐、

解決辦法是將臨時(shí)值也保存在匿名函數(shù)的作用域內(nèi),在聲明匿名函數(shù)時(shí)就查詢變量的值潮模。

了解原理之后亮蛔,讓我們來(lái)改一改代碼,surprise擎厢!

def create_multipliers():

return [lambda x, i=i : i * x for i in range(5)]

for multiplier in create_multipliers():

print (multiplier(2))

0

2

4

6

8

5. 名稱(chēng)與Python標(biāo)準(zhǔn)庫(kù)模塊發(fā)生沖突

Python擁有大量的庫(kù)模塊究流,開(kāi)箱即用。但是动遭,如果您遇到一個(gè)模塊的名稱(chēng)與Python附帶的標(biāo)準(zhǔn)庫(kù)中具有相同名稱(chēng)的模塊之間的名稱(chēng)沖突芬探,則可能會(huì)出現(xiàn)問(wèn)題。

例如導(dǎo)入另一個(gè)庫(kù)厘惦,而這個(gè)庫(kù)又會(huì)嘗試導(dǎo)入模塊的Python標(biāo)準(zhǔn)庫(kù)版本偷仿,但由于你有一個(gè)同名的模塊,另一個(gè)包會(huì)錯(cuò)誤地導(dǎo)入你的版本而不是Python標(biāo)準(zhǔn)庫(kù)宵蕉。

因此酝静,應(yīng)該注意避免使用與Python標(biāo)準(zhǔn)庫(kù)模塊中相同的名稱(chēng),并且更改包中的模塊名稱(chēng)比提交Python Enhancement Proposal(PEP)以請(qǐng)求名稱(chēng)更改更容易羡玛。

6.is和==/=和==

Python中有很多運(yùn)算符别智,例如is,=稼稿,==這三個(gè)亿遂,許多剛剛?cè)腴T(mén)的新手會(huì)誤解這三個(gè)運(yùn)算符的意義和用法,以致于代碼出錯(cuò)渺杉。

在 Python 中會(huì)用到對(duì)象之間比較蛇数,可以用 ==,也可以用 is是越,但對(duì)對(duì)象比較判斷的內(nèi)容并不相同耳舅,區(qū)別在哪里?

·is 比較兩個(gè)對(duì)象的 id 值是否相等,是否指向同一個(gè)內(nèi)存地址浦徊,== 比較的是兩個(gè)對(duì)象的內(nèi)容是否相等馏予,值是否相等;

a = [“Python”]

b = a

b is a

True

id(a)

2222222

id(b)

2222222

b == a

True

可以發(fā)現(xiàn)上面的例子當(dāng)中b和a的內(nèi)存地址是相同的盔性,它們指向同一塊內(nèi)存霞丧,因而 is 和 == 的結(jié)果都為T(mén)rue,這是因?yàn)橹苯淤x值都是賦值的引用。如果新建對(duì)象之后冕香,b 和 a 指向了不同的內(nèi)存蛹尝,那么 b is a 的結(jié)果為False,而 b==a的結(jié)果為T(mén)rue悉尾。

·小整數(shù)對(duì)象[-5,256]在全局解釋器范圍內(nèi)被放入緩存供重復(fù)使用突那,例如:

a = 1

b = 1

a is b

True

a == b

True

a = 257

b = 257

a is b

False

Python僅僅對(duì)比較小的整數(shù)對(duì)象進(jìn)行緩存(范圍為范圍[-5, 256])緩存起來(lái),而并非是所有整數(shù)對(duì)象构眯。需要注意的是愕难,這僅僅是在命令行中執(zhí)行,而在Pycharm或者保存為文件執(zhí)行惫霸,結(jié)果是不一樣的猫缭,這是因?yàn)榻忉屍髯隽艘徊糠謨?yōu)化。

=和==的含義不同:

=代表的含義是賦值壹店,將某一數(shù)值賦給某個(gè)變量猜丹,比如a=3,將3這個(gè)數(shù)值賦予給a茫打。

==是判斷是否相等居触,返回True或False妖混,比如1==1老赤。他們是相等的,那么就返回true制市。1==2抬旺,他們是不相等的,那么就返回false祥楣。

例子:

a = [1,2]

b = [1,2]

c = a

a is b

False

a is c

true

a == b

true

7. 濫用__init__

init__方法在Python中用作構(gòu)造函數(shù)开财,當(dāng)Python將內(nèi)存分配給新的類(lèi)對(duì)象時(shí),它會(huì)自動(dòng)被調(diào)用误褪。

首先责鳍,init__并不相當(dāng)于C#中的構(gòu)造函數(shù),在執(zhí)行它的時(shí)候兽间,實(shí)例已經(jīng)構(gòu)造出來(lái)历葛。

class A(object):

def?init(self,name):

self.name=name

def getName(self):

return A+self.name

執(zhí)行代碼:

a=A(hello)

可以理解為:

a=object.new(A)

A.init(a,hello)

即__init__作用是初始化已實(shí)例化后的對(duì)象。

其次嘀略,子類(lèi)可以不重寫(xiě)__init恤溶,實(shí)例化子類(lèi)時(shí)乓诽,會(huì)自動(dòng)調(diào)用超類(lèi)中已定義的__init

class B(A):

def getName(self):

return B+self.name

if?name==main:

b=B(hello)

print (b.getName())

但如果重寫(xiě)了__init__咒程,實(shí)例化子類(lèi)時(shí)鸠天,則不會(huì)隱式的再去調(diào)用超類(lèi)中已定義的__init__。

class C(A):

def?init(self):

pass

def getName(self):

return C+self.name

if?name==main:

c=C()

print (c.getName())

此時(shí)執(zhí)行代碼則會(huì)報(bào)"AttributeError: ?C ?object has noattribute ?name ”錯(cuò)誤帐姻,所以如果重寫(xiě)了__init__稠集,為了能使用或擴(kuò)展超類(lèi)中的行為,最好顯式的調(diào)用超類(lèi)的__init__方法卖宠。

class C(A):

def?init(self,name):

super(C,self).init(name)

def getName(self):

return C+self.name

if?name==main:

c=C(hello)

print (c.getName())

老天爺都給我點(diǎn)贊了巍杈,你還不點(diǎn)?覺(jué)得這篇文章對(duì)你有所幫助的話可以來(lái)個(gè)一鍵三連呀?肝椤筷畦!若有指正的話可以評(píng)論區(qū)見(jiàn)或者私我呀。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刺洒,一起剝皮案震驚了整個(gè)濱河市鳖宾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逆航,老刑警劉巖鼎文,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異因俐,居然都是意外死亡拇惋,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)抹剩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撑帖,“玉大人,你說(shuō)我怎么就攤上這事澳眷『伲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵钳踊,是天一觀的道長(zhǎng)衷敌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拓瞪,這世上最難降的妖魔是什么缴罗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮祭埂,結(jié)果婚禮上面氓,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好侧但,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布矢空。 她就那樣靜靜地躺著,像睡著了一般禀横。 火紅的嫁衣襯著肌膚如雪屁药。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天柏锄,我揣著相機(jī)與錄音酿箭,去河邊找鬼。 笑死趾娃,一個(gè)胖子當(dāng)著我的面吹牛缭嫡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抬闷,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼戈二,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼颠黎!你這毒婦竟也來(lái)了浪秘?” 一聲冷哼從身側(cè)響起漓帅,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炕泳,沒(méi)想到半個(gè)月后纵诞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡培遵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年浙芙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片籽腕。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗡呼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出节仿,到底是詐尸還是另有隱情晤锥,我是刑警寧澤掉蔬,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布廊宪,位于F島的核電站,受9級(jí)特大地震影響女轿,放射性物質(zhì)發(fā)生泄漏箭启。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一蛉迹、第九天 我趴在偏房一處隱蔽的房頂上張望傅寡。 院中可真熱鬧,春花似錦、人聲如沸荐操。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)托启。三九已至宅倒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屯耸,已是汗流浹背拐迁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疗绣,地道東北人线召。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像多矮,于是被迫代替她去往敵國(guó)和親缓淹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容