deepcopy在具有自定义__new__()方法的对象上增加了类型错误。

时间:2021-07-02 17:01:57

I want to implement a symbol type, which keeps track of the symbols we already have(saved in _sym_table), and return them if they exist, or create new ones otherwise. The code:

我希望实现一个符号类型,它跟踪我们已经拥有的符号(保存在_sym_table中),如果它们存在,则返回它们,否则创建新的符号。代码:

# -*- coding: utf-8 -*-

_sym_table = {}

class Symbol(object):
    def __new__(cls, sym):
        if sym not in _sym_table:
            return super().__new__(cls)
        else:
            return _sym_table[sym]

    def __init__(self, sym):
        self.sym = sym
        _sym_table[sym] = self

    def __str__(self):
        return self.sym

    def __cmp__(self, other):
        return self is other

    def __hash__(self):
        return self.sym.__hash__()

But when I call copy.deepcopy on a list of such Symbol instances, exception is raised:

但当我调用copy.deepcopy在一个这样的符号实例列表时,会出现异常:

a = Symbol('a')
b = Symbol('b')
s = [a, b]
t = copy.deepcopy(s)

Error messages:

错误消息:

Traceback (most recent call last):
  File "xxx.py", line 7, in <module>
    t = copy.deepcopy(s)
  File "/usr/lib/python3.2/copy.py", line 147, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python3.2/copy.py", line 209, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File "/usr/lib/python3.2/copy.py", line 174, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/lib/python3.2/copy.py", line 285, in _reconstruct
    y = callable(*args)
  File "/usr/lib/python3.2/copyreg.py", line 88, in __newobj__
    return cls.__new__(cls, *args)
TypeError: __new__() takes exactly 2 arguments (1 given)

So my questions are:

所以我的问题是:

  • How can I make a deep copy on these objects with self-defined __new__ methods?
  • 如何用自定义的__new__方法对这些对象进行深入的复制?
  • And any suggestions about when and how to use copy.deepcopy?
  • 关于何时以及如何使用copy.deepcopy有什么建议吗?

Thanks a lot!

谢谢!

3 个解决方案

#1


5  

one problem is that deepcopy and copy have no way of knowing which arguments to pass to __new__, therefore they only work with classes that don't require constructor arguments.

一个问题是,deepcopy和copy无法知道要传递给__new__的哪些参数,因此它们只处理不需要构造函数参数的类。

the reason why you can have __init__ arguments is that __init__ isn't called when copying an object, but __new__ must be called to create the new object.

您可以使用__init__参数的原因是,__init__在复制对象时不被调用,但是必须调用__new__来创建新对象。

so if you want to control copying, you'll have to define the special __copy__ and __deepcopy__ methods:

因此,如果你想控制复制,你必须定义特殊的__copy__和__deepcopy__方法:

def __copy__(self):
    return self

def __deepcopy__(self, memo):
    return self

by the way, singletons are evil and not really needed in python.

顺便说一下,单例是邪恶的,在python中不是真正需要的。

#2


1  

Seems to me you want the Symbol instances to be singletons. Deepcopy, however is supposed to be used when you want an exact copy of an instance, i.e. a different instance that is equal to the original.

在我看来,您希望符号实例为单例。但是,当您想要一个实例的确切副本时,应该使用Deepcopy,即一个与原始副本相同的不同实例。

So the usage here kinda contradicts the purpose of deepcopy. If you want to make it work anyhow, you can define the __deepcopy__ method on Symbol.

所以这里的用法与deepcopy的目的有点矛盾。如果你想让它正常工作,你可以在符号上定义__deepcopy__方法。

#3


0  

Define __getnewargs__ — that way you will not only be able to copy and deepcopy, but you'll also be able to pickle.

定义__getnewargs__——这样你不仅可以复制和深度复制,而且还可以pickle。

#1


5  

one problem is that deepcopy and copy have no way of knowing which arguments to pass to __new__, therefore they only work with classes that don't require constructor arguments.

一个问题是,deepcopy和copy无法知道要传递给__new__的哪些参数,因此它们只处理不需要构造函数参数的类。

the reason why you can have __init__ arguments is that __init__ isn't called when copying an object, but __new__ must be called to create the new object.

您可以使用__init__参数的原因是,__init__在复制对象时不被调用,但是必须调用__new__来创建新对象。

so if you want to control copying, you'll have to define the special __copy__ and __deepcopy__ methods:

因此,如果你想控制复制,你必须定义特殊的__copy__和__deepcopy__方法:

def __copy__(self):
    return self

def __deepcopy__(self, memo):
    return self

by the way, singletons are evil and not really needed in python.

顺便说一下,单例是邪恶的,在python中不是真正需要的。

#2


1  

Seems to me you want the Symbol instances to be singletons. Deepcopy, however is supposed to be used when you want an exact copy of an instance, i.e. a different instance that is equal to the original.

在我看来,您希望符号实例为单例。但是,当您想要一个实例的确切副本时,应该使用Deepcopy,即一个与原始副本相同的不同实例。

So the usage here kinda contradicts the purpose of deepcopy. If you want to make it work anyhow, you can define the __deepcopy__ method on Symbol.

所以这里的用法与deepcopy的目的有点矛盾。如果你想让它正常工作,你可以在符号上定义__deepcopy__方法。

#3


0  

Define __getnewargs__ — that way you will not only be able to copy and deepcopy, but you'll also be able to pickle.

定义__getnewargs__——这样你不仅可以复制和深度复制,而且还可以pickle。