溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

學(xué)習(xí)用Python編程時(shí)要避免的3個(gè)錯(cuò)誤分別是什么

發(fā)布時(shí)間:2021-10-26 17:23:59 來(lái)源:億速云 閱讀:150 作者:柒染 欄目:編程語(yǔ)言

這篇文章將為大家詳細(xì)講解有關(guān)學(xué)習(xí)用Python編程時(shí)要避免的3個(gè)錯(cuò)誤分別是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

這些錯(cuò)誤會(huì)造成很麻煩的問(wèn)題,需要數(shù)小時(shí)才能解決。

當(dāng)你做錯(cuò)事時(shí),承認(rèn)錯(cuò)誤并不是一件容易的事,但是犯錯(cuò)是任何學(xué)習(xí)過(guò)程中的一部分,無(wú)論是學(xué)習(xí)走路,還是學(xué)習(xí)一種新的編程語(yǔ)言都是這樣,比如學(xué)習(xí)  Python。

為了讓初學(xué) Python 的程序員避免犯同樣的錯(cuò)誤,以下列出了我學(xué)習(xí) Python  時(shí)犯的三種錯(cuò)誤。這些錯(cuò)誤要么是我長(zhǎng)期以來(lái)經(jīng)常犯的,要么是造成了需要幾個(gè)小時(shí)解決的麻煩。

年輕的程序員們可要注意了,這些錯(cuò)誤是會(huì)浪費(fèi)一下午的!

1、 可變數(shù)據(jù)類型作為函數(shù)定義中的默認(rèn)參數(shù)

這似乎是對(duì)的?你寫了一個(gè)小函數(shù),比如,搜索當(dāng)前頁(yè)面上的鏈接,并可選將其附加到另一個(gè)提供的列表中。

def search_for_links(page, add_to=[]):      new_links = page.search_for_links()      add_to.extend(new_links)      return add_to

從表面看,這像是十分正常的 Python 代碼,事實(shí)上它也是,而且是可以運(yùn)行的。但是,這里有個(gè)問(wèn)題。如果我們給 add_to  參數(shù)提供了一個(gè)列表,它將按照我們預(yù)期的那樣工作。但是,如果我們讓它使用默認(rèn)值,就會(huì)出現(xiàn)一些神奇的事情。

試試下面的代碼:

def fn(var1, var2=[]):      var2.append(var1)      print var2  fn(3)  fn(4)  fn(5)

可能你認(rèn)為我們將看到:

[3]  [4]  [5]

但實(shí)際上,我們看到的卻是:

[3]  [3, 4]  [3, 4, 5]

為什么呢?如你所見,每次都使用的是同一個(gè)列表,輸出為什么會(huì)是這樣?在 Python  中,當(dāng)我們編寫這樣的函數(shù)時(shí),這個(gè)列表被實(shí)例化為函數(shù)定義的一部分。當(dāng)函數(shù)運(yùn)行時(shí),它并不是每次都被實(shí)例化。這意味著,這個(gè)函數(shù)會(huì)一直使用完全一樣的列表對(duì)象,除非我們提供一個(gè)新的對(duì)象:

fn(3, [4])
[4, 3]

答案正如我們所想的那樣。要想得到這種結(jié)果,正確的方法是:

def fn(var1, var2=None):      if not var2:          var2 = []      var2.append(var1)

或是在***個(gè)例子中:

def search_for_links(page, add_to=None):      if not add_to:          add_to = []      new_links = page.search_for_links()      add_to.extend(new_links)      return add_to

這將在模塊加載的時(shí)候移走實(shí)例化的內(nèi)容,以便每次運(yùn)行函數(shù)時(shí)都會(huì)發(fā)生列表實(shí)例化。請(qǐng)注意,對(duì)于不可變數(shù)據(jù)類型,比如元組、字符串、整型,是不需要考慮這種情況的。這意味著,像下面這樣的代碼是非常可行的:

def func(message="my message"):  print message

2、 可變數(shù)據(jù)類型作為類變量

這和上面提到的***一個(gè)錯(cuò)誤很相像。思考以下代碼:

class URLCatcher(object):      urls = []      def add_url(self, url):          self.urls.append(url)

這段代碼看起來(lái)非常正常。我們有一個(gè)儲(chǔ)存 URL 的對(duì)象。當(dāng)我們調(diào)用 add_url 方法時(shí),它會(huì)添加一個(gè)給定的 URL  到存儲(chǔ)中。看起來(lái)非常正確吧?讓我們看看實(shí)際是怎樣的:

a = URLCatcher()  a.add_url('http://www.google.com')  b = URLCatcher()  b.add_url('http://www.bbc.co.hk')

b.urls:

['http://www.google.com', 'http://www.bbc.co.uk']

a.urls:

['http://www.google.com', 'http://www.bbc.co.uk']

等等,怎么回事?!我們想的不是這樣啊。我們實(shí)例化了兩個(gè)單獨(dú)的對(duì)象 a 和 b。把一個(gè) URL 給了 a,另一個(gè)給了 b。這兩個(gè)對(duì)象怎么會(huì)都有這兩個(gè) URL  呢?

這和***個(gè)錯(cuò)例是同樣的問(wèn)題。創(chuàng)建類定義時(shí),URL  列表將被實(shí)例化。該類所有的實(shí)例使用相同的列表。在有些時(shí)候這種情況是有用的,但大多數(shù)時(shí)候你并不想這樣做。你希望每個(gè)對(duì)象有一個(gè)單獨(dú)的儲(chǔ)存。為此,我們修改代碼為:

class URLCatcher(object):      def __init__(self):          self.urls = []      def add_url(self, url):          self.urls.append(url)

現(xiàn)在,當(dāng)創(chuàng)建對(duì)象時(shí),URL 列表被實(shí)例化。當(dāng)我們實(shí)例化兩個(gè)單獨(dú)的對(duì)象時(shí),它們將分別使用兩個(gè)單獨(dú)的列表。

3、 可變的分配錯(cuò)誤

這個(gè)問(wèn)題困擾了我一段時(shí)間。讓我們做出一些改變,并使用另一種可變數(shù)據(jù)類型 – 字典。

a = {'1': "one", '2': 'two'}

現(xiàn)在,假設(shè)我們想把這個(gè)字典用在別的地方,且保持它的初始數(shù)據(jù)完整。

b = a  b['3'] = 'three'

簡(jiǎn)單吧?

現(xiàn)在,讓我們看看原來(lái)那個(gè)我們不想改變的字典 a:

{'1': "one", '2': 'two', '3': 'three'}

哇等一下,我們?cè)倏纯?b?

{'1': "one", '2': 'two', '3': 'three'}

等等,什么?有點(diǎn)亂……讓我們回想一下,看看其它不可變類型在這種情況下會(huì)發(fā)生什么,例如一個(gè)元組:

c = (2, 3)  d = c  d = (4, 5)

現(xiàn)在 c 是 (2, 3),而 d 是 (4, 5)。

這個(gè)函數(shù)結(jié)果如我們所料。那么,在之前的例子中到底發(fā)生了什么?當(dāng)使用可變類型時(shí),其行為有點(diǎn)像 C 語(yǔ)言的一個(gè)指針。在上面的代碼中,我們令 b =  a,我們真正表達(dá)的意思是:b 成為 a 的一個(gè)引用。它們都指向 Python  內(nèi)存中的同一個(gè)對(duì)象。聽起來(lái)有些熟悉?那是因?yàn)檫@個(gè)問(wèn)題與先前的相似。其實(shí),這篇文章應(yīng)該被稱為「可變引發(fā)的麻煩」。

列表也會(huì)發(fā)生同樣的事嗎?是的。那么我們?nèi)绾谓鉀Q呢?這必須非常小心。如果我們真的需要復(fù)制一個(gè)列表進(jìn)行處理,我們可以這樣做:

b = a[:]

這將遍歷并復(fù)制列表中的每個(gè)對(duì)象的引用,并且把它放在一個(gè)新的列表中。但是要注意:如果列表中的每個(gè)對(duì)象都是可變的,我們將再次獲得它們的引用,而不是完整的副本。

假設(shè)在一張紙上列清單。在原來(lái)的例子中相當(dāng)于,A 某和 B  某正在看著同一張紙。如果有個(gè)人修改了這個(gè)清單,兩個(gè)人都將看到相同的變化。當(dāng)我們復(fù)制引用時(shí),每個(gè)人現(xiàn)在有了他們自己的清單。但是,我們假設(shè)這個(gè)清單包括尋找食物的地方。如果“冰箱”是列表中的***個(gè),即使它被復(fù)制,兩個(gè)列表中的條目也都指向同一個(gè)冰箱。所以,如果冰箱被  A 修改,吃掉了里面的大蛋糕,B 也將看到這個(gè)蛋糕的消失。這里沒有簡(jiǎn)單的方法解決它。只要你記住它,并編寫代碼的時(shí)候,使用不會(huì)造成這個(gè)問(wèn)題的方式。

字典以相同的方式工作,并且你可以通過(guò)以下方式創(chuàng)建一個(gè)昂貴副本:

b = a.copy()

再次說(shuō)明,這只會(huì)創(chuàng)建一個(gè)新的字典,指向原來(lái)存在的相同的條目。因此,如果我們有兩個(gè)相同的列表,并且我們修改字典 a 的一個(gè)鍵指向的可變對(duì)象,那么在字典 b  中也將看到這些變化。

可變數(shù)據(jù)類型的麻煩也是它們強(qiáng)大的地方。以上都不是實(shí)際中的問(wèn)題;它們是一些要注意防止出現(xiàn)的問(wèn)題。在第三個(gè)項(xiàng)目中使用昂貴復(fù)制操作作為解決方案在 99%  的時(shí)候是沒有必要的。你的程序或許應(yīng)該被改改,所以在***個(gè)例子中,這些副本甚至是不需要的。

關(guān)于學(xué)習(xí)用Python編程時(shí)要避免的3個(gè)錯(cuò)誤分別是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

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

AI