Выбор типа метода зависит от других факторов.
У вас есть два случая. Первый случай, когда метод должен быть частью интерфейса класса - например, он должен вызываться пользователями, или его нужно переопределять в подклассах, или он использует информацию сам по себе, или вполне вероятно, что в будущей версии программного обеспечения вам может понадобиться любой из них.
В этом первом случае вы часто либо используете обычный метод (это когда метод относится к экземплярам, а не к классу), либо 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
Что дает вам лучшее представление о том, что делают эти объекты при чтении исходного кода, и даже позволяет добавлять документацию. Но это все еще может пригодиться, когда вы динамически создаете классы или добавляете их в метакласс (создание метода-оболочки вручную не очень удобно).