logo

Переопределение оператора 'in' в Python: функция contains

Быстрый ответ

Чтобы переопределить оператор 'in' в собственном классе, вам нужно реализовать метод __contains__. Данный метод даёт возможность указать собственные условия проверки вхождения элемента в объект этого класса.

Вот пример простого класса:

Python
Скопировать код
class OddContainer:
    def __contains__(self, item):
        return item % 2 != 0

# Пример использования:
print(1 in OddContainer())  # True, потому что 1 – нечётное число.
print(2 in OddContainer())  # False, 2 – чётное число.

Настройка проверки принадлежности с помощью contains

Метод __contains__ применяется для определения логики проверки принадлежности элемента вашему классу. Разберём пример, в котором этот метод используется для проверки наличия объекта в коллекции:

Python
Скопировать код
class PortfolioItem:
    def __init__(self, ticker):
        self.ticker = ticker

class Portfolio:
    def __init__(self, *args):
        self._holdings = list(args)
    
    def __contains__(self, item):
        return any(item.ticker == obj.ticker for obj in self._holdings)

# Пример использования:
portfolio = Portfolio(PortfolioItem('AAPL'), PortfolioItem('GOOG'), PortfolioItem('TSLA'))
print(PortfolioItem('AAPL') in portfolio)  # True, т.к. AAPL присутствует в портфолио.
print(PortfolioItem('MSFT') in portfolio)  # False, MSFT отсутствует в портфолио.

Когда contains недостаточно

Если в классе не определён метод __contains__, Python по умолчанию использует метод __iter__ для проверки принадлежности. Это неплохой вариант для больших структур данных, однако он может быть неэффективным в некоторых ситуациях.

Визуализация

Вы можете сравнить стандартную проверку оператора 'in' с поиском ключа под ковриком у двери:

Markdown
Скопировать код
Стандартный 'in':       Дом (🏠) --(🔑?)--> Коврик (🚪)
# Есть ли ключ (🔑) под ковриком (🚪)? [Да/Нет]

Переопределённый 'in':   Дом (🏠) --(🔑?)--> Специализированная проверка (🗝️)

Переопределение метода позволяет задать свой алгоритм поиска.

Сложные условия принадлежности

Метод __contains__ способен обрабатывать сложные условия, не ограничиваясь базовой проверкой вхождения:

Python
Скопировать код
class FancyContainer:
    def __init__(self):
        self._data = set()

    def __contains__(self, item):
        return (item in self._data or some_other_complex_condition(item))

    def add(self, item):
        self._data.add(item)

Не забывайте про тестирование!

Важно проводить тестирование разных сценариев использования метода __contains__, чтобы гарантировать его корректное функционирование.

Поддерживайте pythonic-стиль

При создании метода __contains__ не забывайте об основных принципах Python, а именно: стремитесь к простоте и логичности вашей реализации.

Полезные материалы

  1. 3. Data model — Python 3.12.2 documentation
  2. Operator and Function Overloading in Custom Python Classes – Real Python
  3. PEP 3119 – Introducing Abstract Base Classes | peps.python.org
  4. Enriching Your Python Classes With Dunder (Magic, Special) Methods – dbader.org
  5. Educative: Interactive Courses for Software Developers
  6. [Keeping References to Bound Methods Without Inhibiting Garbage Collection – Python Cookbook [Book]](https://www.oreilly.com/library/view/python-cookbook/0596001673/ch05s15.html)