2010-06-04 12 views
10

Una pregunta simple, tal vez, pero no puedo pronunciar mi consulta de Google para encontrar la respuesta aquí. He tenido el hábito de hacer copias de los objetos cuando los paso en objetos constructores, así:¿Python copia el valor o la referencia en la instanciación de objetos?

... 
def __init__(self, name): 
    self._name = name[:] 
... 

Sin embargo, cuando me encontré con el siguiente código de prueba, parece no ser necesario, que Python está haciendo copias en profundidad de los valores de los objetos sobre instancias de objetos:

>>> class Candy(object): 
...  def __init__(self, flavor): 
...    self.flavor = flavor 
... 
>>> flav = "cherry" 
>>> a = Candy(flav) 
>>> a 
<__main__.Candy object at 0x00CA4670> 
>>> a.flavor 
'cherry' 
>>> flav += ' and grape' 
>>> flav 
'cherry and grape' 
>>> a.flavor 
'cherry' 

Así que, ¿cuál es la verdadera historia aquí? ¡Gracias!

EDIT:

Gracias a @Olivier por su gran respuesta. El siguiente código documenta un ejemplo mejor que Python no copiar por referencia:

>>> flav = ['a','b'] 
>>> a = Candy(flav) 
>>> a.flavor 
['a', 'b'] 
>>> flav[1] = 'c' 
>>> flav 
['a', 'c'] 
>>> a.flavor 
['a', 'c'] 

Respuesta

13

Se debe a que las cadenas son inmutables .

El operador +=, en lugar de crear confusión, en realidad reasigna la variable que se aplica, si el objeto es inmutable:

s = 'a' 
ids = id(s) 
s += 'b' 
ids == id(s) # False, because s was reassigned to a new object 

Así, en su caso, en un principio, tanto flav y a.flavor punto con el mismo objeto de cadena:

flav --------\ 
       'cherry' 
a.flavor ----/ 

Pero cuando se escribe la variable flav += 'and grape'flav consigue reasignados a un nuevo objeto de cadena:

flav --------> 'cherry and grape' 
a.flavor ----> 'cherry' # <-- that string object never changes 

Es confuso, porque por lo general, cuando se llama a un operador en una variable, no cambia la variable. Pero solo en el caso de un objeto inmutable, reasigna la variable.

Así que la respuesta final a su pregunta es, sí, tiene sentido copiar los objetos en la instanciación, especialmente si está esperando un objeto mutable (que a menudo es el caso). Si el objeto era inmutable, no estaría de más copiarlo de todos modos.

+3

Para aclarar, 'self.flavor = flavor' no copia por referencia, pero como las cadenas son inmutables, el objeto al que se hace referencia no se puede cambiar. Por lo tanto, 'flav + = 'y grape' en realidad crea un nuevo objeto de cadena y hace que' flav' lo haga referencia. – taleinat

+0

@taleinat: gracias, actualicé la respuesta, esperando que no llegue a ser confusa. –

+0

Gracias chicos por sus respuestas. Supongo que entonces, todavía me pregunto si copiar objetos en una instanciación es una buena idea, ya que no veo muchos lugares donde se hace. Alguna sugerencia? – daveslab

1

parece no ser necesario

aparezca? Su pregunta es enteramente sobre el diseño y el significado. Esta no es una pregunta de preferencia o hábito.

¿El contrato de clase incluye la capacidad de modificar un argumento mutable? Si es así, NO hagas una copia.

¿El contrato de clase afirma que un argumento mutable no se modificará? Si es así, DEBE hacer una copia.

Sus preguntas han sido respondidas por completo por la definición de contrato para la clase.

+0

Veo el área de tu confusión. Debería haber tenido una oración en la parte superior diciendo que mi objetivo era asegurarme de que las variables pasadas a '__init__' se copiaran por valor, no por referencia al objeto. Lo que quise decir con 'Parece que no es necesario' es que parecía que no necesitaba usar mis métodos de copia porque Python lo estaba haciendo de todos modos. Estaba equivocado – daveslab

+1

@daveslab: No comentar. Arregla la pregunta Por favor ** actualice ** la pregunta para indicar claramente cuál es su objetivo en realidad. Otras personas leen estas preguntas tratando de aprender Python y un buen diseño del programa. Por favor, corrija la pregunta para que quede perfectamente clara. –

Cuestiones relacionadas