Diseño de la clase Python (método estático vs método)

¿Cuál es la mejor manera para los métodos que no necesitan ninguna información pasada (instancia de objeto o clase) porque, por ejemplo, simplemente hacen una conversión simple? ¿ Método estático o método ?

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 

La elección del tipo de método depende de otros factores.

Tienes dos casos. El primer caso es cuando el método tiene que ser parte de la interfaz de clase, por ejemplo, debe ser llamado por los usuarios, o debe ser anulable en las subclases, o usa la información por sí mismo, o es probable que en una versión futura del software que pueda necesitar cualquiera de esos.

En este primer caso, a menudo usaría un método normal (esto es cuando el método se relaciona con las instancias y no la clase) o un método de clase (cuando el método se relaciona con la clase, por ejemplo, es un constructor alternativo, un método para descubriendo características de clase, etc.). En ambos casos, puede usar un staticmethod en su lugar si el staticmethod no staticmethod ninguna información de la clase / instancia, pero no obtiene nada al hacerlo. Y también rompería tu capacidad de hacer cls.method(instance, *args) que ya es demasiado para no ganar nada.

El segundo caso es cuando el método no forma parte de la clase de ninguna manera. Por lo general, es recomendable utilizar una función: el método no es realmente parte de la interfaz, por lo que no tiene lugar allí. Tu ejemplo parece ser ese caso, a menos que quieras anular la calculadora de árbol / dinero en las subclases, pero eso depende en gran medida de lo que estés haciendo con él.

Un caso especial son los métodos privados: entonces es posible que desee utilizar un método, incluso si no está realmente relacionado con la clase, los métodos privados no forman parte de la interfaz, por lo que no importa dónde los coloque. El uso de un staticmethod aún no le gana mucho, pero tampoco hay ninguna razón para no usarlo.

En realidad, hay un caso en el que el staticmethod es muy útil: cuando se ponen funciones externas (u otros objetos) en la clase.

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

Pero cuando tienes una definición estática de la clase, eso no es realmente bueno, porque siempre puedes hacer lo siguiente.

 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 

Lo que le da una mejor idea de lo que hacen estos objetos al leer la fuente e incluso le permite agregar documentación. Pero puede ser útil cuando crea clases dinámicamente, o las agrega en una metaclase (crear un método de envoltura manualmente no es muy conveniente).

Mi regla general, para todo el diseño orientado a objetos, es que si una clase no tiene estado, considere usar métodos estáticos. Si la clase tiene estado, use métodos de instancia – sin duda.

Además, si la clase no tiene ningún estado, reflexione durante unos minutos y vea si no puede mover el comportamiento estático más cerca de los datos y, por lo tanto, elimine esos métodos estáticos con una refactorización del Método de extracción .

Cualquier método que no use nombres del espacio de nombres de objeto debe ser por métodos de clase, y aquellos que tampoco usan nombres del espacio de nombres de clase – staticmetdods, o incluso ponerse en el nivel de módulo como funciones.

Cuando se usa el método de objeto real, el comportamiento esperado es que se accederá a otros atributos / métodos del mismo objeto.