2012-01-07 4 views
5

Spędziłem ostatnie 2 godziny na tym i prawdopodobnie przeczytałem każde pytanie tutaj odnoszące się do zmiennych przekazywanych do funkcji. Mój problem jest typowy dla parametru/argumentu, na który wpływają zmiany wprowadzone w funkcji, mimo że usunąłem referencję/alias za pomocą funkcji variable_cloned = variable[:] w funkcji kopiowania zawartości bez odniesienia.Podane argumenty/parametry w funkcji są wciąż zmieniane po usunięciu odniesienia/aliasu.

Oto kod:

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 

Co mam zauważyć, że parametr „m” w funkcji zmienia się tak, jakby to aliasem m_cloned - ale o ile mogę powiedzieć, mam usunął alias z pierwszym wierszem funkcji. Gdziekolwiek indziej wyglądałem online wydaje się sugerować, że ta linia upewni się, że nie ma odniesienia do parametru - ale to nie działa.

Jestem pewien, że popełniłem prosty błąd, ale po 2 godzinach nie sądzę, żebym go znalazł.

+1

"... mimo że usunąłem odniesienie/alias przy użyciu zmiennej_kloned = zmienna [:] w funkcji kopiowania treści bez odniesienia. " To sprawia, że ​​'zmienna_klikowana' odnosi się do osobnej listy z' zmiennej', ale obie listy będą zawierały identyczną zawartość: odniesienia do twoich trzech (2-elementowych) list. –

Odpowiedz

9

Wygląda na to trzeba deepcopy zamiast płytkim egzemplarzu, który jest co [:] daje:

from copy import deepcopy 
list2 = deepcopy(list1) 

Oto już przykład porównując dwa typy kopii:

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 

Wyjścia:

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

Wow, dzięki, nigdy bym tam nie dotarł sam. Patrzę na [link] (http://docs.python.org/library/copy.html), który wydaje się nieco wyjaśniać różnice między głęboką i płytką kopią, ale nie jestem pewien, co to właściwie oznacza - czy powinienem wykonuję deepcopy za każdym razem, gdy przekazuję zmienną do funkcji? – FiveAlive

+1

@FiveAlive Niekoniecznie. Czasami chcesz zachować odniesienia do obiektów "potomnych". Czasami nie ma to znaczenia (gdy mamy do czynienia z niezmiennymi "dziećmi"), ponieważ rzeczy takie jak string/int nie mogą zmieniać wartości, ale zamiast tego są zastępowane przez nowe kopie, które nie byłyby problemem w twoim przypadku. "Wiedza" to połowa sukcesu (mówią), teraz, gdy już wiesz, jestem pewien, że następnym razem będziesz zwracać baczniejszą uwagę na to, czego potrzebujesz. –

+0

Jeszcze raz dziękuję, to oczyściło wszystko dla mnie :) – FiveAlive

Powiązane problemy