"Олег Бройтман. Питон - модули, пакеты, классы, экземпляры " - читать интересную книгу автора

с параметрами!
Python позволяет переопределить все инфиксные операции, причем отдельно
для левого и правого аргумента выражения. Например, если a - экземпляр
класса A, и b - экземпляр класса B, то для вычисления выражения a + b Питон
будет сначала искать метод __add__ в классе A, а если не найдет - то метод
__radd__ в классе B (а если и там не найдет - возбудит исключение
TypeError).
Многие программисты, особенно писавшие на C++, боятся и не любят
множественного наследования. Авторы языка Java вообще не включили
множественное наследование в язык. Совершенно напрасно! Python позволяет
использовать множественное наследование весьма успешно и удобно.
Множественное наследование облегчает переиспользование кода (code reuse)
вместо copy/paste-программирования, что очень важно и для эффективности, и
для читаемости программ, и для отладки. Часто программисты на Питоне создают
класс с помощью множественного наследования из нескольких связанных между
собой "кирпичиков", словно из конструктора. Такие "кирпичики" в
ОО-программировании называются MixIn-классами. Подробную статью про
программирование с помощью MixIn-классов можно прочесть в Linux Journal
Еще один способ использования классов (точнее, экземпляров), не
связанный непосредственно с ОО-программированием - использование
пространства имен, которое предоставляет объект. Рассмотрим следующую
проблему. Вам надо пройти циклом по списку, сохраняя между итерациями цикла
некоторую информацию. Это можно сделать циклом for, никаких проблем. А можно
воспользоваться возможностями функционального программирования, которые есть
в Питоне - функциями map, filter, reduce и тому подобное. Эти функции требую
в качестве первого параметра функцию, которую они в процессе цикла вызывают.
Это эффективнее, чем цикл for (эти функции-то написаны на C), но возникает
проблема с хранением состояния между итерациями. Функция, которую вызывает
map может хранить состояние только в глобальных переменных. Для простых
программ это вполне приемлемо. Но вот, скажем, с многопоточными программами
будут проблемы - необходимо запирать и синхронизировать доступ к глобальным
переменным. Да и вообще к глобальным переменным надо обращаться только при
крайней нужде.
Вот тут на помощь приходит дополнительное пространство имен,
существующее в экземпляре класса. Создадим класс
class Process:
def __init__(self):
self.foo = 0

def __call__(self, v):
if self.foo · 100:
raise OverflowError
self.foo += v
return self.foo
Создадим экземпляр этого класса: p = Process(), и передадим этот объект
в map вместо функции: result = map(p, sequence). Функция map, ничего не
подозревая, будет вызывать переданный ей объект как функцию с одним
параметром. Никаких проблем - мы так описали класс, что его экземпляры можно
вызывать, и именно с одним параметром! И от итерации к итерации объект p
сохраняет необходимое состояние.