How to write Strategy Pattern in Python differently than example in Wikipedia?
Question:
In the 2009 Wikipedia entry for the Strategy Pattern, there’s a example written in PHP.
Most other code samples do something like:
a = Context.new(StrategyA.new)
a.execute #=> Doing the task the normal way
b = Context.new(StrategyB.new)
b.execute #=> Doing the task alternatively
c = Context.new(StrategyC.new)
c.execute #=> Doing the task even more alternative
In the Python code a different technique is used with a Submit button. I wonder what the Python code will look like if it also did it the way the other code samples do.
Update: Can it be shorter using first-class functions in Python?
Answers:
The example in Python is not so different of the others. To mock the PHP script:
class StrategyExample:
def __init__(self, func=None):
if func:
self.execute = func
def execute(self):
print("Original execution")
def executeReplacement1():
print("Strategy 1")
def executeReplacement2():
print("Strategy 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat2 = StrategyExample(executeReplacement2)
strat0.execute()
strat1.execute()
strat2.execute()
Output:
Original execution
Strategy 1
Strategy 2
The main differences are:
- You don’t need to write any other class or implement any interface.
- Instead you can pass a function reference that will be bound to the method you want.
- The functions can still be used separately, and the original object can have a default behavior if you want to (the
if func == None
pattern can be used for that).
- Indeed, it’s clean short and elegant as usual with Python. But you lose information; with no explicit interface, the programmer is assumed as an adult to know what they are doing.
Note that there are 3 ways to dynamically add a method in Python:
-
The way I’ve shown you. But the method will be static, it won’t get the “self” argument passed.
-
Using the class name:
StrategyExample.execute = func
Here, all the instance will get func
as the execute
method, and will get self
passed as an argument.
-
Binding to an instance only (using the types
module):
strat0.execute = types.MethodType(executeReplacement1, strat0)
or with Python 2, the class of the instance being changed is also required:
strat0.execute = types.MethodType(executeReplacement1, strat0,
StrategyExample)
This will bind the new method to strat0
, and only strat0
, like with the first example. But start0.execute()
will get self
passed as an argument.
If you need to use a reference to the current instance in the function, then you would combine the first and the last method. If you do not:
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = func
def execute(self):
print(self.name)
def executeReplacement1():
print(self.name + " from execute 1")
def executeReplacement2():
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
You will get:
Traceback (most recent call last):
File "test.py", line 28, in <module>
strat1.execute()
File "test.py", line 13, in executeReplacement1
print self.name + " from execute 1"
NameError: global name 'self' is not defined
So the proper code would be:
import sys
import types
if sys.version_info[0] > 2: # Python 3+
create_bound_method = types.MethodType
else:
def create_bound_method(func, obj):
return types.MethodType(func, obj, obj.__class__)
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = create_bound_method(func, self)
def execute(self):
print(self.name)
def executeReplacement1(self):
print(self.name + " from execute 1")
def executeReplacement2(self):
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
This will output the expected result:
Strategy Example 0
Strategy Example 1 from execute 1
Strategy Example 2 from execute 2
Of course, in the case the functions cannot be used stand alone anymore, but can still be bound to any other instance of any object, without any interface limitation.
For clarity, I would still use a pseudo-interface:
class CommunicationStrategy(object):
def execute(self, a, b):
raise NotImplementedError('execute')
class ConcreteCommunicationStrategyDuck(CommunicationStrategy):
def execute(self, a, b):
print "Quack Quack"
class ConcreteCommunicationStrategyCow(CommunicationStrategy):
def execute(self, a, b):
print "Mooo"
class ConcreteCommunicationStrategyFrog(CommunicationStrategy):
def execute(self, a, b):
print "Ribbit! Ribbit!"
You’re right, the wikipedia example isn’t helpful. It conflates two things.
-
Strategy.
-
Features of Python that simplify the implementation of Strategy. The “there’s no need to implement this pattern explicitly” statement is incorrect. You often need to implement Strategy, but Python simplifies this by allowing you to use a function without the overhead of a class wrapper around a function.
First, Strategy.
class AUsefulThing( object ):
def __init__( self, aStrategicAlternative ):
self.howToDoX = aStrategicAlternative
def doX( self, someArg ):
self. howToDoX.theAPImethod( someArg, self )
class StrategicAlternative( object ):
pass
class AlternativeOne( StrategicAlternative ):
def theAPIMethod( self, someArg, theUsefulThing ):
pass # an implementation
class AlternativeTwo( StrategicAlternative ):
def theAPImethod( self, someArg, theUsefulThing ):
pass # another implementation
Now you can do things like this.
t = AUsefulThing( AlternativeOne() )
t.doX( arg )
And it will use the strategy object we created.
Second, Python alternatives.
class AUsefulThing( object ):
def __init__( self, aStrategyFunction ):
self.howToDoX = aStrategyFunction
def doX( self, someArg ):
self.howToDoX( someArg, self )
def strategyFunctionOne( someArg, theUsefulThing ):
pass # an implementation
def strategyFunctionTwo( someArg, theUsefulThing ):
pass # another implementation
We can do this.
t= AUsefulThing( strategyFunctionOne )
t.doX( anArg )
This will also use a strategy function we provided.
Answering an old question for the Googlers who searched “python strategy pattern” and landed here…
This pattern is practically non-existent in languages that support first class functions. You may want to consider taking advantage of this feature in Python:
def strategy_add(a, b):
return a + b
def strategy_minus(a, b):
return a - b
solver = strategy_add
print solver(1, 2)
solver = strategy_minus
print solver(2, 1)
This approach is very clean and simple.
Also, be sure to check out Joe Gregorio’s PyCon 2009 talk about Python and design patterns (or lack thereof): http://pyvideo.org/video/146/pycon-2009–the–lack-of–design-patterns-in-pyth
I’ve tried to convert the ‘Duck’ example from the 1st chapter (covering Strategy Pattern) of Head First Design Pattern in Python:
class FlyWithRocket():
def __init__(self):
pass
def fly(self):
print 'FLying with rocket'
class FlyWithWings():
def __init__(self):
pass
def fly(self):
print 'FLying with wings'
class CantFly():
def __init__(self):
pass
def fly(self):
print 'I Cant fly'
class SuperDuck:
def __init__(self):
pass
def setFlyingBehaviour(self, fly_obj):
self.fly_obj = fly_obj
def perform_fly(self):
self.fly_obj.fly()
if __name__ == '__main__':
duck = SuperDuck()
fly_behaviour = FlyWithRocket()
#fly_behaviour = FlyWithWings()
duck.setFlyingBehaviour(fly_behaviour)
duck.perform_fly()
In the 2009 Wikipedia entry for the Strategy Pattern, there’s a example written in PHP.
Most other code samples do something like:
a = Context.new(StrategyA.new)
a.execute #=> Doing the task the normal way
b = Context.new(StrategyB.new)
b.execute #=> Doing the task alternatively
c = Context.new(StrategyC.new)
c.execute #=> Doing the task even more alternative
In the Python code a different technique is used with a Submit button. I wonder what the Python code will look like if it also did it the way the other code samples do.
Update: Can it be shorter using first-class functions in Python?
The example in Python is not so different of the others. To mock the PHP script:
class StrategyExample:
def __init__(self, func=None):
if func:
self.execute = func
def execute(self):
print("Original execution")
def executeReplacement1():
print("Strategy 1")
def executeReplacement2():
print("Strategy 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat2 = StrategyExample(executeReplacement2)
strat0.execute()
strat1.execute()
strat2.execute()
Output:
Original execution
Strategy 1
Strategy 2
The main differences are:
- You don’t need to write any other class or implement any interface.
- Instead you can pass a function reference that will be bound to the method you want.
- The functions can still be used separately, and the original object can have a default behavior if you want to (the
if func == None
pattern can be used for that). - Indeed, it’s clean short and elegant as usual with Python. But you lose information; with no explicit interface, the programmer is assumed as an adult to know what they are doing.
Note that there are 3 ways to dynamically add a method in Python:
-
The way I’ve shown you. But the method will be static, it won’t get the “self” argument passed.
-
Using the class name:
StrategyExample.execute = func
Here, all the instance will get func
as the execute
method, and will get self
passed as an argument.
-
Binding to an instance only (using the
types
module):strat0.execute = types.MethodType(executeReplacement1, strat0)
or with Python 2, the class of the instance being changed is also required:
strat0.execute = types.MethodType(executeReplacement1, strat0,
StrategyExample)
This will bind the new method to strat0
, and only strat0
, like with the first example. But start0.execute()
will get self
passed as an argument.
If you need to use a reference to the current instance in the function, then you would combine the first and the last method. If you do not:
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = func
def execute(self):
print(self.name)
def executeReplacement1():
print(self.name + " from execute 1")
def executeReplacement2():
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
You will get:
Traceback (most recent call last):
File "test.py", line 28, in <module>
strat1.execute()
File "test.py", line 13, in executeReplacement1
print self.name + " from execute 1"
NameError: global name 'self' is not defined
So the proper code would be:
import sys
import types
if sys.version_info[0] > 2: # Python 3+
create_bound_method = types.MethodType
else:
def create_bound_method(func, obj):
return types.MethodType(func, obj, obj.__class__)
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = create_bound_method(func, self)
def execute(self):
print(self.name)
def executeReplacement1(self):
print(self.name + " from execute 1")
def executeReplacement2(self):
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
This will output the expected result:
Strategy Example 0
Strategy Example 1 from execute 1
Strategy Example 2 from execute 2
Of course, in the case the functions cannot be used stand alone anymore, but can still be bound to any other instance of any object, without any interface limitation.
For clarity, I would still use a pseudo-interface:
class CommunicationStrategy(object):
def execute(self, a, b):
raise NotImplementedError('execute')
class ConcreteCommunicationStrategyDuck(CommunicationStrategy):
def execute(self, a, b):
print "Quack Quack"
class ConcreteCommunicationStrategyCow(CommunicationStrategy):
def execute(self, a, b):
print "Mooo"
class ConcreteCommunicationStrategyFrog(CommunicationStrategy):
def execute(self, a, b):
print "Ribbit! Ribbit!"
You’re right, the wikipedia example isn’t helpful. It conflates two things.
-
Strategy.
-
Features of Python that simplify the implementation of Strategy. The “there’s no need to implement this pattern explicitly” statement is incorrect. You often need to implement Strategy, but Python simplifies this by allowing you to use a function without the overhead of a class wrapper around a function.
First, Strategy.
class AUsefulThing( object ):
def __init__( self, aStrategicAlternative ):
self.howToDoX = aStrategicAlternative
def doX( self, someArg ):
self. howToDoX.theAPImethod( someArg, self )
class StrategicAlternative( object ):
pass
class AlternativeOne( StrategicAlternative ):
def theAPIMethod( self, someArg, theUsefulThing ):
pass # an implementation
class AlternativeTwo( StrategicAlternative ):
def theAPImethod( self, someArg, theUsefulThing ):
pass # another implementation
Now you can do things like this.
t = AUsefulThing( AlternativeOne() )
t.doX( arg )
And it will use the strategy object we created.
Second, Python alternatives.
class AUsefulThing( object ):
def __init__( self, aStrategyFunction ):
self.howToDoX = aStrategyFunction
def doX( self, someArg ):
self.howToDoX( someArg, self )
def strategyFunctionOne( someArg, theUsefulThing ):
pass # an implementation
def strategyFunctionTwo( someArg, theUsefulThing ):
pass # another implementation
We can do this.
t= AUsefulThing( strategyFunctionOne )
t.doX( anArg )
This will also use a strategy function we provided.
Answering an old question for the Googlers who searched “python strategy pattern” and landed here…
This pattern is practically non-existent in languages that support first class functions. You may want to consider taking advantage of this feature in Python:
def strategy_add(a, b):
return a + b
def strategy_minus(a, b):
return a - b
solver = strategy_add
print solver(1, 2)
solver = strategy_minus
print solver(2, 1)
This approach is very clean and simple.
Also, be sure to check out Joe Gregorio’s PyCon 2009 talk about Python and design patterns (or lack thereof): http://pyvideo.org/video/146/pycon-2009–the–lack-of–design-patterns-in-pyth
I’ve tried to convert the ‘Duck’ example from the 1st chapter (covering Strategy Pattern) of Head First Design Pattern in Python:
class FlyWithRocket():
def __init__(self):
pass
def fly(self):
print 'FLying with rocket'
class FlyWithWings():
def __init__(self):
pass
def fly(self):
print 'FLying with wings'
class CantFly():
def __init__(self):
pass
def fly(self):
print 'I Cant fly'
class SuperDuck:
def __init__(self):
pass
def setFlyingBehaviour(self, fly_obj):
self.fly_obj = fly_obj
def perform_fly(self):
self.fly_obj.fly()
if __name__ == '__main__':
duck = SuperDuck()
fly_behaviour = FlyWithRocket()
#fly_behaviour = FlyWithWings()
duck.setFlyingBehaviour(fly_behaviour)
duck.perform_fly()