Атрибуты класса и экземпляра: разница и области видимости
Атрибуты класса vs атрибуты экземпляра: что выбрать? ⚖️
В Python всё — объекты. Но даже среди объектов есть иерархия! Давайте разберёмся, чем отличаются атрибуты класса от атрибутов экземпляра и когда использовать каждый из них.
class Spaceship:
# Атрибут класса (общий для всех экземпляров)
fuel_type = "антиматерия"
def __init__(self, name):
# Атрибут экземпляра (уникальный для каждого объекта)
self.name = name
Как работают атрибуты класса? 🌌
Атрибуты класса принадлежат самому классу, а не его экземплярам. Они похожи на "глобальные переменные" внутри класса — их значение одинаково для всех объектов.
Ключевые особенности:
- Определяются прямо в теле класса (не в
__init__) - Доступны через имя класса и через экземпляры
- Изменение отражается на всех экземплярах
print(Spaceship.fuel_type) # "антиматерия"
enterprise = Spaceship("Enterprise")
print(enterprise.fuel_type) # Тоже "антиматерия"
# Меняем для всего класса
Spaceship.fuel_type = "термоядерный синтез"
print(enterprise.fuel_type) # Теперь "термоядерный синтез"
Атрибуты экземпляра — ваши персональные данные 🏷️
Эти атрибуты уникальны для каждого объекта. Они определяются в методе __init__ (или других методах) через self.
Почему они важны:
- Хранят состояние конкретного объекта
- Не влияют на другие экземпляры
- Могут переопределять атрибуты класса
voyager = Spaceship("Voyager")
# Добавляем атрибут экземпляра
voyager.captain = "Кэтрин Джейнвей"
print(voyager.captain) # "Кэтрин Джейнвей"
print(enterprise.captain) # Ошибка! Атрибут существует только у voyager
Приоритет доступа: кто главнее? 🥇
Python ищет атрибуты в строгом порядке:
- Экземпляр — сначала проверяет собственные атрибуты
- Класс — если не найдено, ищет в классе
- Родительские классы — при наследовании
class Alien:
home_planet = "Марс"
martian = Alien()
martian.home_planet = "Земля" # Создали атрибут экземпляра
print(martian.home_planet) # "Земля" (приоритет у экземпляра)
print(Alien.home_planet) # "Марс" (оригинальное значение класса)
Практические паттерны использования 🔧
1. Константы класса
Идеально для значений, общих для всех экземпляров:
class Pizza:
# Атрибут класса
BASE_PRICE = 100
def __init__(self, toppings):
self.toppings = toppings
def calculate_price(self):
return self.BASE_PRICE + len(self.toppings) * 20
2. Счётчики экземпляров
Отслеживание количества созданных объектов:
class Robot:
count = 0
def __init__(self):
Robot.count += 1 # Обращаемся через имя класса
print(Robot.count) # 0
r2d2 = Robot()
print(Robot.count) # 1
3. Переопределение в экземплярах
Гибкая настройка объектов:
class Character:
speed = 1
mario = Character()
sonic = Character()
sonic.speed = 10 # Уникальное значение для sonic
Главные выводы для запоминания 🧠
- Атрибуты класса — для данных, общих для всех экземпляров (как глобальные переменные класса)
- Атрибуты экземпляра — для уникальных данных каждого объекта (состояние)
- Приоритет — экземпляр > класс > родительские классы
- Использование:
- Класс — для констант, счётчиков, общих настроек
- Экземпляр — для персональных данных объекта
Попробуйте создать класс BankAccount с атрибутом класса interest_rate и атрибутами экземпляра balance и owner_name — это отличная тренировка! 💰