В Python замыкание является экземпляром функции, с которой переменные связаны с ней неизменно.
Фактически, модель данных объясняет это в описании функций __closure__
атрибут:
Нет или кортеж ячеек , которые содержат привязки для свободных переменных функции. Только для чтения
Чтобы продемонстрировать это:
def enclosure(foo):
def closure(bar):
print(foo, bar)
return closure
closure_instance = enclosure('foo')
Очевидно, мы знаем, что теперь у нас есть функция, указанная из имени переменной closure_instance
. Якобы, если мы вызываем его с помощью объекта bar
, он должен вывести строку 'foo'
и все, что представляет собой строковое представление bar
.
На самом деле строка 'foo' связана с экземпляром функции, и мы можем непосредственно прочитать ее здесь, обратившись к атрибуту cell_contents
первой (и единственной) ячейки в кортеж атрибута __closure__
:
>>> closure_instance.__closure__[0].cell_contents
'foo'
Кроме того, объекты ячеек описаны в документации C API:
Объекты «Cell» используются для реализации переменных, на которые ссылаются множественные
прицелы
И мы можем продемонстрировать использование нашего замыкания, отметив, что 'foo'
застрял в функции и не изменяется:
>>> closure_instance('bar')
foo bar
>>> closure_instance('baz')
foo baz
>>> closure_instance('quux')
foo quux
И ничто не может изменить это:
>>> closure_instance.__closure__ = None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute
Частичные функции
В приведенном примере закрытие используется как частичная функция, но если это наша единственная цель, то же можно достичь с помощью functools.partial
>>> from __future__ import print_function # use this if you're in Python 2.
>>> partial_function = functools.partial(print, 'foo')
>>> partial_function('bar')
foo bar
>>> partial_function('baz')
foo baz
>>> partial_function('quux')
foo quux
Существуют и более сложные замыкания, которые не вписываются в пример с частичной функцией, и я покажу их дальше, если позволит время.