Jestem początkującym w Pythonie i używam książki Mark Lutza, aby poznać podstawy Pythona.

Oto przykład, który autor używa do wykazania magazynowania informacji o stanie za pomocą list:

def tester(start):
    def nested(label):
        print(label,state[0])
        state[0] += 1
    state = [start]
    return nested

Oto kod do testowania informacji o stanie:

F = tester(3)
F('sam')
F('sam')

Zobaczysz, że licznik wzrasta z 3, a potem kontynuuje. W istocie, powyżej kodu przechowuje stan początkowym start (przekazywany podczas inicjalizacji obiektu) w [state] i przyniesiono go za każdym razem label.

Jednak nie jestem pewien, dlaczego Python nie rzuca błąd w bloku nested. W szczególności [state] jest lokalny na tester i nie nested.

Aby zademonstrować, co mam na myśli, zamierzam zastąpić state[0] przez state.

def tester(start):
    def nested(label):
        print(label,state) #Replaced state[0] with state
        state += 1         #Replaced state[0] with state
        print("after:",state)
    state = start          #Replaced state[0] with state
    return nested

Technicznie, powyższy kod powinien również działać dobrze, ponieważ wszystko, co zrobiłem, to zastąpiła listę ze zmienną. Jednak Pycharm nie uruchomiłby nawet tego kodu. Dostaję błąd nboundLocalError: local variable 'state' referenced before assignment

Czy ktoś może wyjaśnić, dlaczego wersja z list działa dobrze? Autor stwierdził, że "to wykorzystuje niezutowalność list i opiera się na fakcie, że obiekt w miejscu nie klasyfikuje nazwy jako lokalnej".

Nie jestem pewien, co to znaczy. Czy ktoś może mi pomóc? Dziękujemy za wszelką pomoc rozszerzoną mi.

3
watchtower 2 czerwiec 2018, 06:11

3 odpowiedzi

Najlepsza odpowiedź

Powinieneś przeczytać tę sekcję dokumentacji.

Zasadniczo w obu wersjach zakres zagnieżdżonego bloku pozwala na interakcję z przestrzeni nazw obserwujących blok. Różnica polega na tym, że nie przypiszesz state w pierwszym przykładzie, co go mutując.

W drugim przykładzie Python wie, że zamierzasz przypisać wartość do tego odniesienia później w funkcji, więc jest traktowany jako nazwa z przestrzeni nazw lokalnego {x0}}, a nie przestrzeni nazw tester .

Możesz użyć słowa kluczowego nonlocal, aby ominąć go i używać innego odniesienia z drugiej przestrzeni nazw

def tester(start):
    def nested(label):
        nonlocal state
        print(label,state) 
        state += 1         
        print("after:",state)
    state = start          
    return nested
2
Patrick Haugh 2 czerwiec 2018, 03:29

Jest to funkcja 1), jak przypisanie zmiennej Pythona faktycznie tworzy aliasy (wskaźniki) do podstawowych wartości w pamięci, a różnica między sposobami obróbki niezmiennych i niezmiennych; oraz 2) niektóre pythona "magia" związane z zamkniętymi zamknięciami. Krux twojego pytania jest naprawdę pierwszym punktem.

Aby rozwiązać to, podjąć na przykład następujące:

a = 3
b = 3

Zarówno A, jak i B, wskaż tego samego obiektu bazowego:

assert hex(id(a)) == hex(id(b)) 

Jest prawdziwy. Jednakże, ustawienie b = 4 spowoduje, że b będzie wskazuje na inny obiekt w pamięci (pokazujący, że int jest niezmienny).

Jednak lista jest niezmienna (modyfikowalna "na miejscu"). Na przykład: c = [2] będzie miała tę samą lokalizację pamięci przed i po operacji jak c[0] = 3.

Istnieje wiele konsekwencji tego bardzo podstawowego wyjaśnienia, które zajmuje trochę czasu na interpretację. Na przykład zmienne nie mogą "wskazywać" innych zmiennych, ale raczej w kierunku leżącego obiektów.

W rezultacie listy mogą wykazywać "dziwne" zachowanie (kolejne powiązane, powiązane zamieszanie obraca się wokół ustawienia domyślnej wartości parametru jako listy, która jest następnie modyfikowana w funkcji), ale można również skorzystać ze sposobu, w jaki przykład pokazuje.

1
ZaxR 2 czerwiec 2018, 03:52

Z tego, co rozumiem, ponieważ nested jest zagnieżdżona pod tester, miałoby dostęp do dowolnych obiektów i zmiennych, do których należy do tester, ponieważ tester jest funkcją nadrzędną i {{} X4}} Czy funkcja dzieci w tym przypadku. Python nie wywołać błędu z powodu dziedziczenie.

I o wymianie state[0] za pomocą state, Python automatycznie zakłada, że state jest integer, ponieważ próbujesz dodać do niego. Podczas state jest lista, a nie możesz dodać, chyba że jesteś dołącz / A> element do tego - który to nie jest twoja sprawa. Powodem, dla którego state[0] działa, a nie state jest dlatego, że state[0] jest elementem w liście state i dodaje 0 do niej.

1
sumguy37 2 czerwiec 2018, 03:33