Перейти к основному содержимому

Атрибуты класса и экземпляра

Разберём, где хранить общее для всех объектов, а где — личные данные конкретного экземпляра, и как 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.*; на выходе готовы независимые экземпляры с одинаковой «формой», но разным содержимым.