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 = 2print(f"{coffee.name}: {coffee.price * coffee.quantity} €")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.
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} €")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)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
- Product(...) crea un objeto nuevo. Todavía no tiene campos: los creará __init__.
- Se ejecuta __init__. self es el objeto nuevo, y los argumentos van a los parámetros.
- self.name = name: del parámetro a un campo nuevo de este objeto.
- Lo mismo para el precio y la cantidad.
- __init__ termina y los parámetros desaparecen. coffee recibe una flecha al objeto terminado.
- 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 = quantityself 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
AttributeError: 'Product' object has no attribute 'name'. ¿Qué línea tiene el error?Elige la línea con el error.
name = name guarda el parámetro en sí mismo. El campo name nunca se crea, así que tea.name no existe. Necesitas self.name = name. El error solo aparece en la línea que lee el nombre, lejos de la causa real.
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()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 = quantityquantity=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:
SyntaxError: parameter without a default follows parameter with a defaultMá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:
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)Product("Pan", 1.20) no tiene cantidad, así que quantity toma el valor por defecto 1. Para la leche se pasa la cantidad: 3.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__init__: es el nombre del constructor en todas las clases, con dos guiones bajos a cada lado.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.
María, 34 añosPablo, 19 años2. Animal. Una clase Animal con una especie y una edad. Crea un gato de 3 años y un perro de 7.
Especie: gato, edad: 3Especie: perro, edad: 73. 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.
moonwalk: 5 sMás práctica
- Un libro con constructor. Reescribe
Bookde 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.
Productconquantity=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
Bookingcon 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
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Listas · Funciones · Parámetros y return · Clases y objetos
- Continúa en: Métodos de instancia · Encapsulamiento · Lo que comparten todos los objetos: atributos de clase · Herencia
- Ejercicios sobre el tema: Clases y objetos