面試題-python 淺拷貝和深拷貝(copy模塊)

2021-02-26 從零開始學自動化測試
前言

面試的時候經常會問到深拷貝和淺拷貝,那麼python的深拷貝和淺拷貝有什麼區別呢?

思考題

先來看 2 個簡單的案例, 對元素 a/aa 重新賦值一個新的變量 b/bb 後,改變原來 a/aa 的值,看會不會影響新的變量 b/bb 的值

# 1.stra = "hello"b = aa = "world"print('a: {}'.format(a))print('b: {}'.format(b))# 2.listaa = [1, 2, 3]bb = aaaa.append(4)print('aa: {}'.format(aa))print('bb: {}'.format(bb))

運行結果

a: worldb: helloaa: [1, 2, 3, 4]bb: [1, 2, 3, 4]

這是個很有趣的事情,字符串重新賦值給b後,改變原來a的值,b不會跟著變。
但是list重新賦值給bb後,改變aa的值,bb的值也跟著變了。
這裡有個知識點:在python中,都是將「對象的引用(內存地址)」賦值給變量的。其次,在python中有6個標準數據類型,他們分為可變和不可變兩類。

可變和不可變對象

在python中有6個標準數據類型,他們分為可變和不可變兩類。

不可變類型:Number(數字)String(字符串)Tuple(元組)可變類型:List(列表)Dictionary(字典)Set(集合)

可變對象和不可變對象的內存地址可以通過id函數獲取

可變對象:可變對象可以在其 id() 保持固定的情況下改變其取值;不可變對象:具有固定值的對象。不可變對象包括數字、字符串和元組。這樣的對象不能被改變。如果必須存儲一個不同的值,則必須創建新的對象。id(object):函數用於獲取對象的內存地址,函數返回對象的唯一標識符,標識符是一個整數。

字符串和數字都是不可變類型,不同變量賦值一樣,通過id獲取的內存地址是一樣的

# 作者-上海悠悠 QQ交流群:717225969# blog地址 https://www.cnblogs.com/yoyoketang/a = "abc"b = "abc"print(id(a))print(id(b))print(a is b)c = 100d = 100print(id(c))print(id(d))print(c is d)

運行結果

15572126035921557212603592True15610328321561032832True

list、dict 和 set集合是可變類型,雖然值一樣,但是id獲取的內存地址不一樣

# 作者-上海悠悠 QQ交流群:717225969# blog地址 https://www.cnblogs.com/yoyoketang/a = {"key": "123"}b = {"key": "123"}print(id(a))print(id(b))print(a is b)print(a == b)c = [1, 2, 3]d = [1, 2, 3]print(id(c))print(id(d))print(c is d)print(c == d)

運行結果

16389203101441638920310216FalseTrue16389212923601638921292680FalseTrue

現在知道了id函數獲取內存地址,我們說的深拷貝和淺拷貝是針對可變對象:list、dict 和 set集合

copy模塊

python 中的深拷貝和淺拷貝使用 copy 模塊

淺拷貝 A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

上面這段話是官方文檔上的描述,有2個含義:

1.淺拷貝會創建一個新的容器對象(compound object)2.對於對象中的元素,淺拷貝就只會使用原始元素的引用(內存地址)

常見的淺拷貝操作有:

使用切片操作[:]使用工廠函數(如list/dict/set)copy模塊的copy()方法

深拷貝 A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

上面這段話是官方文檔上的描述,也是有2個含義:

1.深拷貝和淺拷貝一樣,都會創建一個新的容器對象(compound object)2.和淺拷貝的不同點在於,深拷貝對於對象中的元素,深拷貝都會重新生成一個新的對象淺拷貝

淺拷貝使用 copy 模塊的 copy 方法

# 作者-上海悠悠 QQ交流群:717225969# blog地址 https://www.cnblogs.com/yoyoketang/import copya = [1, "hello", [2, 3], {"key": "123"}]b = copy.copy(a)print(id(a)) # 外面容器拷貝了,所以a和b的id不一樣print(id(b))# a和b容器裡面的元素對象idprint(id(a[2]))print(id(b[2]))

運行結果

1340977220424134097722157613409772201681340977220168

淺拷貝是拷貝了list外面一層的, 創建一個新的容器對象(compound object),所以a和b的id是不一樣的
對於容器裡面的元素對象,淺拷貝就只會使用原始元素的引用(內存地址),所以可以看到子元素的內存地址還是一樣的

如果改變a裡面的不可變對象數字和字符串,此時a和b的值就不一樣了,但是b的後面沒改變的元素還是指向a

# 改變a的 數字和字符串對象a[0] = 2# a 和b 的值不一樣了print(a)print(b)# 但是後面的元素還是指的aprint(id(a[2]))print(id(b[2]))

運行結果

[2, 'hello', [2, 3], {'key': '123'}][1, 'hello', [2, 3], {'key': '123'}]24881340442322488134044232

如果改變a裡面的可變對象, 把[2, 3]裡面的3改成 [2, 4]

# 改變a的 可變對象 [2, 4]a[2][1] = 4print(a)print(b)print(id(a[2]))print(id(b[2]))

運行結果

[1, 'hello', [2, 4], {'key': '123'}][1, 'hello', [2, 4], {'key': '123'}]23851256735442385125673544

此時b會隨著a的改變而改變,這就是淺拷貝了

深拷貝

淺拷貝使用 copy 模塊的 deepcopy 方法

import copy# 作者-上海悠悠 QQ交流群:717225969# blog地址 https://www.cnblogs.com/yoyoketang/a = [1, "hello", [2, 3], {"key": "123"}]b = copy.deepcopy(a)print(id(a)) # 外面容器拷貝了,所以a和b的id不一樣print(id(b))# a和b容器裡面的元素對象idprint(id(a[2]))print(id(b[2]))# 改變a的 可變對象 [2, 4]a[2][1] = 4print(a)print(b)print(id(a[2]))print(id(b[2]))

深拷貝和淺拷貝的不同點在於,深拷貝對於對象中的元素,深拷貝都會重新生成一個新的對象。
所以不管a怎麼變,都不會影響b的值

賦值

賦值跟淺拷貝 深拷貝是有區別的,可以看下面的示例

# 作者-上海悠悠 QQ交流群:717225969# blog地址 https://www.cnblogs.com/yoyoketang/a = [1, "hello", [2, 3], {"key": "123"}]b = aprint(id(a))print(id(b))# a和b容器裡面的元素對象idprint(id(a[2]))print(id(b[2]))a[0] = 2print(a)print(b)

運行結果

1992198687560199219868756019921986873041992198687304[2, 'hello', [2, 3], {'key': '123'}][2, 'hello', [2, 3], {'key': '123'}]

賦值語句並沒有生成新的容器,跟淺拷貝的區別在於外面的容器也是指向的a的內存地址,並沒有生成新的容器

參考博客資料https://www.nowcoder.com/discuss/203654?type=2&order=0&pos=1232&page=0
參考博客資料https://copyfuture.com/blogs-details/2020031720252559878eggumgw4iaj7c

2021年第六期《python接口自動化+測試開發》課程,1月9號開學(火熱報名中!)

本期上課時間:1月9號-4月18號,每周六、周日晚上20:30-22:30
聯繫微信/QQ:283340479

相關焦點

  • 深拷貝和淺拷貝之list、dataframe
    python list:b = a是淺拷貝,b = list(a)和b = copy.cpoy(a)是深拷貝。淺拷貝,a和b指向的是一個地址。當b改變後,a也會改變。深拷貝,a和b指向的是兩個地址,當b改變後,a不受影響。
  • 圖解 Python 中深淺拷貝(copy)
    注意:l2 = l1是一個指向,是賦值,和深淺copy無關。但是python對深copy做了一個優化,將可變的數據類型在內存中重新創建一份,而不可變的數據類型則沿用之前的,所以內存中是下面這樣的:小結:深copy:會在內存中開闢新空間,將原列表以及列表裡面的可變數據類型重新創建一份,不可變數據類型則沿用之前的。為什麼Python默認的拷貝方式是淺拷貝?
  • Python深拷貝和淺拷貝詳解
    對於淺拷貝(shallow copy)和深度拷貝(deep copy),本節並不打算一上來拋出它們的概念,而是先從它們的操作方法說起,通過代碼來理解兩者的不同
  • 5 張圖徹底理解 Python 中的淺拷貝與深拷貝
    Python 開發崗,面試官如果對基礎比較看重的話,那麼很可能會問你這樣的問題「談談你對 Python 中的淺拷貝和深拷貝的理解?」若平時你在開發中過度使用 deepcopy,以至於忘記了淺拷貝(shallow copy)和深拷貝(deep copy)的區別,那很可能要栽大跟頭了。本文轉載一篇小吉大佬的文章,幫助大家更好的理解深拷貝和淺拷貝的區別。
  • 前端面試-深拷貝和淺拷貝
    面試題目:如何實現對一個數組或對象的淺拷貝和深拷貝?WTF,複製還分兩種,第一次遇到這種問題的時候很是無語呢,先來看看一般的答案的理解。淺拷貝是只拷貝一層,深層次的對象級別就只拷貝引用。 深拷貝是拷貝多層,每一級別的數據都拷貝出來。
  • C++之拷貝構造函數的淺copy和深copy
    一、深拷貝和淺拷貝構造函數總結:1、兩個特殊的構造函數:(1)無參構造函數::(1)淺拷貝拷貝後對象的物理狀態相同(2)深拷貝拷貝後對象的邏輯狀態相同5、什麼時候需要進行深拷貝?(也就是我們自己手寫的),必然需要實現深拷貝!
  • 看看你知道的「淺拷貝」是對的嗎
    她: 「複製對象有深拷貝和淺拷貝...」大佬:」說一下這兩者之間的區別「她: 」我給你寫一段淺拷貝的代碼「var a = { x: 1 };var b = a;大佬:」回去等通知吧 ~.~「2. 於是我去MDN(https://developer.mozilla.org)上查了一下shallow copy的關鍵字,也沒有關於shallow copy的準確定義,這也難怪部分人對於淺拷貝會有不同的認識。第一種定義:一個新的對象直接拷貝已存在的對象的引用,即淺拷貝。
  • 一篇文章讀懂Python賦值與拷貝
    該功能由 copy 模塊提供。拷貝又分為淺拷貝和深拷貝。>>> s = [1,2,3]>>> sc = copy.copy(s) # 淺拷貝>>> sc[1, 2, 3]>>> sdc = copy.deepcopy(s)  >>> sdc[1, 2, 3]拷貝出來的對象只是值相同,實為不同的對象
  • JavaScript的深拷貝實現
    在實際開發當中,我們經常會遇到要對對象進行深拷貝的情況。而且深拷貝這個問題在面試過程中也經常會遇到,下面就對本人在學習過程中的收穫,做以簡單的總結。什麼是淺拷貝,什麼是深拷貝?什麼是淺拷貝關於淺拷貝的概念,我在網上看到一種說法,直接上代碼。
  • 一文讀懂 javascript 深拷貝與淺拷貝
    讀完本文,希望你能明白:淺拷貝與深拷貝淺拷貝是創建一個新對象,這個對象有著原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值,如果屬性是引用類型,拷貝的就是內存地址 ,所以如果其中一個對象改變了這個地址,就會影響到另一個對象。
  • 吐血整理的 Python 面試題,請務必收藏!
    年關將至,給年後準備跳槽的準備一份面試指南,希望大家在漲薪和成長的路上多一點指引!python2和python3區別?os模塊:負責程序與作業系統的交互,提供了訪問作業系統底層的接口。sys模塊:負責程序與python解釋器的交互,提供了一系列的函數和變量,用於操控python的運行時環境。簡述Python引用計數機制?python垃圾回收主要以引用計數為主,標記-清除和分代清除為輔的機制,其中標記-清除和分代回收主要是為了處理循環引用的難題。Python賦值、淺拷貝和深拷貝的區別?
  • JavaScript系列--如何優雅簡單的實現深拷貝和淺拷貝
    優雅簡單的實現深拷貝和淺拷貝淺析JavaScript解析賦值、淺拷貝和深拷貝的區別:裡面介紹了解析賦值,淺拷貝,深拷貝的原理和實現。淺拷貝方法:Object.assign(),展開語法Spread,Array.prototype.alice(),array.prototype.concat()。深拷貝方法:JSON.parse(JSON.stringify(object)),對於undefined,symbol和函數的會直接忽略。
  • 低門檻徹底理解JavaScript中的深拷貝和淺拷貝
    在說深拷貝與淺拷貝前,我們先看兩個簡單的案例:按照常規思維,obj1應該和num1一樣,不會因為另外一個值的改變而改變,而這裡的obj1 卻隨著obj2的改變而改變了。同樣是變量,為什麼表現不一樣呢?案例2中的賦值就是典型的淺拷貝,並且深拷貝與淺拷貝的概念只存在於引用類型。深拷貝與淺拷貝既然已經知道了深拷貝與淺拷貝的來由,那麼該如何實現深拷貝?
  • 面試題:如何實現一個深拷貝
    今天這篇文章我們來看看一道必會面試題,即如何實現一個深拷貝。第一步:簡單實現其實深拷貝可以拆分成 2 步,淺拷貝 + 遞歸,淺拷貝時判斷屬性值是否是對象,如果是對象就進行遞歸操作,兩個一結合就實現了深拷貝。根據上篇文章內容,我們可以寫出簡單淺拷貝代碼如下。
  • python2020年最新面試題,你會幾道?(附答案)
    編程網站DataFlair的技術團隊分享了一份2020年最常見Python面試題合集,既有基本的Python面試題,也有高階版試題來指導你準備面試,試題均附有答案。面試題內容包括編碼、數據結構、腳本撰寫等話題。1:Python有哪些特點和優點?
  • 這8道Python面試題,你答不答的出來
    我挑了一些Python的基礎面試題,看看你能不能的答上來,也許面試的同學用的著!Python是一種解釋型語言,這意味著,與C,C++不同,Python不需要在運行之前進行編譯。它是邊運行邊解釋。Python是動態類型化的,這意味著當你聲明它們或類似的東西時,你不需要聲明變量的類型。
  • Pandas和Numpy的視圖和拷貝
    在Numpy和Pandas中,有兩個重要概念,容易混淆,一個是淺拷貝,也稱為視圖,另外一個是深拷貝,或者就稱為拷貝。如果操作不當,Pandas會爆出SettingWithCopyWarning的異常。本文我將就視圖和拷貝問題,結合異常進行總結。
  • 年薪30萬的騰訊公司Python工程師面試題曝光!漲知識了!
    作為Python開發工程師,進入大公司是開啟職業新起點的關鍵,今天給小夥伴特別分享了其在騰訊公司面試Python工程師的題目和經歷,希望對廣大Python工程師的求職者有一個幫助。(標點符號可忽略)(1) 創建文件對象f後,解釋f的readlines和xreadlines方法的區別?(2) 追加需求:引號內元素需要算作一個單詞,如何實現?3、簡述python GIL的概念, 以及它對python多線程的影響?
  • 2021年最常見的Python面試題答案
    編程網站DataFlair的技術團隊分享了一份2020年最常見Python面試題合集,既有基本的Python面試題,也有高階版試題來指導你準備面試,試題均附有答案。面試題內容包括編碼、數據結構、腳本撰寫等話題。1:Python有哪些特點和優點?
  • Python面試必刷題系列(5)
    本篇是【Python面試必刷題系列】的第5篇文章。