Ques/Help/Req Dunder-методы: зачем они нужны и что могут

XakeR

Member
Регистрация
13.05.2006
Сообщения
1 912
Реакции
0
Баллы
16
Местоположение
Ukraine
Абсолютно все питонисты рано или поздно спотыкаются о методы с двойными подчеркиваниями. Зачем они вообще нужны? Почему без них не обойтись? Кто это придумал? В чем отличие от классических методов без подчеркиваний? Почему они не везде? Если вы тоже задаетесь такими вопросами, то вашему вниманию обзор на некоторые из самых популярных методов с двойным подчеркиванием. В Python они определяют кастомные свойства и поведение объектов.

ВРЕЗКА. Стоит отличать их от магических методов IPython, которые делают работу в Google Colaboratory / Jupyter Notebook удобнее. Если вы хотите познакомиться с последними поближе, прочитайте мою статью “Топ самых полезных магических команд для завсегдатаев Python”.

Например, когда вы выполняете операции, такие как сложение (+), вычитание (-), умножение (*), и деление (/), Python автоматически вызывает соответствующие «магические» методы (__add__, __sub__, __mul__, и __div__ соответственно).

QA Automation Python Иннотех, , можно удалённо, По итогам собеседования tproger.ru Вакансии на tproger.ru

Слово «dunder» здесь – не ругательство, оно отсылает к двойному подчеркиванию. Два underscore нужны только для того, чтобы предотвратить конфликт имен с другими методами, реализованными ничего не подозревающими программистами. И внедрил их, конечно, создатель языка Гвидо ван Россум.

Да кому нужны эти Dunder-методы?​


Dunder-методы: зачем они нужны и что могут0


Чтобы понять, зачем этот класс методов выделен в отдельную группу, рассмотрим пример из треда на Stack Overflow. Пользователь Greg Beech спрашивает, зачем вообще нужны такие усложнения, если вместо __len__ можно использовать просто len()? Замечательный сниппет от Mangu Singh Rajpurohit раз и навсегда отвечает на этот вопрос, на мой взгляд:

«Представьте, что у вас есть два словаря, и вы хотите их сложить:

dict1 = {1 : «ABC»} dict2 = {2 : «EFG»} dict1 + dict2

При исполнении этого кода будет вызываться ошибка:

TypeError: unsupported operand type(s) for +: ‘dict’ and ‘dict’

Ошибка TypeError гласит, что словари складывать нельзя. А ведь нам так надо! Так что давайте добавим классу “словарь” этот функционал. Точнее, инициируем дочерний класс AddableDict:

class AddableDict(dict): def __add__(self, otherObj): self.update(otherObj) return AddableDict(self) dict1 = AddableDict({1 : «ABC»}) dict2 = AddableDict({2 : «EFG»}) print (dict1 + dict2)

И вуаля! Словари складываются:

{1: ‘ABC’, 2: ‘EFG’}

Некоторые интересные Dunder-методы​


1. __init__:

Если у вас есть определенные классы в Python, вы обязательно встретитесь с методом __init__. Он отвечает за инициализацию экземпляра класса, поэтому именно в нем вы обычно устанавливаете его неотъемлемые атрибуты – например, длина ребра квадрата:

class Square: def __init__(self, side_length): «»» Чтобы создать квадрат (Square), нам нужно знать длину его стороны, чтобы позднее передать это значение как аргумент: Square(1). Чтобы убедиться, что сущность знает свою длину стороны, сохраним ее так: «»» self.side_length = side_length sq = Square(1) 2. __call__:

Этот метод позволяет создать так называемые «вызываемые» объекты, то есть их можно вызывать как функции.

class CallableObject: def __call__(self, x): return x ** 2 callable_object = CallableObject() print(callable_object(5)) # выводит 25 3. __getitem__ и __setitem__:

Методы позволяют обращения к объекту по индексу или ключу, как если бы это был список или словарь.

class MyDictionary: # выводит «value» def __init__(self): self.dictionary = {} def __getitem__(self, key): return self.dictionary[key] def __setitem__(self, key, value): self.dictionary[key] = value my_dict = MyDictionary() my_dict[«test»] = «value» print(my_dict[«test»]) 4. __iter__ и __next__:

Эти методы позволяют создавать итерируемые объекты, которые можно использовать в цикле for.

class IterableObject: def __init__(self, max): self.max = max self.current = 0 def __iter__(self): return self def __next__(self): if self.current < self.max: result = self.current self.current += 1 return result else: raise StopIteration iterable_object = IterableObject(5) for i in iterable_object: print(i) # выводит числа от 0 до 4 5. __enter__ и __exit__:

Эти методы используются для создания контекстных менеджеров (то есть объектов, которые можно использовать в блоке with), и позволяют управлять ресурсами, которые нужно освободить после использования.

class MyContextManager: def __init__(self): print(«Инициализируем блок») def __enter__(self): print(«Входим в блок») return self def __exit__(self, exc_type, exc_val, exc_tb): print(«Выходим из блока») with MyContextManager(): pass

При входе и выходе из блока with будут выведены соответствующие сообщения.

И небольшая шпаргалка​


Вашему вниманию перечень несложных методов, которые могут пригодиться, если вы в целом готовы впустить Dunder’ы в свой код:

Dunder-методы: зачем они нужны и что могут1


Заключение​


Если честно, у меня ушел не один год, чтобы понять и принять концепцию Dunder-методов. Из-за информационной перегрузки мозг часто стремился избегать дополнительных сложностей — и магические методы как раз попали в эту категорию. Лишь исчерпав на практике классические возможности тех или иных объектов, я вернулась к этой теме с помощью StackOverflow.

Так что не корите себя, если эту тему хочется поначалу увидеть и тут же забыть: не все в Python подходит новичкам, на некоторые вещи нужны опыт и спрос. Но освоившись с такой крутой фишкой (и еще десятком таких), вы получите преимущество в конкурентной борьбе за интереснейшие проекты, лучшие условия труда и больший оффер.


Как часто вы используете Dunder-методы?

  • Каждый божий день
  • Реже раза в неделю
  • Реже раза в месяц
  • Другое (напишите в комментариях)
  • Никогда не использовал

Написать свой вариант
 
198 237Темы
635 209Сообщения
3 618 425Пользователи
Pandar96Новый пользователь
Верх