您好,登錄后才能下訂單哦!
本篇內容介紹了“使用Python坑有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
1、縮進,符號和空格不正確
寫代碼時大家會使用縮進、對齊、空格等,其目的是為了提高代碼的可讀性。
但在python語言中,許多功能都依賴于縮進。
比如在創建一個新類時,該類中的所有內容都在聲明下縮進,決策、循環還有其它結構語句也會出現類似的情況,
如果你在代碼執行時發現問題,可以查看一下是否使用了正確的縮進。
來看看下面的例子,在使用IF語句時,請確保使用正確且合適的冒號和縮進,因為它們會導致語法和縮進錯誤。
val = 500 if val > 100 print("value is grater then 100") File "<ipython-input-1-a271e37c300f>", line 2 if val > 100 ^ SyntaxError: invalid syntax
在上面的代碼當中,出現了兩處錯誤:if語句后面的:缺失;下一行沒有進行正確的縮進,執行代碼出錯。
val = 500 if val > 100: print("value is grater then 100") value is grater then 100
當你更正上述代碼中的兩個問題后,你會發現整段代碼能夠很好的運行。
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,然后我們試著來改變一下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中,命名空間是名字到對象映射的結合,不同命名空間中的名字是沒有關聯的,這種映射的實現有點類似于python中的字典。
當你名字訪問一個對象的屬性時,先從對象的命名空間尋找。如果找到了這個屬性,就返回這個屬性的值;如果沒有找到的話,則從類的命名空間中尋找,找到了就返回這個屬性的值,找不到則拋出異常。
在Python中,類變量在內部作為字典處理,并遵循通常稱為方法解析順序(MRO)的方法。
MRO:Method Resolution Order 方法解析順序,Python支持多繼承,該方法用于解決父類存在同名函數的時存在的二義性問題。
因此在上面的代碼中,由于x在對象的命名空間中找不到該屬性C,因此將在類中查找它。換句話說,C沒有自己的x屬性,獨立于A。因此,引用C.x實際上是指A.x。
3、誤解python范圍規則
如果你不了解python的范圍規則,那么你很容易犯錯誤,這是因為Python使用一種獨有的范圍規則來確定變量范圍。
python范圍解析是基于LEGB規則,以下是Python范圍規則的概述:
L -代表Local。它包含在函數內指定的(標識符/變量)名稱(使用def或lambda),而不是使用global關鍵字聲明。
E -代表Enclosing function locals。它包含來自任何/所有封閉函數的本地范圍的名稱(例如,使用def或lambda)。
G -指全球實體。它包括在模塊文件的頂層運行或使用global關鍵字定義的名稱。
B -指內置插件。它跨越預先指定為內置名稱的名稱,如打印,輸入,打開等。
LEGB規則指定名稱空間的以下順序,用于搜索名稱:
Local - > Enclosed - > Global - > Built-in
考慮以下的例子:
x = 10 def foo(): x += 1 print(x) foo() UnboundLocalError Traceback (most recent call last): <ipython-input-26-234e54482865> in <module> <ipython-input-26-234e54482865> in foo() UnboundLocalError: local variable 'x' referenced before assignment
發生上述錯誤的原因是,對作用域中的變量進行賦值時,Python會自動將該變量視為該作用域的本地變量,并在外部作用域中隱藏任何類似命名的變量。
因此,許多人在代碼提示出錯并顯示需要在函數中添加賦值語句而感到不解。
考慮一個在使用列表時遇到的例子:
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): <ipython-input-30-579469eed71a> in <module> <ipython-input-30-579469eed71a> in foo2() UnboundLocalError: local variable 'lst' referenced before assignment
為什么foo2出錯了但是foo1運行良好?
答案在前面就已經有所提示,在這個例子當中foo1()做一個分配到lst,而在foo2()當中lst += [5]其實只是lst = lst + [5]的簡寫,我們希望分配一個值給lst,但是分配的值lst是基于lst自身,但其尚未定義。
4、python閉包變量綁定
python的閉包變量問題也是新手們容易混淆的一個點,來看看下面的例子:
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
為什么結果是88888,和我所想的02468不一樣呢?
這是由于Python的遲綁定(late binding)機制,閉包中內部函數的值只有在被調用時才會進行查詢。
因此create_multipliers函數返回的lambda函數被調用時,會在附近的作用域中查詢變量i的值,而在create_multipliers生成返回數組之后,整數i的值是4,不會再改變,因此返回數組中每個匿名函數實際上都是:lambda x: 4*x。、
解決辦法是將臨時值也保存在匿名函數的作用域內,在聲明匿名函數時就查詢變量的值。
了解原理之后,讓我們來改一改代碼,surprise!
def create_multipliers(): return [lambda x, i=i : i * x for i in range(5)] for multiplier in create_multipliers(): print (multiplier(2)) 2 4 6 8
5、名稱與Python標準庫模塊發生沖突
Python擁有大量的庫模塊,開箱即用。但是,如果您遇到一個模塊的名稱與Python附帶的標準庫中具有相同名稱的模塊之間的名稱沖突,則可能會出現問題。
例如導入另一個庫,而這個庫又會嘗試導入模塊的Python標準庫版本,但由于你有一個同名的模塊,另一個包會錯誤地導入你的版本而不是Python標準庫。
因此,應該注意避免使用與Python標準庫模塊中相同的名稱,并且更改包中的模塊名稱比提交Python Enhancement Proposal(PEP)以請求名稱更改更容易。
6、is和==/=和==
Python中有很多運算符,例如is,=,==這三個,許多剛剛入門的新手會誤解這三個運算符的意義和用法,以致于代碼出錯。
在 Python 中會用到對象之間比較,可以用 ==,也可以用 is,但對對象比較判斷的內容并不相同,區別在哪里?
·is 比較兩個對象的 id 值是否相等,是否指向同一個內存地址,== 比較的是兩個對象的內容是否相等,值是否相等;
a = ["Python"] b = a b is a True
id(a) 2222222 id(b) 2222222 b == a True
可以發現上面的例子當中b和a的內存地址是相同的,它們指向同一塊內存,因而 is 和 == 的結果都為True,這是因為直接賦值都是賦值的引用。如果新建對象之后,b 和 a 指向了不同的內存,那么 b is a 的結果為False,而 b==a的結果為True。
·小整數對象[-5,256]在全局解釋器范圍內被放入緩存供重復使用,例如:
a = 1 b = 1 a is b True a == b True
a = 257 b = 257 a is b False
Python僅僅對比較小的整數對象進行緩存(范圍為范圍[-5, 256])緩存起來,而并非是所有整數對象。需要注意的是,這僅僅是在命令行中執行,而在Pycharm或者保存為文件執行,結果是不一樣的,這是因為解釋器做了一部分優化。
=和==的含義不同:
=代表的含義是賦值,將某一數值賦給某個變量,比如a=3,將3這個數值賦予給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中用作構造函數,當Python將內存分配給新的類對象時,它會自動被調用。
首先,__init__并不相當于C#中的構造函數,在執行它的時候,實例已經構造出來。
class A(object): def __init__(self,name): self.name=name def getName(self): return 'A '+self.name
執行代碼:
a=A('hello')
可以理解為:
a=object.__new__(A) A.__init__(a,'hello')
即__init__作用是初始化已實例化后的對象。
其次,子類可以不重寫__init__,實例化子類時,會自動調用超類中已定義的__init__。
class B(A): def getName(self): return 'B '+self.name if __name__=='__main__': b=B('hello') print (b.getName())
但如果重寫了__init__,實例化子類時,則不會隱式的再去調用超類中已定義的__init__。
class C(A): def __init__(self): pass def getName(self): return 'C '+self.name if __name__=='__main__': c=C() print (c.getName())
此時執行代碼則會報"AttributeError: 'C' object has noattribute 'name'”錯誤,所以如果重寫了__init__,為了能使用或擴展超類中的行為,最好顯式的調用超類的__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())
“使用Python坑有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。