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

def __init__(self, name, age, pay):

Person.__init__(self, name, age, pay, ‘manager’)

Теперь при создании экземпляра класса Manager его поле job будет заполняться автоматически. Вся хитрость заключается в явном вызове версии метода суперкласса, так же, как мы делали при реализации метода giveRaise выше. Единственное отличие здесь - необычное имя метода-конструктора.

Альтернативные классы

В последующих примерах мы не будем использовать ни одно из трех расширений, представленных в этом разделе, но для демонстрации их в действии соберем все эти идеи в примере 1.17, где представлены альтернативные реализации классов Person и Manager.

Пример 1.17. PP4E\Preview\person_alternative.py

Альтернативные реализации классов Person и Manager с данными, методами и с перегрузкой операторов (не используется в объектах, предусматривающих возможность сохранения)

class Person:

универсальное представление человека: данные+логика

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

self.name = name self.age = age self.pay = pay self.job = job def lastName(self):

return self.name.split()[-1] def giveRaise(self, percent): self.pay *= (1.0 + percent)

def __str__(self):

return (‘<%s => %s: %s, %s>’ %

(self.__class__.__name__, self.name, self.job, self.pay))

class Manager(Person):

класс со специализированным методом giveRaise, наследующий обобщенные методы lastName и __str__

def __init__(self, name, age, pay):

Person.__init__(self, name, age, pay, ‘manager’)

def giveRaise(self, percent, bonus=0.1):

Person.giveRaise(self, percent + bonus)

if__name__== ‘__main__’:

bob = Person(‘Bob Smith’, 44)

sue = Person(‘Sue Jones’, 47, 40000, ‘hardware’)

tom = Manager(name=’Tom Doe’, age=50, pay=50000)

print(sue, sue.pay, sue.lastName())

for obj in (bob, sue, tom):

obj.giveRaise(.10) # вызовет метод giveRaise объекта obj print(obj)    # вызовет обобщенную версию метода __str__

Обратите внимание на полиморфизм в цикле for, находящемся в программном коде самопроверки этого модуля: все три объекта используют один и тот же конструктор, метод lastName и методы вывода, но при обращении к методу giveRaise вызывается версия в зависимости от класса, на основе которого был создан экземпляр. Если запустить сце-

нарий из примера 1.17, он выведет в стандартный поток вывода приведенные ниже строки; поле job в экземпляре класса Manager заполняется конструктором, форматированный вывод наших объектов осуществляется с помощью нового метода__str__, а новая версия метода giveRaise

в классе Manager действует точно так же, как и прежде:

<Person => Sue Jones: hardware, 40000> 40000 Jones <Person => Bob Smith: None, 0.0>

<Person => Sue Jones: hardware, 44000.0>

<Manager => Tom Doe: manager, 60000.0>

Такая реструктуризация программного кода часто применяется по мере роста и развития иерархий классов. Фактически мы никак не сможем увеличить оклад тем, у кого он оказался равным нулю (Бобу явно не повезло), поэтому нам, вероятно, необходимо предусмотреть возможность прямого изменения оклада, но оставим это усовершенствование до следующей версии. Самое приятное, что гибкость и удобочитаемость, присущие языку Python, существенно упрощают реструктуризацию программного кода - вы легко и просто сможете реструктурировать свои программы. Если прежде вы не пользовались языком Python, то со временем обнаружите, что разработка программ на Python выполняется быстро, поэтапно и в интерактивном режиме, что хорошо подходит для постоянно изменяющихся потребностей реальных проектов.

Добавляем возможность сохранения

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

Пример 1.18. PP4E\Preview\make_db_classes.py

import shelve

from person import Person

from manager import Manager

bob = Person(‘Bob Smith’, 42, 30000, ‘software’) sue = Person(‘Sue Jones’, 45, 40000, ‘hardware’) tom = Manager(‘Tom Doe’, 50, 50000)

db = shelve.open(‘class-shelve’)

db[‘bob’] = bob

db[‘sue’] = sue

db[‘tom’] = tom

db.close()

Этот сценарий создает три экземпляра (два экземпляра оригинального класса и один - его специализированной версии) и присваивает их ключам вновь созданного хранилища. Другими словами, сценарий создает хранилище с экземплярами классов. Для нашего программного кода база выглядит в точности, как словарь экземпляров классов, с той лишь разницей, что словарь верхнего уровня отображается в файл хранилища, как и прежде. Убедиться, что все работает, поможет сценарий в примере 1.19, который читает содержимое хранилища и выводит значения полей записей.

Пример 1.19. PP4E\Preview\dump_db_classes.py