2012-05-16 17 views
8

Quiero implementar un tipo de símbolo, que realiza un seguimiento de los símbolos que ya tenemos (guardado en _sym_table), y los devuelve si existen, o crea nuevos de lo contrario. El código:copy.deepcopy plantea TypeError en objetos con el método __new __() autodefinido

# -*- 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__() 

Pero cuando llamo copy.deepcopy en una lista de tales Symbol casos, se produce una excepción:

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

mensajes de error:

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) 

Así que mis preguntas son:

  • H ¿Cómo puedo hacer una copia profunda de estos objetos con los métodos autodefinidos __new__?
  • Y cualquier sugerencia sobre cuándo y cómo usar copy.deepcopy?

¡Muchas gracias!

Respuesta

5

Un problema es que deepcopy y copy no tienen manera de saber qué argumentos para pasar a __new__, por lo tanto, que sólo funcionan con las clases que no requieren argumentos de constructor.

la razón por la que puede tener argumentos __init____init__ es que no se llama al copiar un objeto, pero __new__ debe ser llamado para crear el nuevo objeto.

por lo que si desea controlar la copia, usted tiene que definir las especiales __copy__ y __deepcopy__ métodos:

def __copy__(self): 
    return self 

def __deepcopy__(self, memo): 
    return self 

por cierto, son singletonsevil y no es realmente necesario en pitón.

1

Me parece que desea que las instancias de Symbol sean singletons. Sin embargo, se supone que Deepcopy se debe usar cuando desee una copia exacta de una instancia, es decir, una instancia diferente que sea igual a la original.

Por lo que el uso aquí contradice el propósito de deepcopy. Si desea que funcione de todos modos, puede definir el método __deepcopy__ en Símbolo.

0

Definir __getnewargs__ - de ese modo no sólo será capaz de copy y deepcopy, pero también será capaz de pickle.

Cuestiones relacionadas