溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Python坑有哪些

發(fā)布時間:2021-11-20 16:48:10 來源:億速云 閱讀:128 作者:iii 欄目:編程語言

本篇內(nèi)容介紹了“使用Python坑有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1、縮進,符號和空格不正確

寫代碼時大家會使用縮進、對齊、空格等,其目的是為了提高代碼的可讀性。

但在python語言中,許多功能都依賴于縮進。

比如在創(chuàng)建一個新類時,該類中的所有內(nèi)容都在聲明下縮進,決策、循環(huán)還有其它結構語句也會出現(xiàn)類似的情況,

如果你在代碼執(zhí)行時發(fā)現(xiàn)問題,可以查看一下是否使用了正確的縮進。

來看看下面的例子,在使用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

在上面的代碼當中,出現(xiàn)了兩處錯誤:if語句后面的:缺失;下一行沒有進行正確的縮進,執(zhí)行代碼出錯。

val = 500
if val > 100:
print("value is grater then 100")
value is grater then 100

當你更正上述代碼中的兩個問題后,你會發(fā)現(xià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,然后我們試著來改變一下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中,命名空間是名字到對象映射的結合,不同命名空間中的名字是沒有關聯(lián)的,這種映射的實現(xiàn)有點類似于python中的字典。

當你名字訪問一個對象的屬性時,先從對象的命名空間尋找。如果找到了這個屬性,就返回這個屬性的值;如果沒有找到的話,則從類的命名空間中尋找,找到了就返回這個屬性的值,找不到則拋出異常。

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

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

因此在上面的代碼中,由于x在對象的命名空間中找不到該屬性C,因此將在類中查找它。換句話說,C沒有自己的x屬性,獨立于A。因此,引用C.x實際上是指A.x。

3、誤解python范圍規(guī)則

如果你不了解python的范圍規(guī)則,那么你很容易犯錯誤,這是因為Python使用一種獨有的范圍規(guī)則來確定變量范圍。

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

L -代表Local。它包含在函數(shù)內(nèi)指定的(標識符/變量)名稱(使用def或lambda),而不是使用global關鍵字聲明。

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

G -指全球實體。它包括在模塊文件的頂層運行或使用global關鍵字定義的名稱。

B -指內(nèi)置插件。它跨越預先指定為內(nèi)置名稱的名稱,如打印,輸入,打開等。

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

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

發(fā)生上述錯誤的原因是,對作用域中的變量進行賦值時,Python會自動將該變量視為該作用域的本地變量,并在外部作用域中隱藏任何類似命名的變量。

因此,許多人在代碼提示出錯并顯示需要在函數(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):
<ipython-input-30-579469eed71a> in <module> 
<ipython-input-30-579469eed71a> in foo2()
UnboundLocalError: local variable 'lst' referenced before assignment

為什么foo2出錯了但是foo1運行良好?

答案在前面就已經(jīng)有所提示,在這個例子當中foo1()做一個分配到lst,而在foo2()當中l(wèi)st += [5]其實只是lst = lst + [5]的簡寫,我們希望分配一個值給lst,但是分配的值lst是基于lst自身,但其尚未定義。

4、python閉包變量綁定

python的閉包變量問題也是新手們?nè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

為什么結果是88888,和我所想的02468不一樣呢?

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

因此create_multipliers函數(shù)返回的lambda函數(shù)被調(diào)用時,會在附近的作用域中查詢變量i的值,而在create_multipliers生成返回數(shù)組之后,整數(shù)i的值是4,不會再改變,因此返回數(shù)組中每個匿名函數(shù)實際上都是:lambda x: 4*x。、

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

了解原理之后,讓我們來改一改代碼,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標準庫模塊發(fā)生沖突

Python擁有大量的庫模塊,開箱即用。但是,如果您遇到一個模塊的名稱與Python附帶的標準庫中具有相同名稱的模塊之間的名稱沖突,則可能會出現(xiàn)問題。

例如導入另一個庫,而這個庫又會嘗試導入模塊的Python標準庫版本,但由于你有一個同名的模塊,另一個包會錯誤地導入你的版本而不是Python標準庫。

因此,應該注意避免使用與Python標準庫模塊中相同的名稱,并且更改包中的模塊名稱比提交Python Enhancement Proposal(PEP)以請求名稱更改更容易。

6、is和==/=和==

Python中有很多運算符,例如is,=,==這三個,許多剛剛入門的新手會誤解這三個運算符的意義和用法,以致于代碼出錯。

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

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

a = ["Python"]
b = a
b is a
True
id(a)
2222222
id(b)
2222222
b == a
True

可以發(fā)現(xiàn)上面的例子當中b和a的內(nèi)存地址是相同的,它們指向同一塊內(nèi)存,因而 is 和 == 的結果都為True,這是因為直接賦值都是賦值的引用。如果新建對象之后,b 和 a 指向了不同的內(nèi)存,那么 b is a 的結果為False,而 b==a的結果為True。

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

a = 1
b = 1
a is b
True
a == b
True
a = 257
b = 257
a is b
False

Python僅僅對比較小的整數(shù)對象進行緩存(范圍為范圍[-5, 256])緩存起來,而并非是所有整數(shù)對象。需要注意的是,這僅僅是在命令行中執(zhí)行,而在Pycharm或者保存為文件執(zhí)行,結果是不一樣的,這是因為解釋器做了一部分優(yōu)化。

=和==的含義不同:

=代表的含義是賦值,將某一數(shù)值賦給某個變量,比如a=3,將3這個數(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中用作構造函數(shù),當Python將內(nèi)存分配給新的類對象時,它會自動被調(diào)用。

首先,__init__并不相當于C#中的構造函數(shù),在執(zhí)行它的時候,實例已經(jīng)構造出來。

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__作用是初始化已實例化后的對象。

其次,子類可以不重寫__init__,實例化子類時,會自動調(diào)用超類中已定義的__init__。

class B(A):
 def getName(self):
 return 'B '+self.name
if __name__=='__main__':
 b=B('hello')
 print (b.getName())

但如果重寫了__init__,實例化子類時,則不會隱式的再去調(diào)用超類中已定義的__init__。

class C(A):
 def __init__(self):
 pass
 def getName(self):
 return 'C '+self.name
if __name__=='__main__':
 c=C()
 print (c.getName())

此時執(zhí)行代碼則會報"AttributeError: 'C' object has noattribute 'name'”錯誤,所以如果重寫了__init__,為了能使用或擴展超類中的行為,最好顯式的調(diào)用超類的__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坑有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI