8.7. Operator Contains

  • a in b - will call "contains" on object b (b.__contains__(a))

8.7.1. Syntax

>>> class MyClass:
...     def __contains__(self, other): ...  # x in self

8.7.2. Problem

>>> class Vector:
...     x: int
...     y: int
...
...     def __init__(self, x, y):
...         self.x = x
...         self.y = y
...
...     def __repr__(self):
...         return f'Vector(x={self.x}, y={self.y})'
>>> a = Vector(x=1, y=2)
>>>
>>> 1 in a
Traceback (most recent call last):
TypeError: argument of type 'Vector' is not iterable
>>>
>>> 3 in a
Traceback (most recent call last):
TypeError: argument of type 'Vector' is not iterable

8.7.3. Solution

>>> class Vector:
...     x: int
...     y: int
...
...     def __init__(self, x, y):
...         self.x = x
...         self.y = y
...
...     def __repr__(self):
...         return f'Vector(x={self.x}, y={self.y})'
...
...     def __contains__(self, item):
...         if self.x == item:
...              return True
...         if self.y == item:
...              return True
...         return False
>>> a = Vector(x=1, y=2)
>>>
>>> 1 in a
True
>>>
>>> 3 in a
False

8.7.4. Operator

  • operator.contains(a, b) - contains - a in b

>>> import operator
>>> operator.contains([1, 2, 3], 2)
True

8.7.5. Use Case - 1

>>> class Group:
...     def __init__(self):
...         self.users = []
...
...     def add_user(self, user):
...         self.users.append(user)
...
...     def __contains__(self, who):
...         for user in self.users:
...             if who == user:
...                 return True
...         return False
>>>
>>>
>>> admins = Group()
>>> admins.add_user('mwatney')
>>> admins.add_user('mlewis')
>>> admins.add_user('rmartinez')
>>>
>>> 'mwatney' in admins
True

8.7.6. Use Case - 2

>>> class Group:
...     def __init__(self):
...         self.members = []
...
...     def __iadd__(self, user):
...         self.members.append(user)
...         return self
...
...     def __contains__(self, user):
...         return user in self.members
>>>
>>>
>>> admins = Group()
>>> admins += 'mwatney'
>>> admins += 'mlewis'
>>> admins += 'rmartinez'
>>>
>>> admins.members
['mwatney', 'mlewis', 'rmartinez']
>>>
>>> 'mwatney' in admins
True
>>>
>>> 'avogel' in admins
False

8.7.7. Assignments

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Operator Comparison Contains
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5

# %% English
# 1. Override operators for code to work correctly
# 2. Do not use `dataclasses`
# 3. Run doctests - all must succeed

# %% Polish
# 1. Nadpisz operatory aby poniższy kod zadziałał poprawnie
# 2. Nie używaj `dataclasses`
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - `object.__contains__()`
# - `object.__eq__()`

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> mark = User(firstname='Mark', lastname='Watney', groups=[
...     Group(gid=1, name='admins'),
...     Group(gid=2, name='staff'),
...     Group(gid=3, name='managers'),
... ])

>>> Group(gid=1, name='admins') == Group(gid=1, name='admins')
True
>>> Group(gid=1, name='admins') == Group(gid=2, name='staff')
False
>>> Group(gid=1, name='admins') == Group(gid=3, name='managers')
False
>>> Group(gid=1, name='admins') == Group(gid=0, name='root')
False

>>> Group(gid=1, name='admins') in mark
True
>>> Group(gid=2, name='staff') in mark
True
>>> Group(gid=0, name='root') in mark
False
"""


class Group:
    gid: int
    name: str

    def __init__(self, gid: int, name: str) -> None:
        self.gid = gid
        self.name = name


class User:
    firstname: str
    lastname: str
    groups: list[Group]

    def __init__(self, firstname: str, lastname: str, groups: list) -> None:
        self.firstname = firstname
        self.lastname = lastname
        self.groups = groups