Za kulisami funkcji domknięcia w Pythonie
Autor: Idego Group

W tym artykule dowiemy się, czym jest domknięcie w Pythonie, jak z niego korzystać i do czego może służyć. Wyjaśnimy również takie pojęcia jak nonlocal i zmienne wolne, czym jest zakres zmiennych oraz czym są funkcje zagnieżdżone i funkcje pierwszej klasy.
Domknięcie to technika implementowania leksykalnie zasięgowego wiązania nazw w języku z funkcjami pierwszej klasy. Operacyjnie domknięcie to rekord przechowujący funkcję razem ze środowiskiem. Środowisko to odwzorowanie wiążące każdą wolną zmienną funkcji z wartością lub odwołaniem, do którego nazwa była powiązana w momencie tworzenia domknięcia.
Funkcja zdefiniowana wewnątrz innej funkcji nazywana jest funkcją zagnieżdżoną. W Pythonie do zmiennej można uzyskać dostęp z wnętrza zakresu, w którym została utworzona. Funkcje w Pythonie są funkcjami pierwszej klasy, co oznacza, że mogą być traktowane jak obiekty — przekazywane jako argumenty, przypisywane lub zwracane.
Przykład domknięcia w porównaniu z podejściem opartym na klasach pokazuje, że oba mogą osiągać podobne wyniki. Kluczowa różnica polega na sposobie utrzymywania stanu. W klasie stan jest przechowywany jako atrybuty instancji. W domknięciu stan jest utrzymywany przez zmienne wolne — zmienne niepowiązane z lokalnym zakresem. Domknięcie zachowuje powiązanie z wolnymi zmiennymi istniejącymi w momencie definiowania funkcji.
Podczas pracy z typami niemutowalnymi w domknięciach potrzebne jest słowo kluczowe nonlocal. Bez niego ponowne przypisanie zmiennej wewnątrz funkcji zagnieżdżonej tworzy nową zmienną lokalną zamiast modyfikować tę zamkniętą. Słowo kluczowe nonlocal sprawia, że zmienna staje się zmienną wolną i umożliwia zmianę niemutowalnych wartości przechowywanych w domknięciu.
Istnieją trzy wymagania, aby utworzyć domknięcie: funkcja zagnieżdżona, dostęp do zmiennej wolnej i zwrócenie funkcji zagnieżdżonej. Domknięcia są przydatne, gdy chcemy ograniczyć użycie zmiennych globalnych w celu ukrycia danych oraz gdy implementujemy proste funkcje. Do bardziej złożonych zadań klasy i OOP są generalnie lepszym wyborem.
Atrybut __closure__ może być użyty do uzyskania dostępu do wartości zamkniętych przez domknięcie, zwracając krotkę obiektów komórkowych, których właściwość cell_contents ujawnia przechowywane wartości.