Атрибуты класса и экземпляра
Разберём, где хранить общее для всех объектов, а где — личные данные конкретного экземпляра, и как Python ищет атрибуты.
Общее свойство: атрибут класса
Иногда удобно хранить одно общее значение для всех объектов, например позицию по умолчанию. Такое значение кладут прямо внутрь класса, без методов.
class HockeyPlayer:
default_position = 'Forward' # общее для всех
print(HockeyPlayer.default_position) # Forward
HockeyPlayer.default_position = 'Defender' # меняем общее значение
print(HockeyPlayer.default_position) # Defender
Forward
Defender
Атрибут класса живёт один на всех. Поменяли его в одном месте — и новое значение увидят все текущие и будущие объекты при обращении через класс или методы класса. В Python поиск атрибута идёт по цепочке: сначала в самом объекте, потом в его классе, затем в родителях (если есть наследование). Поэтому общее значение «подхватывается» автоматически. Если у конкретного объекта появится поле с тем же именем, оно «перекроет» значение класса только для этого объекта — это нормальная работа цепочки поиска.
class HockeyPlayer:
default_position = 'Forward'
player = HockeyPlayer()
print(HockeyPlayer.default_position) # читаем у класса
print(player.default_position) # объект берёт из класса
player.default_position = 'Winger' # создаём одноимённый атрибут у объекта
print(player.default_position) # теперь берётся из объекта
print(HockeyPlayer.default_position) # у класса значение не менялось
Forward
Forward
Winger
Forward
Личные данные: конструктор __init__ и self
Чтобы у каждого объекта было своё имя, возраст и команда, добавим конструктор. Он запускается автоматически при создании экземпляра и раскладывает переданные аргументы в атрибуты.
class HockeyPlayer:
default_position = 'Forward'
def __init__(self, name, surname, age, team):
self.name = name # self — это «этот самый объект»
self.surname = surname
self.age = age
self.team = team
player = HockeyPlayer('Иван', 'Иванов', 17, 'Метеор')
captain = HockeyPlayer('Павел', 'Петров', 20, 'Вымпел')
print(player.name, player.team) # Иван Метеор
print(captain.name, captain.team) # Павел Вымпел
Иван Метеор
Павел Вымпел
Первый параметр каждого метода внутри класса — self. Читайте это как «этот объект». Запись self.name = name создаёт у конкретного экземпляра личный атрибут name. Что происходит по шагам: Python создаёт пустой объект, вызывает для него __init__, передавая self; внутри мы заполняем поля self.*; на выходе готовы независимые экземпляры с одинаковой «формой», но разным содержимым.