Consider this example of a strategy pattern in Python (adapted from the example here). In this case the alternate strategy is a function.
class StrategyExample(object):
def __init__(self, strategy=None) :
if strategy:
self.execute = strategy
def execute(*args):
# I know that the first argument for a method
# must be 'self'. This is just for the sake of
# demonstration
print locals()
#alternate strategy is a function
def alt_strategy(*args):
print locals()
Here are the results for the default strategy.
>>> s0 = StrategyExample()
>>> print s0
<__main__.StrategyExample object at 0x100460d90>
>>> s0.execute()
{'args': (<__main__.StrategyExample object at 0x100460d90>,)}
In the above example s0.execute
is a method (not a plain vanilla function) and hence the first argument in args
, as expected, is self
.
Here are the results for the alternate strategy.
>>> s1 = StrategyExample(alt_strategy)
>>> s1.execute()
{'args': ()}
In this case s1.execute
is a plain vanilla function and as expected, does not receive self
. Hence args
is empty. Wait a minute! How did this happen?
Both the method and the function were called in the same fashion. How does a method automatically get self
as the first argument? And when a method is replaced by a plain vanilla function how does it not get the self
as the first argument?
The only difference that I was able to find was when I examined the attributes of default strategy and alternate strategy.
>>> print dir(s0.execute)
['__cmp__', '__func__', '__self__', ...]
>>> print dir(s1.execute)
# does not have __self__ attribute
Does the presence of __self__
attribute on s0.execute
(the method), but lack of it on s1.execute
(the function) somehow account for this difference in behavior? How does this all work internally?