Специальные (Магические) Методы
В Python существуют методы со специальными именами, которые начинаются и заканчиваются двойным подчеркиванием (например, __init__
, __str__
). Их называют магическими или dunder (double underscore) методами.
Они не предназначены для прямого вызова (обычно вы не пишете my_object.__str__()
). Вместо этого Python вызывает их автоматически в ответ на определенные операции или встроенные функции. Они позволяют настраивать поведение объектов вашего класса, чтобы они работали с операторами и функциями Python ожидаемым образом.
Основные Специальные Методы:
__init__(self, ...)
: Инициализатор объекта (конструктор). Вызывается при создании экземпляра (MyClass(...)
).__str__(self)
: Возвращает неформальное, удобочитаемое строковое представление объекта. Вызывается функциейprint()
иstr()
. Если не определен,print()
использует__repr__
.__repr__(self)
: Возвращает официальное, однозначное строковое представление объекта, которое в идеале позволяет воссоздать объект (eval(repr(obj)) == obj
). Вызывается, когда объект отображается в интерактивной консоли, а также функциейrepr()
. Если__str__
не определен, используется__repr__
. Рекомендуется всегда определять__repr__
.__len__(self)
: Возвращает “длину” объекта. Вызывается функциейlen()
.__add__(self, other)
: Позволяет использовать оператор+
с объектами (obj1 + obj2
).__sub__(self, other)
: Оператор-
.__mul__(self, other)
: Оператор*
.__eq__(self, other)
: Позволяет использовать оператор сравнения - (obj1 == obj2
).__lt__(self, other)
: Оператор<
(меньше чем).__le__(self, other)
: Оператор<=
(меньше или равно).__gt__(self, other)
: Оператор>
(больше чем).__ge__(self, other)
: Оператор>=
(больше или равно).__getitem__(self, key)
: Позволяет обращаться к элементам объекта по индексу или ключу (obj[key]
).__setitem__(self, key, value)
: Позволяет присваивать значения элементам по индексу или ключу (obj[key] = value
).__delitem__(self, key)
: Позволяет удалять элементы по индексу или ключу (del obj[key]
).__call__(self, ...)
: Позволяет “вызывать” объект как функцию (obj(...)
).
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
# Неформальное представление для пользователя
def __str__(self):
return f'"{self.title}" автора {self.author}'
# Официальное представление для разработчика
def __repr__(self):
return f"Book(title='{self.title}', author='{self.author}', pages={self.pages})"
# Длина книги - количество страниц
def __len__(self):
return self.pages
# Сравнение книг по количеству страниц
def __eq__(self, other):
if isinstance(other, Book):
return self.pages == other.pages
return NotImplemented
def __lt__(self, other):
if isinstance(other, Book):
return self.pages < other.pages
return NotImplemented
book1 = Book("Война и Мир", "Л. Толстой", 1225)
book2 = Book("Гарри Поттер", "Дж. Роулинг", 400)
print(book1) # Вызывает __str__: "Война и Мир" автора Л. Толстой
print(str(book1)) # Вызывает __str__: "Война и Мир" автора Л. Толстой
print(repr(book1)) # Вызывает __repr__: Book(title='Война и Мир', author='Л. Толстой', pages=1225)
print(len(book1)) # Вызывает __len__: 1225
print(book1 == book2) # False (__eq__)
print(book1 > book2) # True (__lt__ определяет и > через отражение)
7.2. Свойства (@property
)
Декоратор @property
позволяет определить метод, который будет доступен как атрибут (без вызова через скобки ()
). Это основной “питоничный” способ реализации геттеров, сеттеров и делитеров, позволяющий контролировать доступ к атрибутам и добавлять логику при их чтении, записи или удалении.
- Геттер (
@property
): Метод, декорированный@property
, выполняется при чтении атрибута. - Сеттер (
@attribute_name.setter
): Метод, декорированный сеттером свойства, выполняется при попытке присвоить значение атрибуту. Позволяет добавить валидацию. - Делитер (
@attribute_name.deleter
): Метод, декорированный делитером свойства, выполняется при попытке удалить атрибут (del obj.attribute
).
class Product:
def __init__(self, name, price):
self.name = name
# Используем сеттер при инициализации для валидации
self.price = price
@property
def price(self):
# Этот метод вызывается при чтении obj.price
print(f"Получение цены для {self.name}")
return self._price # Возвращаем значение из "приватного" атрибута
@price.setter
def price(self, value):
# Этот метод вызывается при присваивании obj.price = value
print(f"Установка цены {value} для {self.name}")
if value < 0:
raise ValueError("Цена не может быть отрицательной")
# Сохраняем значение в "приватном" атрибуте (с подчеркиванием)
self._price = value
@price.deleter
def price(self):
# Этот метод вызывается при del obj.price
print(f"Удаление цены для {self.name}")
del self._price
# Создаем объект, сеттер вызывается из __init__
item = Product("Ноутбук", 50000)
# Вывод: Установка цены 50000 для Ноутбук
# Читаем цену - вызывается геттер (@property)
current_price = item.price
# Вывод: Получение цены для Ноутбук
print(f"Текущая цена: {current_price}") # 50000
# Изменяем цену - вызывается сеттер (@price.setter)
item.price = 55000
# Вывод: Установка цены 55000 для Ноутбук
# Попытка установить невалидную цену
try:
item.price = -100
except ValueError as e:
print(e) # Вывод: Цена не может быть отрицательной
# Удаляем цену - вызывается делитер (@price.deleter)
del item.price
# Вывод: Удаление цены для Ноутбук
# print(item.price) # AttributeError: _price (атрибут был удален)
Использование свойств позволяет сохранить простой синтаксис доступа к атрибутам (obj.price
), но при этом добавить сложную логику или валидацию при необходимости. Имя “приватного” атрибута (_price
) обычно начинается с одного подчеркивания.
〰〰〰 𓆝 𓆟 𓆞 𓆝 𓆟 𓆝 𓆟 𓆞 〰〰〰