Zamknięcia w Pythonie: jak go używać i dlaczego?

W tym samouczku dowiesz się o zamknięciu w Pythonie, jak zdefiniować zamknięcie i dlaczego warto go używać.

Zmienna nielokalna w funkcji zagnieżdżonej

Zanim przejdziemy do tego, czym jest zamknięcie, musimy najpierw zrozumieć, czym jest funkcja zagnieżdżona i zmienna nielokalna.

Funkcja zdefiniowana wewnątrz innej funkcji nazywana jest funkcją zagnieżdżoną. Funkcje zagnieżdżone mogą uzyskiwać dostęp do zmiennych z otaczającego zakresu.

W Pythonie te zmienne nielokalne są domyślnie tylko do odczytu i musimy je jawnie zadeklarować jako nielokalne (używając słowa kluczowego nielokalnego), aby je zmodyfikować.

Poniżej znajduje się przykład zagnieżdżonej funkcji uzyskującej dostęp do zmiennej nielokalnej.

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg("Hello")

Wynik

 cześć

Widzimy, że printer()funkcja zagnieżdżona była w stanie uzyskać dostęp do nielokalnej zmiennej msg funkcji otaczającej.

Definiowanie funkcji zamknięcia

W powyższym przykładzie, co by się stało, gdyby ostatni wiersz funkcji print_msg()zwrócił printer()funkcję zamiast ją wywołać? Oznacza to, że funkcja została zdefiniowana następująco:

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) return printer # returns the nested function # Now let's try calling this function. # Output: Hello another = print_msg("Hello") another()

Wynik

 cześć

To niespotykane.

print_msg()Funkcja została wywołana z łańcucha "Hello"i funkcja zwrócony był związany z inną nazwą. Podczas wywoływania another()wiadomość była nadal zapamiętywana, chociaż zakończyliśmy już wykonywanie print_msg()funkcji.

Ta technika, za pomocą której niektóre dane ( "Hellow tym przypadku) są dołączane do kodu, w Pythonie nazywa się zamknięciem .

Ta wartość w otaczającym zakresie jest zapamiętywana nawet wtedy, gdy zmienna wykracza poza zakres lub sama funkcja zostanie usunięta z bieżącej przestrzeni nazw.

Spróbuj uruchomić następujące polecenie w powłoce Pythona, aby zobaczyć dane wyjściowe.

 >>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined

Tutaj zwrócona funkcja nadal działa, nawet jeśli oryginalna funkcja została usunięta.

Kiedy mamy zamknięcia?

Jak widać z powyższego przykładu, w Pythonie mamy zamknięcie, gdy funkcja zagnieżdżona odwołuje się do wartości w swoim zakresie obejmującym.

Kryteria, które należy spełnić, aby utworzyć domknięcie w Pythonie, podsumowano w poniższych punktach.

  • Musimy mieć zagnieżdżoną funkcję (funkcję wewnątrz funkcji).
  • Zagnieżdżona funkcja musi odnosić się do wartości zdefiniowanej w funkcji otaczającej.
  • Funkcja otaczająca musi zwracać funkcję zagnieżdżoną.

Kiedy używać zamknięć?

Więc do czego służą zamknięcia?

Zamknięcia pozwalają uniknąć stosowania wartości globalnych i zapewniają pewną formę ukrywania danych. Może również zapewnić zorientowane obiektowo rozwiązanie problemu.

Kiedy istnieje kilka metod (w większości przypadków jedna metoda) do zaimplementowania w klasie, zamknięcia mogą stanowić alternatywne i bardziej eleganckie rozwiązanie. Ale gdy liczba atrybutów i metod rośnie, lepiej jest zaimplementować klasę.

Oto prosty przykład, w którym zamknięcie może być lepsze niż definiowanie klasy i tworzenie obiektów. Ale preferencje należą do Ciebie.

 def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # Multiplier of 3 times3 = make_multiplier_of(3) # Multiplier of 5 times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2)))

Wynik

 27 15 30

Dekoratory Pythona również szeroko wykorzystują zamknięcia.

Na zakończenie warto zaznaczyć, że można znaleźć wartości, które są zawarte w funkcji domknięcia.

Wszystkie obiekty funkcji mają __closure__atrybut, który zwraca krotkę obiektów komórek, jeśli jest to funkcja zamykająca. Nawiązując do powyższego przykładu, znamy times3i times5jesteśmy funkcjami domknięcia.

 >>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)

Obiekt komórki ma atrybut cell_contents, który przechowuje zamkniętą wartość.

 >>> times3.__closure__(0).cell_contents 3 >>> times5.__closure__(0).cell_contents 5

Interesujące artykuły...