Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Устройство класса в Python
Класс в Python — это объект, который описывает структуру и поведение других объектов. Классы сами по себе являются объектами (экземплярами метакласса), что делает Python очень гибким языком.
Базовая структура класса
class Dog:
# Атрибут класса (общий для всех экземпляров)
species = "Canis familiaris"
# Метод инициализации (конструктор)
def __init__(self, name, age):
# Атрибуты экземпляра
self.name = name
self.age = age
# Метод экземпляра
def speak(self):
return f"{self.name} говорит Гав"
# Классметод
@classmethod
def create_from_string(cls, data):
name, age = data.split(",")
return cls(name, int(age))
# Статический метод
@staticmethod
def is_valid_age(age):
return age >= 0
dog = Dog("Rex", 5)
print(dog.speak()) # Rex говорит Гав
Внутреннее устройство класса
Когда Python встречает определение класса, происходит следующее:
1. Класс как dict (словарь)
Внутри класса хранится словарь (__dict__), содержащий все определения:
class Simple:
x = 10
def method(self):
pass
print(Simple.__dict__)
# {x: 10, method: <function>}
# Доступ к атрибутам класса
print(Simple.x) # 10
print(type(Simple.x)) # <class int>
2. Метакласс (metaclass)
Каждый класс — это экземпляр метакласса (по умолчанию type):
class MyClass:
pass
print(type(MyClass)) # <class type>
print(isinstance(MyClass, type)) # True
# MyClass это объект, созданный метаклассом type
# type это объект, созданный самим type
print(type(type)) # <class type>
3. MRO (Method Resolution Order)
Порядок поиска методов в иерархии наследования:
class A:
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C):
pass
print(D.mro()) # [D, B, C, A, object]
print(D().method()) # "B"
# MRO: D -> B -> C -> A -> object
Атрибуты класса vs атрибуты экземпляра
class Counter:
count = 0 # Атрибут класса (общий)
def __init__(self, name):
self.name = name # Атрибут экземпляра
Counter.count += 1
def get_count(self):
return Counter.count
# Использование
c1 = Counter("c1")
c2 = Counter("c2")
print(c1.count) # 2 (относится к классу)
print(c2.count) # 2 (относится к классу)
print(Counter.count) # 2 (явно класса)
print(c1.name) # "c1" (атрибут экземпляра)
print(c2.name) # "c2" (атрибут экземпляра)
Как создаётся класс: процесс определения
Когда интерпретатор встречает class, происходит это:
# Это написано в коде:
class MyClass:
x = 10
def method(self):
return self.x
# Интернально это эквивалентно:
MyClass = type(
MyClass, # Имя класса
(), # Кортеж базовых классов
{ # Словарь атрибутов
x: 10,
method: lambda self: self.x
}
)
Специальные методы (dunder methods)
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Person: {self.name}"
def __repr__(self):
return f"Person({self.name})"
def __eq__(self, other):
return self.name == other.name
def __lt__(self, other):
return len(self.name) < len(other.name)
def __add__(self, other):
return f"{self.name} + {other.name}"
def __call__(self, *args):
return f"Вызвана {self.name} с аргументами {args}"
def __len__(self):
return len(self.name)
p1 = Person("Alice")
print(str(p1)) # Person: Alice
print(repr(p1)) # Person(Alice)
print(p1 + Person("Bob")) # Alice + Bob
print(p1()) # Вызвана Alice с аргументами ()
print(len(p1)) # 5
Слоты (slots) для оптимизации памяти
# Без слотов
class RegularClass:
def __init__(self, x, y):
self.x = x
self.y = y
# Со слотами
class SlottedClass:
__slots__ = [x, y]
def __init__(self, x, y):
self.x = x
self.y = y
# SlottedClass использует меньше памяти
import sys
r = RegularClass(1, 2)
s = SlottedClass(1, 2)
print(sys.getsizeof(r.__dict__)) # ~280 байт
print(sys.getsizeof(s)) # ~56 байт (SlottedClass намного меньше)
Дескрипторы (descriptors)
Это специальный протокол для переопределения доступа к атрибутам:
class Descriptor:
def __get__(self, obj, objtype=None):
return obj._value if obj else self
def __set__(self, obj, value):
obj._value = value
def __delete__(self, obj):
del obj._value
class MyClass:
prop = Descriptor()
def __init__(self, value):
self.prop = value
obj = MyClass(42)
print(obj.prop) # 42
obj.prop = 100
print(obj.prop) # 100
Свойства (properties) — частный случай дескрипторов
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("Невозможная температура")
self._celsius = value
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
temp = Temperature(0)
print(temp.celsius) # 0
print(temp.fahrenheit) # 32
temp.celsius = 100
print(temp.fahrenheit) # 212
Иерархия классов
class Animal: # Базовый класс
def speak(self):
return "Звук"
class Dog(Animal): # Наследование
def speak(self): # Переопределение
return "Гав"
class GoldenRetriever(Dog): # Множественное наследование
def fetch(self):
return "Принёс мяч"
# Вызов метода базового класса
class Bird(Animal):
def speak(self):
return super().speak() + ", но это чирик" # Чирик, но это чирик
bird = Bird()
print(bird.speak())
Выводы
- Классы — это объекты, созданные метаклассом
type - Атрибуты класса — общие для всех экземпляров
- Атрибуты экземпляра — уникальные для каждого объекта
- MRO определяет порядок поиска методов в наследовании
- Специальные методы позволяют переопределить поведение операторов
- Дескрипторы — мощный механизм для управления атрибутами
- Слоты оптимизируют память для классов с фиксированным числом атрибутов