W Pythonie zamknięcie jest instancją funkcji, do której są niezmiennie przypisane zmienne.
W rzeczywistości model danych wyjaśnia to w swoim opisie __closure__
atrybutu funkcji :
Brak lub krotka komórek, które zawierają powiązania dla wolnych zmiennych funkcji. Tylko czytać
Aby to zademonstrować:
def enclosure(foo):
def closure(bar):
print(foo, bar)
return closure
closure_instance = enclosure('foo')
Oczywiście wiemy, że mamy teraz wskazaną funkcję z nazwy zmiennej closure_instance
. Pozornie, jeśli wywołasz go za pomocą obiektu, bar
powinien wypisać łańcuch 'foo'
i niezależnie od jego reprezentacji bar
.
W rzeczywistości ciąg „foo” jest powiązany z wystąpieniem funkcji i możemy go bezpośrednio przeczytać tutaj, uzyskując dostęp do cell_contents
atrybutu pierwszej (i jedynej) komórki w krotce __closure__
atrybutu:
>>> closure_instance.__closure__[0].cell_contents
'foo'
Na marginesie, obiekty komórek są opisane w dokumentacji C API:
Obiekty „komórki” służą do implementowania zmiennych, do których istnieją odwołania w wielu zakresach
Możemy zademonstrować użycie naszego zamknięcia, zauważając, że 'foo'
utknęło w funkcji i się nie zmienia:
>>> closure_instance('bar')
foo bar
>>> closure_instance('baz')
foo baz
>>> closure_instance('quux')
foo quux
I nic nie może tego zmienić:
>>> closure_instance.__closure__ = None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute
Funkcje częściowe
Podany przykład wykorzystuje zamknięcie jako funkcję częściową, ale jeśli jest to nasz jedyny cel, ten sam cel można osiągnąć za pomocą functools.partial
>>> from __future__ import print_function
>>> partial_function = functools.partial(print, 'foo')
>>> partial_function('bar')
foo bar
>>> partial_function('baz')
foo baz
>>> partial_function('quux')
foo quux
Istnieją również bardziej skomplikowane domknięcia, które nie pasowałyby do przykładu funkcji częściowej, i pokażę je dalej, gdy pozwoli na to czas.
nonlocal
został dodany w pythonie 3, python 2.x nie miał zamkniętych zamknięć do odczytu i zapisu (tj. Można było czytać zamknięte zmienne, ale nie zmieniać ich wartości)