Одно из интересных понятий функционального программирования — это замыкания (closure). Эта идея оказалась настолько заманчивой для многих разработчиков, что была реализована даже в некоторых нефункциональных языках программирования (Perl). Девид Мертц приводит следующее определение замыкания: "Замыкание - это процедура вместе с привязанной к ней совокупностью данных" (в противовес объектам в объектном программировании, как: "данные вместе с привязанным к ним совокупностью процедур" ).
В питоне не слишком часто используют замыкания явно, в то время, как, скажем, в javascript без замыканий обойтись практически невозможно.
Смысл замыкания состоит в том, что определение функции "замораживает" окружающий её контекст на момент определения. Это может делаться различными способами, например, за счёт параметризации создания функции. При замыкании будут использованы переменные из объемлющих функций. Для того, чтобы переменная попала в замыкание, она должна быть упомянута в коде функции:
В данном случае обе функции используют одну и ту же захваченную из функции
В питоне не слишком часто используют замыкания явно, в то время, как, скажем, в javascript без замыканий обойтись практически невозможно.
Смысл замыкания состоит в том, что определение функции "замораживает" окружающий её контекст на момент определения. Это может делаться различными способами, например, за счёт параметризации создания функции. При замыкании будут использованы переменные из объемлющих функций. Для того, чтобы переменная попала в замыкание, она должна быть упомянута в коде функции:
def print_msg(msg): def fun(): print (msg) return fun # Помните, что в питоне всё - это объект. Функция тоже, её можно вернуть и воспользоваться потом. printer = print_msg( "Hello" ) printer() >>>Hello |
def multiplier( n ): # multiplier возвращает функцию умножения на n def mul( k ): return n * k return mul mul3 = multiplier( 3 ) # mul3 - функция, умножающая на 3 print (mul3( 3 ), mul3( 5 )) >>> 9 15 |
Правильно захваченные переменные при этом можно даже успешно модифицировать:
def tester(start): state = start # В каждом вызове сохраняется свое значение state def nested(label): nonlocal state # Объект state находится print (label, state) # в объемлющей области видимости state + = 1 # Изменит значение переменной, объявленной как nonlocal return nested >>> F = tester( 0 ) >>> F( 'spam' ) # Будет увеличивать значение state при каждом вызове spam 0 >>> F( 'ham' ) ham 1 >>> F( 'eggs' ) eggs 2 |
Но вообще тема эта достаточно сложная. В результате неаккуратного использования может быть отстрелено произвольное количество конечностей. Например, нужно иметь в виду, что в замыкание попадает имя переменной, а не её значение.
def gen_adders(): i = 5 def add5(x): return x + i i = 10 def add10(x): return x + i i = 15 return add5, add10 adder1, adder2 = gen_adders() print (adder1( 0 )) # -> 15 print (adder2( 0 )) # -> 15 |
gen_adders
переменную i
, что и приводит к такому «неожиданному» поведению.Последнее изменение: Суббота, 15 Август 2020, 02:35