The setup code: class MyContainer: def __init__(self): self.stuff = [1, 2, 3] def __iter__(self): print("__iter__") return iter(self.stuff) def __len__(self): print("__len__") return len(self.stuff) mc = MyContainer()  Now, in my shell: >>> i = iter(mc) __iter__ >>> [x for x in i] [1, 2, 3] >>> list(mc) __iter__ __len__ [1, 2, 3]  Why is __len__() getting called by list()? And where is that documented?
The behavior of calling __len__ of the given iterable during initialization of a new list is an implementation detail and is meant to help pre-allocate memory according to the estimated size of the result list, as opposed to naively and inefficiently grow the list as it is iteratively extended with items produced by a given generic iterable. You can find the logics in Objects/listobject.c of CPython, where it defaults the pre-allocation of memory to a size of 8 if the iterable has neither __len__ nor __length_hint__, which is documented in PEP-424: static int list_extend_iter_lock_held(PyListObject *self, PyObject *iterable) { PyObject *it = PyObject_GetIter(iterable); if (it == NULL) { return -1; } PyObject *(*iternext)(PyObject *) = *Py_TYPE(it)->tp_iternext; /* Guess a result list size. */ Py_ssize_t n = PyObject_LengthHint(iterable, 8); ... } 