點評:這個題目本身出現的頻率非常高,但是就題論題而言沒有什么技術含量。
對于這種面試題,在回答的時候一定要讓你的答案能夠超出面試官的預期,這樣才能獲得更好的印象分。
所以回答這個題目的要點不僅僅是能夠說出淺拷貝和深拷貝的區別
深拷貝的時候可能遇到的兩大問題,還要說出Python標準庫對淺拷貝和深拷貝的支持,然后可以說說列表、字典如何實現拷貝操作以及如何通過序列化和反序列的方式實現深拷貝,最后還可以提到設計模式中的原型模式以及它在項目中的應用。
淺拷貝通常只復制對象本身,而深拷貝不僅會復制對象,還會遞歸的復制對象所關聯的對象。
深拷貝可能會遇到兩個問題:
一是一個對象如果直接或間接的引用了自身,會導致無休止的遞歸拷貝;
二是深拷貝可能對原本設計為多個對象共享的數據也進行拷貝。
Python通過 copy模塊中的copy和deepcopy函數來實現淺拷貝和深拷貝操作,其中deepcopy可以通過memo字典來保存已經拷貝過的對象,從而避免剛才所說的自引用遞歸問題;
此外,可以通過copyreg模塊的pickle函數來定制指定類型對象的拷貝行為。
deepcopy函數的本質其實就是對象的一次序列化和一次返回序列化,面試題中還考過用自定義函數實現對象的深拷貝操作,顯然我們可以使用pickle模塊的dumps和loads來做到
代碼如下所示:
import pickle my_deep_copy = lambda obj: pickle.loads(pickle.dumps(obj)) 列表的切片操作 [:]相當于實現了列表對象的淺拷貝,而字典的copy方法可以實現字典對象的淺拷貝。
對象拷貝其實是更為快捷的創建對象的方式。在Python中,通過構造器創建對象屬于兩階段構造,首先是分配內存空間,然后是初始化。在創建對象時,我們也可以基于”原型“的對象來創建新對象,通過對原型對象的拷貝(復制內存)就完成了對象的創建和初始化,這種做法其實更加高效,這也就是設計模式中的原型模式。我們可以通過元類的方式來實現原型模式
代碼如下所示:
import copy class PrototypeMeta(type): """實現原型模式的元類""" def __init__(cls, *args, **kwargs): super().__init__(*args, **kwargs)
# 為對象綁定clone方法來實現對象拷貝 cls.clone = lambda self, is_deep=True: \ copy.deepcopy(self) if is_deep else copy.copy(self) class Person(metaclass=PrototypeMeta): pass p1 = Person() p2 = p1.clone()
# 深拷貝 p3 = p1.clone(is_deep=False)
# 淺拷貝