DEV Community

Super Kai (Kazuya Ito)
Super Kai (Kazuya Ito)

Posted on • Edited on

Iterator in Python (1)

Buy Me a Coffee

*Memo:

An iterator:

  • is the immutable(hashable) collection of zero or more elements which can return an element one by one:
    • Whether it's ordered or unordered, what type of an iterator it's, whether duplicated elements it can have and how many mixed types it can have all depend on the base type of an iterator.
    • Immutable(Hashable) means the elements of an iterator cannot be changed.
  • has __iter__() and __next__().
  • can be read by next() or __next__() to get the elements one by one.
  • raises StopIteration: if there are no elements to return.
  • can be used indirectly with len() after using list(), tuple(), set() and frozenset() and directly with more_itertools.ilen() to get the length:
    • more-itertools must be installed with pip install more-itertools.
    • An iterator cannot be directly used with len() to get the length.
  • is True no matter if it's non-empty or empty, checking it with bool().
  • is False no matter if it's non-empty or empty, inverting the truth value with not keyword.
  • can be checked if a specific element is and isn't in the iterator with in keyword and with not and in keyword respectively.
  • can be checked if the iterator is and isn't referred to by two variables with is keyword and with is and not keyword respectively.
  • and other iterator can be checked if all the elements in them are and aren't the same with == and != respectively.
  • and other iterator cannot be checked if all the elements in:
    • the iterator are in other iterator with <=.
    • other iterator are in the iterator with >=.
    • the iterator and other elements are in other iterator with <.
    • other iterator and other elements are in the iterator with >.
  • and other iterator cannot be checked if they have and don't have their common elements with bool() and & and with not keyword and & respectively.
  • cannot be enlarged with * and a number.
  • and other iterators cannot be concatenated with +.
  • and other iterators cannot return:
    • all the elements in them with '|' (Union: A ∪ B).
    • their common elements with '&' (Intersection: A ∩ B).
    • the elements in the iterator which aren't in other iterators with '-' (Difference: A - B).
  • and other iterator cannot return the elements in the iterator but not in other iterator or not in the iterator but in other iterator with '^' (Symmetric Difference: A Δ B).
  • can be iterated with a for statement.
  • can be unpacked with an assignment and for statement, function and * but not with **.
  • can be created by iter() and __iter__() with an iterable, by a generator and by a generator comprehension:
    • For iter(), the words type conversion are also suitable in addition to the word creation.
  • can be big because it's the special object which always uses small memory not to get MemoryError.
  • cannot be read by indexing and slicing.
  • cannot be changed by indexing, slicing and a del statement.
  • can be continuously used through multiple variables.
  • except the one created by a generator and by a generator comprehension can be copied(shallow-copied by copy.copy() and deep-copied by copy.deepcopy()).

Even a big iterator doesn't get MemoryError.


iter() or __iter__() can create an iterator, then next(), __next__() or for loop can get each element one by one from the iterator as shown below:

*Memo:

  • iter():
    • The 1st argument is object(Required-Type:Iterable/Callable):
      • It's for an iterable if sentinel isn't set.
      • It's for a callable if sentinel is set.
      • Don't use object=.
    • The 2nd argument is sentinel(Optional-Type:Any):
      • It terminates object(Callable) if object(Callable) returns the same value as it:
        • The returned same value as it cannot be seen.
      • Don't use sentinel=.
  • iter() has no arguments.
  • next():
    • The 1st argument is iterator(Required-Type:Iterator):
      • Don't use iterator=.
    • The 2nd argument is default(Optional-Type:Any):
      • It's returned if the iterator is terminated:
        • Error occurs if it's not set and if the iterator is terminated.
      • Don't use default=.
  • next() has no arguments.
v = iter([])                                       # Empty 1D iterator
v = iter([0, 1, 2, 3, 4])                          # 1D iterator
v = iter([0, 1, 2, 0, 1, 2])                       # 1D iterator
v = iter([0, 1, 2, 3, iter([4, 5, 6, 7])])         # 2D iterator
v = iter([iter([0, 1, 2, 3]), iter([4, 5, 6, 7])]) # 2D iterator
v = iter([iter([0, 1, 2, 3]),                      # 3D iterator
          iter([iter([4, 5]), iter([6, 7])])])
v = iter([iter([iter([0, 1]), iter([2, 3])]),      # 3D iterator
          iter([iter([4, 5]), iter([6, 7])])])
# No error

print(len(list(iter([0, 1, 2, 3, 4]))))
print(len(tuple(iter([0, 1, 2, 3, 4]))))
print(len(set(iter([0, 1, 2, 3, 4]))))
print(len(frozenset(iter([0, 1, 2, 3, 4]))))
from more_itertools import ilen
print(ilen(iter([0, 1, 2, 3, 4])))
print(bool(iter([0])))
print(bool(iter([iter([])])))
print(bool(iter([])))
print(not iter([0]))
print(not iter([iter([])]))
print(not iter([]))
print('A' in iter(['A', iter(['B', 'C'])]))
print('A' not in iter(['A', iter(['B', 'C'])]))
print(iter(['A', iter(['B', 'C'])]) is iter(['A', iter(['B', 'C'])]))
print(iter(['A', iter(['B', 'C'])]) is not iter(['A', iter(['B', 'C'])]))
print(iter(['A', iter(['B', 'C'])]) == iter(['A', iter(['B', 'C'])]))
print(iter(['A', iter(['B', 'C'])]) != iter(['A', iter(['B', 'C'])]))
for x in iter([0, 1, 2, 3, 4]): pass
for x in iter([iter([0, 1, 2, 3]), iter([4, 5, 6, 7])]): pass
for x in iter([iter([iter([0, 1]), iter([2, 3])]),
               iter([iter([4, 5]), iter([6, 7])])]): pass
v1, v2, v3 = iter([0, 1, 2])
v1, *v2, v3 = iter([0, 1, 2, 3, 4, 5])
for v1, v2, v3 in iter([iter([0, 1, 2]), iter([3, 4, 5])]): pass
for v1, *v2, v3 in iter([iter([0, 1, 2, 3, 4, 5]),
                         iter([6, 7, 8, 9, 10, 11])]): pass
print(*iter([0, 1]), 2, *iter([3, 4, *iter([5])]))
print([*iter([0, 1]), 2, *iter([3, 4, *iter([5])])])
v = (x**2 for x in [0, 1, 2, 3, 4, 5, 6, 7])
v = ((y**2 for y in x) for x in [[0, 1, 2, 3], [4, 5, 6, 7]])
v = (((z**2 for z in y) for y in x) for x in [[[0, 1], [2, 3]],
                                              [[4, 5], [6, 7]]])
v = iter(range(100000000))
v = (x for x in range(100000000))
# No error

print(len(iter([0, 1, 2, 3, 4])))
print(iter(['A', iter(['B', 'C'])]) <= iter(['A', iter(['B', 'C'])]))
print(iter(['A', iter(['B', 'C'])]) >= iter(['A', iter(['B', 'C'])]))
print(iter(['A', iter(['B', 'C'])]) < iter(['A', iter(['B', 'C'])]))
print(iter(['A', iter(['B', 'C'])]) > iter(['A', iter(['B', 'C'])]))
print(bool(iter([0, 1, 2]) & iter([3, 4])))
print(not (iter([0, 1, 2]) & iter([3, 4])))
v = iter([0, 1, 2, 3, 4]) * 3
v = iter([0, 1, 2]) + iter([3, 4]) + iter([5, 6, 7, 8])
print(iter([0, 4]) | iter([0, 2, 4]) | iter([0, 1, 3, 4]))
print(iter([0, 4]) & iter([0, 2, 4]) & iter([0, 1, 3, 4]))
print(iter([0, 4]) - iter([0, 2, 4]) - iter([0, 1, 3, 4]))
print(iter([0, 1, 2, 3]) ^ iter([0, 2, 4]))
# Error
Enter fullscreen mode Exit fullscreen mode

<iter(object) & next(iterator)>:

v = iter([0, 1, 2, 3, 4])

print(v)
# <list_iterator object at 0x000002821F75D240>

print(type(v))
# <class 'list_iterator'>

print(next(v)) # 0
print(next(v)) # 1
print(next(v)) # 2
print(next(v)) # 3
print(next(v)) # 4
print(next(v)) # StopIteration:
Enter fullscreen mode Exit fullscreen mode

<__iter__() & __next__()>:

v = [0, 1, 2, 3, 4].__iter__()

print(v)
# <list_iterator object at 0x000001FCD2883280>

print(v.__next__()) # 0
print(v.__next__()) # 1
print(v.__next__()) # 2
print(v.__next__()) # 3
print(v.__next__()) # 4
print(v.__next__()) # StopIteration: 
Enter fullscreen mode Exit fullscreen mode

<iter(object) & next(iterator, default)>:

v = iter([0, 1, 2, 3, 4])

print(v)
# <list_iterator object at 0x000002821F75D240>

print(next(v, 'No value')) # 0
print(next(v, 'No value')) # 1
print(next(v, 'No value')) # 2
print(next(v, 'No value')) # 3
print(next(v, 'No value')) # 4
print(next(v, 'No value')) # No value
Enter fullscreen mode Exit fullscreen mode

<iter(object, sentinel)>:

import random

def get_random_numbers():
    return random.randint(0, 9)

v = iter(get_random_numbers, 3)

print(v)
# <callable_iterator object at 0x000001FCD2F376A0>

print(next(v)) # 7
print(next(v)) # 0
print(next(v)) # 2
print(next(v)) # 9
print(next(v)) # 5
print(next(v)) StopIteration:
Enter fullscreen mode Exit fullscreen mode

Top comments (0)