Python可变序列中的一些坑
聽說面試官比較喜歡這些坑。
函數默認參數可變
默認參數有個最大的坑,演示如下:
先定義一個函數,傳入一個 list,添加一個END再返回:
當你正常調用時,結果似乎不錯:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' >>> add_end([1, 2, 3]) [1, 2, 3, 'END'] >>> add_end(['x', 'y', 'z']) ['x', 'y', 'z', 'END']當你使用默認參數調用時,一開始結果也是對的:
>>> add_end() ['END']但是,再次調用add_end()時,結果就不對了:
>>> add_end() ['END', 'END'] >>> add_end() ['END', 'END', 'END']很多初學者很疑惑,默認參數是[],但是函數似乎每次都“記住了”上次添加了’END’后的 list。
原因解釋如下:
Python 函數在定義的時候,默認參數L的值就被計算出來了,即[],因為默認參數L也是一個變量,它指向對象[],每次調用該函數,如果改變了L的內容,則下次調用時,默認參數的內容就變了,不再是函數定義時的[]了。
定義默認參數要牢記一點:默認參數必須指向不變對象!
要修改上面的例子,我們可以用None這個不變對象來實現:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' def add_end(L=None):if L is None:L = []L.append('END')return L現在,無論調用多少次,都不會有問題:
>>> add_end() ['END'] >>> add_end() ['END']序列中存儲同一個可變對象的多個引用
如果想要把一個序列復制幾份然后再拼接起來,可以把這個序列乘一個整數,這個操作會產生一個新序列:
>>> l = [1, 2, 3] >>> l * 3 [1, 2, 3, 1, 2, 3, 1, 2, 3]如果在a n這個語句中,序列 a
里的元素是對其他可變對象的引用的話,你就需要格外注意了,因為這個式子的結果可能會出乎意料。
比如,你想用my_list = [[]]
3來初始化一個由列表組成的列表,但是你得到的列表里包含的 3 個元素其實是 3 個引用,而且這 3
個引用指向的都是同一個列表。這可能不是你想要的結果。
下面來看看如何初始化一個由列表組成的列表。`
下面展示了另一個方法,這個方法看上去是個誘人的捷徑,但實際上它是錯的。
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' >>> weird_board = [['_'] * 3] * 3 >>> weird_board [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] >>> weird_board[1][2] = 'O' >>> weird_board [['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]# 等價于下面這種寫法 >>> row = ['_'] * 3 >>> board = [] >>> for i in range(3): ... board.append(row)含有 3 個指向同一對象的引用的列表是毫無用處的。
當我們不做修改的時候,看起來都還好。一旦我們試圖標記第 1 行第 2 列的元素,就立馬暴露了列表內的 3 個引用指向同一個對象的事實。
總結
以上是生活随笔為你收集整理的Python可变序列中的一些坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 提高Python程序运行效率三种模式第一
- 下一篇: python3中map()函数用法