熱線電話:13121318867

登錄
首頁精彩閱讀python導入csv文件出現SyntaxError問題分析
python導入csv文件出現SyntaxError問題分析
2018-05-10
收藏

python導入csv文件出現SyntaxError問題分析

先簡單描述下碰到的題目,要求是寫出2個print的結果

可以看到,a指向了一個列表list對象,在Python中,這樣的賦值語句,其實內部含義是指a指向這個list所在內存地址,可以看作類似指針的概念。

而b,注意,他是把a對象包裹進一個list,并且乘以5,所以b的樣子應該是一個大list,里面元素都是a

而當a對象進行了append操作后,其實,隱含的意思是,內存中的這個list進行了修改,所有對此對象進行引用的對象,都會發生改變

我將a的id打印出來,并且,同時打印b這個對象中所包含的元素a的id,這樣可以看到,在b這個list中,每個元素的id,和a是一樣的

我們可以看到,a對象的id(內存地址)為10892296,雖然b把a包裹進了新的list,但是,這個元素引用的,還是相同地址的對象,可以用下圖來解釋

之后,我們對a進行了append操作,由于list是一個可變對象,所以,他的內存地址并沒有改變,但是,對于內存中這個地址的引用的所有對象,都會被一同改變可以從上面測試圖分割線下半部分看出來.

由此,引出了對Python引用機制和淺復制及深復制的復習

Python的引用機制

引用機制案例1

由上面的例子,我們可以看到,python的引用傳遞,最終結果是讓2個對象都引用內存中同一塊區域的內容

所以我們來看一下下面的例子

B通過A,同樣引用了id為17446024的地址的內容,2者的id(內存地址)都是一毛一樣的

所以,通過A的操作  A[0]=3  或是   A[3].append(6)  ,都會對這塊內存中的內容進行修改(因為list是可變對象,所以內存地址并不會改變,這個后面再講)

這個是最基本的引用案例 (另外說句,由于A和B都指向了同一塊內存地址,所以通過B修改的內容,也能反映到A上面去)

引用機制案例2

我們再來看一個案例

看題目貌似是會把元素2替換成本身這個列表,結果也許應該是 A=[1,[1,2,3],3]

但其實并不是??!你可以看到,紅框中部分,中間有無限多個嵌套

為什么會這樣呢?

其實是因為,A指向的是[1,2,3]這個列表,在這個例子中,只是把A的第2個元素,指向了A對象本身,所以說,只是A的結構發生了變化!但是,A還是指向那個對象

我們可以通過打印A的id來看,他的指向是沒有變的??!

來看一下,A的指向并沒有變

那如果我們要達到最后輸出效果是 [1,[1,2,3],3]的效果,應該如何來操作呢?

這里,我們就要用到淺復制了,用法可以如下

淺復制和深復制

淺復制

現在,就來說說淺復制和深復制,上面的方法實際上只是進行了淺復制,shallow copy,含義是他是對原來引用的對象進行了復制,但是不再引用同一對象地址

看下面的例子,B通過 B = A[:] 操作,來進行了淺復制,你可以看到,淺復制之后,A和B引用的內存地址已經是不同的了
但是,A和B內部的元素的引用地址,還是相同的,這點要非常注意!是有區別的?。?!

A和B的引用內存地址的不同,帶來的效果是,你在B上面進行的操作,并不會影響到A。

淺拷貝歸納:

所以淺拷貝,可以歸納為,復制一份引用,新的對象和原來的對象的引用被區分開,但是內部元素的地址引用還是相同的

但是淺復制也會有問題,問題在哪里呢?就是碰到有嵌套的情況,比如下面的情況可以看到,我給B賦值了一份A的淺復制,這樣A和B的id(內存地址)就不一樣了。

所以,當我修改A[0]=8的時候,B不會被影響到,因為他們A和B兩者是獨立的引用,但是這里中間有一個嵌套的列表 [4,5,6]
這個[4,5,6]我們可以理解為:A和B還共同引用著,也就是對于A和B的第二個元素來說,他們還是指向同一塊內存地址的。

另外要說一句,由于int是不可變類型,所以,把A[0]修改成8之后,他的引用地址就變了!就和B[0]這個元素的引用區分開了。

深復制

那如何面對這樣的情況呢?就要用到python模塊里面的copy模塊了

copy模塊有2個功能

1: copy.copy(你要復制的對象) : 這個是淺拷貝,和前面對list進行的 [:] 操作性質是一樣的

2: copy.deepcopy(你要復制的對象) : 這個是深拷貝,他除了和淺拷貝一樣,會新生成一份對象的引用,另外對于內部的元素,都會新生成引用,以獨立分開.

看下面的例子,當你給B賦值一份A的深復制之后,他倆可以說是完全獨立開了,無論你修改的是A里面的不可變元素,還是修改A里面嵌套的可變元素,結果都不會影響到B

我的理解是:深復制可以稱之為遞歸拷貝,他會把所有嵌套的可變元素都拷貝一下,然后獨立引用出來.

深復制歸納:

深復制的效果,除了和淺復制一樣,將對象的引用新生成一份引用之外,內部所有嵌套的元素,他都會幫你一一獨立開.

自己畫了2張圖,以表示淺復制和深復制的效果區別

需要說明的是,雖然淺復制之后,列表內不可變元素的引用地址還是相同的,但是,正因為他們是不可變元素,所以,其中任意不可變元素被改變之后,引用地址都會是新的,而不會影響到原來的引用地址。



總結

所以,到這里,淺復制和深復制的機制,基本上理解了。

另外還有特殊情況需要說明

對于不可變類型:int, str, tuple, float 這樣的元素來說,沒有拷貝這個說法,他們被修改之后,引用地址就是直接改變了,如下面

但是,如果不可變類型內部有嵌套的可變類型的時候,還是可以使用深復制的

另外要提醒一句,平時我們用的最多的直接賦值(或者可以說是直接傳遞引用)的方法,比如下面的例子

他是將a和b兩個可變元素同時指向一個內存地址,所以,任何改變都是波及到a和b的

最后

可變類型:list , set , dict

不可變類型:int, str , float , tuple

淺復制方法:[:] , copy.copy() ,  使用工廠函數(list/dir/set)

深復制方法:copy.deepcopy()

以上就是本文的全部內容,希望對大家的學習有所幫助

數據分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數據分析師資訊
更多

OK
客服在線
立即咨詢
日韩人妻系列无码专区视频,先锋高清无码,无码免费视欧非,国精产品一区一区三区无码
客服在線
立即咨詢