Выбрать главу

хотелось бы, чтобы наше программное обеспечение предусматривало возможность расширения и настройки естественными способами.

Если вы уже погружались в изучение Python, то, наверное, знаете, что это тот случай, когда начинает проявляться привлекательность ООП:

Структурирование

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

Инкапсуляция

Благодаря ООП можно скрыть детали реализации таких операций, как обработка имени или увеличение оклада, внутри методов - то есть в дальнейшем мы легко сможем изменять реализацию методов, не влияя на работоспособность программного кода, использующего их.

Специализация

Применение ООП обеспечивает естественный способ дальнейшего расширения. Классы могут расширяться и специализироваться за счет создания новых подклассов, без изменения или нарушения работоспособности существующего программного кода.

Таким образом, в объектно-ориентированном программировании мы специализируем и повторно используем программный код, а не переписываем его заново. ООП в Python является дополнительной возможностью, которая, честно признаться, лучше подходит для решения стратегических, а не тактических задач. ООП лучше подходит, когда у вас имеется время для предварительного планирования, что может оказаться непозволительной роскошью, когда ваши пользователи уже начали штурмовать ворота.

Преимущества структурирования и повторного использования программного кода в крупных системах, которые продолжают развиваться в течение длительного времени, перевешивают затраты на изучение ООП и способны существенно сократить время разработки. Даже в нашем простом случае возможность специализации и снижения избыточности, которую дают классы, может оказаться решающим преимуществом.

Использование классов

ООП в Python отличается простотой использования, в значительной степени благодаря динамической модели типов. Фактически программировать в объектно-ориентированном стиле настолько просто, что я сразу же перейду к примеру: пример 1.14 реализует наши записи уже не в виде словарей, а в виде экземпляров класса.

Пример 1.14. PP4E\Preview\person_start.py

class Person:

def __init__(self, name, age, pay=0, job=None):

self.name = name self.age = age self.pay = pay self.job = job

if__name__== ‘__main__’:

bob = Person(‘Bob Smith’, 42, 30000, ‘software’) sue = Person(‘Sue Jones’, 45, 40000, ‘hardware’) print(bob.name, sue.pay)

print(bob.name.split()[-1]) sue.pay *= 1.10 print(sue.pay)

Это очень простой класс - он содержит единственный метод-конструктор, заполняющий экземпляр класса данными, переданными в виде аргументов при обращении к имени класса. Тем не менее этого вполне достаточно для представления записи, а кроме того, сюда уже можно добавить такие элементы, как значения по умолчанию для полей pay и job, чего нельзя сделать в словарях. Программный код самотестирования в конце этого файла создает два экземпляра класса (две записи) и обращается к их атрибутам (полям). Ниже приводится вывод, полученный в результате запуска этого сценария в среде IDLE (при запуске из командной строки результаты получаются такими же):

Bob Smith 40000

Smith

44000.0

Это еще не база данных, но мы могли бы, как и прежде, вставить эти объекты в список или в словарь, чтобы объединить их в одно целое:

>>> from person_start import Person >>> bob = Person(‘Bob Smith', 42)

>>> sue = Person(‘Sue Jones', 45, 40000)

>>> people = [bob, sue]    # список "базы данных”

>>> for person in people:

print(person.name, person.pay)

Bob Smith 0 Sue Jones 40000

>>> x = [(person.name, person.pay) for person in people]

>>> x

[(‘Bob Smith’, 0), (‘Sue Jones’, 40000)]

>>> [rec.name for rec in people if rec.age >= 45]    # SQL-подобный запрос

[‘Sue Jones’]

>>> [(rec.age ** 2 if rec.age >= 45 else rec.age) for rec in people]

[42, 2025]

Обратите внимание, что для Боба был установлен оклад (поле pay) по умолчанию, равный 0, потому что при создании записи мы не указали сумму в соответствующем аргументе (может быть, Сью его поддерживает?). Мы также могли бы реализовать класс, представляющий базу данных, возможно, как подкласс списка или словаря, добавив в него методы вставки и удаления, реализующие особенности функционирования базы данных. Однако пока мы откажемся от этого, потому что гораздо полезнее реализовать сохранение записей в хранилище, которое уже обладает методами записи и чтения. Но прежде чем попытаться использовать хранилище, добавим в наши записи немного логики.