2015-04-22 16 views
6

Mam następujący kod i zmiennych, i chcę, aby znaleźć to, co zmienne a, a1, a2, b, b1 i b2 znajdują się po kod został wykonany.realokacja zmienne w Pythonie

def do_something(a, b): 
    a.insert(0, "z") 
    b = ["z"] + b 

a = ["a", "b", "c"] 
a1 = a 
a2 = a[:] 
b = ["a", "b", "c"] 
b1 = b 
b2 = b[:] 

do_something(a, b) 

Moja próba rozwiązania jest następująca:

a = ["z", "a", "b", "c"] 
a1 = ["a", "b", "c"] 
a2 = ["a", "b", "c"] 
b = ["z" "a", "b", "c"] 
b1 = ["a", "b", "c"] 
b2 = ["a", "b", "c"] 

Ale rzeczywista rozwiązaniem jest:

a = ["z", "a", "b", "c"] 
a1 = ["z", "a", "b", "c"] 
a2 = ["a", "b", "c"] 
b = ["a", "b", "c"] 
b1 = ["a", "b", "c"] 
b2 = ["a", "b", "c"] 

Czy ktoś może mi chodzić przez moją pomyłkę?

+0

w jakim punkcie czy znajdujesz/drukujesz wartości wszystkich zmiennych? Być może ma to coś wspólnego z zasięgiem – Totem

+2

Myślę, że przez "moje usiłowanie rozwiązania" masz na myśli "to, czego się spodziewam" ... czy to prawda? To może wyjaśnić pewne zamieszanie. – Ajean

+2

Przeczytaj [to] (http: // stackoverflow.com/questions/1132941/najmniej-zdziwienie-w-python-the-mutable-default-argument) może pomóc zrozumieć, dlaczego tak się stało – Anzel

Odpowiedz

6

OK, możesz myśleć o zmiennych w Pythonie jako odniesieniach. Gdy to zrobisz:

a1 = a 

Zarówno a1 i a są odwołania do tego samego obiektu, więc jeśli zmodyfikować obiekt wskazywany przez a widać zmiany w a1, bo - zaskoczenie - są one ten sam przedmiot (i metoda list.insert mutuje listę w miejscu).

Ale kiedy to zrobić:

a2 = a[:] 

Następnie a2 to nowy list instancji, a po zmodyfikowaniu a nie modyfikują a2.

Wynik operatora + na listach jest nowa lista, więc kiedy to zrobić:

b = ['z'] + b 

Jesteś przypisując nową listę do b zamiast mutacji b w miejscu jak byś zrobił z b.insert('z') . Teraz b wskazuje na nowy obiekt, podczas gdy b1 nadal wskazuje na starą wartość b.

Ale zakresy mogą być jeszcze trudniejsze: możesz zobaczyć otaczający zakres z funkcji, ale jeśli przypiszesz zmienną w funkcji, nie zmieni ona zmiennej o tej samej nazwie w otaczającej (lub globalnej lub wbudowany) zakres, utworzy zmienną o tej nazwie w zasięgu lokalnym. Dlatego b nie został zmieniony - cóż, nie całkiem, przekazywanie parametrów w Pythonie jest operacją przypisania, więc b jest już zmienną lokalną, gdy jest parametr o nazwie b - ale próba zmutowania zmiennej zdefiniowanej w otaczającym zakresie prowadzi do podobny problem. BTW, złym zwyczajem jest polegać na zmiennych z otaczającego zakresu, chyba że są to stałe na poziomie modułu (tradycyjnie są one nazwane w stylu ALL_UPPERCASE i nie powinno się ich mutować). Jeśli potrzebujesz wartości wewnątrz funkcji, przekazać ją jako parametr, i chcesz zmienić wartość zmiennej w zakresie zamykającego, zwraca wartość i przypisać wartość zwracaną tam:

def do_something(a, b): 
    a.insert(0, "z") # mutates a in-place 
    return ["z"] + b 

b = do_something(a, b) 
+2

również warto wspomnieć, że 'b' w' do_something' został przypisany lokalnie, więc to się nie zmienia globalna wartość "b". – Anzel

+2

Wartość 'b' obliczana w' do_something() 'jest lokalna dla funkcji i jest odrzucana, gdy ta funkcja się kończy. Żadna ze zmiennych globalnych "b", "b1" lub "b2" nie jest dotknięta przez funkcję. – kindall

+0

dzięki chłopaki, dobry połów. –

Powiązane problemy