__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__ для реализации декоратора функции.

results matching ""

    No results matching ""