Python中list复制引发的问题
問題來源
當使用py時,總是隨手使用list/dict保存一切(盡管仍然有更效率的數據數據結構),因為list/dict足夠方便,而且包含了大部分的常用操作??墒亲罱野l現了一些問題,這些問題可能會導致嚴重的錯誤。
一個簡單的例子
復制語句是比較常用的語句,但是如果在py中不小心使用了list的復制,那么下面的代碼會帶來災難:
a = [0, 1, 2, 3] b = a for item in a:b.append(item) print(b)如果按照正常的理解,那么b應該是a的雙份數據,也就是 b = [0, 1, 2, 3, 0, 1, 2, 3],但是如果你真的運行以上的代碼,就會發現CPU會很快上升到100%,為什么會出現這樣呢?是不是py的設計缺陷呢?
我們先完成上面的需求,就是把a進行double copy成b,那么正確的寫法應該是:
a = [0, 1, 2, 3] b = a * 2 print(b)實際上上述代碼使用了生成器,對list/dict進行乘法運算時,往往是將其擴展為n倍。注意這里要和numpy中的操作加以區別。
一切皆對象
在Python Reference[1]中關于Data Model的說明中提到,對象是python對數據的抽象,在python的世界里,一切皆對象。其中最基本的數值,字符串,甚至函數都是一個對象,在py中自定義對象時,可以設置callable方法,可以使得對象像函數一樣被調用。
每個對象均包含3個基本元素:identify,type,value。其中,對象的id是創建對象時分配的,在其生存期內保持不變,id是內存地址的一個散列值;對象的type也是對象創建時就決定了的,在生命周期內不可變;而value既可能為可變的,又可能為不可修改的,具體情況視其type而定。
Python的built-in function中提供了id()來返回對象的identify value,提供了type()來返回對象的type。
根據Python Reference關于Naming and binding[2]的說明,對象的name是該對象的引用,在這里,“引用”的背后的含義是指對象的name只是對象的一個tag而已,也即是說,python的復制語句實際上并不是真正的復制語句,而是類似于c語言中的指針,指向的是對象的內存地址。
如以下代碼所示:
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:725638078 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' a = 1 b = a print(id(a),id(b))上面的代碼中id(a)和id(b)將指向同一個值,也即是兩者指向了同一個內存地址,當改變b的值的時候,a同時也會發生改變。
py的‘指針’
在c語言中最讓人頭疼的一個特性就是指針,指針是為了解決c語言的一些缺陷而設計的,本身非常靈活,于是cpp也繼承了c的指針特性,但是并不是所有人都能夠用好指針,特別是對于新手,使用指針往往會導致令人崩潰的錯誤。py在設計時吸取了教訓,拋棄了指針特性,但是在寫py程序的時候,我仍然能夠感覺到ptr in everywhere。
在復制語句的時候,py的表現讓人感覺怪異,那么當查看renfrence的復制語句的時候,我們可以發現這么一句話:
Assignment statements are used to (re)bind names to values and to modify attributes or items of mutable objects.
也就是復制語句實際上是一種綁定,是聲明了一個指向某個對象的內存地址的‘指針’。那么以下代碼便很容易理解了:
a = 1 # int *a = Int(1) b = a # int *b = aHow to do
那么該如何做來避免上述的問題呢, 有3種常用的方法:
1.引入copy庫,注意這里是淺copy
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:725638078 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' import copy a = [0, 1, 2, 3] b = copy.copy(a) for item in a:b.append(item) print (a) print (b)2.既然一切皆對象,那么使用對象方法重新生成一個:
a = [0, 1, 2, 3] b = list(a) for item in a:b.append(item) print (a) print (b)3.切片法,切片會生成一個原對象的一個copy:
a = [0, 1, 2, 3] b = a[:] for item in a:b.append(item) print (a) print (b)結尾給大家推薦一個非常好的學習教程,希望對你學習Python有幫助!
Python基礎入門教程推薦:更多Python視頻教程-關注B站:Python學習者
Python爬蟲案例教程推薦:更多Python視頻教程-關注B站:Python學習者
總結
以上是生活随笔為你收集整理的Python中list复制引发的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python深浅拷贝教程-面试必问内容
- 下一篇: Python动态类和动态方法的创建和调用