Ir al contenido
wannacode

Constructores y self

En resumen: El constructor en Python es el método __init__, que se ejecuta al crear el objeto y rellena sus atributos a través de self.

Problema

Un café de 0 €

Creas un producto, igual que en la lección anterior, y rellenas los campos línea por línea. Se te olvidó una línea:

coffee = Product()
coffee.name = "Café"
coffee.quantity = 2
print(f"{coffee.name}: {coffee.price * coffee.quantity} €")
Salida
Café: 0.0 €

El café cuesta 0 €. Python no se queja: el precio tiene un valor, 0.0 de __init__. Cuantos más campos tiene una clase, más fácil es saltarse uno. Y un producto sin precio ni siquiera debería poder existir.

La idea

Constructor: sin estos datos no hay objeto

Una clase puede decir qué necesita antes de que puedas crear un objeto a partir de ella. Para eso sirve el constructor: un método especial que se ejecuta con Product(...). En Python es __init__, que ya conoces, solo que ahora recibe parámetros.

shop.py
class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
coffee = Product("Café", 7.50, 2)
print(f"{coffee.name}: {coffee.price * coffee.quantity} €")
Salida
Café: 15.0 €
  • El constructor se llama __init__ (dos guiones bajos antes y dos después), en todas las clases.
  • Su primer parámetro es self: el objeto que se está creando. Python lo pasa por ti.
  • Los demás parámetros son los datos sin los que un producto no puede existir. Los pasas en los paréntesis: Product("Café", 7.50, 2).
  • No devuelve nada. Product(...) devuelve el objeto nuevo.

Ahora no hay forma de olvidar el precio. Si pasas dos argumentos en lugar de tres, el programa se detiene justo en esa línea:

coffee = Product("Café", 7.50)
Error
TypeError: Product.__init__() missing 1 required positional argument: 'quantity'

class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
coffee = Product("Café", 7.50, 2)
print(f"{coffee.name}: {coffee.price * coffee.quantity} €")
Paso a paso, en palabras
  1. Product(...) crea un objeto nuevo. Todavía no tiene campos: los creará __init__.
  2. Se ejecuta __init__. self es el objeto nuevo, y los argumentos van a los parámetros.
  3. self.name = name: del parámetro a un campo nuevo de este objeto.
  4. Lo mismo para el precio y la cantidad.
  5. __init__ termina y los parámetros desaparecen. coffee recibe una flecha al objeto terminado.
  6. El objeto sale de Product(...) ya rellenado, así que el precio no es 0.

La idea

self: el campo de este objeto

Dentro de __init__ hay dos cosas que se llaman name: el parámetro y el campo. name es el parámetro. El campo es self.name.

class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity

self es el objeto que se está creando ahora mismo. self.name = name significa «guarda el parámetro name en el campo name de este objeto».

En Python, self. es obligatorio. Sin él, name = name es solo una variable dentro de __init__, y desaparece en cuanto __init__ termina. El nombre self es una convención, no una palabra clave, pero todo el mundo lo escribe así.

Pruébalo

Encuentra el error

El programa debería imprimir «Té: 3.2 €». En cambio, se detiene con AttributeError: 'Product' object has no attribute 'name'. ¿Qué línea tiene el error?

Elige la línea con el error.

La idea

¿Y el Product() de la lección anterior?

En la lección anterior, __init__ no tenía parámetros aparte de self, así que Product() funcionaba. Ahora __init__ necesita tres argumentos, y sin ellos el programa se detiene:

empty = Product()
Error
TypeError: Product.__init__() missing 3 required positional arguments: 'name', 'price', and 'quantity'

De eso se trata: ya no se puede crear un producto sin nombre ni precio.

Más precisamente, para curiosos

Si una clase no tiene ningún __init__, Product() sigue funcionando: Python crea un objeto sin ningún campo. Por eso en Python los campos siempre se crean en __init__.

La idea

Una cantidad por defecto

La mayoría de los productos del carrito van de uno en uno. Escribir 1 cada vez cansa.

En Python una clase tiene un __init__. En lugar de un segundo constructor, el parámetro recibe un valor por defecto: si no pasas una cantidad, es 1.

class Product:
def __init__(self, name, price, quantity=1):
self.name = name
self.price = price
self.quantity = quantity

quantity=1 (sin espacios alrededor de =) significa «si no se pasa una cantidad, usa 1». Los parámetros con valor por defecto van al final. Si pones un parámetro sin valor por defecto después de quantity=1, Python no ejecuta el archivo:

Error
SyntaxError: parameter without a default follows parameter with a default
Más precisamente, para curiosos

Un segundo __init__ en la clase no crea un segundo constructor. Simplemente reemplaza al primero, sin ningún aviso, y Product("Pan", 1.20) se detiene con:

Error
TypeError: Product.__init__() missing 1 required positional argument: 'quantity'

Por eso Python tiene un solo constructor. La ventaja: si mañana añades una comprobación del precio, está en un solo lugar.

Pruébalo

¿Qué constructor?

¿Qué imprimirá el programa?

class Product:
def __init__(self, name, price, quantity=1):
self.name = name
self.price = price
self.quantity = quantity
bread = Product("Pan", 1.20)
milk = Product("Leche", 2.10, 3)
print(bread.quantity, milk.quantity)
Respuesta

Pruébalo

¿Cómo se llama el constructor?

¿Qué va en el hueco?

class Book:
    def (self, title, author):
        self.title = title
        self.author = author

Ejercicio

Objetos creados completos

Resuélvelos en tu editor. Cada clase recibe un constructor con parámetros para todos sus campos.

1. Persona. Una clase Person con un nombre y una edad. Crea dos personas e imprime sus datos.

Salida
María, 34 años
Pablo, 19 años

2. Animal. Una clase Animal con una especie y una edad. Crea un gato de 3 años y un perro de 7.

Salida
Especie: gato, edad: 3
Especie: perro, edad: 7

3. Paso de baile. Una clase DanceMove con un nombre y una duración en segundos. En la lección «Métodos de instancia», el paso aprenderá a «ejecutarse» solo.

Salida
moonwalk: 5 s

Más práctica

  • Un libro con constructor. Reescribe Book de la lección anterior con un constructor __init__(self, title, author). ¿Cuántas líneas ahorraste en el código de debajo de la clase?
  • Un producto con cantidad por defecto. Product con quantity=1, como en la lección. Haz una lista [Product("Pan", 1.20, 2), Product("Café", 7.50)] e imprime el nombre y la cantidad de cada uno: «Pan x2», «Café x1».
  • Reserva. Una clase Booking con el nombre del huésped, el número de noches y el precio por noche. Imprime cuánto cuesta la estancia: 3 noches a 85 € son 255 €.

Test

Ponte a prueba

1. ¿Cuándo se ejecuta __init__?
2. ¿Cómo se llama el constructor en Python?
3. La clase solo tiene def __init__(self, name, price). ¿Qué pasa con Product()?
4. El __init__ dice self.name = name. ¿Qué es self.name?
5. ¿Cómo da la clase una cantidad de 1 cuando no se pasa ninguna al crear el objeto?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·