¿Qué es self de Python?

Todos los métodos de clase llevan un primer parámetro
obligatorio llamado self
. Esto mismo lo has
visto en los métodos de ejemplo de la clase
Usuario
de capítulos anteriores.
Por ejemplo, los tres siguientes métodos lo están
utilizando:
# Métodos
def iniciar_sesion(self):
print("El usuario ha iniciado sesión")
def cerrar_sesion(self):
print("El usuario ha cerrado sesión")
def cambiar_nombre_perfil(self):
print("Se cambió el nombre")
Espacio publicitario
Este parámetro debe ser siempre el primero. Es decir, en métodos que tengan varios parámetros, esa será siempre su posición.
Aunque crees un método que no lleva parámetros, deberá
estar self
presente, ya que si lo dejas sin
poner, recibirás un error como este al intentar llamarlo:
. . .
def cerrar_sesion():
print("El usuario ha cerrado sesión")
def cambiar_nombre_perfil(self):
print("Se cambió el nombre")
. . .
usuario_1.cerrar_sesion()
TypeError: Usuario.cerrar_sesion() takes 0 positional arguments but 1 was given
El método cerrar_sesión() de la clase Usuario espera 0 argumentos posicionales, pero se le proporcionó 1.
El error demuestra que el intérprete de Python está pasando el valor de
self
internamente, ya que en la consola nos dice que el método no espera argumentos, pero que se le ha pasado 1, siendo que no se le está pasando ninguno explícitamente.
El parámetro self
sirve para representar al
propio objeto. Gracias a esto, podemos acceder mediante
él, a los atributos y métodos de una clase.
Sin self
, los métodos de una clase no
tendrían forma de saber a qué instancia de la clase se
están aplicando.
Quiere decir que self
se emplea como comodín,
para reemplazarse por el objeto con el que se llama a un
atributo de la clase, o un método, dentro de ella.
Por ejemplo, tenemos dos objetos de Usuario
:
# Instancias
usuario_1 = Usuario("Enrique", "Barros Fernández",
32, "C/Programación Fácil n.º 34",
"123456789")
usuario_2 = Usuario("Adriana", "Barca López",
28, "Sin dirección",
"987654321")
Cuando llamamos a un método con un objeto como
usuario_2.método(argumento1, argumento2, argumento3)
, Python lo convierte automáticamente en
método(usuario_2,
argumento1, argumento2, argumento3)
.
El nombre del propio objeto que realiza la llamada, es el
que se le pasa implícitamente al parámetro
self
. De esta forma, self
nos
automatiza y simplifica la sintaxis, ya que si no,
tendríamos que estar indicando el objeto cada vez que
llamásemos a un método.
Por ejemplo:
Usuario.iniciar_sesion(usuario_2)
Que, de hecho, esta sintaxis es válida, pero mucho más confusa bajo mi punto de vista.
En lugar de tener que hacer uso de esa sintaxis, podemos
utilizar de forma correcta el parámetro self
,
y hacer uso de esta:
usuario_2.iniciar_sesion()
Así, el intérprete ya se encarga de hacer el “trabajo sucio”.
El nombre self es una convención
El nombre de parámetro self
, no es una
palabra reservada de Python. Esto quiere decir, que
llamarlo así, es una convención; lo puedes llamar de otra
forma perfectamente.
Mira este ejemplo:
def __init__(objeto, color, longitud_metros, ruedas):
objeto.color = color
objeto.longitud_metros = longitud_metros
objeto.ruedas = ruedas
Ten en cuenta, que si utilizas otro nombre, deberás seguir usando ese mismo, como puedes ver en el ejemplo.
Espacio publicitario
Personalmente, no cambiaría el self
por otro
nombre, ya que si alguien tiene que editar tu código, le
vas a complicar más la tarea de leerlo y entenderlo.
Si no entiendas todavía al 100% como funciona
self
, no te preocupes, puesto que lo
importante es que lo apliques siempre a los atributos de
instancia y a los métodos, tal y como te he enseñado. Con
el tiempo irás ganando mayor profundidad en tus
conocimientos de la programación orientada a objetos.
En otros lenguajes de programación, como puede ser Java, el equivalente a
self
de Python, esthis
.
Utilizar atributos en los métodos de clases
Ahora, vamos a intentar modificar uno de los tres métodos
de la clase Usuario
. Por ejemplo,
iniciar_sesion()
.
Sencillamente, quiero que consigas, que cuando se llame
mediante un objeto con este método, muestre el propio
valor del atributo nombre, del objeto de tipo
Usuario
.
Empezamos con la clase así, y dos objetos:
class Usuario:
# Atributos de instancia
def __init__(self, nombre, apellidos,
edad, direccion, telefono):
self.nombre = nombre
self.apellidos = apellidos
self.edad = edad
self.direccion = direccion
self.telefono = telefono
# Métodos
def iniciar_sesion(self):
print("El usuario ha iniciado sesión")
# Instancias
usuario_1 = Usuario("Enrique", "Barros Fernández",
32, "C/Programación Fácil n.º 34",
"123456789")
usuario_2 = Usuario("Adriana", "Barca López",
28, "Sin dirección",
"987654321")
Podríamos pensar, que haciendo esto, nos serviría:
def iniciar_sesion(self):
print(f"El usuario {nombre} ha iniciado sesión")
Sin embargo, al llamar al método, ocurre el siguiente error:
usuario_1.iniciar_sesion()
NameError: name 'nombre' is not defined. Did you mean: 'self.nombre'?
Error de nombre: el nombre 'nombre' no está definido. ¿Quizás querías decir 'self.nombre'?
El error nos indica muy bien la solución. Si dentro de la clase, cada vez que llamamos a un atributo no hacemos la referencia al objeto con self, nos ocurrirá este fallo.
Para evitarlo, solo pon self
:
def iniciar_sesion(self):
print(f"El usuario {self.nombre} ha iniciado sesión")
Ahora, al llamar al método con los dos objetos, se
reemplazará internamente self.nombre
por
usuario_1.nombre
y
usuario_2.nombre
, respectivamente:
usuario_1.iniciar_sesion()
usuario_2.iniciar_sesion()
El usuario Enrique ha iniciado sesión
El usuario Adriana ha iniciado sesión
Espacio publicitario
Espacio publicitario
Ejercicios de Python para resolver
11. Crea una clase llamada Perro
, con método
__init__
, que conste de los siguientes
atributos:
nombre
raza
edad
color
Creamos la clase Perro
, con el siguiente
método __init__
:
class Perro:
def __init__(self, nombre, raza, edad, color):
self.nombre = nombre
self.raza = raza
self.edad = edad
self.color = color
12. Crea dos objetos de tipo Perro
.
Creamos dos objetos de tipo Perro
:
perro1 = Perro("Estrella", "Golden Retriever", 4, "Dorado")
perro2 = Perro("Sr. Nieves", "Husky Siberiano", 3, "Gris y blanco")
13. Añade un método llamado ladrar()
. Este,
al ser llamado, deberá indicar una frase como esta:
Chester ha ladrado.
El método deberá ir colocado después del método
__init__
:
def ladrar(self):
print(f"{self.nombre} ha ladrado.")
14. Llama con los dos objetos, al método
ladrar()
. Este deberá mostrar el nombre de
cada perro, con la frase creada en el ejercicio anterior.
Hacemos una llamada con cada objeto.
Te dejo el código completo de la práctica, por si te has perdido en algún punto:
class Perro:
def __init__(self, nombre, raza, edad, color):
self.nombre = nombre
self.raza = raza
self.edad = edad
self.color = color
def ladrar(self):
print(f"{self.nombre} ha ladrado.")
perro1 = Perro("Estrella", "Golden Retriever", 4, "Dorado")
perro2 = Perro("Sr. Nieves", "Husky Siberiano", 3, "Gris y blanco")
perro1.ladrar()
perro2.ladrar()
Estrella ha ladrado.
Sr. Nieves ha ladrado.
15. En la instanciación, se está recibiendo un error de
tipo TypeError
.
¿Podrías solucionarlo?
class Vehiculo():
def __init__(self, color, longitud_metros, ruedas):
self.color = color
self.longitud = longitud_metros
self.ruedas = ruedas
vehiculo_1 = Vehiculo ("rojo", 5, 4, "Ford")
Si ejecutas el código, en la consola podrás ver el siguiente error:
TypeError: Vehiculo.__init__() takes 4 positional arguments but 5 were given
Error de tipo: Vehiculo.init() toma 4 argumentos posicionales, pero se dieron 5
El error indica que el objeto tiene 4 argumentos posicionales, pero se han pasado 5.
El método espera los siguientes argumentos:
-
self
(Lo pasa el intérprete. No lo escribimos en la instanciación) color
longitud
ruedas
En el ejercicio estoy haciendo la llamada con estos argumentos:
self
(objeto)-
color ("rojo")
-
longitud (5)
-
ruedas (4)
-
"Ford"
(no tiene parámetro. Este argumento sobra)
La instanciación podría quedar así:
vehiculo_1 = Vehiculo ("rojo", 5, 4)
Espacio publicitario