Python admite tres tipos de métodos en las definiciones de clase: métodos de instancia, métodos de clase y métodos estáticos. Se diferencian en la forma de invocación y acceso a los datos de la clase y de la instancia.
Historia:
Inicialmente, los métodos de instancia (los que llevan "self") eran el único tipo de comportamiento, se asumía que los métodos siempre invocaban un comportamiento o modificaban/leían datos de un objeto concreto. Más tarde, en Python aparecieron los métodos de clase (con "cls"), que brindan un comportamiento a la clase en su conjunto (por ejemplo, constructores alternativos), y los métodos estáticos, que son similares a las funciones normales pero están relacionados con la clase.
Problema:
A veces se requiere una funcionalidad común para todas las instancias (métodos estáticos). A veces, la operación debe estar disponible "para la clase en su totalidad" (por ejemplo, crear una instancia). Si se define incorrectamente el tipo de método, se pueden presentar errores (por ejemplo, intentar modificar la clase a través de un método de instancia, o viceversa).
Solución:
Ejemplo de código:
class MyClass: def instance_method(self): return f"Instancia: {self}" @classmethod def class_method(cls): return f"Clase: {cls}" @staticmethod def static_method(): return "Este es un método estático" obj = MyClass() print(obj.instance_method()) # Instancia: <MyClass object...> print(MyClass.class_method()) # Clase: <class 'MyClass'> print(MyClass.static_method())# Este es un método estático
Características clave:
¿Se puede invocar un método de instancia directamente a través de la clase?
Sí, pero se requiere pasar explícitamente el objeto:
MyClass.instance_method(obj)
lo cual rara vez es apropiado.
¿El comportamiento de los métodos estáticos al heredar: pueden ser sobrescritos?
Sí, se puede declarar un staticmethod en la clase hija con el mismo nombre, y ese será el que se llame al acceder desde el heredero.
¿Para qué se utilizan los métodos de clase si siempre se pueden usar métodos estáticos con cls como argumento?
cls no es solo el primer argumento: en el classmethod, Python sustituye automáticamente como cls a la clase correspondiente, incluso si la llamada proviene de un heredero. Esto permite crear una jerarquía alternativa de constructores sin una vinculación estricta con el padre.
Ejemplo:
class Base: @classmethod def make(cls): return cls() class Child(Base): pass Child.make() # devolverá Child, no Base
En el proyecto se utilizaron métodos normales para crear instancias alternativas (por ejemplo, create_from_json). Debido a esto, al heredar, el método siempre devolvía un objeto de la clase base, no del heredero.
Pros:
Contras:
Se implementaron fábricas con classmethod que devuelven instancias de la clase actual (cls()), incluso si se llaman desde el heredero.
Pros:
Contras: