Biorąc pod uwagę następujący kod:
def A() :
b = 1
def B() :
# I can access 'b' from here.
print( b )
# But can i modify 'b' here? 'global' and assignment will not work.
B()
A()
Ponieważ kod w B()
zmiennej funkcji b
znajduje się w zakresie zewnętrznym, ale nie w zasięgu globalnym. Czy można modyfikować b
zmienną z poziomu B()
funkcji? Z pewnością mogę to przeczytać stąd i print()
, ale jak to zmodyfikować?
python
python-2.7
grigoryvp
źródło
źródło
b
jest zmienna. Przypisanie dob
spowoduje zamaskowanie zakresu zewnętrznego.nonlocal
nie zostało przeniesione do wersji 2.x. To nieodłączna część wsparcia zamknięcia.Odpowiedzi:
Python 3.x ma
nonlocal
słowo kluczowe . Myślę, że robi to, co chcesz, ale nie jestem pewien, czy używasz Pythona 2 czy 3.W przypadku Pythona 2 zwykle używam po prostu zmiennego obiektu (takiego jak lista lub dict) i mutuję wartość zamiast ponownie przypisywać.
przykład:
Wyjścia:
źródło
class nonlocal: pass
zewnętrzny zakres. Następnienonlocal.x
można przypisać do w zakresie wewnętrznym.SyntaxError
. MożeNonLocal
?Nonlocal
,? :-)Możesz użyć pustej klasy do przechowywania tymczasowego zakresu. To jest jak zmienne, ale trochę ładniejsze.
Daje to następujące interaktywne wyjście:
źródło
Jestem trochę nowy w Pythonie, ale trochę o tym czytałem. Uważam, że najlepsze, co uzyskasz, jest podobne do obejścia w Javie, które polega na zawinięciu zewnętrznej zmiennej w listę.
Edycja: Wydaje mi się, że to prawdopodobnie prawda przed Pythonem 3. Wygląda na
nonlocal
to, że to twoja odpowiedź.źródło
Nie, nie możesz, przynajmniej w ten sposób.
Ponieważ „operacja set” utworzy nową nazwę w obecnym zakresie, który obejmuje zakres zewnętrzny.
źródło
Dla każdego, kto patrzy na to znacznie później, jest bezpieczniejsze, ale cięższe obejście. Bez potrzeby przekazywania zmiennych jako parametrów.
źródło
Krótka odpowiedź, która po prostu zadziała automagicznie
Stworzyłem bibliotekę Pythona do rozwiązania tego konkretnego problemu. Jest uwalniany pod wpływem nielubienia, więc używaj go, jak chcesz. Możesz go zainstalować za pomocą
pip install seapie
lub sprawdzić stronę główną tutaj https://github.com/hirsimaki-markus/SEAPIEuser@pc:home$ pip install seapie
wyjścia
argumenty mają następujące znaczenie:
B()
, 1 oznacza rodzica,A()
a 2 oznaczałoby dziadka<module>
znanego jako globalnyDługa odpowiedź
To jest bardziej skomplikowane. Seapie działa poprzez edycję ramek w stosie wywołań przy użyciu interfejsu API CPython. CPython jest de facto standardem, więc większość ludzi nie musi się tym martwić.
Magiczne słowa, które prawdopodobnie najprawdopodobniej Cię interesują, jeśli to czytasz, to:
Ten ostatni wymusi przejście aktualizacji do zakresu lokalnego. Zasięg lokalny jest jednak optymalizowany inaczej niż zasięg globalny, więc wprowadzenie nowych obiektów powoduje pewne problemy przy próbie wywołania ich bezpośrednio, jeśli nie zostały one w żaden sposób zainicjowane. Skopiuję kilka sposobów obejścia tych problemów ze strony github
Jeśli czujesz, że używanie
exec()
nie jest czymś, z czym chciałbyś iść, możesz emulować zachowanie, aktualizując prawdziwy słownik lokalny (a nie ten zwracany przez locals ()). Skopiuję przykład z https://faster-cpython.readthedocs.io/mutable.htmlWynik:
źródło
Myślę, że nie powinieneś tego chcieć. Funkcje, które mogą zmieniać rzeczy w otaczającym ich kontekście, są niebezpieczne, ponieważ ten kontekst można zapisać bez znajomości funkcji.
Możesz to uczynić jawnym, albo przez uczynienie B metodą publiczną, a C metodą prywatną w klasie (prawdopodobnie najlepszy sposób); lub używając zmiennego typu, takiego jak lista, i przekazując go jawnie do C:
źródło
nonlocal
słowo kluczowe - ale to od Ciebie zależy, czy będziesz go używać z wielką ostrożnością.Możesz, ale będziesz musiał użyć statystyki globalnej (niezbyt dobre rozwiązanie, jak zawsze, gdy używasz zmiennych globalnych, ale działa):
źródło
Nie wiem, czy istnieje atrybut funkcji, który daje
__dict__
przestrzeń zewnętrzną funkcji, gdy ta przestrzeń zewnętrzna nie jest przestrzenią globalną == moduł, co ma miejsce, gdy funkcja jest funkcją zagnieżdżoną, w Pythonie 3.Ale w Pythonie 2, o ile wiem, nie ma takiego atrybutu.
Więc jedyne możliwości robienia tego, co chcesz, to:
1) używanie zmiennego obiektu, jak mówią inni
2)
wynik
.
Nota
Rozwiązanie Cédrica Juliena ma wadę:
wynik
Globalne b po wykonaniu
A()
zostało zmodyfikowane i może być inaczejDzieje się tak tylko wtedy, gdy istnieje obiekt o identyfikatorze b w globalnej przestrzeni nazw
źródło