POO. Métodos.
Cuando hablamos de los métodos como componentes de una clase, asimilamos éstos con las funciones, llegando incluso a insinuar que eran denominaciones intercambiables. Así son considerados por muchos autores, aunque puede que no de forma explícita, y no faltan razones para ello, ya que básicamente un método es una función; no obstante, el ser parte constituyente de una clase otorga a los métodos algunas diferencias respecto a las funciones que es necesario conocer para entender el código de terceros y para trabajar adecuadamente con ambos.
En esta entrada vamos a exponer las diferencias existentes entre una función y un método, las cuales radican fundamentalmente en el uso de parámetros y en las implicaciones que tiene la pertenencia del método a la clase para su uso por parte de los objetos.
La primera diferencia que debemos señalar entre una función y un método es que en los métodos no vamos a encontrarnos nunca con el paréntesis vacío: como mínimo (y muy frecuentemente, como único) nos encontraremos con el parámetro self, que referencia a la clase y en su momento al objeto).
La segunda diferencia es que aunque el método utilice parámetros/atributos de la clase, no es necesario (y no se debe) establecerlos como tales parámetros, siendo suficiente con utilizar la formula self.nombre_atributo dentro de la función para que ésta utilice adecuadamente el valor que el parámetro tenga en el objeto.
La tercera diferencia es que para llamar al método desde el objeto no es necesario incluir valor alguno como argumento: ni para self (ya que es el propio objeto) ni para los argumentos (ya que están definidos previamente en la construcción del objeto.
Bien podría ser que el método en su formulación abstracta (como parte de la clase) cuente con parámetros o con variables específicas (y privadas) no contempladas como atributos. En ese caso deberemos proceder del mismo modo que hacemos con las funciones tanto en la construcción del método como en el momento de llamarlo desde (y en función del) objeto.
Vamos a presentar un ejemplo en el que el método de una clase cuenta con un parámetro no incluido como atributo (aunque en realidad bien podría serlo) y una variable privada. Podemos comparar el funcionamiento de este código con el que se desarrolló en su momento para ver unas diferencias que explicaremos a continuación.
En el archivo actual, ni los argumentos ni el constructor de la clase se diferencia del archivo inicial...
def __init__(self,nombre,edad):
self.nombre = nombre
self.edad = edad
... pero sí el método sentarse(). Observa:
Original:
def sentarse(self):
print(f"{self.nombre} se sienta cuando se lo ordeno (y quiere, claro).")
Actual:
def sentarse(self,sexo):
if sexo =="perrito":
tratamiento = "educado"
else:
tratamiento= "educada"
print(f"Mi {sexo} {self.nombre} tiene {self.edad} años. Está muy bien {tratamiento} y se sienta cuando se lo pido.")
- Podemos identificar ambos como métodos (y no funciones) por el hecho de que ni en el primero ni en el segundo nombre y edad (ambos atributos identificados como tales en la construcción de la clase) son declarados como parámetros y por ser empleados dentro de print() mediante la auto-referencia (self.nombre, por ejemplo)
- Además, el parámetro self presente en ambos métodos nos confirma que se trata de métodos, ya que este parámetro no se usa en funciones.
De hecho si formulásemos el método como función podríamos hacerlo como sigue (obviamente en este caso no se generan atributos ni se utiliza una función de inicialización):
def sentarse(nombre,edad,sexo):
if sexo=="perrito":
tratamiento = "educado"
else:
tratamiento = "educada"
print(f"Mi {sexo} se llama {nombre} y tiene {edad} años. Es muy {tratamiento} ya que se sienta cuando se lo ordeno.")
Fíjate que, a consecuencia de ello, además de trabajar con los parámetros de una forma claramente diferente, en el print() de la función las variables incluidas como parte de la cadena f no se expresan mediante la sintaxis del punto, como sí hacemos en sus dos formulaciones como método.
Finalmente vamos a ver las diferencias en el modo de hacer la llamada a la función y al método.
Función (tras cuestionario asociado a variables/argumentos)
sentarse(perro_nombre,perro_edad,perro_sexo)
Método (formulación simple)
perrita = MiPerro("Atenea",10) -> Creación del objeto
perrita.sentarse() -> Llamada al método
Método (formulación similar a función, esto es: con cuestionario previo)
perro = MiPerro(perro_nombre,perro_edad) -> Creación del objeto
perro.sentarse(perro_sexo) -> Llamada al método
Al margen de lo que implica trabajar con clase-objeto, primero nos vamos a fijar en las similitudes y diferencias entre la llamada a la función y la llamada al método: en realidad llamar a la función equivale a desarrollar en una única instrucción el doble proceso de creación de objeto y llamada al método que se produce cunado trabajamos con clases y objetos.
La presencia necesaria de argumentos se concreta en la función en el momento de ser llamada, mientras que en el método se diferencia en función del doble proceso de creación del objeto, que se produce una vez y ya no tiene que volver a repetirse, lo que supone una ahorro importante de trabajo en caso de utilizar el objeto múltiples veces y con diferentes métodos, y la llamada al método propiamente dicho, que se resume como llamada a método sin más en su forma más simple, o que puede incluir algún parámetro en caso de haberse incluido alguno, como es el caso del segundo método.
Pero volvamos al análisis de la formulación del método en sus dos versiones: la más simple no incluye parámetros añadidos ni variables privadas, por lo que se presenta en su forma más simple, tanto en su definición como parte de la clase...
def sentarse(self):
print(f"{self.nombre} se sienta cuando se lo ordeno (y quiere, claro).")
... como al ser llamada desde el objeto
perrita.sentarse()
La segunda formulación incluye el uso de un parámetro no establecido como argumento en la definición de la clase (sexo), y una variable privada (tratamiento).
def sentarse(self,sexo):
if sexo =="perrito":
tratamiento = "educado"
else:
tratamiento= "educada"
print(f"Mi {sexo} {self.nombre} tiene {self.edad} años. Está muy bien {tratamiento} y se sienta cuando se lo pido.")
Fíjate en las implicaciones de la presencia de este parámetro y de esta variable en cómo se escriben las variables en la cadena f: ninguno de los dos se formula con self., mientras que sí se utiliza con las variables-argumentos.
Esta diferencia en el tratamiento se traslada después a la llamada al método, que incluye explicitar el argumento asociado al parámetro sexo:
perro.sentarse(perro_sexo)
Esta diferencia entre ambos métodos es más importante en lo que estamos tratando en la presente entrada que el hecho de que en la creación del objeto en una formulación introduzcamos directamente los valores que concretan los parámetros
perrita = MiPerro("Atenea",10)
Mientras que en la segunda asociemos dichos parámetros a sendas variables que nos permiten modificar de forma interactiva (input) el valor de los atributos.
perro_nombre = input("Nombre del perro: ")
perro_edad = eval(input("Edad del perro: "))
perro_sexo = input("perrito o perrita: ")
perro = MiPerro(perro_nombre,perro_edad)
perro.sentarse(perro_sexo)
Aunque esta formulación se asemeje aparentemente a la fórmula empleada en la función...
perro_nombre = input("Dime el nombre de tu perro: ")
perro_edad = eval(input("¿Cuántos años tiene? "))
perro_sexo = input("¿Es perrito o perrita? ")
sentarse(perro_nombre,perro_edad,perro_sexo)
... si te fijas bien hay una diferencia que revela que se trata de dos formas diferentes de abordar la cuestión: en la función empleamos los tres argumentos, mientras que en el objeto utilizamos dos argumentos para establecer el contenido de los parámetros en la construcción del objeto y utilizamos el tercero (perro_sexo) como parámetro del método, dado que (el método) cuenta con ese parámetro en su definición y lo utiliza para dar contenido a la variable privada que tiene el método (tratamiento)
Es posible que todo esto te haya parecido algo lioso, incluso una minucia poco relevante: no lo es, créeme: de no tenerse en cuenta se producirán errores que impiden que funcione todo correctamente y tú no comprenderás el código de terceros que empleen parámetros y variables dentro de los métodos.
Para ayudarte a comprender con ejemplos estas diferencias te dejo acceso a los tres archivos que me han servido de ejemplo: