Python Glossary English

все Python 3ООПпонятие

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

магические методы

Магические методы для протокола последовательности/контейнера. Позволяют использовать len(), [], in.

Синтаксис

def __len__(self): ...
def __getitem__(self, idx): ...

Один только __getitem__ уже делает объект итерируемым и заставляет работать оператор in — Python перебирает индексы 0, 1, 2... пока не поймает IndexError, даже если __iter__ и __contains__ не заданы. А объект, у которого __len__ вернул 0, считается ложным в булевом контексте (if obj).

Примеры

class MyList:
    def __init__(self, data):
        self._data = list(data)
    def __len__(self):
        return len(self._data)
    def __getitem__(self, idx):
        return self._data[idx]
ml = MyList([1,2,3])
print(len(ml))   # → 3
print(ml[0])     # → 1
print(ml[-1])    # → 3
class FibSequence:
    def __getitem__(self, n):
        a, b = 0, 1
        for _ in range(n):
            a, b = b, a+b
        return a
fib = FibSequence()
print(fib[0], fib[5], fib[10])  # → 0 5 55
class MyDict:
    def __init__(self):
        self._data = {}
    def __setitem__(self, key, val):
        self._data[key] = val
    def __getitem__(self, key):
        return self._data[key]
d = MyDict()
d['x'] = 10
print(d['x'])  # → 10
class Bag:
    def __init__(self, items):
        self._items = list(items)
    def __contains__(self, item):
        return item in self._items
b = Bag([1,2,3])
print(2 in b)  # → True
print(5 in b)  # → False
# Срезы через __getitem__
class Sliceable:
    def __init__(self, data):
        self._data = data
    def __getitem__(self, key):
        return self._data[key]
s = Sliceable([10,20,30,40,50])
print(s[1:3])  # → [20, 30]
# Полный контейнер
class NumberSet:
    def __init__(self, *nums):
        self._nums = set(nums)
    def __len__(self):
        return len(self._nums)
    def __contains__(self, n):
        return n in self._nums
    def __repr__(self):
        return f'NumberSet({self._nums})'
ns = NumberSet(1,2,3,4,5)
print(len(ns), 3 in ns, 9 in ns)  # → 5 True False
# __iter__ через __getitem__
class Range:
    def __init__(self, n):
        self.n = n
    def __getitem__(self, i):
        if i >= self.n:
            raise IndexError
        return i
print(list(Range(5)))  # → [0,1,2,3,4]

См. также

Открыть в полном глоссарииdocs.python.orgСообщить о неточности