2009-12-21 52 views
4

在我的代碼中,我試圖使用copy.deepcopy來獲取一個類的實例副本。問題是,在某些情況下它與下面的錯誤示數:如何調試針對自定義類型調用Python的copy.deepcopy()的問題?

TypeError: 'object.__new__(NotImplementedType) is not safe, use NotImplementedType.__new__()' 

多挖後,我發現,我可以使用下面的代碼重現錯誤:

import copy 
copy.deepcopy(__builtins__) 

問題似乎是在某種程度上它試圖複製內建的NotImplementedType。問題是爲什麼它這樣做?我在班上並沒有重寫__deepcopy__,而且這種情況一直沒有發生。有沒有人有任何提示來追蹤製作此類拷貝的請求來自哪裏?

我已經在copy模塊本身中加入了一些調試代碼,以確保這是發生了什麼事情,但問題發生的地方是遞歸堆棧的這麼遠,很難做出我很多東西看到。

+0

你的實例擁有什麼類型的引用? – 2009-12-21 19:11:17

+0

@Matt:實例持有configobj實例和其他東西(其他東西是標準列表和字典等)。 – jkp 2009-12-21 19:12:30

+0

好吧,看起來問題是其中一個成員是一個包含對模塊的引用的詞典。所以現在這個問題似乎是我如何能夠在遇到某些類型時停止深層複製,而不是試圖複製它們(模塊和類在我的情況下)。任何線索? – jkp 2009-12-21 20:33:58

回答

1

您可以覆蓋__deepcopy__方法:(python documentation

In order for a class to define its own copy implementation, it can define special methods __copy__() and __deepcopy__(). The former is called to implement the shallow copy operation; no additional arguments are passed. The latter is called to implement the deep copy operation; it is passed one argument, the memo dictionary. If the __deepcopy__() implementation needs to make a deep copy of a component, it should call the deepcopy() function with the component as first argument and the memo dictionary as second argument.

否則,你可以在模塊保存在一個全局列表或別的東西。

3

在我到底在copy源代碼一些挖掘和用以下解決方案上來:

from copy import deepcopy, _deepcopy_dispatch 
from types import ModuleType 

class MyType(object): 

    def __init__(self): 
     self.module = __builtins__ 

    def copy(self): 
     ''' Patch the deepcopy dispatcher to pass modules back unchanged ''' 
     _deepcopy_dispatch[ModuleType] = lambda x, m: x 
     result = deepcopy(self) 
     del _deepcopy_dispatch[ModuleType] 
     return result 

MyType().copy() 

我意識到這使用私有API,但我找不到實現的另一種清潔方式一樣。我在網上做了一個quick search,發現其他人使用相同的API沒有任何麻煩。如果它在未來發生變化,我會接受命中。

我也意識到這不是線程安全的(如果一個線程需要舊的行爲,而我正在另一個線程上做一個副本,我會被搞砸),但是現在它對我來說也不是問題。

希望在某個時候幫助別人。

1

可以覆蓋包含一個指向一個模塊,通過使用pickle protocol,這是由複製模塊支持的類的deepcopy的行爲,如規定here。特別是,您可以爲該類定義__getstate____setstate__。例如:

>>> class MyClass: 
...  def __getstate__(self): 
...   state = self.__dict__.copy() 
...   del state['some_module'] 
...   return state 
...  def __setstate__(self, state): 
...   self.__dict__.update(state) 
...   self.some_module = some_module 
+0

我剛剛注意到你說的問題模塊是字典的成員。如果有一個擁有該字典的(單個)對象,那麼該對象可以定義自定義的getstate/setstate來適當地修改該字典。如果該字典是由多個對象共享的,那麼您可能會使用猴子修補方法卡住。 (或者重構一下你的代碼。) – 2009-12-23 18:20:30

相關問題