问题
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:
# -*- 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:
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? - And any suggestions about when and how to use
copy.deepcopy?
Thanks a lot!
回答1:
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.
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.
so if you want to control copying, you'll have to define the special __copy__ and __deepcopy__ methods:
def __copy__(self):
return self
def __deepcopy__(self, memo):
return self
by the way, singletons are evil and not really needed in python.
回答2:
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.
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.
回答3:
Define __getnewargs__ — that way you will not only be able to copy and deepcopy, but you'll also be able to pickle.
来源:https://stackoverflow.com/questions/10618956/copy-deepcopy-raises-typeerror-on-objects-with-self-defined-new-method