Как реализовать конструктор __init__ с параметрами age и name в Python
Что проверяют
Вопрос простой, поэтому оценивают глубину: понимаете ли вы, что делает __init__, чем он отличается от __new__, и умеете ли защитить объект от неверных данных. Следом почти всегда просят добавить валидацию возраста или переписать класс на dataclass.
Как отвечать
Базовый ответ: class Person с методом def __init__(self, name: str, age: int) -> None, внутри self.name = name и self.age = age. Дальше добавьте то, что отличает уверенного разработчика:
__init__не создаёт объект: экземпляр создаёт__new__, а__init__получает готовыйselfи заполняет его. Вернуть из__init__что-то кромеNoneнельзя, будетTypeError;- аннотации не проверяются:
Person("Ann", "тридцать")отработает без ошибок. Для проверки нужен явный код или mypy в CI; - валидация:
if not isinstance(age, int) or isinstance(age, bool) or age < 0: raise ValueError(...). Проверка наboolнужна, потому чтоTrueявляется экземпляромint; - property: если проверить возраст только в
__init__, присваиваниеp.age = -5её обойдёт. Возраст оформляют свойством с сеттером, а__init__присваивает через него же; - наследование: в наследнике вызывается
super().__init__(name, age), иначе атрибуты родителя не появятся; dataclass:@dataclass(slots=True)сгенерирует__init__,__repr__и__eq__, валидация пишется в__post_init__. Параметрslotsдоступен с Python 3.10. Для входных данных из API уместнее pydantic.
Хорошо добавить __repr__ для отладки, а __str__ оставить для вывода пользователю.
Где спотыкаются
Ставят изменяемое значение по умолчанию: def __init__(self, name, age, tags=[]). Список создаётся один раз при определении функции и становится общим для всех экземпляров. Правильно tags=None и новый список внутри.
Объявляют name = "" и age = 0 на уровне класса и считают их полями экземпляра. Это атрибуты класса, и изменяемый атрибут класса разделяют все объекты.
Забывают self. и пишут name = name. Код не падает, значение уходит в локальную переменную, а позже появляется AttributeError.