Абсолютно все питонисты рано или поздно спотыкаются о методы с двойными подчеркиваниями. Зачем они вообще нужны? Почему без них не обойтись? Кто это придумал? В чем отличие от классических методов без подчеркиваний? Почему они не везде? Если вы тоже задаетесь такими вопросами, то вашему вниманию обзор на некоторые из самых популярных методов с двойным подчеркиванием. В Python они определяют кастомные свойства и поведение объектов.
ВРЕЗКА. Стоит отличать их от магических методов IPython, которые делают работу в Google Colaboratory / Jupyter Notebook удобнее. Если вы хотите познакомиться с последними поближе, прочитайте мою статью “Топ самых полезных магических команд для завсегдатаев Python”.
Например, когда вы выполняете операции, такие как сложение (+), вычитание (-), умножение (*), и деление (/), Python автоматически вызывает соответствующие «магические» методы (__add__, __sub__, __mul__, и __div__ соответственно).
QA Automation Python Иннотех, , можно удалённо, По итогам собеседования tproger.ru Вакансии на tproger.ru
Слово «dunder» здесь – не ругательство, оно отсылает к двойному подчеркиванию. Два underscore нужны только для того, чтобы предотвратить конфликт имен с другими методами, реализованными ничего не подозревающими программистами. И внедрил их, конечно, создатель языка Гвидо ван Россум.
Чтобы понять, зачем этот класс методов выделен в отдельную группу, рассмотрим пример из треда на 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’}
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-методов. Из-за информационной перегрузки мозг часто стремился избегать дополнительных сложностей — и магические методы как раз попали в эту категорию. Лишь исчерпав на практике классические возможности тех или иных объектов, я вернулась к этой теме с помощью StackOverflow.
Так что не корите себя, если эту тему хочется поначалу увидеть и тут же забыть: не все в Python подходит новичкам, на некоторые вещи нужны опыт и спрос. Но освоившись с такой крутой фишкой (и еще десятком таких), вы получите преимущество в конкурентной борьбе за интереснейшие проекты, лучшие условия труда и больший оффер.
Как часто вы используете Dunder-методы?
Написать свой вариант
ВРЕЗКА. Стоит отличать их от магических методов IPython, которые делают работу в Google Colaboratory / Jupyter Notebook удобнее. Если вы хотите познакомиться с последними поближе, прочитайте мою статью “Топ самых полезных магических команд для завсегдатаев Python”.
Например, когда вы выполняете операции, такие как сложение (+), вычитание (-), умножение (*), и деление (/), Python автоматически вызывает соответствующие «магические» методы (__add__, __sub__, __mul__, и __div__ соответственно).
QA Automation Python Иннотех, , можно удалённо, По итогам собеседования tproger.ru Вакансии на tproger.ru
Слово «dunder» здесь – не ругательство, оно отсылает к двойному подчеркиванию. Два underscore нужны только для того, чтобы предотвратить конфликт имен с другими методами, реализованными ничего не подозревающими программистами. И внедрил их, конечно, создатель языка Гвидо ван Россум.
Да кому нужны эти Dunder-методы?
Чтобы понять, зачем этот класс методов выделен в отдельную группу, рассмотрим пример из треда на 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-методов. Из-за информационной перегрузки мозг часто стремился избегать дополнительных сложностей — и магические методы как раз попали в эту категорию. Лишь исчерпав на практике классические возможности тех или иных объектов, я вернулась к этой теме с помощью StackOverflow.
Так что не корите себя, если эту тему хочется поначалу увидеть и тут же забыть: не все в Python подходит новичкам, на некоторые вещи нужны опыт и спрос. Но освоившись с такой крутой фишкой (и еще десятком таких), вы получите преимущество в конкурентной борьбе за интереснейшие проекты, лучшие условия труда и больший оффер.
Как часто вы используете Dunder-методы?
- Каждый божий день
- Реже раза в неделю
- Реже раза в месяц
- Другое (напишите в комментариях)
- Никогда не использовал
Написать свой вариант