>>> tail = Tail('long')
>>> bill = Bill('wide orange')
>>> duck = Duck(bill, tail)
>>> duck.about()
This duck has a wide orange bill and a long tail
Когда лучше использовать классы и объекты, а когда — модули
Рассмотрим несколько рекомендаций, которые помогут вам понять, где лучше разместить свой код — в классе или в модуле.
• Объекты наиболее полезны, когда вам нужно иметь некоторое количество отдельных экземпляров с одинаковым поведением (методами), но различающихся внутренним состоянием (атрибутами).
• Классы, в отличие от модулей, поддерживают наследование.
• Если вам нужен только один объект, модуль подойдет лучше. Независимо от того, сколько обращений к модулю имеется в программе, будет загружена только одна копия. (Программистам на Java и С++: если вы знакомы с книгой Эриха Гаммы «Приемы объектно-ориентированного проектирования. Паттерны проектирования» (Gamma E.
• Если у вас есть несколько переменных, которые содержат разные значения и могут быть переданы как аргументы в несколько функций, лучше всего определить их как классы. Например, вы можете использовать словарь с ключами size и color, чтобы представить цветное изображение. Вы можете создать разные словари для каждого изображения в программе и передавать их в качестве аргументов в функции scale() и transform(). По мере добавления новых ключей и функций может начаться путаница. Более последовательно было бы определить класс Image с атрибутами size или color и методами scale() и transform(). В этом случае все данные и методы для работы с цветными изображениями будут определены в одном месте.
• Используйте простейшее решение задачи. Словарь, список или кортеж проще, компактнее и быстрее, чем модуль, который, в свою очередь, проще, чем класс.
Совет от Гвидо ван Россума: «Избегайте усложнения структур данных. Кортежи лучше объектов (можно воспользоваться именованными кортежами). Предпочитайте простые поля функциям, геттерам и сеттерам. Используйте больше чисел, строк, кортежей, списков, множеств, словарей. Взгляните также на библиотеку collections, особенно на класс deque».
Именованные кортежи. Поскольку Гвидо только что упомянул их, а я про них еще не говорил, самое время рассмотреть
Рассмотрим пример из предыдущего раздела и преобразуем класс Duck в именованный кортеж, сохранив bill и tail как простые строковые аргументы. Функцию namedtuple можно вызвать, передав ей два аргумента:
• имя;
• строку, содержащую имена полей, разделенные пробелами.
Именованные кортежи не поддерживаются Python автоматически, вам понадобится загрузить отдельный модуль для того, чтобы их использовать. Мы сделаем это в первой строке следующего примера:
>>> from collections import namedtuple
>>> Duck = namedtuple('Duck', 'bill tail')
>>> duck = Duck('wide orange', 'long')
>>> duck
Duck(bill='wide orange', tail='long')
>>> duck.bill
'wide orange'
>>> duck.tail
'long'
Именованный кортеж можно сделать также на основе словаря:
>>> parts = {'bill': 'wide orange', 'tail': 'long'}
>>> duck2 = Duck(**parts)
>>> duck2
Duck(bill='wide orange', tail='long')
В коде, показанном ранее, обратите внимание на конструкцию **parts. Это
>>> duck2 = Duck(bill = 'wide orange', tail = 'long')
Именованные кортежи неизменяемы, но вы можете заменить одно или несколько полей и вернуть другой именованный кортеж:
>>> duck3 = duck2._replace(tail='magnificent', bill='crushing')
>>> duck3
Duck(bill='crushing', tail='magnificent')
Мы могли бы объявить duck как словарь:
>>> duck_dict = {'bill': 'wide orange', 'tail': 'long'}
>>> duck_dict
{'tail': 'long', 'bill': 'wide orange'}
Вы можете добавить поля в словарь:
>>> duck_dict['color'] = 'green'