__call__
Вызывается, когда мы обращаемся к экземпляру класса как к функции.
Передаются любые позиционные и именованные аргументы.
>>> class Callee:
... def __call__(self, *pargs, **kargs): # Реализует вызов экземпляра
... print('Called:', pargs, kargs) # Принимает любые аргументы
...
>>> C = Callee()
>>> C(1, 2, 3) # C – вызываемый объект
Called: (1, 2, 3) {}
>>> C(1, 2, 3, x=4, y=5)
Called: (1, 2, 3) {'y': 5, 'x': 4}
Можно реализовать метод __call__ одним из способов:
class C:
def __call__(self, a, b, c=5, d=6): ... # Обычные и со значениями по умолчанию
class C:
def __call__(self, *pargs, **kargs): ... # Произвольные аргументы
class C:
def __call__(self, *pargs, d=6, **kargs): ... # Аргументы, которые могут передаваться
# только по имени в версии 3.0
и при этом любая вышеописанная реализация __call__ подойдет для следующих вызовов:
X = C()
X(1, 2) # Аргументы со значениями по умолчанию опущены
X(1, 2, 3, 4) # Позиционные
X(a=1, b=2, d=4) # Именованные
X(*[1, 2], **dict(c=3, d=4)) # Распаковывание произвольных аргументов
X(1, *(2,), c=3, **dict(d=4)) # Смешанные режимы
Очень распространненый метод. Экземпляры класса имитируют поведение функции, а так же могут сохранять свое состояние между вызовами.
>>> class Prod:
... def __init__(self, value): # Принимает единственный аргумент
... self.value = value
... def __call__(self, other):
... return self.value * other
...
>>> x = Prod(2) # "Запоминает" 2 в своей области видимости
>>> x(3) # 3 (передано) * 2 (сохраненное значение)
6
>>> x(4)
8
Callback
Библиотека для GUI tkinter позволяет регистрировать функции как event handler (обработчики событий), они же callback: возникло событие - tkinter вызывает зарегистрированные объекты.
Если нужно, чтобы обработчик событий запоминал свое состояние между вызовами (в терминах С - имел статическую переменную), то регистрируем либо связанный метод класса (следующая глава), либо экземпляр класса, который можно вызвать как функцию с нужными параметрами благодаря методу __call__.
В примерах x.comp
(первый пример) и x
(второй пример) могут передаваться как объекты функций.
Кнопка при нажатии должна окрашиваться в цвет. Этот цвет хранится в объекте класса. Этот объект может вызываться как функция.
class Callback:
def __init__(self, color): # Функция + информация о состоянии
self.color = color
def __call__(self): # Поддерживает вызовы без аргументов
print('turn', self.color)
GUI сделан так, что обработчики событий вызываются как функции без аргументов. Зарегистрируем объекты класса Callback, как обработчики событий:
cb1 = Callback('blue') # 'Запомнить' голубой цвет
cb2 = Callback('green')
b1 = Button(command=cb1) # Зарегистрировать обработчик
b2 = Button(command=cb2) # Зарегистрировать обработчик
Когда кнопка будет нажата, cb1 и cb2 будут вызваны как функции без аргументов. Так как эти объекты сохранили цвет в атрибутах экземпляра класса, то будет использован нужный цвет:
cb1() # По событию: выведет 'turn blue'
cb2() # Выведет 'turn green'
Лучше сохранять информацию так, чем использовать глобальные переменные, ссылки в область видимости объемлющей функции и изменяемые аргументы со значениями по умолчанию.
Аргументы со значением по умолчанию (пример):
cb3 = (lambda color='red': 'turn ' + color) # Или: по умолчанию
print(cb3())
Связанные методы класса. Запоминается экземпляр self + ссылка на функцию. Потом вызваем функцию без использования экземпляра. (пример):
class Callback:
def __init__(self, color): # Класс с информацией о состоянии
self.color = color
def changeColor(self): # Обычный метод экземпляра класса
print('turn', self.color)
cb1 = Callback('blue')
cb2 = Callback('yellow')
# ссылка, а не вызов функции; запоминаются функция + self:
b1 = Button(command=cb1.changeColor)
b2 = Button(command=cb2.changeColor)
При нажатии кнопки имитируется поведение GUI и вызывается метод changeColor. Он обрабатывает информацию о состоянии объекта:
object = Callback('blue')
cb = object.changeColor # Регистрация обработчика событий
cb() # По событию выведет 'blue'
В следующей главе о связанных методах подробнее. Еще позже будет рассказано об использовании __call__ для реализации декоратора функции.