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