Beginners guide to Iteration in python

The basics of dealing with many things in code.

gaetanlee [CC BY (https://creativecommons.org/licenses/by/2.0)]
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
_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)
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

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'
# 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
Here to commandeer your bathtub ?

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:

Object Definitions on the left and Object Instances on the right.

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.
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?
_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.
#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>}
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

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.
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
Our ducks are numbered now.
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.  

AI, Software Developer, Designer : www.k3no.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store