Отложенные вызовы с применением инструкций lambda и ссылок на объекты

otlozhennye vyzovy s primeneniem instrukcij lambda i ssylok na obekty Графические интерфейсы пользователя

Очень часто lambda-выражения используются для передачи дополнительных данных в обработчик события (для простоты я опустил вызовы функций pack и mainloop в следующем фрагменте):

def handler(A, B): # обычно вызывается без аргументов

…использование A и B

X = 42

Button(text=’ni’, command=(lambda: handler(X, ‘spam’))) # lambda добавляет # аргументы

Библиотека tkinter вызывает обработчики command, не передавая им никаких аргументов, тем не менее с помощью такого lambda-выражения можно создать косвенную анонимную функцию, которая будет играть роль оболочки для действительного обработчика и передавать ему информацию, существовавшую в момент создания графического интерфейса. Вызов фактического обработчика откладывается, благодаря чему мы получаем возможность добавлять необходимые аргументы. В данном случае значение глобальной переменной X и строка spamбудут переданы в аргументах A и B даже при том, что библиотека tkinter вызывает функции обратного вызова без аргументов. Таким образом, инструкция lambda может использоваться для отображения вызова без аргументов в вызов с аргументами, которые поставляются самим lambda-выражением.

Если такой синтаксис приводит вас в замешательство, запомните, что такое lambda-выражение, как показано выше, обычно может быть реализовано в виде простой инструкции def. Вторая функция в следующем фрагменте выполняет ту же операцию, что и lambda-выражение в предыдущем фрагменте, — ссылка на нее в операции создания кнопки фактически откладывает вызов действительного обработчика, чтобы ему можно было передать дополнительные аргументы:

def handler(A, B): # обычно вызывается без аргументов

…использование A и B

X = 42

def func(): # косвенная функция-обертка, добавляющая аргументы

handler(X, ‘spam’)

Button(text=’ni’, command=func)

Чтобы более отчетливо понять, зачем необходимы отложенные вызовы, обратите внимание, что произойдет, если в операцию создания кнопки вставить вызов самого обработчика с аргументами без использования lambda-выражения или другой промежуточной функции, — обработчик будет вызван немедленно, в момент создания кнопки, а не когда на ней будет выполнен щелчок. Именно для того чтобы отложить вызов обработчика, обращение к нему требуется обернуть промежуточной функцией:

def handler(name): print(name)

Button(command=handler(‘spam’)) # ОШИБКА: обработчик будет вызван немедленно!

Использование lambda-выражений или ссылок на вызываемые объекты позволяет отложить вызов обработчика до появления события. Например, использование lambda-выражения для передачи дополнительных данных с помощью определения встроенной функции, вызов которой откладывается:

def handler(name): print(name)

Button(command=(lambda: handler(‘spam’))) # OK: обертывание lambdaвыражением # откладывает вызов

всегда эквивалентно более длинной и, по мнению некоторых, менее удобной форме с двумя функциями:

def handler(name): print(name)

def temp():

handler(‘spam’)

Button(command=temp) # OK: ссылка на функцию, а не ее вызов

Нам достаточно применять только какой-то один прием — либо lambdaвыражение без аргументов, либо ссылку на вызываемый объект, не принимающий аргументов, но не оба сразу. Бессмысленно использовать lambda-выражение, просто вызывающее функцию, которая не принимает дополнительных аргументов, так как в этом случае будет выполняться один лишний вызов:

def handler(name): print(name)

def temp():

handler(‘spam’)

Button(command=(lambda: temp())) # БЕССМЫСЛЕННО: добавляет лишний вызов!

Как будет показано далее, допускается также использовать ссылки на другие вызываемые объекты, такие как связанные методы и вызываемые экземпляры классов, которые сохраняют необходимую информацию в своих атрибутах. Если они не принимают аргументов, их имена можно просто указывать на этапе создания виджетов и их не требуется обертывать лишними lambda-выражениями.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий