Beginners guide to Iteration in python
The basics of dealing with many things in code.

Writing software usually starts in your head, you think about something and then you want to take that something out of your imagination and write it into code and execute it as a program, many times, what’s in your head involves making and manipulating many things; I hope that by the end of this short tutorial you will be able to do just that, think in multiples of things and write those things in Python code.
We will be using a rubber duck as the thing we will be dealing with throughout this guide, as such here’s a simple Rubber duck module:
File: Rubber_Duck_Factory.py*You can also include this class at the top of your scripts instead of the import statements if you find that more convenient.class RubberDuck():
color = 'yellow'USAGE:File: makeOne.pyimport Rubber_Duck_FactoryOneDucky = Rubber_Duck_Factory.RubberDuck()
print(OneDucky.color)
# yellow* Not to be confused with the factory method pattern, that's related but advanced stuff not covered here.

Make many
import Rubber_Duck_Factory# A dictionary to store our ducks:
_ducks = {}# create 7 ducks and add them to the dictionary:
for i in range(7):
_ducks[i] = Rubber_Duck_Factory.RubberDuck()print(_ducks)# {0: <Rubber_Duck_Factory.RubberDuck object at 0x106d9f080>, 1: <Rubber_Duck_Factory.RubberDuck object at 0x10725c780>, 2: <Rubber_Duck_Factory.RubberDuck object at 0x10725c748>, 3: <Rubber_Duck_Factory.RubberDuck object at 0x10725c940>, 4: <Rubber_Duck_Factory.RubberDuck object at 0x10725c828>, 5: <Rubber_Duck_Factory.RubberDuck object at 0x10725ca58>, 6: <Rubber_Duck_Factory.RubberDuck object at 0x10725cac8>}# Get the color of the 5th duck, we start counting from zero:
print(_ducks[4].color)
# yellow

Make each one special
In order to make each ducky unique, we can assign them a random color at creation time :
import Rubber_Duck_Factory
import random_ducks = {}
# Colors list :
COLORS = ['blue','red','purple','orange']# create 5 ducks:
for i in range(5):
_ducks[i] = Rubber_Duck_Factory.RubberDuck()
# Assign each duck a random color
_ducks[i].color = random.choice(COLORS)# Go over the _ducks dictionary:
for i in range(5):
print('ducky: '+ str(i+1) + ' color is :' + _ducks[i].color)ducky: 1 color is :red
ducky: 2 color is :blue
ducky: 3 color is :blue
ducky: 4 color is :orange
ducky: 5 color is :purple

Looking good, note that we can modify the color of one (or all) after we have created them, for instance to change the color of one we would add the line:
_ducks[3].color = 'burberry'

More Object Oriented
This type of assignment ( we are assigning the color ) works fine but can prove limiting and messy down the road, the alternative is to add attributes as part of the rubber duck class, note that we also got 2 blue duckies ( twins ? ) , so while we are making changes, let’s also give them proper names to make them even more unique, let’s rewrite the rubber duck module/class:
File: Rubber_Duck_Factory.pyimport randomCOLORS = ['Red', 'Blue', 'Yellow', ‘Grey']
NAMES = ['Peter', ’Susan', 'Oswald', 'Maria', 'James']class RubberDuck():
def __init__(self):
self.color = random.choice(COLORS)
self.name = random.choice(NAMES)
The _init_
method ( a special function ) of the class allows you to initialize the object ( in this case the RubberDuck ) the self
keyword is passed to this function and refers to the object itself, besides that everything else should look familiar, lets use our new class:
import Rubber_Duck_Factory_ducks = {}# create 6 Ducks
for i in range(6):
_ducks[i] = Rubber_Duck_Factory.RubberDuck()# Go over the _ducks dictionary:
for i in range(6):
print( _ducks[i].color + ' Ducky\'s Name is ' + _ducks[i].name)
OUTPUT:Blue Ducky's Name is Oswald
Grey Ducky's Name is James
Yellow Ducky's Name is Maria
Red Ducky's Name is Oswald
Blue Ducky's Name is Susan
Grey Ducky's Name is Peter

There is now less code on our main file and all the initialization is relegated to the module/class.
Even more OOP (Object Oriented Programming)
One thing we need to mention is class methods, which provide a way to do direct assignment from the module/class, let’s say for instance we wanted to modify one or various ducks after creation, let’s start by modifying the Rubber_Duck_factory
class:
File: Rubber_Duck_Factory.pyimport randomCOLORS = ['Red', 'Blue', 'Yellow', 'Pink', 'Grey']
NAMES = ['Peter', 'Susan', 'Oswald', 'Maria', 'James']class RubberDuck():
def __init__(self):
self.color = random.choice(COLORS)
self.name = random.choice(NAMES)
def goRouge(self):
self.color = 'Pirate'
self.name = 'Captain Morgan'
In usage:
# Tell duck #3 to do something
_ducks[2].goRouge()print( _ducks[2].color + ' Ducky\'s Name is ' + _ducks[2].name)OUTPUT:
Pirate Ducky's Name is Captain Morgan

Small Recap - Pattern:
We can now make many things, give each one unique attributes when they are made, and modify them afterwards, this last two snippets focused in making this process more Object Oriented, which in our case means encapsulating individual methods and attributes in a RubberDuck class and leaving creation and interaction to our main script:

Iteration
We’ve already done some basic iteration going over our _ducks
dictionary with for i in range(x)
, but there are certainly other ways that do not depend on having a value for x
, if for instance we wanted to change all our ducks there are other ways that iterate over the dictionary instead of a given value and this is the start of more complex iterations:
Iterate and change all the elements of our _ducks dictionary after creation:for i in _ducks:
_ducks[i].color = 'money'

Another way through key/values:for i, duck in _ducks.items():
duck.color = ‘rainbow'

Selecting ,Removing, Adding.
Very often when you have a bunch of things you want to select a few here and there based on certain requirements, this is where the object oriented approach is really helpful, in general we want to either filter or test for a certain object property (name, color, id, etc, etc )and that way we can select one or many, here’s an example:

# Turn Grey Ducks into White ones:for i in _ducks:
if _ducks[i].color == 'Grey':
_ducks[i].color = 'White'# Note that == tests equality and = assigns.

Let’s now remove any white rubber ducks named James :
for i in list(_ducks):
if _ducks[i].color == 'White' and _ducks[i].name == 'James':
del _ducks[i]This bit while seemingly simple has one gotcha, we are using a list before our dictionary, this is because we are iterating and changing the iteration elements, so we need to make a copy, read more about it here: How to avoid “RuntimeError: dictionary changed size during iteration” error?

Turns out James was on vacation and just came back, let’s reinsert him:
_ducks[1] = Rubber_Duck_Factory.RubberDuck()
_ducks[1].color = 'Tan'
_ducks[1].name = 'James'⚠️ Note that we need to provide the index or slot _ducks[1], which requires us to keep track of what position or key in our dictionary James used to occupy, but we could also have added James somewhere else _ducks[111], it also doesn’t need to be a number, we could for instance have done _ducks[‘returningDuck’], the dictionary just doesn't care, next sections deal with this.

Just to reiterate the previous point, if you are using a dictionary to store objects, you will most likely be accessing your objects through a key, this might not be ideal if you need uniqueness, consider the following way (That doesn’t work ) of creating and storing objects:
#Try to create 5 ducks THIS DOESN'T WORK:for i in range(5):
tempDuck = Rubber_Duck_Factory.RubberDuck()
_ducks[tempDuck.name] = tempDuck# _ducks{} Dictionary :# {'Susan': <Rubber_Duck_Factory.RubberDuck object at 0x1041c5be0>, 'Oswald': <Rubber_Duck_Factory.RubberDuck object at 0x103d07080>, 'Maria': <Rubber_Duck_Factory.RubberDuck object at 0x103ce2ef0>}
We only got 3 ducks instead of the 5we wanted, why ? we are are creating a temporary duck tempduck
, then using it’s name as a key for insertion into our dictionary, but the next duck that we make might have the same name ( in this case 2had the same names ) and then since it’s a dictionary replaces the existing ones.
A possible alternative is to use a unique object identifier :
THIS SOMETIMES WORKS:for i in range(5):
tempDuck = Rubber_Duck_Factory.RubberDuck()
_ducks[id(tempDuck)] = tempDuck# _ducks{} Dictionary :{4485467888: <Rubber_Duck_Factory.RubberDuck object at 0x10b5acef0>, 4485615744: <Rubber_Duck_Factory.RubberDuck object at 0x10b5d1080>, 4490585984: <Rubber_Duck_Factory.RubberDuck object at 0x10ba8e780>, 4490587104: <Rubber_Duck_Factory.RubberDuck object at 0x10ba8ebe0>, 4490587440: <Rubber_Duck_Factory.RubberDuck object at 0x10ba8ed30>, 4490587496: <Rubber_Duck_Factory.RubberDuck object at 0x10ba8ed68>, 4490587608: <Rubber_Duck_Factory.RubberDuck object at 0x10ba8edd8>}Note: 0x10b5acef0 is hex for 4485467888
I say it sometimes works because the ids are only unique while your program runs and you might need to keep track of the id’s somewhere else to select them.
To try and wrap up this unexpectedly complex issue of what key to use in a dictionary, it really depends on your data and what you are trying to make, you could use a timestamp, some long random number or a combination of object attributes, and if this sounds like overkill or too much, you might be better off using lists which we will briefly cover next.
Lists vs Dictionaries for Storing Objects
Our _ducks
dictionary was working great until we decided to remove and then re add some element, it still works, but keeping track of where the removed element used to be might not work for your project, a list might be better suited to store objects where order plays an important role.
Don't feel bad if halfway through your project your data structure turns out to be the wrong one, this happens more often than we'd like to admit and is usually caused by us learning about the domain and/or language as we write, so it's part of the process, rectifying the situation is usually less of an issue if you use objects.
Let’s rewrite our examples with lists:
import Rubber_Duck_Factory# Now a List:
_ducks = []# create 6 Ducks
for i in range(6):
_ducks.append(Rubber_Duck_Factory.RubberDuck())# Iterate :for i, duckObject in enumerate(_ducks):
print (i, ",",duckObject)# OUTPUT:# 0 , <Rubber_Duck_Factory.RubberDuck object at 0x0000022FE7CA1308>
# 1 , <Rubber_Duck_Factory.RubberDuck object at 0x0000022FE7CA6208>
# 2 , <Rubber_Duck_Factory.RubberDuck object at 0x0000022FE7CA6448>
# 3 , <Rubber_Duck_Factory.RubberDuck object at 0x0000022FE7CA6948>
# 4 , <Rubber_Duck_Factory.RubberDuck object at 0x0000022FE7CA6BC8>
# 5 , <Rubber_Duck_Factory.RubberDuck object at 0x0000022FE7CA6CC8>for duck in _ducks:
print(duck.name + ' the ' + duck.color + ' ducky')# OUTPUT:
# James the Yellow ducky
# Maria the Blue ducky
# Susan the Red ducky
# Oswald the Pink ducky
# Peter the Grey ducky
# James the Blue ducky# Change all:
for duck in _ducks:
duck.color ='black'# OUTPUT:
# James the black ducky
# Maria the black ducky
# Susan the black ducky
# Oswald the black ducky
# Peter the black ducky
# James the black ducky# Select and Remove:
for duck in _ducks:
if duck.name == 'James' and duck.color == 'black':
_ducks.remove(duck)# OUTPUT:
# Maria the black ducky
# Susan the black ducky
# Oswald the black ducky
# Peter the black ducky

The changes are minimal and the iteration is very similar to a dictionary, lists though have a few methods that make them work better with ordered objects, for instance:
insert a new duck at the third slot.
_ducks.insert(2, Rubber_Duck_Factory.RubberDuck())Note that the ducks reorder themselves after insertion.

What to use ? Lists for when you need to keep objects ordered,dictionaries for when key,value selection makes more sense, realistically you will be using both (or a mix )most of the time.
Conclusions
There is a certain magic in commanding a script or program to make a bunch of things on the fly, it’s a good skill to have. Here I’ve tried to give you an overview of how to create many things ( with objects and a pattern ), manipulate them ( object and list/dict methods ) and a few details and pitfalls (list vs dictionaries and naming objects ) you might encounter.
Where to go next ? - List/Dict Comprehension: For complex selection and modification - Object Inheritance and Patterns For more varied Data Structures and efficient creation of many things ( ex. factory pattern ). - Itertools, collections, tuples More ways to iterate and places to put your objects.
Thanks for reading.