all Python 3OOPterm
Container protocol
magic methods
The magic methods of the sequence/container protocol. They make len(), [] and in work on your object.
Syntax
def __len__(self): ...
def __getitem__(self, idx): ...
__getitem__ alone already makes the object iterable and makes the in operator work — Python walks indices 0, 1, 2... until it hits IndexError, even without __iter__ or __contains__. And an object whose __len__ returns 0 is treated as falsy in a boolean context (if obj).
Examples
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]
See also
Open in the full glossarydocs.python.orgReport an inaccuracy