<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python的深淺拷貝講解!

          共 3467字,需瀏覽 7分鐘

           ·

          2020-12-07 03:48

          ↑↑↑關注后"星標"Datawhale
          每日干貨?&?每月組隊學習,不錯過
          Datawhale干貨?
          作者:皮錢超,廈門大學,Datawhale原創(chuàng)作者

          本文約3000字,建議閱讀9分鐘
          審稿人:耿遠昊,Datawhale成員,華東師范大學,開源教程《Joyful-Pandas》核心貢獻者。

          前言

          在很多語言中都存在深淺拷貝兩種拷貝數據的方式,Python中也不例外。本文中詳細介紹了Python中的深淺拷貝的相關知識,文章的內容包含:

          • 對象、數據類型、引用
          • 賦值
          • 淺拷貝
          • 深拷貝

          一、Python對象

          我們經常聽到:在Python中一切皆對象。其實,說的就是我們在Python中構造的任何數據類型都是一個對象,不管是數字、字符串、字典等常見的數據結構,還是函數,甚至是我們導入的模塊等,Python都會把它當做是一個對象來處理。

          所有的Python對象都擁有3個屬性:

          • 身份
          • 類型

          我們看一個簡單的例子來理解上面的3個屬性:

          假設我們聲明了一個name變量,通過id、type方法能夠查看對象的身份和類型:

          甚至是type本身也是一個對象,它也擁有自己的身份、類型:

          Python中,萬物皆對象

          二、數據類型

          2.1 可變和不可變類型

          在Python中,按照更新對象的方式,我們可以將對象分為2大類:可變數據類型不可變數據類型

          • 不可變數據類型:數值、字符串、布爾值。不可變對象就是對象的身份和值都不可變。新創(chuàng)建的對象被關聯(lián)到原來的變量名,舊對象被丟棄,垃圾回收器會在適當的時機回收這些對象。

          • 可變數據類型:列表、字典、集合。所謂的可變指的是可變對象的值可變,但是身份是不可變的。

          首先我們看看不可變對象:

          當我們定義了一個對象str1,給其賦值了“python”,便會在內存中找到一個固定的內存地址來存放;但是,當我們將“python”定義成另一個變量名的時候,我們發(fā)現(xiàn):它在內存中的位置是不變的

          也就是說,這個變量在計算機內存中的位置是不變的,只是換了一個名字來存放,來看3個實際的例子:

          以上的例子說明:當我們對字符串、數值型、布爾值的數據改變變量名,并不會影響到數據在內存中的位置。

          我們看看可變類型的例子,列表、字典、集合都是一樣的效果:

          雖然是相同的數據,但是變量名字不同,內存中仍然會開辟新的內存地址來進行存放相同的數據,我們以字典為例:

          2.2 引用

          在Python語言中,每個對象都會在內存中申請開辟一塊新的空間來保存對象;對象在內存中所在位置的地址稱之為引用。

          可以說,我們定義的變量名實際上就是對象的地址引用。引用實際上就是內存中的一個數字地址編號。在使用對象的時候,只要知道這個對象的地址,我們就可以操作這個對象。

          因為這個數字地址不太容易記憶,所以我們使用變量名的形式來代替對象的數字地址。在Python中,變量就是地址的一種表示形式,并不會開辟新的存儲空間。

          我們通過一個例子來說明變量和變量指向的引用(內存地址)實際上就是一個東西:

          三、賦值

          3.1 相同數據,不同變量名

          討論完Python的對象、屬性和引用3個重要的概念之后,在正式介紹深淺拷貝之前,我們先討論Python中的賦值

          在Python中,每次賦值都會開辟新的內存地址來存放數據,比如我們同時存放一個列表[1,2,3],即使數據是相同的,但是內存地址卻不同:

          其實就是兩個不同的變量,只是恰好它們存放了相同的數據而已,但是存放的地址是不同的。

          我們給v1列表追加了一個元素,發(fā)現(xiàn)它的內存地址是不變的,當然v2肯定是不變的:

          3.2 一個變量多次賦值

          如果我們對一個變量多次賦值,其內存是會變化的:

          3.3 變量賦值

          將一個變量賦值給另一個變量,其實它們就是同一個對象:數據相同,在內存中的地址也相同:

          當我們給V1追加一個元素,V2也會同時變化:

          實際上它們就是同一個對象!!!!

          3.4 嵌套賦值

          如果是列表中嵌套著另外的列表,那么當改變其中一個列表的時候,另一個列表中的也會隨著改變:

          原始數據信息:

          當我們給v1追加了新元素之后:

          總結:賦值其實就是將一個對象的地址賦值給一個變量,使得變量指向該內存地址。

          四、淺拷貝

          在Python中進行拷貝之前,我們需要導入模塊:

          import copy

          ??淺拷貝只是拷貝數據的第一層,不會拷貝子對象

          4.1 不可變類型的淺拷貝

          如果只是針對不可變的數據類型(字符串、數值型、布爾值),淺拷貝的對象和原數據對象是相同的內存地址:

          從上面的結果中我們可以看出來:針對不可變類型的淺拷貝,只是換了一個名字,對象在內存中的地址其實是不變的

          image-20201115225938833

          4.2 可變類型的淺拷貝

          首先我們討論的是不存在嵌套類型的可變類型數據(列表、字典、集合):

          image-20201115232303901

          從上面的例子看出來:

          • 列表本身的淺拷貝對象的地址和原對象的地址是不同的,因為列表是可變數據類型。
          • 列表中的元素(第1個元素為例)和淺拷貝對象中的第一個元素的地址是相同的,因為元素本身是數值型,是不可變的

          通過一個圖形來說明這個關系:

          字典中也存在相同的情況:字典本身的內存地址不同,但是里面的鍵、值的內存地址是相同的,因為鍵值都是不可變類型的數據。

          如果可變類型的數據中存在嵌套的結構:

          從上面的兩個例子中我們可以看出來:

          在可變類型的數據中,如果存在嵌套的結構類型,淺拷貝只復制最外層的數據,導致內存地址發(fā)生變化,里面數據的內存地址不會變

          五、深拷貝

          深拷貝不同于淺拷貝的是:深拷貝會拷貝所有的可變數據類型,包含嵌套的數據中的可變數據。深拷貝是變量對應的值復制到新的內存地址中,而不是復制數據對應的內存地址。

          5.1 不可變類型的深拷貝

          關于不可變類型的深淺拷貝,其效果是相同的,具體看下面的例子:

          我們得出一個結論:針對不可變數據類型的深淺拷貝,其結果是相同的。

          5.2 可變類型的深拷貝

          首先我們討論的是不存在嵌套的情況:

          針對列表數據

          針對字典數據

          我們可以得出結論:

          • 深拷貝對最外層數據是只拷貝數據,會開辟新的內存地址來存放數據。
          • 深拷貝對里面的不可變數據類型直接復制數據和地址,和可變類型的淺拷貝是相同的效果。

          我們討論存在嵌套類型的深拷貝(以列表為例)。

          結論1:對整個存在嵌套類型的數據進行深淺拷貝都會發(fā)生內存的變化,因為數據本身是可變的。

          結論2:我們查看第一個元素1的內存地址,發(fā)生三者是相同的,因為1是屬于數值型,是不可變類型。

          結論3:我們查看第三個元素即里面嵌套列表的內存,發(fā)現(xiàn)只有深拷貝是不同的,因為這個嵌套的列表是可變數據類型,深拷貝在拷貝了最外層之后還會繼續(xù)拷貝子層級的可變類型。

          結論4:我們查看嵌套列表中的元素的內存地址,發(fā)現(xiàn)它們是相同的,因為元素是數值型,是不可變的,不受拷貝的影響。

          六、元組的深淺拷貝

          元組本身是不可變數據類型,但是其中的值是可以改變的,內部可以有嵌套可變數據類型,比如列表等,會對它的拷貝結果造成影響。

          6.1 不存在嵌套結構

          當元組中不存在嵌套結構的時候,元組的深淺拷貝是相同的效果:

          6.2 存在嵌套結構

          當元組的數據中存在嵌套的可變類型,比如列表等,深拷貝會重新開辟地址,將元組重新成成一份

          七、is和==

          在文章的開始就已經談過:在Python中每個變量都有自己的標識、類型和值。每個對象一旦創(chuàng)建,它的標識就絕對不會變。一個對象的標識,我們可以理解成其在內存中的地址。is()運算符比較的是兩個對象的標識;id()方法返回的就是對象標識的整數表示。

          總結:is()比較對象的標識;==運算符比較兩個對象的值(對象中保存的數據)。在實際的編程中,我們更多關注的是值,而不是標識本身。

          第一個例子我們創(chuàng)建了兩個不同的對象,只是它們的值剛好相同而已

          第二個例子我們先創(chuàng)建了一個對象v3,然后將他賦值給另一個對象v4,其實它們就是相同的對象,所以標識(內存地址)是相同的,只是它們的名字不同而已

          總結

          通過大量的例子,我們得出結論:

          • 在不可變數據類型中,深淺拷貝都不會開辟新的內存空間,用的都是同一個內存地址。
          • 在存在嵌套可變類型的數據時,深淺拷貝都會開辟新的一塊內存空間;同時,不可變類型的值還是指向原來的值的地址。

          不同的是:在嵌套可變類型中,淺拷貝只會拷貝最外層的數據,而深拷貝會拷貝所有層級可變類型數據


          “整理不易,三連
          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄免费视频 | 亚洲日韩字幕 | 五月婷婷乱伦 | 黄色电影中文字幕在线观看 | 日韩操逼视频 |