Atributos del objeto

Ya hemos comentado que las clases definen los atributos y métodos de los objetos que se creen a partir de ella. Veamos un ejemplo sencillo en el que vamos a crear una clase que incluye un simple valor (es decir, cuando creemos un objeto de esta clase, tendrá un valor asociado):

class MiClase:
    
    def __init__(self, numero):
        self.valor = numero

Si no has trabajado antes con programación orientada a objetos, el código anterior puede sonarte un tanto críptico, pero es más sencillo de lo que parece. Vamos punto por punto:

  • En primer lugar hemos escrito el identificador "class" seguido del nombre de la clase y los dos puntos, como ya sabíamos.
  • Debajo, y con la sangría habitual en estos casos (cuatro espacios en blanco o un tabulador), se definen los métodos de nuestra clase. En este caso solo hay uno: __init__
  • ¿Por qué el único método que hay tiene un nombre tan sofisticado? ¿Y para qué sirve? La respuesta compleja es que "incluye dos guiones bajos al principio y al final porque se trata de lo que se denomina un método de sobrecarga, y sirve para inicializar el objeto cuando se crea", pero de esta respuesta compleja solo nos sirve aquí la última parte: "el método __init__ sirve para inicializar el objeto cuando se crea", lo que suena mucho más útil. Es decir, cuando "instanciamos" un objeto de la clase MiClase, se ejecuta el método __init__. Este método suele llamarse constructor de la clase (aunque, si somos estrictos, este método se ejecuta para inicializar el objeto una vez se ha construido. En todo caso podemos llamarlo "constructor" para abreviar...).
  • ¿Y por qué tiene este método dos parámetros? El segundo parámetro ("numero") parece ser el número que queremos asociar al objeto, pero ¿y "self"? La respuesta sencilla aquí es que todos los métodos de una clase deberán tener como primer parámetro "self", parámetro que hace referencia al objeto al que van asociados. En realidad no necesitamos usar el identificador "self", podríamos usar otro nombre. Pero el uso de "self" es una convención entre la comunidad Python.
  • Dentro del constructor ejecutamos "self.valor = numero". Aquí estamos creando un atributo del objeto llamado "valor" al que también se accede usando el prefijo self, y le estamos asignando el número que hemos recibido como segundo parámetro.
  • Una vez se ha instanciado el objeto -es decir, una vez que se haya ejecutado el constructor-, el objeto resultante tendrá asociado un atributo llamado "valor" que contendrá el número que hayamos pasado como argumento al crear el objeto.
  • Una cosa importante: si el constructor tiene un parámetro (además de self) es porque para crear el objeto tenemos que incluir tras el nombre de la clase y entre paréntesis un argumento. Por ejemplo:

c = MiClase(4)

En esta instrucción hemos instanciado la clase MiClase pasando como argumento el número 4. Este argumento es el que le llega al constructor de la clase que, como ya sabemos, va a asociar al objeto. Para acceder al atributo "valor" basta con escribir el nombre del objeto seguido de un punto y del nombre del atributo:

c.valor

4

Si el método __init__ tuviese dos parámetros (además de self) sería porque tenemos que incluir dos argumentos al instanciar el objeto. Para verlo, supongamos que el valor que queda asociado al objeto es la suma de los dos números que pasemos al constructor:

class MiClase:
    
    def __init__(self, numero1, numero2):
        self.valor = numero1 + numero2

Ahora instanciamos la clase:

c = MiClase(3, 5)

...y mostramos el contenido del atributo valor:

c.valor

8

En el constructor podemos inicializar los atributos que necesitemos. En el siguiente ejemplo se inicializan dos de ellos ("nombre" y "sexo") a partir de los datos pasados como argumentos, y un tercero ("parking") con el valor -1, indicando que todavía no se ha asociado a dicha persona una plaza de parking (se supone que podrá ser actualizado más tarde):

class Trabajador:
    
    def __init__(self, nombre, sexo):
        self.nombre = nombre
        self.sexo = sexo
        self.parking = -1

Instanciamos dos objetos a partir de esta clase, uno para representar a Óscar y otro para representar a Luisa, ambos trabajadores de la empresa en cuestión:

trabajador1 = Trabajador("Óscar", "H")
trabajador2 = Trabajador("Luisa", "M")

Ahora podemos visualizar los diferentes atributos de ambos objetos:

trabajador1.nombre, trabajador1.sexo, trabajador1.parking

('Óscar', 'H', -1)

trabajador2.nombre, trabajador2.sexo, trabajador2.parking

('Luisa', 'M', -1)

Cada objeto que creemos a partir de la clase "Trabajador" tendrá su propio conjunto de atributos, independientes unos de otros.

Un comentario adicional: los atributos de los objetos pueden crearse en cualquiera de los métodos, no necesariamente en el constructor. Hacerlo en éste simplemente permite dar un valor por defecto (y evitar errores si se intenta acceder al atributo antes de haberlo creado) y poner  un poco de orden en la clase.