14

Estoy aprendiendo Python y me topé con la parte de POO. En su momento hice mis pinitos con la POO de PHP pero me pasa lo mismo, no entiendo que se utilice el valor self dentro de un método.

He estado leyendo por internet y habla de autoreferenciar a la clase y demás, pero sinceramente, no entiendo ese concepto.

Por ejemplo:

class Persona:

    def inicializar(self,nom):
        self.nombre=nom

    def imprimir(self):
        print("Nombre",self.nombre)

persona1=Persona()
persona1.inicializar("Pedro")
persona1.imprimir()

persona2=Persona()
persona2.inicializar("Carla")
persona2.imprimir()

¿Alguien sería tan amable de explicarme para qué sirve ese self?

fedorqui
  • 15,850
  • 17
  • 58
  • 112
jask
  • 255
  • 1
  • 2
  • 7
  • Las respuestas que te han dado son suficientes para hacerte una idea ahora que estás empezando. Pero cuando profundices más, mírate el `protocolo descriptor` que es el responsable del funcionamientos interno de la POO en python. En python se tiene herencia múltiple, no siendo posible saber *a priori* en qué orden buscar el método a ejecutar sin conocer la instancia en concreto que lo están invocando. De ahí que sea importante indicar la instancia, por convenio como `self`. – ChemaCortes Jul 25 '17 at 20:14
  • Gracias @ChemaCortes lo tengo en cuenta. Ha sido muy útil toda la información aquí recogida. – jask Jul 26 '17 at 13:14

4 Answers4

7

En Python casi todo es un objeto, a diferencia de otros lenguajes, una clase es un objeto también, suena raro pero efectivamente es así:

class Prueba():
  pass

p = Prueba()

print(type(Prueba))
print(type(p))

> <class 'type'>
> <class 'Prueba'>

Podemos observar que la clase Prueba es un objeto del tipo <class 'type'> y el objeto instanciado es ahora si, del tipo <class 'Prueba'>. Con esto en mente puede que sea más claro el porque del uso del self. Supongamos algo parecido a tu ejemplo:

class Persona:

    def __init__(self,nom):
        self.nombre=nom

    def imprimir(self):
        print("Nombre: {0}".format(self.nombre))

p1 = Persona("Juan")
p2 = Persona("Pedro")
print(type(Persona))
print(type(p1))
print(type(p2))

> <class 'type'>
> <class 'Persona'>
> <class 'Persona'>

Hemos usado el objeto Persona del tipo <class 'type'> (clase) para crear dos nuevos objetos de <class 'Persona'>. La forma normal de acceder a los métodos sería haciendo esto:

p1.imprimir())
p2.imprimir())
> Juan
> Pedro

Pero lo que en realidad está ocurriendo por debajo, es decir lo que Python hace en realidad, es algo así:

Persona.imprimir(p1))
Persona.imprimir(p2))
> Juan
> Pedro

Una forma de ver esto es que cada instancia p1 y p2 no posee "copias" del método imprimir no tiene sentido, el método es de la clase Persona, los datos self.nombre si, son de cada instancia. De modo que para que Persona pueda invocar imprimir pero con los datos de la instancia adecuada, es necesario declarar el método como imprimir(<instancia>).

Aclaración: self es una convención podríamos usar cualquier nombre pero no es recomendable.

Patricio Moracho
  • 54,367
  • 12
  • 35
  • 68
5

Para completar y para tener en cuenta. El uso de self es una convención en Python, una buena práctica pero no una regla (no es una palabra reservada ni nada por el estilo).

Con esto quiero decir que puedes usar cualquier nombre para representar la instancia de la clase:

>>> class A:
...   def __init__(instancia, numero):
...     instancia.numero = numero
...   def get_numero(instancia):
...     return instancia.numero
... 
>>> a = A(10)
>>> a.get_numero()
10

Para Python esto es una clase perfectamente normal. En la clase A he cambiado el self por instancia. Ojo, esto es solo una aclaración.

También te puedes encontrar con algunos métodos que carecen de self como cuando se usan métodos estáticos:

>>> class A:
...   def __init__(self, numero):
...     self.numero = numero
...   @staticmethod
...   def saludo():
...     print('Hola')
... 
>>> a = A(10)
>>> a.saludo()
Hola

El uso de self como el primer argumento de los métodos está especificado en Function and method arguments del PEP 8 (la guía de estilos para el código en Python).

César
  • 16,990
  • 6
  • 37
  • 76
  • 1
    Gracias! Aún no llegué a la parte de métodos estáticos por lo que no entiendo lo que son :) . – jask Jul 25 '17 at 18:38
3

El parámetro self se refiere al objeto instanciado de esa clase sobre el cual se está invocando dicho método. Es decir, el objeto que usaste para llamar al método (en tu ejemplo persona1 y persona2).

Python, dentro de los métodos definidos de una clase, establece que el primer parámetro definido en un método recibirá el objeto con el cual se invoca dicho método. Este parámetro (que se suele llamar self aunque se puede usar cualquier nombre de variable [ver comentarios]) es usado dentro de la implementación del método para modificar el contenido o atributos de dicho objeto como desees.

Por lo tanto, es una condición necesaria que todos los métodos de una clase que puedan ser llamados a través de un objeto tengan al menos un parámetro, el cual se asignará automáticamente al objeto usado en la invocación.

Aunque en la definición del método, self es el primer parámetro, a la hora de llamar a dicho método no hace falta pasarle el propio objeto como primer parámetro explícitamente ya que Python lo hace de manera implícita sin necesidad de hacerlo manualmente. Es decir, el primer parámetro self del método se asigna automáticamente al propio objeto y el resto de parámetros a los argumentos con que llames al método.

En el caso del método __init__(), el parámetro self se refiere al objeto recién instanciado de la clase que quieres obtener al crear dicho objeto con Nombre_Clase().

self es el equivalente al this de otros lenguajes (aunque self no es palabra reservada como this [ver comentarios]), con la diferencia de que en otros lenguajes no hace falta definir los métodos con un parámetro this, mientras que en Python sí es necesario.

Carlos A. Gómez
  • 1,601
  • 1
  • 12
  • 29
0

Como tu mismo dices, es una auto referencia y en general, en un método de instancia de un modelo, deberías usar self cuando modifiques atributos o cuando exista alguna ambigüedad entre llamar a una variable local y un atributo/método ya definido. Esto sucede en todos los lenguajes que usan POO y es una practica muy común y la mas correcta, por lo que te aconsejo que lo uses.

Manuel Robles
  • 1,594
  • 1
  • 7
  • 17
  • Es lo que más o menos entendí yo cuando buscaba info. Que sin el self es local, para ese método, pero con el self se pueden utilizar en diferentes métodos dentro de esa clase. – jask Jul 25 '17 at 18:42