Six GoF design patterns, Python style
Although it usually requires some adaptation, Python makes implementing most of the GoF design patterns trivial. In some cases, they're actually part of the core language; in most of the others, they're a lot simpler in Python than C++ et al. Here I have implemented examples of the following common design patterns in Python:
- Iterator
- Decorator
- Abstract factory
- Factory
- State
- Template
Please see the links below for the Wiki articles describing each pattern. For now, I'll punt on when design patterns should be used.
Iterator
Iterators are built into the Python language. Anything that is iterable can be iterated, including dictionaries, lists, tuples, strings, streams, generators, and classes for which you implement iterator syntax.
This example shows a generator that counts by number words.
def count_to(count):
"""Counts by word numbers, up to a maximum of five"""
numbers = ["one", "two", "three", "four", "five"]
# The zip keeps from counting over the limit
for number, pos in zip(numbers, range(count)):
yield number
# Test the generator
count_to_two = lambda : count_to(2)
count_to_five = lambda : count_to(5)
print "Counting to two…"
for number in count_to_two():
print number,
print "\n"
print "Counting to five…"
for number in count_to_five():
print number,
Output:
one two
Counting to five…
one two three four five
Decorator
This one is another gimme — decorators have built-in syntax since Python 2.4 (they're still trivial to implement in earlier versions).
This example shows a time_this decorator, which measures and prints the time it takes the decorated function to run, in seconds.
def time_this(func):
"""The time_this decorator"""
def decorated(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print "Ran in", time.time() – start, "seconds"
return result
return decorated
# Decorator syntax
@time_this
def count(until):
"""Counts to 'until', then returns the result"""
print "Counting to", until, "…"
num = 0
for i in xrange(to_num(until)):
num += 1
return num
def to_num(numstr):
"""Turns a comma-separated number string to an int"""
return int(numstr.replace(",", ""))
# Run count with various values
for number in ("10,000", "100,000", "1,000,000"):
print count(number)
print "-" * 20
Output:
Ran in 0.0159997940063 seconds
10000
——————–
Counting to 100,000 …
Ran in 0.0160000324249 seconds
100000
——————–
Counting to 1,000,000 …
Ran in 0.233999967575 seconds
1000000
——————–
Although the built-in decorator syntax is for functions and methods, it's also very simple to decorate classes in Python. Here's a simple output-stream decorator I wrote.
Abstract factory
This pattern is a lot simpler to implement than the GoF example, because there's no need to inherit just to satisfy types. In the example below, the PetShop class has an abstract factory as a member (pet_factory). We can configure it at runtime with the desired concrete factory. The pet shop will then generate the appropriate pet type depending on its factory.
import random
class PetShop:
"""A pet shop"""
def __init__(self, animal_factory=None):
"""pet_factory is our abstract factory.
We can set it at will."""
self.pet_factory = animal_factory
def show_pet(self):
"""Creates and shows a pet using the
abstract factory"""
pet = self.pet_factory.get_pet()
print "This is a lovely", pet
print "It says", pet.speak()
print "It eats", self.pet_factory.get_food()
# Stuff that our factory makes
class Dog:
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat:
def speak(self):
return "meow"
def __str__(self):
return "Cat"
# Factory classes
class DogFactory:
def get_pet(self):
return Dog()
def get_food(self):
return "dog food"
class CatFactory:
def get_pet(self):
return Cat()
def get_food(self):
return "cat food"
# Create the proper family
def get_factory():
"""Let's be dynamic!"""
return random.choice([DogFactory, CatFactory])()
# Show pets with various factories
shop = PetShop()
for i in range(3):
shop.pet_factory = get_factory()
shop.show_pet()
print "=" * 10
Sample output:
It says woof
It eats dog food
==========
This is a lovely Cat
It says meow
It eats cat food
==========
This is a lovely Cat
It says meow
It eats cat food
==========
Factory
We don't need our factory products to have a common base class in order to give them a common type, but we can if we want to in order to share functionality.
In this example, we have a factory function called get_localizer, which returns the appropriate localizer class depending on the language name we pass to it.
class JapaneseGetter:
"""A simple localizer a la gettext"""
def __init__(self):
self.trans = dict(dog="犬", cat="猫")
def get(self, msgid):
"""We'll punt if we don't have a translation"""
try:
return unicode(self.trans[msgid], "utf-8")
except KeyError:
return unicode(msgid)
class EnglishGetter:
"""Simply echoes the msg ids"""
def get(self, msgid):
return unicode(msgid)
def get_localizer(language="English"):
"""The factory method"""
languages = dict(English=EnglishGetter,
Japanese=JapaneseGetter)
return languages[language]()
# Create our localizers
e, j = get_localizer("English"), get_localizer("Japanese")
# Localize some text
for msgid in "dog parrot cat".split():
print e.get(msgid), j.get(msgid)
Output:
parrot parrot
cat 猫
State
The state pattern allows us to change an object's behavior at runtime — something that Python naturally excels at!
This example has a very simple radio. It has an AM/FM toggle switch, and a scan button to scan to the next station.
class State(object):
"""Base state. This is to share functionality"""
def scan(self):
"""Scan the dial to the next station"""
self.pos += 1
if self.pos == len(self.stations):
self.pos = 0
print "Scanning… Station is", self.stations[self.pos], self.name
class AmState(State):
def __init__(self, radio):
self.radio = radio
self.stations = ["1250", "1380", "1510"]
self.pos = 0
self.name = "AM"
def toggle_amfm(self):
print "Switching to FM"
self.radio.state = self.radio.fmstate
class FmState(State):
def __init__(self, radio):
self.radio = radio
self.stations = ["81.3", "89.1", "103.9"]
self.pos = 0
self.name = "FM"
def toggle_amfm(self):
print "Switching to AM"
self.radio.state = self.radio.amstate
class Radio(object):
"""A radio.
It has a scan button, and an AM/FM toggle switch."""
def __init__(self):
"""We have an AM state and an FM state"""
self.amstate = AmState(self)
self.fmstate = FmState(self)
self.state = self.amstate
def toggle_amfm(self):
self.state.toggle_amfm()
def scan(self):
self.state.scan()
# Test our radio out
radio = Radio()
actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2
actions = actions * 2
for action in actions:
action()
Output:
Scanning… Station is 1510 AM
Switching to FM
Scanning… Station is 89.1 FM
Scanning… Station is 103.9 FM
Scanning… Station is 81.3 FM
Scanning… Station is 89.1 FM
Switching to AM
Scanning… Station is 1250 AM
Scanning… Station is 1380 AM
Template
The template pattern allows us to abstract away common parts of an algorithm. We simply supply a template skeleton with concrete actions.
In Python, functions are first-class objects, so we can create template functions via composition rather than classes and inheritance as shown in the GoF.
In this example, we build functions that iterate over a sequence, performing some action on each element; we fill in a skeleton function with a getter that retrieves the sequence, and an action that acts on each element.
# Skeletons
def iter_elements(getter, action):
"""Template skeleton that iterates items"""
for element in getter():
action(element)
print "-" * 10
def rev_elements(getter, action):
"""Template skeleton that iterates items in reverse order"""
for element in getter()[::-1]:
action(element)
print "-" * 10
# Getters
def get_list():
return "spam eggs".split()
def get_lists():
return [list(x) for x in "spam eggs".split()]
# Actions
def print_item(item):
print item
def reverse_item(item):
print item[::-1]
# Makes templates
def make_template(skeleton, getter, action):
"""Instantiate a template method with getter and action"""
def template():
skeleton(getter, action)
return template
# Create our template functions
templates = [make_template(s, g, a)
for g in (get_list, get_lists)
for a in (print_item, reverse_item)
for s in (iter_elements, rev_elements)]
# Execute them
for template in templates:
template()
As you can see, it's quite easy to alternate among both concrete functions and skeletons.
Output:
eggs
———-
eggs
spam
———-
maps
sgge
———-
sgge
maps
———-
['s', 'p', 'a', 'm']
['e', 'g', 'g', 's']
———-
['e', 'g', 'g', 's']
['s', 'p', 'a', 'm']
———-
['m', 'a', 'p', 's']
['s', 'g', 'g', 'e']
———-
['s', 'g', 'g', 'e']
['m', 'a', 'p', 's']
———-
Conclusion
It's fairly straightforward to adapt most of the GoF patterns to Python — and they end up a lot simpler in the bargain!
Edit: Modified abstract factory to match "classic" pattern.
Edit 2: Implemented new iterator and state patterns.

In the factory example did the parrot input gave an error in the Japanese translation and thus it was only echoed? BTW why unicode(msgid). I’d thought that anything would have __str__.
It looks like your abstract factory is broken. I think you need
shop.pet_factory = get_factory
instead. Also the “get” makes it sound like that method “gets” factories. ie. is a factory or a getter of factories. When really it is a pet factory, or it “gets” pets. Maybe random_get_factory is a better name.
“In the factory example did the parrot input gave an error in the Japanese translation and thus it was only echoed?”
The idea was to fail gracefully. Failure to find a translation shouldn’t crash your program. And instead of checking for the msgid in the dictionary, it assumes it’s there, then deals with the error if it’s not (BTAFTP)…
The reason I did Unicode was that in real life(TM), I’d imagine the translation dictionary stored on disk in utf-8, then have the strings converted to Unicode for display on screen.
@David
You’re right that the abstract factory is a bit off. I think that in a “pure” version, I’d return a DogFactory or a CatFactory, then in the PetShop class, do
pet = self.pet_factory.get_pet()
food = self.pet_factory.get_food()
…
However, all I needed was a pet, and not a family of classes, so I fudged. But I can see how that would confuse the issue, so I’ve edited the code to show the “pure” pattern. What do you think?
THX
very good article
Thanks a bunch for this.
[...] The GITS Blog » Six GoF design patterns, Python styleDesign patterns in Python. [...]
[...] PyGoF<br/> [...]
I wonder if the factory stuff is worth doing with metaclasses (I’m new to metaclasses, so might be talking rubbish).
@Stu
That’s a good point. Metaclasses are certainly very powerful, but they’re also complex and harder.