Python 类设计 (静态方法 vs 实例方法)

7 投票
3 回答
3018 浏览
提问于 2025-04-16 13:06

对于那些不需要任何传入信息(比如对象实例或类)的函数,比如说它们只是做一些简单的转换,使用@staticmethodmethod哪种方式更好呢?

class Foo(object):
    def __init__(self, trees):
        self.money = Foo.trees2money(trees)

    @staticmethod
    def trees2money(trees):
        return trees * 1.337

class Quu(object):
    def __init__(self, trees):
        self.money = self.trees2money(trees)

    def trees2money(self, trees):
        return trees * 1.337

3 个回答

0

任何不使用对象命名空间中名称的方法应该是类方法,而那些不使用类命名空间中名称的方法则应该是静态方法,甚至可以直接作为模块级别的函数。

当我们使用实际的对象方法时,预期的行为是会访问到同一个对象中的其他属性或方法。

2

我在面向对象设计中的一般原则是,如果一个类没有状态,就考虑使用静态方法。如果这个类有状态,那就用实例方法,毫无疑问。

此外,如果这个类确实没有状态,可以花几分钟思考一下,看看能不能把静态行为更靠近数据,这样就可以通过一种叫做提取方法的重构方式来消除那些静态方法。

8

选择方法的类型要考虑其他因素。

这里有两种情况。第一种情况是这个方法必须是类的一部分,比如说它需要被用户调用,或者在子类中可以被重写,或者它需要使用到实例中的信息,或者将来软件的版本更新中可能会需要这些功能。

在这种情况下,你通常会使用普通方法(这意味着这个方法是和实例相关的,而不是和类相关的)或者使用classmethod(当这个方法是和类相关的,比如说它是一个替代构造函数,或者是用来发现类特性的某个方法等)。如果这个方法不使用类或实例中的任何信息,你也可以使用staticmethod,但这样做并没有什么好处。而且这样会让你无法使用cls.method(instance, *args),这就显得得不偿失了。

第二种情况是这个方法根本不是类的一部分。在这种情况下,通常建议使用函数,因为这个方法并不是真正的接口的一部分,所以放在哪里都无所谓。你的例子似乎就是这种情况,除非你想在子类中重写树/钱的计算器,但这主要取决于你具体想做什么。

还有一种特殊情况是私有方法——在这种情况下,即使这个方法和类没有太大关系,你可能还是想使用它,因为私有方法并不是接口的一部分,所以放在哪里都无所谓。使用staticmethod也没有太大好处,但也没有理由不使用它。

其实有一种情况是staticmethod非常有用的——当你把外部函数(或其他对象)放进类里时。

class Foo(object):
     trees2money = staticmethod(calculators.trees2money)
     foo = staticmethod(calculators.bar)

但是当你有一个静态定义的类时,这并不是很好,因为你总是可以选择其他方式。

class Foo(object):
     def trees2money(self, trees):
         """Calculator for trees2money, you can override when subclassing"""
         return calculators.trees2money(trees)
     @property
     def foo(self):
         """The foo of the object"""
         return calculators.bar

这样可以让你在阅读源代码时更清楚这些对象的作用,甚至可以添加文档说明。但在你动态构建类,或者在元类中添加类时,这可能还是会派上用场(手动创建一个包装方法并不是很方便)。

撰写回答