Iterable
# -------------------------------
# ITERABLE
# -------------------------------
# In Python:
# - Iterable: something you can loop over
# - Iterator: something that produces values one at a time
#
# Think of it like this:
# - An iterable is a book
# - An iterator is a bookmark that remembers where you are
#
# Iterable:
# - An iterable is an object that can return its elements one at a time.
#
# Examples:
# - list
# - string
# - tuple
# - dictionary
# - se
#
# An iterable is an object that can be passed to iter() to produce an iterator.
A = [1, 2, 3] # list - iterable
I = iter(A) # crete an iterator from the iterable
# -----------------------------
# ITERATOR
# ------------------------------
# An iterator remembers its current position
# and knows how to get the next value.
#
# Each call to next() advances the iterator.
print(next(I)) # 1
print(next(I)) # 2
print(next(I)) # 3
# End of iterator
try:
print(next(I))
except StopIteration:
print("StopIteration")
# ------------------------------
# LOOP MECHANISM
# ------------------------------
# A for-loop:
# 1. Calls iter()
# 2. Calls next() repeatedly
# 3. Stops on Stop Iterator
A = [1, 2, 3]
for i in A:
print(i)
# Equivalent to:
# --------------
I = iter(A)
while True:
try:
i = next(I)
print(i)
except StopIteration:
break
Memory Efficiency
# ---------------------------------
# MEMORY EFFICIENCY
# ---------------------------------
# An iterator is more efficient than a for loop,
# because it does not store the collection in memory.
import sys
numbers = list(range(1_000_000))
# Loop
m = sys.getsizeof(numbers)
for n in numbers:
if n == 10:
print("Loops: ", n)
print("Memory:", m) # 8 MB
break
# Loops: 10
# Memory: 8000056
# Iterator
m = 0
iterator = iter(numbers)
while True:
n = next(iterator)
m += sys.getsizeof(n)
if n == 10:
print("Iterations: ", n)
print("Memory:", m) # 300 bytes
break
# Iterantions: 10
# Memory: 304
Complex Looping
# -------------------------------------
# COMPLEX LOOPING
# -------------------------------------
# An iterator can be used to implement
# more complex looping patterns than a for loop.
import json
json_data = """
{
"name": "John",
"age": 30,
"city": "New York",
"children": [
{
"name": "Alice",
"age": 5
},
{
"name": "Bob",
"age": 8
}
]
}
"""
def depth_first_traversal(json_obj):
stack = [json_obj]
# Loop until there are no iterable elements (such as strings or numbers)
while stack:
current = stack.pop()
yield current
if isinstance(current, dict):
stack.extend(current.values())
elif isinstance(current, list):
stack.extend(current[::-1]) # new list in reverse order
# Parse json
json_obj = json.loads(json_data)
# Display elements
print("Depth-First Traversal:")
for node in depth_first_traversal(json_obj):
print(node)
"""
Depth-First Traversal:
{'name': 'John', 'age': 30, 'city': 'New York', 'children': [{'name': 'Alice', 'age': 5}, {'name': 'Bob', 'age': 8}]}
[{'name': 'Alice', 'age': 5}, {'name': 'Bob', 'age': 8}]
{'name': 'Alice', 'age': 5}
5
Alice
{'name': 'Bob', 'age': 8}
8
Bob
New York
30
John
"""