问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/21672041/how-can-i-use-a-static-method-as-a-default-parameter-for-the-strategy-design-pat