I want to make a class that uses a strategy design pattern similar to this:
class C:
@staticmethod
def default_concrete_strategy():
print("default")
@staticmethod
def other_concrete_strategy():
print("other")
def __init__(self, strategy=C.default_concrete_strategy):
self.strategy = strategy
def execute(self):
self.strategy()
This gives the error:
NameError: name 'C' is not defined
Replacing strategy=C.default_concrete_strategy
with strategy=default_concrete_strategy
will work but, left as default, the strategy instance variable will be a static method object rather than a callable method.
TypeError: 'staticmethod' object is not callable
It will work if I remove the @staticmethod
decorator, but is there some other way? I want the default parameter to be self documented so that others will immediately see an example of how to include a strategy.
Also, is there a better way to expose strategies rather than as static methods? I don't think that implementing full classes makes sense here.
No, you cannot, because the class
definition has not yet completed running so the class name doesn't exist yet in the current namespace.
You can use the function object directly:
class C:
@staticmethod
def default_concrete_strategy():
print("default")
@staticmethod
def other_concrete_strategy():
print("other")
def __init__(self, strategy=default_concrete_strategy.__func__):
self.strategy = strategy
C
doesn't exist yet when the methods are being defined, so you refer to default_concrete_strategy
by the local name. .__func__
unwraps the staticmethod
descriptor to access the underlying original function (a staticmethod
descriptor is not itself callable).
Another approach would be to use a sentinel default; None
would work fine here since all normal values for strategy
are static functions:
class C:
@staticmethod
def default_concrete_strategy():
print("default")
@staticmethod
def other_concrete_strategy():
print("other")
def __init__(self, strategy=None):
if strategy is None:
strategy = self.default_concrete_strategy
self.strategy = strategy
Since this retrieves default_concrete_strategy
from self
the descriptor protocol is invoked and the (unbound) function is returned by the staticmethod
descriptor itself, well after the class definition has completed.