Что такое класс?
Класс — шаблон для создания объектов. Объект — экземпляр класса.
class Dog:
# Конструктор — вызывается при создании объекта
def __init__(self, name, breed):
self.name = name # атрибут экземпляра
self.breed = breed
# Метод экземпляра
def bark(self):
print(f"{self.name}: Гав!")
# Создание объектов
rex = Dog("Rex", "Лабрадор")
buddy = Dog("Buddy", "Пудель")
rex.bark() # Rex: Гав!
buddy.bark() # Buddy: Гав!
print(rex.name) # Rex
Инкапсуляция
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = balance # "защищённый" (соглашение)
self.__secret = "тайна" # "приватный" (name mangling)
@property
def balance(self):
return self._balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Сумма должна быть положительной")
self._balance += amount
def withdraw(self, amount):
if amount > self._balance:
raise ValueError("Недостаточно средств")
self._balance -= amount
acc = BankAccount("Alice", 1000)
acc.deposit(500)
print(acc.balance) # 1500
# acc._balance = -9999 # можно, но не нужно
# acc.__secret # AttributeError
Наследование
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Подкласс должен реализовать метод speak()")
def __str__(self):
return f"{self.__class__.__name__}({self.name})"
class Dog(Animal):
def speak(self):
return f"{self.name}: Гав!"
class Cat(Animal):
def speak(self):
return f"{self.name}: Мяу!"
class Duck(Animal):
def speak(self):
return f"{self.name}: Кря!"
animals = [Dog("Rex"), Cat("Whiskers"), Duck("Donald")]
for animal in animals:
print(animal.speak())
# Rex: Гав!
# Whiskers: Мяу!
# Donald: Кря!
super() — вызов родительского класса
class Vehicle:
def __init__(self, brand, speed):
self.brand = brand
self.speed = speed
def info(self):
return f"{self.brand}, {self.speed} км/ч"
class ElectricCar(Vehicle):
def __init__(self, brand, speed, battery):
super().__init__(brand, speed) # вызов родительского __init__
self.battery = battery
def info(self):
base = super().info()
return f"{base}, батарея: {self.battery} кВтч"
tesla = ElectricCar("Tesla", 250, 100)
print(tesla.info()) # Tesla, 250 км/ч, батарея: 100 кВтч
Магические методы (dunder methods)
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __str__(self):
return f"({self.x}, {self.y})"
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __len__(self):
return 2
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __abs__(self):
return (self.x**2 + self.y**2) ** 0.5
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # (4, 6)
print(v1 * 3) # (3, 6)
print(len(v1)) # 2
print(abs(v2)) # 5.0
print(v1 == Vector(1, 2)) # True
@classmethod и @staticmethod
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, date_string):
"""Альтернативный конструктор"""
year, month, day = map(int, date_string.split("-"))
return cls(year, month, day)
@staticmethod
def is_valid(year, month, day):
"""Утилита, не требует доступа к экземпляру"""
return 1 <= month <= 12 and 1 <= day <= 31
def __str__(self):
return f"{self.year:04d}-{self.month:02d}-{self.day:02d}"
d = Date.from_string("2025-12-01")
print(d) # 2025-12-01
print(Date.is_valid(2025, 2, 30)) # False
@dataclass — современный подход
from dataclasses import dataclass, field
import math
@dataclass
class Point:
x: float
y: float
def distance_to(self, other: "Point") -> float:
return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
@dataclass
class Circle:
center: Point
radius: float
@property
def area(self) -> float:
return math.pi * self.radius ** 2
p1 = Point(0, 0)
p2 = Point(3, 4)
print(p1.distance_to(p2)) # 5.0
c = Circle(Point(0, 0), 5)
print(f"{c.area:.2f}") # 78.54
Абстрактные классы
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
@abstractmethod
def perimeter(self) -> float:
pass
def describe(self):
return f"Площадь: {self.area():.2f}, Периметр: {self.perimeter():.2f}"
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self): return self.width * self.height
def perimeter(self): return 2 * (self.width + self.height)
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self): return 3.14159 * self.radius ** 2
def perimeter(self): return 2 * 3.14159 * self.radius
shapes = [Rectangle(4, 5), Circle(3)]
for s in shapes:
print(s.describe())
Принципы SOLID кратко
| Принцип | Суть |
|---|---|
| S Single Responsibility | Класс отвечает за одну вещь |
| O Open/Closed | Открыт для расширения, закрыт для изменений |
| L Liskov Substitution | Подкласс можно использовать вместо родительского |
| I Interface Segregation | Маленькие интерфейсы лучше одного большого |
| D Dependency Inversion | Зависимость от абстракций, не от реализаций |
Практикуйте ООП в разделе «Классы» тренажёра — 30 задач от базовых __init__ до дескрипторов и метаклассов!