2013-06-24 76 views
1

我想創建一個類,它可以提供一個屬性列表,它不會被copy.deepcopy()深度覆蓋。例如像這樣:在Python中,如何在我的__deepcopy __()實現中調用copy.deepcopy?

class CustomDeepcopy(object): 

    a = SomeSimpleObject() 
    b = SomeBigObject() 

    def dont_deepcopy(self): 
     return ['b'] 

    def __deepcopy__(self,memo): 
     #Somehow call copy.deepcopy(self) and have it 
     #deepcopy self.a but not self.b 
     # 
     #For example, this *almost* works, 
     for attr in self.dont_deepcopy(): 
      val = getattr(self,attr,None) 
      if val is not None: 
       memo[id(val)]=val 
     return copy.deepcopy(self,memo) 

的問題是,我不認爲我可以從__deepcopy__()內調用copy.deepcopy(),因爲這會導致無窮遞歸(因爲copy.deepcopy()首先檢查我的對象有一個__deepcopy__()方法)。有什麼辦法可以做到這一點?

+1

爲什麼你叫'和'self' deepcopy'作爲第一個參數 – Blender

+0

因爲我想'__deepcopy __()'方法返回的'一個deepcopy的自我「,以sm爲模所有改變,我不深'複製'self.b'。 – marius

+0

'deepcopy'只有一個參數。你是淺拷貝它們嗎? – Blender

回答

1

任何時候你實現一個特殊的方法(如__getattr__,__deepcopy__,__str__等)你或者需要上超mro或使用原始的一些子集。

我不完全清楚你如何記憶屬性,但我會簡化你的例子。假設你總是使用相同的a(並且它是不可變的,並且不需要被複制),否則,你想複製b。 (你可以通過ab直接構造,使一個新的對象

class CustomDeepcopy(object): 
    def __init__(self, a=None, b=None): 
     if a: 
      self.a = a 
     if b: 
      self.b = b 

    a = SomeSimpleObject() 
    b = SomeBigObject() 

    @property 
    def dont_deepcopy(self): 
     return ['b'] 
    @property 
    def deepcopy_attributes(self): 
     return ['a'] 

    def __deepcopy__(self,memo): 
     new_kwargs = dict((k, getattr(self, attr, None)) for attr in self.dont_deepcopy) 
     for attr in self.deepcopy_attributes: 
      new_kwargs[attr] = copy.deepcopy(getattr(self, attr, None)) 
     return self.__class__(**new_kwargs) 
+1

在這種情況下,MRO上升的問題是深層拷貝代碼在靜態方法'copy.deepcopy'中,而不是在'object .__ deepcopy__'中。 否則你給的答案是一個很好的解決方法,但我希望能夠使用deepcopy。 – marius

+0

@marius現在檢查答案,它應該涵蓋你要找的東西(或至少解釋如何工作) –

+0

謝謝。我用這個解決方案看到的問題是它依賴於__init__構造函數保持不變。我想讓後來的某個人用完全不同的東西覆蓋它,而不是依賴構造函數採取特定形式的事實。 – marius

0

copy.deepcopy只會調用__deepcopy__如果方法存在 - 我們可以通過保存的__deepcopy__價值,呼籲copy.deepcopy(...)避免這一點,然後返回結果之前恢復的__deepcopy__值:

class CustomDeepcopy(object): 

    a = SomeSimpleObject() 
    b = SomeBigObject() 

    def dont_deepcopy(self): 
     return ['b'] 

    def __deepcopy__(self,memo): 
     for attr in self.dont_deepcopy(): 
      val = getattr(self,attr,None) 
      if val is not None: 
       memo[id(val)]=val 
     deepcopy_method = self.__deepcopy__ 
     self.__deepcopy__ = None 
     result = copy.deepcopy(self,memo) 
     self.__deepcopy__ = deepcopy_method 
     return result