Специальные методы в Python

Содержание
Введение
Пример
__repr__()
__str__()
__add__()
__repr__() из datetime
__str__() из datetime
__add__() из datetime
Похожие статьи

Введение

Это продолжение статьи «Классы» из раздела «ООП в Python» .

Для лучшего понимания этого материала пригодятся знания из следующих статей: Методы , Класс методы , Статические методы , super() , Декораторы , isinstance()

Специальные методы всегда окружены двумя нижними подчёркиваниями слева и справа.

Мы уже сталкивались со специальным методом __init__()

В англоязычном сообществе принято произносить такое написание как “dunder init”

Пример

Создадим класс Employee и посмотрим что покажут методы repr и str

class Employee: num_of_emps = 0 raise_amount = 1.04 def __init__(self, first, last, pay): self.first = first self.last = last self.pay = pay self.email = first + '.' + last + '@kaspersky.com' Employee.num_of_emps += 1 def fullname(self): return f'{self.first} {self.last}' def apply_raise(self): self.pay = int(self.pay * self.raise_amount) emp_1 = Employee("Eugene", "Kaspersky", 50000) print(emp_1) print(repr(emp_1)) print(str(emp_1)) # Same as # print(emp_1.__repr__()) # print(emp_1.__str__())

python special_methods.py

<__main__.Employee object at 0x7f486bee5fd0> <__main__.Employee object at 0x7f486bee5fd0> <__main__.Employee object at 0x7f486bee5fd0>

Как видно из вывод выше методы работают, выдают одну и ту же информацию о том, что это объект класса Employee который находится по данному адресу.

РЕКЛАМА хостинга Beget, которым я пользуюсь более десяти лет

Изображение баннера

Конец рекламы хостинга Beget, который я всем рекомендую.

__repr__()

Реализуем метод __repr__()

def __repr__(self): return f"Employee({self.first}, {self.last}, {self.pay})"

python special_methods.py

Employee(Eugene, Kaspersky, 50000) Employee(Eugene, Kaspersky, 50000) Employee(Eugene, Kaspersky, 50000)

Теперь информация соответствует тому, что мы определили в методе, причем снова везде одно и то же.

Рассмотрим метод __repr__() на примере класса Rectangle из примера про __future__

Сперва попробуем распечатать all_rectangles и r1 не прописывая __repr__()

from __future__ import annotations class Rectangle: all_rectangles: list[Rectangle] = [] def __init__(self, length: float, width: float) -> None: self.length = length self.width = width Rectangle.all_rectangles.append(self) def area(self) -> float: return self.length * self.width r1 = Rectangle(3, 2) r2 = Rectangle(4, 4) print(r1.all_rectangles) print(r1)

[<__main__.Rectangle object at 0x0000023A7ED84860>, <__main__.Rectangle object at 0x0000023A7ED84890>] <__main__.Rectangle object at 0x0000023A7ED84860>

Добавим __repr__()

def __repr__(self) -> str: return f"{self.__class__.__name__}({self.length!r} x {self.width!r}) area {self.area()}"

[Rectangle(3 x 2) area 6, Rectangle(4 x 4) area 16] Rectangle(3 x 2) area 6

__str__()

Добавим в класс Employee метод __str__()

def __repr__(self): return f"Employee({self.first}, {self.last}, {self.pay})" def __str__(self): return f"{self.fullname()} - {self.email}"

python special_methods.py

Eugene Kaspersky - Eugene.Kaspersky@kaspersky.com Employee(Eugene, Kaspersky, 50000) Eugene Kaspersky - Eugene.Kaspersky@kaspersky.com

Вывод метода __repr__() никак не изменился, а print(emp_1) теперь повторяет не за __repr__() а за __str__()

Добавим метом __str__() в класс Rectangle

from __future__ import annotations class Rectangle: all_rectangles: list[Rectangle] = [] def __init__(self, length: float, width: float) -> None: self.length = length self.width = width Rectangle.all_rectangles.append(self) def area(self) -> float: return self.length * self.width def __repr__(self) -> str: return (f"{self.__class__.__name__}({self.length!r} " f"x {self.width!r}) area {self.area()}") def __str__(self) -> str: return (f"String: {self.__class__.__name__}({self.length!r} " f"x {self.width!r})") r1 = Rectangle(3, 2) r2 = Rectangle(4, 4) print(r1.all_rectangles) print(r1)

[Rectangle(3 x 2) area 6, Rectangle(4 x 4) area 16] String: Rectangle(3 x 2)

Видно, что в переменную класса all_rectangles пошло, то, что задано в __repr__() а при выводе самого объекта используется __str__()

__add__()

Рассмотрим метод __add__()

print(1+2) print(int.__add__(1, 2)) print("a" + "b") print(str.__add__("a", "b"))

python special_methods.py

3 3 ab ab

Если сходу попробовать сложить два объекта класса Employee получится TypeError

Можно сделать свой __add__() для любого класса. В классе Employee можно, например, складывать заплаты сотрудников с помощью следующего метода:

def __add__(self, other): return self.pay + other.pay emp_1 = Employee("Eugene", "Kaspersky", 330) emp_2 = Employee("Andrei", "Olegovich", 330) print(emp_1 + emp_2)

python special_methods.py

660

__repr__() из datetime

Изучим реальные примеры применения специальных методов. Для этого рассмотрим библиотеку datetime ( github )

Начнём с __repr__()

def __repr__(self): """Convert to formal string, for repr(). >>> dt = datetime(2010, 1, 1) >>> repr(dt) 'datetime.datetime(2010, 1, 1, 0, 0)' >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc) >>> repr(dt) 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)' """ return "%s.%s(%d, %d, %d)" % (self.__class__.__module__, self.__class__.__qualname__, self._year, self._month, self._day) # XXX These shouldn't depend on time.localtime(), because that # clips the usable dates to [1970 .. 2038). At least ctime() is # easily done without using strftime() -- that's better too because # strftime("%c", ...) is locale specific.

__str__() из datetime

Рассмотрим специальные метод __str__() и библиотеки datetime ( github )

Метод __str__() просто повторяет метод isoformat()

def isoformat(self): """Return the date formatted according to ISO. This is 'YYYY-MM-DD'. References: - http://www.w3.org/TR/NOTE-datetime - http://www.cl.cam.ac.uk/~mgk25/iso-time.html """ return "%04d-%02d-%02d" % (self._year, self._month, self._day) __str__ = isoformat

__add__() из datetime

Рассмотрим специальные метод __add__() и библиотеки datetime ( github )

def __add__(self, other): if isinstance(other, timedelta): # for CPython compatibility, we cannot use # our __class__ here, but need a real timedelta return timedelta(self._days + other._days, self._seconds + other._seconds, self._microseconds + other._microseconds) return NotImplemented

Автор статьи: Андрей Олегович

Похожие статьи
ООП в Python
Классы
Методы
class variables
class methods
Статические методы
Наследование
super()
Специальные методы
dataclass
__slots__
Декоратор property
Полиморфизм

Поиск по сайту

Подпишитесь на Telegram канал @aofeed чтобы следить за выходом новых статей и обновлением старых

Перейти на канал

@aofeed

Задать вопрос в Телеграм-группе

@aofeedchat

Контакты и сотрудничество:
Рекомендую наш хостинг beget.ru
Пишите на info@urn.su если Вы:
1. Хотите написать статью для нашего сайта или перевести статью на свой родной язык.
2. Хотите разместить на сайте рекламу, подходящую по тематике.
3. Реклама на моём сайте имеет максимальный уровень цензуры. Если Вы увидели рекламный блок недопустимый для просмотра детьми школьного возраста, вызывающий шок или вводящий в заблуждение - пожалуйста свяжитесь с нами по электронной почте
4. Нашли на сайте ошибку, неточности, баг и т.д. ... .......
5. Статьи можно расшарить в соцсетях, нажав на иконку сети: