__len__ - это специальный метод (magic method, dunder method) в Python, который определяет длину объекта. 
  len() и должен возвращать целое число, представляющее количество элементов в объекте (например, количество элементов в списке, длину строки и т.д.).  Если метод __len__ не определен для класса, вызов len() для экземпляра этого класса вызовет ошибку TypeError.
 Метод __len__ - это специальный (или "магический") метод в Python, который используется для определения длины объекта. Он является частью Python Data Model и позволяет классу определить, как оператор len() должен возвращать длину экземпляра этого класса.
Когда вы вызываете len(obj) для некоторого объекта obj, Python внутренне пытается вызвать метод obj.__len__().  Если этот метод определен в классе объекта obj, то Python использует возвращаемое значение этого метода как длину объекта. Если же метод __len__() не определен,  Python выдаст ошибку TypeError, указывая, что у данного объекта нет длины.
Для чего он используется?
Метод __len__ необходим для того, чтобы ваши собственные классы могли быть совместимы со встроенными функциями и операторами, ожидающими объекты с определенной длиной.  Например:
__len__ позволяет реализовать такую проверку для пользовательских типов данных.for:  Хотя цикл for обычно использует итераторы, он может также работать с объектами, имеющими определенную длину, если вам нужно просто перебрать элементы по индексу.__len__, могут быть использованы в булевых контекстах.  if len(my_object):  равносильно if my_object.__len__() != 0:Пример:
class MyList:
    def __init__(self, data):
        self.data = data
    def __len__(self):
        return len(self.data)
my_list = MyList([1, 2, 3, 4, 5])
print(len(my_list))  # Выведет: 5
if my_list: # Эквивалентно if len(my_list) > 0:
  print("Список не пуст")
  В этом примере класс MyList определяет метод __len__, который возвращает длину внутреннего списка self.data.  Таким образом, мы можем использовать функцию len() для получения длины экземпляра MyList.