← Назад к вопросам
Как реализован конструктор класса в Python?
1.6 Junior🔥 221 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Реализация конструктора класса в Python
Конструктор в Python реализуется через специальный метод __init__, который вызывается при создании экземпляра класса. Это не совсем конструктор в смысле C++, а скорее инициализатор.
Базовый конструктор
class User:
def __init__(self, name: str, email: str):
"""Конструктор (инициализатор) класса."""
self.name = name
self.email = email
def __repr__(self):
return f"User(name={self.name}, email={self.email})"
# Создание экземпляра
user = User("Alice", "alice@example.com")
print(user) # User(name=Alice, email=alice@example.com)
Процесс:
- Python вызывает
__new__(создание объекта в памяти) - Python вызывает
__init__(инициализация атрибутов) - Возвращается готовый объект
new и init вместе
Это два разных метода:
class MyClass:
def __new__(cls, *args, **kwargs):
"""Создание объекта (allocation)."""
print("__new__ called")
instance = super().__new__(cls)
return instance
def __init__(self):
"""Инициализация объекта (initialization)."""
print("__init__ called")
self.value = 42
obj = MyClass()
# Вывод:
# __new__ called
# __init__ called
Отличия:
__new__— статический метод, создаёт объект, получаетcls__init__— обычный метод, инициализирует объект, получаетself__new__ДОЛЖЕН вернуть экземпляр класса__init__ДОЛЖЕН вернутьNone
Конструктор с параметрами по умолчанию
class Point:
def __init__(self, x: float = 0.0, y: float = 0.0):
self.x = x
self.y = y
def distance(self) -> float:
return (self.x ** 2 + self.y ** 2) ** 0.5
# Использование
p1 = Point(3, 4)
print(p1.distance()) # 5.0
p2 = Point() # Значения по умолчанию
print(p2.distance()) # 0.0
p3 = Point(y=5) # x=0 по умолчанию
print(p3.distance()) # 5.0
Конструктор в наследовании
class Animal:
def __init__(self, name: str):
self.name = name
print(f"Animal.__init__ called for {name}")
class Dog(Animal):
def __init__(self, name: str, breed: str):
# ❌ Правильно ошибка: не вызвали __init__ родителя
self.breed = breed # AttributeError: name не инициализирован
# ✅ Правильно: вызвать родителя
class Dog(Animal):
def __init__(self, name: str, breed: str):
super().__init__(name) # Инициализация родителя
self.breed = breed
def describe(self):
return f"{self.name} is a {self.breed}"
dog = Dog("Buddy", "Golden Retriever")
print(dog.describe()) # Buddy is a Golden Retriever
Множественное наследование:
class Mixin:
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.mixin_attr = "from mixin"
class Base:
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.base_attr = "from base"
class Child(Mixin, Base):
def __init__(self, name: str):
self.name = name
super().__init__()
child = Child("Test")
print(child.name) # Test
print(child.mixin_attr) # from mixin
print(child.base_attr) # from base
Конструкторы через classmethod
Альтернативные способы создания объектов:
from datetime import datetime
class Person:
def __init__(self, name: str, birth_year: int):
self.name = name
self.birth_year = birth_year
@classmethod
def from_age(cls, name: str, age: int):
"""Альтернативный "конструктор" через возраст."""
birth_year = datetime.now().year - age
return cls(name, birth_year)
@classmethod
def from_string(cls, person_str: str):
"""Парсинг из строки."""
name, year = person_str.split(",")
return cls(name, int(year))
def age(self) -> int:
return datetime.now().year - self.birth_year
# Использование
p1 = Person("Alice", 1990)
p2 = Person.from_age("Bob", 30)
p3 = Person.from_string("Charlie,1985")
print(p2.age()) # ~30
Конструктор с проверкой данных
class BankAccount:
def __init__(self, account_number: str, balance: float = 0):
# Валидация
if not account_number or len(account_number) < 5:
raise ValueError("Invalid account number")
if balance < 0:
raise ValueError("Balance cannot be negative")
self.account_number = account_number
self.balance = balance
def deposit(self, amount: float):
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount
# Использование
try:
acc = BankAccount("12345", -100) # ValueError!
except ValueError as e:
print(f"Error: {e}")
acc = BankAccount("12345", 100)
acc.deposit(50)
print(acc.balance) # 150
Конструктор со сложной инициализацией
class Database:
_instance = None
def __new__(cls, connection_string: str):
"""Синглтон паттерн."""
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self, connection_string: str):
if self._initialized:
return # Не инициализируем дважды
self.connection_string = connection_string
self._connect()
self._initialized = True
def _connect(self):
print(f"Connecting to {self.connection_string}")
# Использование
db1 = Database("postgres://localhost")
db2 = Database("mysql://localhost") # Подключение не происходит
print(db1 is db2) # True (один и тот же объект)
Конструктор с @dataclass
Модульный способ (Python 3.7+):
from dataclasses import dataclass, field
from typing import List
@dataclass
class Student:
name: str
age: int
grades: List[float] = field(default_factory=list)
def average_grade(self) -> float:
return sum(self.grades) / len(self.grades) if self.grades else 0
# Автоматически создаётся __init__
student = Student("Alice", 20, [4.5, 4.0, 3.8])
print(student.average_grade()) # 4.1
# __repr__, __eq__ и др. автоматически
print(student) # Student(name='Alice', age=20, grades=[4.5, 4.0, 3.8])
Атрибуты класса vs экземпляра
class Counter:
count = 0 # Атрибут класса
def __init__(self, name: str):
Counter.count += 1 # Изменение атрибута класса
self.name = name # Атрибут экземпляра
self.id = Counter.count
c1 = Counter("First")
c2 = Counter("Second")
print(c1.id) # 1
print(c2.id) # 2
print(Counter.count) # 2
slots для оптимизации памяти
class Point:
__slots__ = ['x', 'y'] # Только эти атрибуты
def __init__(self, x: float, y: float):
self.x = x
self.y = y
p = Point(3, 4)
print(p.x) # 3
p.z = 5 # AttributeError: 'Point' object has no attribute 'z'
Лучшие практики
- Всегда вызывайте
super().__init__()в наследовании - Валидируйте параметры в init
- Используйте type hints для ясности
- Документируйте параметры конструктора через docstring
- Избегайте сложной логики в конструкторе
- Используйте @dataclass для простых классов
- Никогда не создавайте побочные эффекты в init (вроде HTTP запросов)
# ✅ Правильно
class Config:
def __init__(self, path: str):
"""Инициализирует конфиг из файла.
Args:
path: Путь к файлу конфигурации
"""
if not os.path.exists(path):
raise FileNotFoundError(f"Config file not found: {path}")
self.path = path
self.data = self._load_config()
def _load_config(self) -> dict:
with open(self.path) as f:
return json.load(f)
Конструктор в Python — это мощный инструмент для инициализации объектов и установки начального состояния.