- А что вы будете делать, когда от
Dog
вам нужно будет не одно свойство получить, а два, десять, сто свойств? Будете писать сто отдельных функций? Будете писать одну мега-функцию с параметром, в котором будете передавать, какое свойство вы хотите получить или изменить?
- А если вы захотите от
Dog
каких-то действий, зависящих от его внутреннего состояния? Например, у него есть уровень сытости и вы хотите, чтобы он по-разному гавкал в зависимости от этого уровня?
- А если вы захотите иметь несколько разных
Dog
с разным состоянием - вы будете это состояние хранить где-то снаружи и передавать в ваши функции каждый раз вручную?
Просто нужно чуть продолжить мысль о том, что вам может понадобиться от класса и как этим всем было бы удобно пользоваться - и тогда необходимость инкапсуляции, т.е. включения/скрытия полей (переменных) и методов (функций) внутри класса и его объектов, придёт к вам сама собой.
Собственно, self
как-раз и представляет собой собой ссылку на объект класса, на его состояние.
А конструктор __init__
нужен, чтобы в удобной форме задать первоначальное состояние экземпляра объекта. Например, имя для собаки. Вряд ли это имя поменяется в течении жизни объекта "собака", так что очень удобно задать это имя сразу при создании объекта. Так исторически и возникла необходимость в конструкторе класса.
И так со всеми штуками, относящимися к классам. Если начать разбираться, то все они нужны как-раз для удобства программиста.