In my experience, some Patterns are still useful in Python, and even easier to set up than in more static languages. Some Patterns OTOH are just not needed, or even frowned upon, like the Singleton Pattern. Use a module level variable or function instead. Or use the Borg Pattern.
Instead of setting up a Creational Pattern it's often enough to pass a callable around that creates objects. That might be a function, an object with a __call__
method or even a class, since there is no new()
in Python, just an invocation of the class itself:
def make_da_thing(maker, other, stuff):
da_thing = maker(other + 1, stuff + 2)
# ... do sth
return da_thing
def maker_func(x, y):
return x * y
class MakerClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
...
a = make_da_thing(maker_func, 5, 8)
b = make_da_thing(MakerClass, 6, 7)
State and Strategy Pattern share a very similar structure in languages like C++ and Java. Less so in Python. Strategy Pattern stays more or less the same, but State Pattern becomes mostly unnecessary. State Pattern in static languages simulates the change of class at runtime. In Python, you can do just that: change the class of an object at runtime. As long as you do it in a controlled, encapsulated way, you should be fine:
class On(object):
is_on = True
def switch(self):
self.__class__ = Off
class Off(object):
is_on = False
def switch(self):
self.__class__ = On
...
my_switch = On()
assert my_switch.is_on
my_switch.switch()
assert not my_switch.is_on
Patterns that rely on Static Type Dispatch will not work, or work quite differently. You don't have to write as much boiler plate code, e.g. Visitor Pattern: in Java and C++ you have to write an accept method in every visitable class, whereas in Python you can inherit that functionality through a mixin class, like Visitable:
class Visitable(object):
def accept(self, visitor):
visit = getattr(visitor, 'visit' + self.__class__.__name__)
return visit(self)
...
class On(Visitable):
''' exactly like above '''
class Off(Visitable):
''' exactly like above '''
class SwitchStatePrinter(object): # Visitor
def visitOn(self, switch):
print 'the switch is on'
def visitOff(self, switch):
print 'the switch is off'
class SwitchAllOff(object): # Visitor
def visitOn(self, switch):
switch.switch()
def visitOff(self, switch):
pass
...
print_state = SwitchStatePrinter()
turn_em_off = SwitchAllOff()
for each in my_switches:
each.accept(print_state)
each.accept(turn_em_off)
Many situations that call for the application of a Pattern in a Static Language don't do so as much in Python. Many things can be solved with other thechniques, like higher order functions (decorators, function factories) or meta classes.