Python編程中經(jīng)常遇到一些莫名其妙的錯誤, 其實這不是語言本身的問題, 而是我們忽略了語言本身的一些特性導(dǎo)致的,今天就來看下使用Python變量時導(dǎo)致的3個不可思議的錯誤, 以后在編程中要多多注意。
關(guān)于Python編程運行時新手易犯錯誤,這里暫不作介紹,詳情參見:Python運行的17個時新手常見錯誤小結(jié)
1、 可變數(shù)據(jù)類型作為函數(shù)定義中的默認(rèn)參數(shù)
這似乎是對的?你寫了一個小函數(shù),比如,搜索當(dāng)前頁面上的鏈接,并可選將其附加到另一個提供的列表中。
def search_for_links(page, add_to=[]): new_links = page.search_for_links() add_to.extend(new_links) return add_to
從表面看,這像是十分正常的 Python 代碼,事實上它也是,而且是可以運行的。但是,這里有個問題。如果我們給 add_to 參數(shù)提供了一個列表,它將按照我們預(yù)期的那樣工作。但是,如果我們讓它使用默認(rèn)值,就會出現(xiàn)一些神奇的事情。
試試下面的代碼:
def fn(var1, var2=[]): var2.append(var1) print(var2)fn(3)fn(4)fn(5)
可能你認(rèn)為我們將看到:
[3][4][5]
但實際上,我們看到的卻是:
[3][3,4][3,4,5]
為什么呢?如你所見,每次都使用的是同一個列表,輸出為什么會是這樣?在 Python 中,當(dāng)我們編寫這樣的函數(shù)時,這個列表被實例化為函數(shù)定義的一部分。當(dāng)函數(shù)運行時,它并不是每次都被實例化。這意味著,這個函數(shù)會一直使用完全一樣的列表對象,除非我們提供一個新的對象:
fn(3,[4])[4,3]
答案正如我們所想的那樣。要想得到這種結(jié)果,正確的方法是:
def fn(var1, var2=None): ifnot var2: var2 =[] var2.append(var1)
或是在第一個例子中:
def search_for_links(page, add_to=None): ifnot add_to: add_to =[] new_links = page.search_for_links() add_to.extend(new_links) return add_to
這將在模塊加載的時候移走實例化的內(nèi)容,以便每次運行函數(shù)時都會發(fā)生列表實例化。請注意,對于不可變數(shù)據(jù)類型,比如元組、字符串、整型,是不需要考慮這種情況的。這意味著,像下面這樣的代碼是非常可行的:
def func(message="my message"): print(message)
2、 可變數(shù)據(jù)類型作為類變量
這和上面提到的最后一個錯誤很相像。思考以下代碼:
class URLCatcher(object): urls =[] def add_url(self, url): self.urls.append(url)
這段代碼看起來非常正常。我們有一個儲存 URL 的對象。當(dāng)我們調(diào)用 add_url 方法時,它會添加一個給定的 URL 到存儲中。看起來非常正確吧?讓我們看看實際是怎樣的:
新聞熱點
疑難解答