DEV Community

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

Posted on • Edited on

Iterator in Python (2)

Buy Me a Coffee

*Memo:

iter() or __iter__() can create an iterator with an iterable as shown below:

print(iter()) # TypeError: iter expected at least 1 argument, got 0 
Enter fullscreen mode Exit fullscreen mode
v1 = [0, 1, 2, 3, 4] # list v2 = iter(v1) v2 = v1.__iter__() print(v2) # <list_iterator object at 0x0000026906F3C460>  print(type(v2)) # <class 'list_iterator'>  for x in v2: print(x) # 0 # 1 # 2 # 3 # 4 
Enter fullscreen mode Exit fullscreen mode
v1 = (0, 1, 2, 3, 4) # tuple v2 = iter(v1) v2 = v1.__iter__() print(v2) # <tuple_iterator object at 0x000002821F7695A0>  print(type(v2)) # <class 'tuple_iterator'>  for x in v2: print(x) # 0 # 1 # 2 # 3 # 4 
Enter fullscreen mode Exit fullscreen mode
v1 = {0, 1, 2, 3, 4} # set v1 = frozenset({0, 1, 2, 3, 4}) # frozenset  v2 = iter(v1) v2 = v1.__iter__() print(v2) # <set_iterator object at 0x00000282203069C0>  print(type(v2)) # <class 'set_iterator'>  for x in v2: print(x) # 0 # 1 # 2 # 3 # 4 
Enter fullscreen mode Exit fullscreen mode
v1 = {'name': 'John', 'age': 36, 'gender': 'Male'} # dict v1 = {'name': 'John', 'age': 36, 'gender': 'Male'} # dict.keys() v2 = iter(v1) v2 = v1.__iter__() print(v2) # <dict_keyiterator object at 0x0000028220423FB0>  print(type(v2)) # <class 'dict_keyiterator'>  for x in v2: print(x) # name # age # gender 
Enter fullscreen mode Exit fullscreen mode
v1 = {'name': 'John', 'age': 36, 'gender': 'Male'}.values() # dict.values()  v2 = iter(v1) v2 = v1.__iter__() print(v2) # <dict_valueiterator object at 0x00000282204FEE80>  print(type(v2)) # <class 'dict_valueiterator'>  for x in v2: print(x) # John # 36 # Male 
Enter fullscreen mode Exit fullscreen mode
v1 = {'name': 'John', 'age': 36, 'gender': 'Male'}.items() # dict.items()  v2 = iter(v1) v2 = v1.__iter__() print(v2) # <dict_itemiterator object at 0x00000282202F1670>  print(type(v2)) # <class 'dict_itemiterator'>  for x in v2: print(x) # ('name', 'John') # ('age', 36) # ('gender', 'Male') 
Enter fullscreen mode Exit fullscreen mode
v1 = 'Hello' # str v2 = iter(v1) v2 = v1.__iter__() print(v2) # <str_ascii_iterator object at 0x0000026906CEA560>  print(type(v2)) # <class 'str_ascii_iterator'>  for x in v2: print(x) # H # e # l # l # o 
Enter fullscreen mode Exit fullscreen mode
v1 = b'Hello' # bytes v2 = iter(v1) v2 = v1.__iter__() print(v2) # <bytes_iterator object at 0x0000026B42119F30>  print(type(v2)) # <class 'bytes_iterator'>  for x in v2: print(x) # 72 # 101 # 108 # 108 # 111 
Enter fullscreen mode Exit fullscreen mode
v1 = bytearray(b'Hello') # bytearray v2 = iter(v1) v2 = v1.__iter__() print(v2) # <bytearray_iterator object at 0x0000026B423CDBA0>  print(type(v2)) # <class 'bytearray_iterator'>  for x in v2: print(x) # 72 # 101 # 108 # 108 # 111 
Enter fullscreen mode Exit fullscreen mode
v1 = range(5) # range v2 = iter(v1) v2 = v1.__iter__() print(v2) # <range_iterator object at 0x000001F954F52150>  print(type(v2)) # <class 'range_iterator'>  for x in v2: print(x) # 0 # 1 # 2 # 3 # 4 
Enter fullscreen mode Exit fullscreen mode

A generator can create an iterator as shown below:

def func(): yield 0 yield 1 yield from [2, 3, 4] print(func) # <function func at 0x000001FCD2E3CAE0> print(type(func)) # <class 'function'>  gen = func() print(gen) # <generator object func at 0x00000282207E3CC0> print(type(gen)) # <class 'generator'>  for x in v2: print(x) # 0 # 1 # 2 # 3 # 4 
Enter fullscreen mode Exit fullscreen mode

A generator comprehension can create a generator's iterator as shown below:

gen = (x.upper() for x in ['a', 'b', 'c', 'd', 'e']) print(gen) # <generator object func at 0x00000282207E3CC0> print(type(gen)) # <class 'generator'>  for x in gen: print(x) # A # B # C # D # E 
Enter fullscreen mode Exit fullscreen mode

A huge iterator doesn't get MemoryError as shown below:

gen = (x for x in range(100000000)) print(next(gen)) # 0 print(next(gen)) # 1 print(next(gen)) # 2 print(next(gen)) # 3 print(next(gen)) # 4 # ... 
Enter fullscreen mode Exit fullscreen mode

itertools(repeat(), pairwise() and combinations()) can create iterators as shown below:

from itertools import repeat v = repeat(object='Hello', times=3) print(v) # repeat('Hello')  print(type(v)) # <class 'itertools.repeat'>  print(next(v)) # Hello print(next(v)) # Hello print(next(v)) # Hello print(next(v)) # StopIteration: 
Enter fullscreen mode Exit fullscreen mode
from itertools import pairwise v = pairwise('ABCD') v = pairwise(['A', 'B', 'C', 'D']) print(v) # <itertools.pairwise object at 0x000001BE9A1ABF70>  print(next(v)) # ('A', 'B') print(next(v)) # ('B', 'C') print(next(v)) # ('C', 'D') print(next(v)) # StopIteration: 
Enter fullscreen mode Exit fullscreen mode
from itertools import combinations v = combinations(iterable='ABC', r=2) print(v) # <itertools.combinations object at 0x000002690700D170>  print(next(v)) # ('A', 'B') print(next(v)) # ('A', 'C') print(next(v)) # ('B', 'C') print(next(v)) # StopIteration: 
Enter fullscreen mode Exit fullscreen mode

An iterator can be continuously used through multiple variables as shown below:

v1 = v2 = v3 = iter([0, 1, 2, 3, 4]) # Equivalent  # v1 = iter([0, 1, 2, 3, 4]) print(v1) # v2 = v1 print(v2) # v3 = v2 print(v3) # <list_iterator object at 0x000002821F75D240>  print(next(v1)) # 0 print(next(v2)) # 1 print(next(v3)) # 2 print(next(v1)) # 3 print(next(v2)) # 4 print(next(v3)) # StopIteration: 
Enter fullscreen mode Exit fullscreen mode

An iterator except the one created by a generator or generator comprehension can be copied as shown below:

*Memo:

  • copy.copy() does shallow copy:
    • It has no arguments.
  • copy.deepcopy() does deep copy:
    • It has no arguments.
  • iter() doesn't shallow copy.
  • copy.deepcopy() should be used because it's safe, doing copy deeply while copy.copy() isn't safe, doing copy shallowly.
import copy v1 = iter(['A', 'B', 'C', 'D', 'E']) v2 = copy.copy(v1) v2 = copy.deepcopy(v1) print(v1) # <list_iterator object at 0x00000200F45D19C0> print(v2) # <list_iterator object at 0x000002821F75D240>  print(next(v1)) # A print(next(v2)) # A print(next(v1)) # B print(next(v2)) # B print(next(v1)) # C print(next(v2)) # C print(next(v1)) # D print(next(v2)) # D print(next(v1)) # E print(next(v2)) # E print(next(v1)) # StopIteration: print(next(v2)) # StopIteration: 
Enter fullscreen mode Exit fullscreen mode
import copy def func(): yield 'A' yield 'B' yield from ['C', 'D', 'E'] gen1 = func() gen2 = copy.copy(gen1) gen2 = copy.deepcopy(gen1) # TypeError: cannot pickle 'generator' object 
Enter fullscreen mode Exit fullscreen mode
import copy gen1 = (x.upper() for x in ['A', 'B', 'C', 'D', 'E']) gen2 = copy.copy(gen1) gen2 = copy.deepcopy(gen1) # TypeError: cannot pickle 'generator' object 
Enter fullscreen mode Exit fullscreen mode

The variables v1 and v2 refer to the same iterator unless copied as shown below:

*Memo:

  • is keyword or is and not keyword can check if v1 and v2 refer or don't refer to the same iterator respectively.
import copy v1 = iter(['A', 'B', 'C', 'D', 'E']) v2 = v1 # v2 refers to the same iterator as v1.  print(v1) # <list_iterator object at 0x000001FCD6B64DC0> print(v2) # <list_iterator object at 0x000001FCD6B64DC0>  print(v1 is v2, v1 is not v2) # True False  # v2 refers the different iterator from v1. v2 = copy.copy(v1) v2 = copy.deepcopy(v1) print(v1) # <list_iterator object at 0x000001FCD6B64DC0> print(v2) # <list_iterator object at 0x000001FCD6B66020>  print(v1 is v2, v1 is not v2) # False True 
Enter fullscreen mode Exit fullscreen mode

sorted() can convert an iterator to a list, then sort the list, then the sorted list is converted to an iterator with iter() as shown below:

*Memo:

  • The 1st argument is iterable(Required-Type:Iterable):
    • Don't use iterable=.
  • The 2nd argument is key(Optional-Default:None-Type:Callable or NoneType).
  • The 3rd argument is reverse(Optional-Default:False-Type:bool) to reverse the list.
  • sorted() creates a copy:
    • Be careful, sorted() does shallow copy instead of deep copy as my issue.
import copy v1 = iter([3, 5, -2, 1, -4]) v2 = sorted(copy.copy(v1)) v2 = sorted(copy.copy(v1), key=None, reverse=False) print(v2) # [-4, -2, 1, 3, 5]  v2 = iter(sorted(copy.copy(v1))) print(next(v2), next(v2), next(v2), next(v2), next(v2)) # -4 -2 1 3 5  v2 = iter(sorted(copy.copy(v1), reverse=True)) print(next(v2), next(v2), next(v2), next(v2), next(v2)) # 5 3 1 -2 -4  v2 = iter(sorted(copy.copy(v1), key=abs)) print(next(v2), next(v2), next(v2), next(v2), next(v2)) # 1 -2 3 -4 5  v2 = iter(sorted(copy.copy(v1), key=abs, reverse=True)) print(next(v2), next(v2), next(v2), next(v2), next(v2)) # 5 -4 3 -2 1 
Enter fullscreen mode Exit fullscreen mode
v1 = ("apple", "Banana", "Kiwi", "cherry") """ Case sensitive sort """ v2 = iter(sorted(v1)) print(next(v2), next(v2), next(v2), next(v2)) # Banana Kiwi apple cherry  """ Case insensitive sort """ v2 = iter(sorted(v1, key=str.upper)) v2 = iter(sorted(v1, key=str.lower)) print(next(v2), next(v2), next(v2), next(v2)) # apple Banana cherry Kiwi  """ Sort by the length of a word """ v2 = iter(sorted(v1, key=len)) print(next(v2), next(v2), next(v2), next(v2)) # Kiwi apple Banana cherry 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)