2011-08-10 6 views
7

Jestem zdezorientowany, jak Python przegląda ten słownik. Z dokumentacji Pythona, itervalues ​​zwraca iterator na wartości słownika.Dlaczego iteracja słownika Pythona wydaje się działać z kopią?

dict = {"hello" : "wonderful", "today is" : "sunny", "more text" : "is always good"} 

for x in dict.itervalues(): 
    x = x[2:] 

print dict 

Spowoduje to wydrukowanie oryginalnego słownika. Dlaczego? Jeśli mówię, że wartość na pozycji x to "blabla", dlaczego nie jest ustawiona?

+0

+1 na dobre pytanie. Rzucało mnie przez chwilę. –

+0

to dobre pytanie. – Andy

Odpowiedz

7

Nie ma to nic wspólnego z ciągami lub listami. Diabeł tkwi w tym, jak rozłożony jest for.

Doing

for x in d.iteritems(): 
    # loop body 

jest bardziej lub mniej równoważne robi

iter = d.itervalues() 
while True: 
    try: 
     x = next(iter) 
     # loop body 
    except StopIteration: 
     break 

więc mając to na uwadze, że nie jest bardzo trudno zobaczyć, że jesteśmy po prostu realokacja x, który posiada wynik z wywołania funkcji.

iter = d.itervalues() 
while True: 
    try: 
     x = next(iter) 

     x = 5 # There is nothing in this line about changing the values of d 
    except StopIteration: 
     break 
+0

Dzięki, to wyjaśniło to dla mnie. Chciałbym, żeby doktorzy Pythona wyjaśnili rzeczy bardziej szczegółowo, takie jak zawiłości instrukcji for i różnych metod. – Justin

5

Jedyne linia

x = x[2:] 

robi jest stworzenie kawałek ciąg x[2:] i ponownego wiązania nazwę x zwrócić się do tego nowego łańcucha. Nie zmienia on łańcucha znaków x wskazanego wcześniej. (. Struny są niezmienne w Pythonie, nie mogą być zmienione)

Aby osiągnąć to, co rzeczywiście chcesz, musisz dokonać słownika punkt wejścia do nowego obiektu String stworzonej przez krojenie:

for k, v in my_dict.iteritems(): 
    my_dict[k] = v[2:] 
+2

Nie ma to nic wspólnego z niezmiennymi ciągami; jeśli zastąpię "" witaj ":" cudowne "' z '" witaj ": [1,2]' działa tak samo. –

+1

@ Mark: Podałem także prawdziwą przyczynę tego zachowania - fakt, że ciągi są niezmienne, jest raczej notatką poboczną. Wpływa to jednak na rozwiązanie - jeśli wartości były listami, możesz użyć 'for x in my_dict: del x [: 2]', aby osiągnąć pożądane zachowanie. –

+0

@Emil: Nie rozumiem twojego komentarza. Czy w jakikolwiek sposób jest to związane z moją odpowiedzią? A może mój komentarz? Czy to twoja przegrana? –

1

Jak wskazuje Sven Marnach, ciągi są niezmienne i właśnie ponownie wiążą się x z nowym ciągiem utworzonym przez notację plastra. Można wykazać, że xrobi punkt do tego samego obiektu w słowniku za pomocą id:

>>> obj = 'hello' 

>>> id(obj) 
<<< 4318531232 

>>> d = {'key': obj} 

>>> [id(v) for v in d.values()] 
<<< [4318531232] 

>>> [id(v) for v in d.itervalues()] 
<<< [4318531232] 

>>> [(k, id(v)) for k, v in d.items()] 
<<< [('key', 4318531232)] 

>>> [(k, id(v)) for k, v in d.iteritems()] 
<<< [('key', 4318531232)] 

Można użyć iteritems iteracyjne nad kluczem i wartością razem robić to, co chcesz:

for k,v in dict.iteritems(): 
    dict[k] = v[2:]