Атрибуты хранят состояние объекта, а методы определяют его поведение.
3.1. Атрибуты Экземпляра (Instance Attributes)
- Принадлежат конкретному объекту (экземпляру класса).
- Значения этих атрибутов могут быть уникальными для каждого объекта.
- Обычно определяются внутри метода
__init__
с использованиемself.attribute_name = value
. - Также могут быть добавлены или изменены для конкретного объекта в любой момент после его создания.
class Car:
def __init__(self, make, model, year):
# Атрибуты экземпляра
self.make = make
self.model = model
self.year = year
self.mileage = 0 # Начальное значение для всех машин
car1 = Car("Toyota", "Camry", 2021)
car2 = Car("Ford", "Mustang", 2022)
print(f"{car1.make} {car1.model} ({car1.year})") # Toyota Camry (2021)
print(f"{car2.make} {car2.model} ({car2.year})") # Ford Mustang (2022)
car1.mileage = 15000 # Изменяем атрибут для конкретного объекта
print(f"Пробег car1: {car1.mileage}") # 15000
print(f"Пробег car2: {car2.mileage}") # 0
car1.color = "Синий" # Динамически добавляем атрибут
print(f"Цвет car1: {car1.color}") # Синий
# print(car2.color) # AttributeError: 'Car' object has no attribute 'color'
3.2. Атрибуты Класса (Class Attributes)
- Принадлежат самому классу, а не конкретному экземпляру.
- Являются общими для всех экземпляров этого класса.
- Определяются непосредственно внутри класса, но вне каких-либо методов.
- Доступны как через имя класса (
ClassName.attribute
), так и через экземпляр (instance.attribute
), если не переопределены на уровне экземпляра.
class Dog:
# Атрибут класса - общий для всех собак
species = "Canis familiaris"
num_legs = 4
def __init__(self, name):
self.name = name # Атрибут экземпляра
dog1 = Dog("Бобик")
dog2 = Dog("Шарик")
# Доступ к атрибуту класса
print(f"{dog1.name} - вид: {dog1.species}") # Бобик - вид: Canis familiaris
print(f"{dog2.name} - вид: {dog2.species}") # Шарик - вид: Canis familiaris
print(f"Все собаки - вид: {Dog.species}") # Все собаки - вид: Canis familiaris
# Изменение атрибута класса затрагивает все экземпляры (если они не переопределили его)
# Dog.species = "Canis lupus familiaris"
# print(f"Новый вид dog1: {dog1.species}") # Новый вид dog1: Canis lupus familiaris
# Переопределение атрибута на уровне экземпляра
dog1.species = "Домашний любимец"
print(f"Вид dog1 (переопределен): {dog1.species}") # Вид dog1 (переопределен): Домашний любимец
print(f"Вид dog2 (не изменился): {dog2.species}") # Вид dog2 (не изменился): Canis familiaris
print(f"Вид класса (не изменился): {Dog.species}") # Вид класса (не изменился): Canis familiaris
3.3. Методы Экземпляра (Instance Methods)
- Самый распространенный тип методов.
- Принимают
self
в качестве первого аргумента. - Могут получать доступ и изменять атрибуты конкретного экземпляра (
self.attribute
), а также атрибуты класса (self.species
илиDog.species
). - Вызываются для объекта:
my_object.method_name()
.
class Circle:
pi = 3.14159 # Атрибут класса
def __init__(self, radius):
self.radius = radius # Атрибут экземпляра
# Метод экземпляра
def calculate_area(self):
return self.pi * (self.radius ** 2)
# Другой метод экземпляра
def describe(self):
print(f"Круг с радиусом {self.radius}")
c1 = Circle(5)
c2 = Circle(10)
c1.describe() # Круг с радиусом 5
print(f"Площадь c1: {c1.calculate_area()}") # Площадь c1: 78.53975
c2.describe() # Круг с радиусом 10
print(f"Площадь c2: {c2.calculate_area()}") # Площадь c2: 314.159
3.4. Методы Класса (Class Methods)
- Определяются с помощью декоратора
@classmethod
. - Принимают класс (
cls
) в качестве первого аргумента (вместоself
). - Могут получать доступ и изменять атрибуты класса, но не атрибуты конкретного экземпляра (так как у них нет
self
). - Часто используются как альтернативные конструкторы или для работы с состоянием класса.
- Вызываются как для класса (
ClassName.method_name()
), так и для объекта (my_object.method_name()
).
class Employee:
raise_amount = 1.04 # Атрибут класса
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
def apply_raise(self):
self.pay = int(self.pay * self.raise_amount) # Использует атрибут класса
@classmethod
def set_raise_amount(cls, amount): # cls ссылается на класс Employee
print(f"Изменяем ставку повышения для класса {cls.__name__}")
cls.raise_amount = amount
# Альтернативный конструктор через метод класса
@classmethod
def from_string(cls, emp_str):
first, last, pay = emp_str.split('-')
# Вызывает __init__ класса cls (Employee)
return cls(first, last, int(pay))
emp1 = Employee("Иван", "Иванов", 50000)
emp2 = Employee("Петр", "Петров", 60000)
print(f"Ставка повышения: {Employee.raise_amount}") # 1.04
Employee.set_raise_amount(1.05) # Вызов метода класса через класс
print(f"Новая ставка повышения: {Employee.raise_amount}") # 1.05
print(f"Новая ставка у emp1: {emp1.raise_amount}") # 1.05 (доступ через экземпляр)
emp_str_3 = "Мария-Сидорова-70000"
emp3 = Employee.from_string(emp_str_3) # Используем альтернативный конструктор
print(f"Создан сотрудник: {emp3.first} {emp3.last} с ЗП {emp3.pay}")
3.5. Статические Методы (Static Methods)
- Определяются с помощью декоратора
@staticmethod
. - Не принимают ни
self
, ниcls
в качестве первого аргумента. - Ведут себя как обычные функции, но помещены внутрь класса для логической организации.
- Не могут напрямую изменять состояние объекта или класса (у них нет доступа к
self
илиcls
). - Используются для создания утилитных функций, связанных с классом, но не зависящих от его состояния.
- Вызываются как для класса (
ClassName.method_name()
), так и для объекта (my_object.method_name()
).
import datetime
class MathUtils:
@staticmethod
def add(x, y):
return x + y
@staticmethod
def is_workday(day):
# weekday() возвращает 0 для понедельника, ..., 6 для воскресенья
if day.weekday() == 5 or day.weekday() == 6:
return False # Суббота или Воскресенье
return True
print(MathUtils.add(5, 3)) # 8
today = datetime.date.today()
if MathUtils.is_workday(today):
print("Сегодня рабочий день.")
else:
print("Сегодня выходной.")
〰〰〰 𓆝 𓆟 𓆞 𓆝 𓆟 𓆝 𓆟 𓆞 〰〰〰