Python объекты: полное понимание сущностей
Основные понятия и создание объектов
Как создать простой объект в Python с собственными атрибутами и методами?
Базовым способом является определение класса с помощью ключевого слова class и метода __init__. Через self обращаются к атрибутам конкретного экземпляра.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Привет, меня зовут {self.name}"
p = Person("Анна", 30)
print(p.greet())
Python arguments types (типы аргументов в python)
Привет, меня зовут Анна
Python load module (загрузка модуля в python)
Пояснение: метод __init__ вызывается автоматически при создании экземпляра. Параметр self ссылается на создаваемый объект. Каждый метод экземпляра должен иметь self первым параметром.
Типичные ошибки и их решения:
- Забытый self: если в определении метода не указать self, при вызове возникнет ошибка TypeError. Всегда добавляйте self первым параметром.
- Изменяемые аргументы по умолчанию:
def __init__(self, items=[])создаёт один список для всех экземпляров. ИспользуйтеNoneи создавайте новый список внутри. - Попытка изменить атрибут класса через экземпляр: присваивание
p.attr = valueсоздаёт атрибут экземпляра, не изменяя класс. Для изменения атрибута класса обращайтесь кClassName.attr.
Цель: создание полнофункциональных объектов с индивидуальными данными и поведением. Используется для большинства задач ООП.
Как быстро описать объект только с данными, без лишнего кода?
Модуль dataclasses (Python 3.7+) автоматически генерирует __init__, __repr__, __eq__ и другие методы. Достаточно объявить поля с аннотациями типов.
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
p = Person("Иван", 25)
print(p)
print(p == Person("Иван", 25))
Pd pandas python (импорт пакетов python)
Person(name='Иван', age=25) True
How to use python (как использовать python)
Аннотации указывают типы, но не проверяются во время выполнения. Для валидации можно использовать __post_init__.
Проблемы:
- Изменяемые поля по умолчанию: если значение по умолчанию - изменяемый объект (список, словарь), Python выдаст ошибку. Используйте
field(default_factory=list). - Наследование от dataclass: нужно правильно расставлять декораторы и учитывать порядок полей.
Цель: создание простых хранителей данных (DTO) с минимальным кодом. Удобно для конфигураций, ответов API.
Как создать неизменяемый объект с фиксированными полями?
Класс namedtuple из модуля collections создаёт кортежоподобный класс с именованными полями. Экземпляры неизменяемы.
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y)
# p.x = 30 # Ошибка: невозможно изменить атрибут
как писать код на python (как писать код на python)
10 20
Python log 2 (логарифм по основанию 2 в python)
Namedtuple поддерживает распаковку, сравнение, имеет метод _replace для создания копии с новыми значениями.
Проблемы:
- Отсутствие методов экземпляра: для добавления поведения нужно наследоваться от namedtuple, что может быть неудобно.
- Ограниченная читаемость: при большом количестве полей лучше использовать dataclass.
Цель: лёгкие неизменяемые структуры для координат, настроек, ключей словарей (хешируемые, если поля хешируемы).
Как уменьшить потребление памяти объектами при большом количестве экземпляров?
Объявление __slots__ в классе фиксирует набор атрибутов и убирает словарь экземпляра __dict__, экономя память.
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.x, p.y)
# print(p.__dict__) # Ошибка: нет __dict__
Python data model (модель данных python)
1 2
__slots__ препятствует добавлению новых атрибутов напрямую, что может быть как плюсом (защита от опечаток), так и минусом.
Проблемы:
- Наследование: если класс-потомок тоже хочет использовать __slots__, нужно повторить все слоты предка.
- Совместимость с некоторыми библиотеками: например, сериализация (pickle) может потребовать дополнительных настроек.
Цель: оптимизация памяти при создании миллионов однотипных объектов (например, игровые сущности, точки).
Расширенные примеры работы с объектами
Магические методы для настройки поведения
Переопределение __str__, __repr__, __eq__ и __hash__ позволяет объектам корректно отображаться, сравниваться и использоваться в множествах и словарях.
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __eq__(self, other):
if not isinstance(other, Vector):
return NotImplemented
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash((self.x, self.y))
v1 = Vector(1, 2)
v2 = Vector(1, 2)
print(v1)
print(v1 == v2)
print({v1, v2})
Vector(1, 2)
True
{Vector(1, 2)}
NotImplemented возвращается, если сравнение с другим типом не поддерживается. __hash__ обязателен, если объекты помещаются в хеш-структуры.
Свойства (property) для вычисляемых атрибутов
Декоратор @property превращает метод в атрибут, доступный только для чтения или с проверками.
class Rectangle:
def __init__(self, width, height):
self._width = width
self._height = height
@property
def area(self):
return self._width * self._height
@property
def width(self):
return self._width
@width.setter
def width(self, value):
if value <= 0:
raise ValueError("Ширина должна быть положительной")
self._width = value
r = Rectangle(10, 5)
print(r.area)
r.width = 12
print(r.area)
50 60
Свойства позволяют реализовать инкапсуляцию без явных геттеров и сеттеров.
Наследование и вызов super()
Использование super().__init__() в классе-наследнике гарантирует инициализацию родительской части.
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name)
self.breed = breed
def speak(self):
return f"{self.name} говорит Гав!"
d = Dog("Бобик", "Такса")
print(d.speak())
print(d.breed)
Бобик говорит Гав! Такса
При множественном наследовании super() следует порядку MRO (Method Resolution Order).
Статические методы и методы класса
@staticmethod не получает ссылку на класс или экземпляр, @classmethod принимает класс (cls) как первый аргумент.
class MathUtils:
@staticmethod
def add(a, b):
return a + b
@classmethod
def create_from_string(cls, s):
a, b = map(int, s.split(','))
return cls() # возвращает экземпляр класса
print(MathUtils.add(3, 4))
7
Статические методы подходят для утилит, а класс-методы - для альтернативных конструкторов.
Использование dataclass с настройками
Параметры декоратора: order=True для сортировки, frozen=True для неизменяемости.
from dataclasses import dataclass, field
@dataclass(order=True, frozen=True)
class Product:
name: str
price: float
tags: list = field(default_factory=list)
p1 = Product("Кофе", 250)
p2 = Product("Чай", 150)
print(p1 > p2)
# p1.price = 300 # Ошибка: frozen экземпляр
True
Параметр frozen делает экземпляры хешируемыми (если все поля хешируемы).