The mighty hunter: Elmer Fudd
Помните, внутри определения класса Person вы получаете доступ к атрибуту name с помощью конструкции self.name. Когда вы создаете реальный объект вроде hunter, то ссылаетесь на этот атрибут как hunter.name.
Не обязательно иметь метод __init__ в описании каждого класса, он используется для того, чтобы различать объекты одного класса.
Наследование
Может случиться, что, пытаясь решить какую-то задачу, вы обнаружите, что уже существует класс, создающий объекты, которые делают почти все из того, что вам нужно. Что вы можете предпринять? Вы можете модифицировать этот старый класс, но при этом сделаете его сложнее и можете сломать что-то, что раньше работало.
Конечно, можно написать новый класс, скопировав и вставив содержимое старого класса, а затем дополнить его новым кодом. Но это значит, что вам придется поддерживать больше кода и части старого и нового классов могут быть непохожими друг на друга, поскольку теперь находятся в разных местах.
Решением проблемы является
Вы определяете только то, что вам нужно добавить или изменить в новом классе, и этот код переопределяет поведение старого класса. Оригинальный класс называется
Давайте же что-нибудь унаследуем. Мы определим пустой класс, который называется Car. Далее определим подкласс класса Car, который называется Yugo. Вы определяете подкласс с помощью все того же ключевого слова class, но указывая внутри скобок имя родительского класса (class Yugo(Car), как показано ниже):
>>> class Car():
…·····pass
…
>>> class Yugo(Car):
…·····pass
…
Далее создадим объекты каждого класса:
>>> give_me_a_car = Car()
>>> give_me_a_yugo = Yugo()
Класс-потомок является уточненной версией класса-предка; если говорить в терминах объектно-ориентированных языков, Yugo является Car. Объект с именем give_me_a_yugo является экземпляром класса Yugo, но он также наследует все то, что может делать класс Car. В нашем случае классы Car и Yugo полезны как мертвому припарки, поэтому попробуем указать их новые определения, которые действительно могут что-то сделать:
>>> class Car():
…·····def exclaim(self):
…·········print("I'm a Car!")
…
>>> class Yugo(Car):
…·····pass
…
Наконец, создадим по одному объекту каждого класса и вызовем их методы exclaim:
>>> give_me_a_car = Car()
>>> give_me_a_yugo = Yugo()
>>> give_me_a_car.exclaim()
I'm a Car!
>>> give_me_a_yugo.exclaim()
I'm a Car!
Не сделав ничего особенного, класс Yugo унаследовал метод exclaim() класса Car. Фактически класс Yugo говорит, что он является классом Car, что может привести к кризису самоопределения. Посмотрим, что мы можем с этим сделать.
Перегрузка метода
Как вы только что увидели, новый класс наследует все, что находится в его классе-предке. Далее вы увидите, как можно заменить, или
>>> class Car():
…·····def exclaim(self):
…·········print("I'm a Car!")
…
>>> class Yugo(Car):
…·····def exclaim(self):
…·········print("I'm a Yugo! Much like a Car, but more Yugo-ish.")
…
Теперь создадим объекты этих классов:
>>> give_me_a_car = Car()
>>> give_me_a_yugo = Yugo()
Что они говорят?
>>> give_me_a_car.exclaim()
I'm a Car!
>>> give_me_a_yugo.exclaim()
I'm a Yugo! Much like a Car, but more Yugo-ish.
В этих примерах мы перегрузили метод exclaim(). Перегрузить можно любые методы, включая __init__(). Рассмотрим другой пример, который использует наш более старый класс Person. Создадим подклассы, которые представляют докторов (MDPerson) и адвокатов (JDPerson):
>>> class Person():
…·····def __init__(self, name):