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.

"""Implementation of the iterator pattern with a generator"""

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:

Counting to two…
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.

import time

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:

Counting to 10,000 …
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.

"""Implementation of the abstract factory pattern"""

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:

This is a lovely Dog
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.

#coding: UTF8

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:

dog 犬
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.

"""Implementation of the state pattern"""

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 1380 AM
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.

"""An example of the Template pattern in Python"""

# 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:

spam
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.

14 comments to Six GoF design patterns, Python style

  • Anonymous

    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?

  • lvs

    THX
    very good article

  • Jeff

    Thanks a bunch for this.

  • […] The GITS Blog » Six GoF design patterns, Python styleDesign patterns in Python. […]

  • Stu

    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.

  • Spinner

    How about this for Python style State Pattern

    import EasyStatePattern as esp
    class StateContext( esp.ContextBase):
    
    	ttable = esp.TransitionTable('myState')
    
    	def __init__(self):
    		StateContext.ttable.initialize(self)
    
    	@esp.transitionevent(ttable)
    	def writeName(self, name):
    		pass
    
    class StateA(StateContext):
    
    	def writeName(self, name):
    		print name.lower()
    
    class StateB(StateContext):
    
    	def writeName(self, name):
    		print name.upper()
    
    class StateC(StateB):
    	pass
    
    # Set up transition table to cause states totoggle
    StateContext.ttable.nextStates(StateA, (StateB,))
    StateContext.ttable.nextStates(StateB, (StateC,))
    StateContext.ttable.nextStates(StateC, (StateA,))
    StateContext.ttable.initialstate = StateA
    
    
    if __name__=='__main__':
       ctxt = StateContext()
       ctxt.writeName("Monday")
       ctxt.writeName("Tuesday")
       ctxt.writeName("Wednesday")
       ctxt.writeName("Thursday")
       ctxt.writeName("Friday")
       ctxt.writeName("Saturday")
       ctxt.writeName("Sunday")
       x = raw_input("done>")
  • Your decorator example is not a decorator pattern. Decorator patterns encapsulate variations in behavior over time by allowing you to dynamically add and/or remove them (usually add). I think if you switched to a lambda, you’d be okay calling that a decorator.

    Also the iterator pattern example doesn’t do a lot for me. Why not show how to make a newly iterable thing – which is the interesting part – rather than iterate over something like an array or a dictionary – which is the part most people could probably have guessed for themselves.

    The other four are concise, informative, and correct.

  • progressdll

    This is my go at the Proxy pattern ( http://en.wikipedia.org/wiki/Proxy_pattern ) in Python

    class Image:
    def __init__( self, filename ):
    self._filename = filename
    def load_image_from_disk( self ):
    print(“loading ” + self._filename )
    def display_image( self ):
    print(“display ” + self._filename)

    class Proxy:
    def __init__( self, subject ):
    self._subject = subject
    self._proxystate = None

    class ProxyImage( Proxy ):
    def display_image( self ):
    if self._proxystate == None:
    self._subject.load_image_from_disk()
    self._proxystate = 1
    print(“display ” + self._subject._filename )

    proxy_image1 = ProxyImage ( Image(“HiRes_10Mb_Photo1″) )
    proxy_image2 = ProxyImage ( Image(“HiRes_10Mb_Photo2″) )

    proxy_image1.display_image() # loading necessary
    proxy_image1.display_image() # loading unnecessary
    proxy_image2.display_image() # loading necessary
    proxy_image2.display_image() # loading unnecessary
    proxy_image1.display_image() # loading unnecessary

  • […] Design patterns  http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/ […]

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>