如何使用静态方法作为策略设计模式的默认参数?

Posted

技术标签:

【中文标题】如何使用静态方法作为策略设计模式的默认参数?【英文标题】:How can I use a static method as a default parameter for the strategy design pattern? 【发布时间】:2014-03-07 11:30:17 【问题描述】:

我想创建一个使用类似这样的策略设计模式的类:

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()

这给出了错误:

NameError: name 'C' is not defined

strategy=C.default_concrete_strategy 替换为strategy=default_concrete_strategy 将起作用,但默认情况下,策略实例变量将是静态方法对象而不是可调用方法。

TypeError: 'staticmethod' object is not callable

如果我删除 @staticmethod 装饰器,它会起作用,但还有其他方法吗?我希望自行记录默认参数,以便其他人立即看到如何包含策略的示例。

另外,有没有更好的方法来公开策略而不是静态方法?我认为在这里实现完整的类没有意义。

【问题讨论】:

策略模式在python中大多没用。由于您将函数作为第一类对象,因此您可以传递函数。 @Bakuriu 正如您所见,该策略是一流的对象函数。我认为这仍然被称为策略模式不是吗? 是的,但是策略模式主要是在不允许传递函数的语言中发明的。我的意思是,在你的类的 99% 的用例中,你可以简单地直接传递函数并以更低的复杂性获得相同的结果。 @Bakuriu 你能举例说明如何做到这一点吗? 也与问题Calling class staticmethod within the class body?有关 【参考方案1】:

不,您不能,因为 class 定义尚未完成运行,因此当前命名空间中尚不存在类名。

可以直接使用函数对象:

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 还不存在,因此您可以通过本地名称引用default_concrete_strategy.__func__ 解包 staticmethod 描述符以访问底层原始函数(staticmethod 描述符本身不可调用)。

另一种方法是使用哨兵默认值; None 在这里可以正常工作,因为 strategy 的所有正常值都是静态函数:

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

由于这会从self 检索default_concrete_strategy,因此调用描述符协议并由staticmethod 描述符本身返回(未绑定)函数,在类定义完成之后。

【讨论】:

或者他可以先定义default_concrete_strategy装饰它,然后在__init__的定义之后装饰它(因为装饰器在2.4之前使用),虽然这样会很麻烦。 @Bakuriu:完全正确;拆开包装要容易得多。 如果这是唯一的方法,那就太可惜了。如果直接在代码中看到如何传递参数的示例,那就太好了。 @Bakuriu 在构造函数中装饰一个方法会有帮助吗? @mtanti 不,你必须把@staticmethod 放在课堂上。我的意思是def method():pass; def __init__(self, func=method):pass; method = staticmethod(method)。但是我必须说,我更喜欢简单地使用 None 作为默认值并在 __init__ 中检查它。 @mtanti:这不是唯一的方法,但它是最易读的方法。另一种方法是“手动”应用装饰器;定义default_concrete_strategy 不带 @staticmethod 行,然后在定义__init__ 方法后,使用default_concrete_strategy = staticmethod(default_concrete_strategy)

以上是关于如何使用静态方法作为策略设计模式的默认参数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中使用类变量作为默认参数值

C#基础 可选参数调用params无参静态构造函数

如何在Python中定义静态变量

Spring三种实例化Bean的方式

Java基础 -- 静态方法和实例方法有何不同无参构造函数有什么作用import java和javax有什么区别成员变量与局部变量的区别有哪些(成员变量有默认赋值)

使用 expando 元类添加 curried 闭包作为静态属性会丢失默认参数值