Iter () returns an iterator

Docs.python.org/3/library/s…

Iter (object[, sentinel]) — Returns an iterator

  • If the second argument, sendinel, is not given, the first argument, object, must be a collection object that supports the iterative protocol (the __iter __ () method), or it must support the sequence protocol (the __getitem __ () method with integer arguments starting from 0). If it does not support any of these protocols, TypeError is raised. (The following focuses on this situation)
  • If the second argument, sendinel, is given, the first argument, object, must be callable. At this point, iter creates an iterator object that calls Object (callable) every time its __next__() method is called. If the returned value is equal to sendinel, StopIteration is raised, otherwise the value is returned.

The built-in iter() function is derived from the PyObject_GetIter iterator.

static PyObject *builtin_iter(PyObject *self, PyObject *args) { PyObject *v, *w = NULL; if (! PyArg_UnpackTuple(args, "iter", 1, 2, &v, &w)) //[1] Args is a tuple, length min=1, Max =2,args[0] fill variable v,arg[1] fill variable w return NULL; if (w == NULL) return PyObject_GetIter(v); //[2]arg[0] is iter(object[, sentinel]) object parameter if (! PyCallable_Check(v)) { PyErr_SetString(PyExc_TypeError, "iter(v, w): v must be callable"); return NULL; } return PyCallIter_New(v, w); }Copy the code

PyArg_UnpackTuple docs.python.org/2/c-api/arg…

(2) How does the for loop get an iterator for an object

As you can see from the [GET_ITER] section of the for loop, ** iterates using the PyObject_GetIter method, the same method used by the iter() built-in function. ** PyObject_GetIter = PyObject_GetIter;

PyObject* PyObject_GetIter(PyObject *o){ PyTypeObject *t=o->ob_type; getiterfunc f=NULL; If (PyType_HasFeature(t,PY_TPFLAGS_HAVE_ITER)) f=t->tp_iter; if(f==NULL){ ... }else{return iterator PyObject *res=(*f)(o); . return res; }}Copy the code

As you can see from the above code, the PyObject_GetIter method obtains iterators by calling the tp_iter field of an object of type corresponding to (e.g. PyLisyObject). The tp_iter field of PyList_Type is set to the list_iter method (juejin.cn/post/686413…). . When we customize an iterator object, we define the __iter__() method, which essentially sets the tp_iter field to __iter__().

(3) Define an iterator

The iterator object requires two methods that implement the iterator protocol

Iterator.__iter__ () : Returns the iterator object itself.

This method is required to traverse container or iterator objects using for and in statements and corresponds to the TP_iter slot in the type structure of Python objects in the Python/C API. (For lists, tp_iter is set to list_iter.)

Iterator.__next__ () : Returns the next element of the container, or raises a StopIteration exception if it does not

** This method corresponds to the tp_iternext slot in the type structure of Python objects in the Python/C API. ** (For lists, p_iternext is set to listiter_next.)

These two methods, the key methods of the entire for loop, are equivalent as follows:

LST =[1,2,3,4,5] for x in LST: print(LST =[1,2,3,4,5] it=iter(LST) while True: try: x=next(it) print(x) except StopIteration: breakCopy the code

(4) how to define the object that can be iterated by the for loop

The for and in statements and iter() get iterators in the same way, so you can assume that the input arguments are the same. That is, a for loop can iterate over collection objects that support the iterative protocol (the __iter __() method), or it must support the sequence protocol (the __getitem __() method with integer arguments starting from 0) — iterable objects.

Object iteration: docs.python.org/3/glossary….

(1) Support iteration protocols: Generators, file objects, collections, dict.keys(), dict.values() and dict.items();

(2) Support sequence protocol: list, tuple, string, range

(3) Custom objects: implement the iterable protocol (__iter __() method) or sequence protocol (__getitem __() method)

An iterable is implemented by defining __iter__() when defining an object. But it has to be traversable by for and in statements.

The __iter__() method returns an object containing the __next__() method

2. The __iter__() method returns self and defines the __next__() method. The object itself is both an iterable and an iterator.

For method 2, if the __next__() method is not defined, a call to iter () /for loop to fetch iterators will result in “TypeError: PyObject_GetIter PyType_HasFeature(t,PY_TPFLAGS_HAVE_ITER) PyObject_GetIter PyType_HasFeature(t,PY_TPFLAGS_HAVE_ITER)

  • Method 1 implements a for loop through the object

Print (isinstance(TraverseIterator(self.data), Iterator)) True if TraverseIterator has a __iter__ () method, False if not.

But even if there is no TraverseIterator and no __iter__ () method is implemented, that is, code without comments [2] can still be iterated through by the for loop.

  • Method 2 implements a for loop through the object: