DEV Community

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

Posted on

Iterator in Python (4)

Buy Me a Coffee

*Memo:

An iterator can be unpacked with an assignment and for statement, function and * but not with ** as shown below:

v1, v2, v3 = iter([0, 1, 2])

print(v1, v2, v3)
# 0 1 2
Enter fullscreen mode Exit fullscreen mode
v1, *v2, v3 = iter([0, 1, 2, 3, 4, 5])

print(v1, v2, v3)  # 0 [1, 2, 3, 4] 5
print(v1, *v2, v3) # 0 1 2 3 4 5
Enter fullscreen mode Exit fullscreen mode
for v1, v2, v3 in iter([iter([0, 1, 2]), iter([3, 4, 5])]):
    print(v1, v2, v3)
# 0 1 2
# 3 4 5
Enter fullscreen mode Exit fullscreen mode
for v1, *v2, v3 in iter([iter([0, 1, 2, 3, 4, 5]),
                         iter([6, 7, 8, 9, 10, 11])]):
    print(v1, v2, v3)
    print(v1, *v2, v3)
# 0 [1, 2, 3, 4] 5
# 0 1 2 3 4 5
# 6 [7, 8, 9, 10] 11
# 6 7 8 9 10 11
Enter fullscreen mode Exit fullscreen mode
print(*iter([0, 1]), 2, *iter([3, 4, *iter([5])]))
# 0 1 2 3 4 5
Enter fullscreen mode Exit fullscreen mode
print([*iter([0, 1]), 2, *iter([3, 4, *iter([5])])])
# [0, 1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode
def func(p1='a', p2='b', p3='c', p4='d', p5='e', p6='f'):
    print(p1, p2, p3, p4, p5, p6)

func()
# a b c d e f

func(*iter([0, 1, 2, 3]), *iter([4, 5]))
# 0 1 2 3 4 5
Enter fullscreen mode Exit fullscreen mode
def func(p1='a', p2='b', *args):
    print(p1, p2, args)
    print(p1, p2, *args)
    print(p1, p2, ['A', 'B', *args, 'C', 'D'])

func()
# a b ()
# a b
# a b ['A', 'B', 'C', 'D']

func(*iter([0, 1, 2, 3]), *iter([4, 5]))
# 0 1 (2, 3, 4, 5)
# 0 1 2 3 4 5
# 0 1 ['A', 'B', 2, 3, 4, 5, 'C', 'D']
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(shallow-copied and deep-copied) as shown below:

<Shallow copy>:

*Memo:

  • v1 and v2 refer to different outer iterators and the same inner iterator.
  • is keyword can check if v1 and v2 refer to the same outer and/or inner iterator.
  • copy.copy() can shallow-copy an iterator.
  • iter() cannot shallow-copy an iterator.
import copy

v1 = iter([iter([0, 1, 2])])
v2 = copy.copy(v1)

print(v1) # <list_iterator object at 0x0000029DE015CDC0>
print(v2) # <list_iterator object at 0x0000029DE015F340>

print(v1 is v2)
# False

v1 = next(v1)
v2 = next(v2)

print(v1) # <list_iterator object at 0x0000029DD4BF82E0>
print(v2) # <list_iterator object at 0x0000029DD4BF82E0>

print(v1 is v2)
# True

print(next(v1)) # 0
print(next(v2)) # 1
print(next(v1)) # 2
print(next(v2)) # StopIteration:
Enter fullscreen mode Exit fullscreen mode

<Deep copy>:

*Memo:

  • v1 and v2 refer to different outer and inner iterators.
  • copy.deepcopy() can deep-copy an iterator.
  • copy.deepcopy() should be used because it's safe, deeply copying an iterator while copy.copy() isn't safe, shallowly copying an iterator.
import copy

v1 = iter([iter([0, 1, 2])])
v2 = copy.deepcopy(v1)

print(v1) # <list_iterator object at 0x0000029DDF283E80>
print(v2) # <list_iterator object at 0x0000029DDF282080>

print(v1 is v2)
# False

v1 = next(v1)
v2 = next(v2)

print(v1) # <list_iterator object at 0x0000029DDF279D50>
print(v2) # <list_iterator object at 0x0000029DDF283FA0>

print(v1 is v2)
# False

print(next(v1)) # 0
print(next(v2)) # 0
print(next(v1)) # 1
print(next(v2)) # 1
print(next(v1)) # 2
print(next(v2)) # 2

print(next(v1))
print(next(v2))
# StopIteration:
Enter fullscreen mode Exit fullscreen mode

<A generator or generator comprehension>:

import copy

def func():
    yield 0
    yield 1
    yield from [2, 3, 4]

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

Top comments (0)