5

La relacion que hay entre self y cls con metodos estaticos, metodos de clase y metodos de instancia

Desde que me tope con la programación orientada a objetos siempre entendía la referencia a la instancia (this, self, etc) como algo que se debía colocar pero no sabia el porque. Hasta que aprendí los conceptos relacionados a los métodos estáticos, métodos de clase y métodos de instancia.

Entendiendo los métodos como las funciones que se declaran dentro de una clase y modelan el comportamiento de un objeto real, encontramos tres tipos de estas funciones que son usadas en python

El primer tipo de método (función) que se puede declarar dentro de una clase en python es el método de instancia, es el más comun ya que describe el comportamiento de las instancias que son creadas a partir de una clase, lo identificamos por que el primer parámetro que recibe en su definición es self (no es obligatorio usar self, pero se hace por convención) esta palabra se usa para hacer referencia a la instancia creada y a través de esa palabra tener acceso a los atributos de la instancia que son creadas y/o asignados por el método constructor, por ejemplo:

classExample():def__init__(self, nombre):
        self.nombre = nombre

    defhola(self):
        print(f”¡Hola, {self.nombre}!”)

como vemos el método init() recibe como primer parámetro self con el objetivo de cuando la función se ejecute, en su primera línea encuentre una referencia a la instancia del objeto para poder asignarle lo que contenga el segundo parámetro (nombre). Igual pasa con el método hola() ya que recibe como primer parámetro la misma palabra self para poder tener acceso al atributo que se crea con la ejecución del método constructor, en conclusión definimos una clase con solamente métodos de instancia, es decir métodos que solo reciben como referencia la propia instancia de una clase

>>> c1 = Example('Diego')
>>> c1.hola()
¡Hola, Diego!

Si creamos una instancia llamada c1, esta instancia recibirá el string ‘Diego’ a través de la palabra self que usamos en la definición del método constructor y cuando llamamos el método hola(), este método también tiene la palabra self, es decir sabe en donde buscar el atributo que se le esta pidiendo

En caso contrario,si reemplazamos la línea donde se crea la instancia y donde se llama la funcion .hola() desde la instancia creada, Así:

>>> Example.hola()
Traceback (most recent call last):
  File"clases.py", line 11, in <module>
    Clase.hola()
TypeError: unbound method hola() must be called withClase instance as first argument (got nothing instead)

A pesar que llamamos el método con el nombre de la clase, lo cual es posible, este método no tiene referencia a una instancia, ya que esta instancia no se creo y en la definición de la clase y de sus métodos el método .hola() hace referencia a una instancia.

Para comprobar podemos ejecutar las siguientes dos líneas de codigo despues de definir la clase

>>> c1 = Example('Diego')
>>> Example.hola(c1)
¡Hola, Diego!

En este caso la instancia c1 si es creada por lo tanto el método constructor init guarda el string ‘Diego’ en un atributo de instancia, entonces cuando ejecutamos el método .hola desde el nombre de la clase,le pasamos la instancia c1 como parámetro para que la función pueda hacer referencia a la instancia y con esto tener acceso a sus atributos de la instancia pasada como parámetro

Ahora comparemos con los métodos de clase, estos métodos pueden ser accedidos desde el nombre de la clase, se utilizan con el decorador @classmethod y utilizan una referencia a la misma clase para funcionar, esta referencia por convención es cls, es como decirle al interprete de python que eventualmente usaras el método sin tener una instancia de clase previamente creada, pero para poder hacer referencia a los atributos de clase necesita tener una referencia a la misma clase para poder tener acceso a los atributos de clase. Veamos lo en ejemplos:

class Example():
    atributo_de_clase = "Soy un atributo de clase"

    @classmethod
    def obtener_atributos(cls):
        return cls.atributo_de_clase

If __name__ == ‘__main__’:
    print(Example.obtener_atributos())```

Lo primero que podemos destacar es que creamos un atributo de clase, es decir un atributo que puede ser accedido desde el nombre dela clase y además es un atributo que siempre será igual para toda las instancias de esa clase, además creamos un método y lo decoramos con el atributo @classmethod y le pasamos el parámetro “cls” que es usado por convención para hacer referencia a la clase y no a una instancia de ella, como vemos enlalógica del método utilizamos la palabra cls que le pasamos como parámetro para hacer referencia a la clase en cuestión y no a una instancia de esta clase, con esto podríamos obtener atributos de clase sin crear previamente una instancia de esa clase

y por último pero no menos importante tenemos los métodos estaticos que son funciónes dentro de una clase pero no usan la palabra reservada self o cls, es decir no tienen referencia ni a la instancia ni a la clase. estos metodos se deben decorar con @staticmethod y pueden ser accedidos con el doc notation pero no tienen acceso ni a los atributos de instancia ni a los atributos de clases, ejemplo:

class Example(object):
atributo_clase = “soy un atributo de clase”

@classmethod
def metodo_clase(cls):
    return cls.atributo_clase

def __init__(self, atributo_intancia):
    self.atributo_intancia = atributo_intancia

@staticmethod
def metodo_estatico():
    return "soy un metodo estatico"

if name == “main”:

print(Example.metodo_estatico())
instancia = Example("atributo de instancia")
print(instancia.metodo_estatico())```

En este ejemplo vemos como el método (metodo_estatico) es accedido desde la clase y desde la instancia de la clase pero este método no puede interactuar con los atributos de la clase y de la instancia, ya que no recibe una referencia de ellas. Si intentáramos escribir dentro de metodo_estatico() una línea como return self.atributo_instancia o return cls.atributo_clase el interprete de python nos regresara un error de tipo NameError: name < ‘self’ o ‘cls’> is not defined

como conclusión general podemos decir:

  • Los métodos de instancia se declaran como cualquier otra función pero dentro de una clase y recibiendo la referencia de la instancia que por convención se utiliza la palabra self

  • los métodos de clase se declaran dentro de la clase, se le ponen el decorador @classmethod y se le pasa la palabra cls, por convención, como referencia de la clase

  • los métodos estáticas se declaran como una función normal pero se decoran con @staticmethod y no reciben referencia ni de la clase ni de la instancia

Y sus diferencias y similitudes son:

Similitudes

  • todas son funciones que regresan algo
  • están dentro de la definición de una clase

Diferencias

*una recibe referencia a la clase, la otra recibe referencia a la instancia y la otra no recibe referencias a nada los
*métodos de clase y de instancia interactúan con los atributos de la clase y los atributos de la instancia pero los métodos estáticos no lo hacen

El feedback me nutre, si tienes alguna sugerencia o corrección has mela saber

Escribe tu comentario
+ 2
1
665Puntos

Lamento no tener feedback en este momento pues apenas estoy empezando… pero encuentro muy interesate este tipo de analisis.

0
6313Puntos

muy buen aporte compañero, me despejo algunas dudas.

hasta ahora yo solo he usado métodos de instancia, pero los métodos estáticos son muy útiles sobre todo para mandar a llamar algún método que no necesariamente interactué con los atributos y métodos de instancia, siento que la forma en que los llamas es mucho mas fácil para no tener que pasar los atributos que componen esa clase. yo lo usuaria cuando tal vez voy a hacer un query a mi db y asi no tener que mandar tantos atributos.

los métodos de clase siento que son como un híbrido entre métodos de instancia y estáticos, ya que por un lado te permite esa flexibilidad de llamar sin requerir instancia pero también puedes acceder a atributos y métodos de instancia.

wow! me voy con entendiendo muchas cosas que antes no sabia y por eso no utilizaba pero haciendo algunas pruebas puede reducir bastante código en mis proyectos.