如何针对自定义类型调试调用Python的copy.deepcopy()的问题?

时间:2009-12-21 18:50:12

标签: python deep-copy

在我的代码中,我正在尝试使用copy.deepcopy复制一个类的实例。问题是在某些情况下出现以下错误是错误的:

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

经过多次挖掘后,我发现我能够使用以下代码重现错误:

import copy
copy.deepcopy(__builtins__) 

问题似乎是在某些时候它试图复制NotImplementedType内置版。问题是为什么这样做?我没有在课堂上覆盖__deepcopy__并且它不会一直发生。有没有人有任何关于追踪制作此类副本的请求来自哪里的提示?

我在copy模块本身放了一些调试代码,以确保这就是正在发生的事情,但问题发生的地方到目前为止,在递归堆栈中很难做到很多我看到了。

3 个答案:

答案 0 :(得分: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,没有任何麻烦。如果它将来发生变化,我会接受命中。

我也知道这不是线程安全的(如果一个线程需要旧的行为,而我在另一个线程上复制我会被搞砸)但是现在再次对我来说不是问题。 / p>

希望在某些时候帮助其他人。

答案 1 :(得分:1)

你可以覆盖__deepcopy__方法:(python documentation

  

为了让类定义自己的副本实现,它可以定义特殊方法 __ copy __() __ deepcopy __()。前者被称为实现浅拷贝操作;没有传递其他参数。调用后者来实现深拷贝操作;它传递了一个参数,即备忘录字典。如果 __ deepcopy __()实现需要制作组件的深层副本,它应该调用 deepcopy()函数,并将组件作为第一个参数,将备注字典作为第二个参数参数。

否则,您可以将模块保存在全局列表或其他内容中。

答案 2 :(得分:1)

您可以使用复制模块支持的pickle protocol来覆盖包含指向模块的指针的类的deepcopy行为,如here所述。特别是,您可以为该类定义__getstate____setstate__。 E.g:

>>> 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