Introduction To “Iterable” and “Iterator”

Oindrila Chakraborty
4 min readDec 27, 2022

--

Why “Iterables” and “Iterators” are Required?

  • “Comprehensions”, and, “forLoops are the “Most Frequently Used Language Features” for “Performing” the “Iteration”. That is, “Taking Elements One by One” from a “Source”, and, “Doing Something” with “Each Element” in turn.
  • However, “both” the “Comprehensions”, and, “forLoopsIterate Over” the “Whole Sequence” by default.
  • When, “More Fine-Grained Control” is “Needed”, there are “Two Approaches” -
  • 1. Iterable Objects — The “Iterable Protocol” “Allows” to “Pass” an “Iterable Object”, usually a “Collection”, or, “Stream of Objects”, such as a “List” to the Built-In Functioniter ()” to “Get” an “Iterator” for the “Iterable Object”.
  • 2. Iterator Objects — The “Iterable Objects”, in turn, “Support” the “Iterator Protocol”, which “Requires” to “Pass” the “Iterator Object” to the Built-In Functionnext ()” to “Fetch” the “Next Value” from the “Underlying Collection”.
    Each Call” to the Built-In Functionnext ()” “Moves” the “Iterator” through the “Underlying Collection”.
# Create a "List" of "Strings" Containing "Names"
2
listOfNames = ["Oindrila", "Soumyajyoti", "Oishi", "Souvik", "Anamika", "Swaralip", "Soumyajit", "Sagarneel", "Abhirup", "Madhura"]
Create a “List” of “Strings”
iterableListOfNames = iter(listOfNames)
Create an “Iterable Object” by “Passing” the “List of String” to the Function “iter ()”
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
print(next(iterableListOfNames))
“Request” a “Value” from the “Iterable Object”, i.e., “iterableListOfNames” Using the Function “next ()”

When the “Iterator” Reaches the “End”

  • When the “Iterator” “Reaches” the “End” of the “Underlying Collection”, “Python” “Raises” an “Exception”, specifically of the TypeStopIteration”.
print(next(iterableListOfNames))
What Happens When “Iterator” Reaches the “End”?

Clear Example of “Iterable” and “Iterator”

  • With “forLoops, and, “Comprehensions” at the “User’s Fingertips”, the “Utility” of the “Lower Level Iteration Protocols” “May Not” be “Obvious”.
  • To “Demonstrate” “More Concrete Use”, let’s “Create” the following “Utility Function”, which, when an “Iterable Object” is “Passed”, “Returns” the “First Item” in the “Underlying Collection”, or, “If” the “Underlying Collection” is “Empty”, the “Utility Function” “Raises” a “ValueErrorException -
  • First, “Call” the Built-In Functioniter ()” on the “Input Iterable Object” to “Produce” an “Iterator”.
  • Second, the Built-In Functionnext ()” is “Called” on the “Iterator” “Inside” a “tryBlock that “Returns” the “Result”.
    If the “Input Iterable” is “Empty”, the Built-In Functionnext ()” has “No Value” to “Return”, and, it instead “Raises” a “StopIterationException.
    The “StopIterationException is “Caught” in the “exceptBlock, and, a “ValueErrorException is “Raised”.
  • This “Utility Function” “Works as Expected” on “Any Iterable Object”.
def returnFirstElement (iterableObj):
iteratorObj = iter(iterableObj)

try:
return next(iteratorObj)
except StopIteration:
raise ValueError("Iterable Object is Empty")
Create the “Utility Function”, i.e., “returnFirstElement” from “Any Iterable Object”

Clear Example of “Iterable” and “Iterator” with “String”

# Create a "String"
name = 'Oindrila Chakraborty'

print(returnFirstElement(name))
Pass a “String” to the “Utility Function”, i.e., “returnFirstElement”
# Create an "Empty String"
emptyString = ''

print(returnFirstElement(emptyString))
Pass an “Empty String” to the “Utility Function”, i.e., “returnFirstElement”

Clear Example of “Iterable” and “Iterator” with “List”

# Create a "List" of "Integers"
listOfIntNumbers = [25, 19, 15, 20, 1, 7, 0, 21, 29, 35, 55]

print(returnFirstElement(listOfIntNumbers))
Pass a “List of Integers” to the “Utility Function”, i.e., “returnFirstElement”
# Create an "Empty List"
emptyList = []

print(returnFirstElement(emptyList))
Pass an “Empty List” to the “Utility Function”, i.e., “returnFirstElement”

Clear Example of “Iterable” and “Iterator” with “Tuple”

# Create a "Tuple" of "Integers"
tupleOfIntNumbers = (25, 19, 15, 20, 1, 7, 0, 21, 29, 35, 55)

print(returnFirstElement(tupleOfIntNumbers))
Pass a “Tuple of Integers” to the “Utility Function”, i.e., “returnFirstElement”
# Create an "Empty Tuple"
emptyTuple = ()

print(returnFirstElement(emptyTuple))
Pass an “Empty Tuple” to the “Utility Function”, i.e., “returnFirstElement”

Clear Example of “Iterable” and “Iterator” with “Set”

# Create a "Set" of "Integers"
setOfIntNumbers = {25, 19, 15, 20, 1, 7, 0, 21, 29, 35, 55}

print(returnFirstElement(setOfIntNumbers))
Pass a “Set of Integers” to the “Utility Function”, i.e., “returnFirstElement”
# Create an "Empty Set"
emptySet = set()

print(returnFirstElement(emptySet))
Pass an “Empty Set” to the “Utility Function”, i.e., “returnFirstElement”

Clear Example of “Iterable” and “Iterator” with “Dictionary”

# Create a "Dictionary" Having Name" as the "Key", and, the Corresponding "Person's Age" as the "Value"
dictPerson = {
"Oindrila": 34,
"Soumyajyoti": 35,
"Premanshu": 66,
"Rama": 61,
"Kasturi": 29
}

print(returnFirstElement(dictPerson))
Pass a “Dictionary” to the “Utility Function”, i.e., “returnFirstElement”
# Create an "Empty Dictionary"
emptyDictionary = {}

print(returnFirstElement(emptyDictionary))
Pass an “Empty Dictionary” to the “Utility Function”, i.e., “returnFirstElement”
  • It is worth noting that the “Higher-Level Iteration Constructions”, such as “forLoops, and, “Comprehensions” are “Built Directly” upon the “Lower-Level Iteration Protocol”.

--

--

Oindrila Chakraborty

I have 12+ experience in IT industry. I love to learn about the data and work with data. I am happy to share my knowledge with all. Hope this will be of help.