2012-05-17 8 views
8

Me doy cuenta de que se han formulado preguntas bastante similares a esta, aunque no exactamente de esta manera.¿Existe alguna forma decente de crear un constructor de copias en python?

Me gustaría tener un argumento opcional para el constructor de mi clase que, si es una instancia de mi clase, se copiará. Por ejemplo, algo así como (Sé que este código no funciona!):

class Foo(object): 
    def __init__(self, foo=None): 
     self.x = None 
     self.y = None 
     self.z = None 

     if foo is not None and isinstance(foo, Foo): 
      self = copy.deepcopy(foo) 

a = Foo() 
a.x = 1 
a.y = 2 
a.z = 3 

b = Foo(a) 
print b.x 
print b.y 
print b.z 

Sé que hay algunas soluciones prácticas a esto. Podría establecer cada atributo de uno mismo de acuerdo con el valor del atributo correspondiente de foo, pero esto sería realmente molesto porque mi clase tiene muchos, muchos atributos. O simplemente podría usar do:

b = copy.deepcopy(a) 

... Pero prefiero no si eso es posible. También espero evitar anular __new__.

¿Realmente no hay forma decente en python para crear un constructor de copia?

+3

Por qué no hacer ¿Quieres usar b = copy.deepcopy (a)? Quiero decir, si funciona, y no toma más líneas para escribir que b = Foo (a) .... – DGH

+0

Bueno, supongo que mis dedos todavía están cruzados de que un constructor de copia es factible. Y, francamente, ¿por qué no? No es como si fuera una solicitud realmente inusual. Uno podría pensar que todos los lenguajes orientados a objetos tendrían esta característica. – carmenism

+1

¿Por qué no es una característica? Porque es solo azúcar sintáctico, una forma diferente de decir exactamente lo mismo. Mientras exista la funcionalidad para hacer una copia profunda con solo una línea de código muy simple, ¿por qué importa si es un "constructor" o no? – DGH

Respuesta

16

Creo que esta es la forma más pitónica de hacerlo, un método de copia de fábrica.

import copy 

class Foo(object): 
    def __init__(self): 
     self.x = None 
     self.y = None 
     self.z = None 
    def copy(self): 
     return copy.deepcopy(self) 

a = Foo() 
a.x = 1 
a.y = 2 
a.z = 3 

b = a.copy() 
print b.x 
print b.y 
print b.z 

Esto es bastante común en Python tipos básicos (por ejemplo dict.copy). No es un constructor de copias, ¡pero no creo que sea un concepto muy pitónico!

+0

Esa fue otra idea que olvidé mencionar en mi pregunta. Me gusta más que b = copy.deepcopy (a) al menos. ¡Gracias! – carmenism

0

Es posible , en la que sólo puede iterar sobre todos los atributos del objeto de fuente pasado a __init__, y luego setattr() los que se preocupan por el self. Pero no está del todo claro que esta sea una buena forma de resolver un problema. No muy pitónico, y todo.

+0

Me pregunté sobre eso también, pero de hecho no parece muy pitónico. Gracias de cualquier manera. – carmenism

0

Una buena manera de hacer esto es hacer una copia de nivel superior del espacio de nombres de la instancia.

class Tst: 
    def __init__(self, somearg): 
     if isinstance(somearg, self.__class__): 
      self.__dict__ = somearg.__dict__.copy() 
     else: 
      self.var = somearg 
    def echo(self): 
     print(self.var) 

a = Tst(123) 
b = Tst(456) 
a.echo()  # gives 123 
b.echo()  # gives 456 
c = Tst(a) 
c.echo()  # gives 123 
c.var is a.var # gives False -> different objects 

Pero tenga cuidado si su clase aborda __slots__, porque en ese caso __dict__ podría estar ausente y por lo tanto es posible que tenga que depender de mecanismos de atributos-que consigue más neutros, como getattr()

Cuestiones relacionadas