在分享每個Python新手應該知道的4個常見錯誤之前,請確保您熟悉以下文章中的一些Python內置功能。
1.不使用迭代器
每個Python新手都會這樣做,無論他們是否熟練使用其他編程語言。 跑不了的。
給定一個列表list_,您將如何使用for循環逐個訪問列表中的元素? 我們知道Python中的列表已建立索引,因此我們可以通過list_ [i]訪問第i個元素。 然后,我們可以為for循環創建一個介于0到len(list_)之間的整數的迭代器,如下所示:
for i in range(len(list_)): foo(list_[i])
有用。 代碼沒有問題。 這也是在其他語言(例如C)中構造for循環的標準方法。但是實際上,我們可以在Python中做得更好。
怎么樣?
您知道Python中的列表是可迭代的嗎? 通過利用其可迭代的性質,我們可以生成更具可讀性的代碼,如下所示:
for element in list_: foo(element)
Photo by The Creative Exchange on Unsplash
通過zip函數可以在for循環中并行遍歷多個列表,而如果您堅持在迭代可迭代對象時獲取索引號(即計數器),則枚舉可能會有所幫助。 我希望早先了解的5個Python功能對它們進行了介紹和解釋。
2.使用全局變量
全局變量是在主腳本中聲明的具有全局范圍的變量,而局部變量是在具有局部范圍的函數內聲明的變量。 在Python中使用global關鍵字可讓您在函數中本地訪問和更改全局變量。 這是一個例子:
a = 1 # a variable def increment(): a += 1 return adef increment2(): global a # can make changes to global variable “a” a += 1 return a increment() # UnboundLocalError: local variable ‘a’ referenced before assignmentincrement2() # returns 2
許多初學者都喜歡它,因為使用global似乎可以避免傳遞函數所需的所有參數。 但這實際上是不正確的。 它只是隱藏了動作。
使用全局變量也不利于調試。 功能應被視為功能塊框,并且應可重復使用。 修改全局變量的函數可能會給很難發現的主腳本帶來副作用,并且可能導致復雜的意大利面條式代碼,并且調試起來要困難得多。
在局部函數中修改全局變量是不良的編程習慣。 您應該將變量作為參數傳遞,對其進行修改,并在函數末尾將其返回。
Photo by Vladislav Klapin on Unsplash
*不要將全局變量與全局常量混淆,因為在大多數情況下使用后者非常好。
3.不了解可變對象
對于新的Python學習者來說,這也許是最常見的驚喜,因為此功能在該語言中非常獨特。
Python中有兩種對象。 可變對象可以在運行時更改其狀態或內容,而不可變對象則不能。 許多內置對象類型是不可變的,包括int,float,string,bool和tuple。
st = ‘A string’ st[0] = ‘B’ # You cannot do this in Python
另一方面,諸如list,set和dict的數據類型是可變的。 因此,您可以更改列表中元素的內容,例如 list_ [0] =‘new’。
如果函數中的默認參數是可變的,則會發生意外情況。 讓我們以以下函數為例,其中可變的空列表是參數list_的默認值。
def foo(element, list_=[]): list_.append(element) r eturn list_
讓我們兩次調用該函數,而不用輸入list_的參數,以使其采用默認值。 理想情況下,如果不提供第二個參數,則每次調用該函數時都會創建一個新的空列表。
a = foo(1) # returns [1]b = foo(2) # returns [1,2], not [2]! WHY?
什么?
事實證明,在定義函數時,Python中的默認參數會被評估一次。 這意味著調用該函數不會刷新其默認參數。
Photo by Ravi Roshan on Unsplash
因此,如果默認參數是可變的,并且每次調用該函數時都會將其更改。可變的默認參數將適用于所有將來的函數調用。 “標準”解決方案是使用(不可變)None默認值,如下所示。
def foo(element, list_=None): if list_ is None: list_ = [] list_.append(element) return list_
4.不復制
復制的概念對于學習者而言可能是陌生的,甚至是違反直覺的。 假設您有一個列表a = [[0,1],[2,3]],然后通過b = a聲明一個新列表。 現在,您將擁有兩個具有相同元素的列表。 通過更改列表b中的某些元素,它應該不會對列表a產生任何(副作用),對嗎?
錯誤。
a = [[0,1],[2,3]]b = ab[1][1] = 100print(a,b) # [[0, 1], [2, 100]] [[0, 1], [2, 100]]print(id(a)==id(b))# True
當您使用賦值語句(即b = a)“復制”列表時,在一個列表元素上所做的任何修改在兩個列表中均可見。 賦值運算符僅在目標和對象之間創建綁定,因此示例中的列表a和b共享相同的引用,即Python中的id()。
如何復制對象?
如果您要“復制”對象并且僅修改新(或舊)對象中的值而沒有綁定,則有兩種創建副本的方法:淺副本和深副本。 兩個對象將具有不同的引用。
Photo by Louis Hansel on Unsplash
使用前面的示例,可以通過b = copy.copy(a)創建a的淺表副本。 淺表副本會創建一個新對象,該對象存儲原始元素的引用。 這聽起來可能很復雜,但讓我們看下面的示例:
import copya = [[0,1],[2,3]]b = copy.copy(a)print(id(a)==id(b))# Falseb[1] = 100print(a,b)# [[0, 1], [2, 3]] [[0, 1], 100]b[0][0] = -999print(a,b)# [[-999, 1], [2, 3]] [[-999, 1], 100]print(id(a[0]) == id(b[0]))# True
在創建嵌套列表a的淺副本(我們稱為b)之后,兩個列表具有不同的引用id(a)!= id(b),符號!=表示“不等于”。 但是,它們的元素具有相同的引用,因此id(a [0])== id(b [0])。
這意味著更改b內部的元素不會影響列表a,但是修改b [1]內部的元素確實會影響a [1],因此此副本很淺。
簡而言之,如果b是a的淺副本,則對b中的嵌套對象內的元素進行的任何更改都將顯示在a中。
如果要復制嵌套對象而元素之間沒有任何綁定,則需要使用b = copy.deepcopy(a)的深拷貝。 深層副本將創建一個新對象,然后以遞歸方式在原始元素中創建嵌套對象的副本。
簡而言之,深拷貝復制所有內容而沒有任何綁定。
-
函數
+關注
關注
3文章
4333瀏覽量
62684 -
代碼
+關注
關注
30文章
4791瀏覽量
68678 -
python
+關注
關注
56文章
4797瀏覽量
84742
發布評論請先 登錄
相關推薦
評論