2012-01-07 12 views
5

He pasado las últimas 2 horas en esto y probablemente he leído todas las preguntas aquí relacionadas con las variables que se pasan a las funciones. Mi problema es el común del parámetro/argumento que se ve afectado por los cambios realizados dentro de la función, aunque eliminé la referencia/alias usando variable_cloned = variable[:] en la función para copiar los contenidos sin la referencia.El argumento/parámetro pasado en la función todavía se está cambiando después de eliminar la referencia/alias

Aquí está el código:

def add_column(m):  
    #this should "clone" m without passing any reference on  
    m_cloned = m[:] 
    for index, element in enumerate(m_cloned): 
     # parameter m can be seen changing along with m_cloned even 
     # though 'm' is not touched during this function except to 
     # pass it's contents onto 'm_cloned'   
     print "This is parameter 'm' during the for loop...", m 
     m_cloned[index] += [0] 
    print "This is parameter 'm' at end of for loop...", m  
    print "This is variable 'm_cloned' at end of for loop...", m_cloned 
    print "m_cloned is m =", m_cloned is m, "implies there is no reference" 
    return m_cloned 

matrix = [[3, 2], [5, 1], [4, 7]] 
print "\n" 
print "Variable 'matrix' before function:", matrix 
print "\n" 
add_column(matrix) 
print "\n" 
print "Variable 'matrix' after function:", matrix 

Lo que estoy notando es que el parámetro 'm' en la función está cambiando, como si es un alias de m_cloned - pero por lo que yo puedo decir que tengo eliminó el alias con la primera línea de la función. En todas partes que he buscado en línea parece sugerir que esta línea se asegurará de que no haya ninguna referencia al parámetro, pero no está funcionando.

Estoy seguro de que debo haber cometido un simple error, pero después de 2 horas no creo que vaya a encontrarlo.

+1

"... aunque he eliminado la referencia/alias usando variable_cloned = variable [:] en la función para copiar los contenidos sin la referencia. " Esto hace que 'variable_cloned' se refiera a una lista separada de' variable', pero las dos listas contendrán contenidos idénticos: referencias a sus tres listas (de 2 elementos). –

Respuesta

9

Parece que necesita un deepcopy, en lugar de una copia superficial, que es lo que [:] le da:

from copy import deepcopy 
list2 = deepcopy(list1) 

Aquí está un ejemplo ya la comparación de los dos tipos de copia:

from copy import deepcopy 

list1 = [[1], [1]] 
list2 = list1[:] # while id(list1) != id(list2), it's items have the same id()s 
list3 = deepcopy(list1) 

list1[0] += [3] 

print list1 
print list2 
print list3 

Salidas:

[[1, 3], [1]] # list1 
[[1, 3], [1]] # list2 
[[1], [1]]  # list3 - unaffected by reference-madness 
+0

Wow gracias, nunca hubiera llegado allí solo. Estoy viendo [link] (http://docs.python.org/library/copy.html) que parece explicar de alguna manera las diferencias entre la copia profunda y la somera, pero no estoy seguro de lo que significa en la práctica, ¿debería ¿hago una copia profunda cada vez que paso una variable a una función? – FiveAlive

+1

@FiveAlive No necesariamente. Algunas veces quiere mantener referencias a objetos "secundarios". A veces no importa (cuando se trata de "niños" inmutables), ya que cosas como strings/ints no pueden cambiar los valores, sino que se reemplazan por copias nuevas, lo que no sería un problema en su caso. "Saber" es la mitad de la batalla (dicen), ahora que lo sabes, estoy seguro de que prestarás más atención la próxima vez a lo que necesites. –

+0

Gracias de nuevo, eso lo ha aclarado todo :) – FiveAlive

Cuestiones relacionadas