Aprende leyendo en orden

Clases e instancias — Definir tu propio tipo

Aprende las clases e instancias de Python desde cero. Recorre las definiciones de class, el papel de self y el uso de __init__ para establecer atributos, todo con diagramas.

Como ya mencionamos en el resumen anterior, los tipos integrados como int, str, list y dict no pueden representar directamente conceptos de negocio como "usuario", "producto" o "pedido". El siguiente paso es definir tu propio tipo con class: ese es el punto de entrada a la programación orientada a objetos (POO).

¿Por qué programación orientada a objetos?

Todo lo que has escrito hasta ahora es procedimental: combinar funciones para impulsar el comportamiento. A medida que los programas crecen, los datos relacionados y la lógica que opera sobre ellos tienden a dispersarse, y los cambios y la reutilización se vuelven más difíciles.

Con la programación orientada a objetos (POO) agrupas los datos relacionados (atributos) y las operaciones sobre ellos (métodos) en una única unidad: un objeto. Eso te permite dar forma a tu código en torno a conceptos del mundo real.

Procedimental vs POO — Cómo se relacionan los datos y las funciones
ProcedimentalDatos(variables)Funciones(en otro lugar)POOObjetodatos + métodosAgrupadosjuntosseparadosresultado
En el código procedimental, los datos y las funciones viven en lugares completamente separados, y pasas los datos a las funciones cada vez como function(data). La POO pone ambos dentro de un objeto para que vivan juntos.

Una clase es un plano, una instancia es la cosa real

Dos términos anclan todo en POO:

- Clase: un plano que enumera los atributos y métodos que tendrás

- Instancia: la cosa real construida a partir de ese plano

Por ejemplo, define una clase Product para capturar el concepto de producto y podrás crear tantas instancias individuales de productos —apple, banana, orange— como necesites. Juntas, las clases y las instancias se denominan objetos.

Construir múltiples instancias a partir de una sola clase
Product(clase)applename='apple'banananame='banana'orangename='orange'crearcrearcrear
Una clase es como una plantilla: no la usas directamente. Las instancias que nacen de ella son las que realmente contienen datos y sobre las que se llaman métodos.

Definir una clase mínima

Vamos a definir realmente una clase Product para los artículos de una tienda. La sintaxis es class NombreDeClase:. Por convención, los nombres de clase en Python usan CapitalizedCamelCase (Product, UserAccount, etc.).

Una variable escrita directamente dentro de la clase, como name = "apple", se trata como un valor por defecto que la clase contiene, y puedes leerla a través del nombre de la clase como Product.name.

class Product:
    name = "apple"
    price = 150

# Acceder directamente a la clase
print(Product.name)    # apple
print(Product.price)   # 150
Variables que se adhieren a la clase — Variables de clase
Product(cuerpo de clase)name='apple'price=150contienecontiene
Las variables que escribes justo bajo classname / pricese adhieren a la propia clase y se pueden leer directamente a través del nombre de la clase como Product.name.

Las variables escritas directamente bajo class se llaman variables de clase. Se comportan de forma diferente a las variables de instancia (que cada instancia posee por separado), pero volveremos a esa distinción en un artículo posterior. Por ahora, lo único que necesitas es la idea mínima: "adhiere un valor a la propia clase y luego léelo como Product.name".

Construye una pequeña clase para inventario.

① Define class Product:.

② Dentro, añade tres valores: name = "apple", price = 150 y stock = 10.

③ Ejecuta print(Product.name) / print(Product.price) / print(Product.stock) y confirma que puedes leer cada valor directamente desde el nombre de la clase.

(Si lo ejecutas correctamente, aparecerá una explicación.)

Editor Python

Ejecutar el código para ver el resultado

Usa __init__ para dar a cada instancia sus propios valores

La clase mínima anterior solo adhirió un valor fijo como name = "apple" a la clase, así que cada instancia que construyas sería "apple". En código real quieres múltiples instancias a partir de una sola clase —apple, banana, orange— cada una con sus propios valores.

La herramienta para esto es el método especial de Python __init__, también conocido como constructor o inicializador. Cuando llamas a Product("apple", 150) con argumentos, Python llama automáticamente a __init__, y dentro de él escribes self.name = name para almacenar valores en la propia instancia.

Doble guión bajo — Una convención de Python

Los nombres envueltos en doble guión bajo como __init__ se llaman métodos dunder. Python les da un significado especial y los llama automáticamente en ciertos momentos: __init__ cuando se crea una instancia, __str__ cuando se imprime algo, etc. Cubriremos __init__ con más profundidad y conoceremos __del__ en el próximo artículo.

Qué ocurre cuando llamas a Product("apple", 150)
apple = Product( 'apple', 150)__init__(self, name, price)self.name = nameself.price = priceapplename='apple', price=150auto-llamadaasignarlisto
Llamar a Product("apple", 150) hace que Python ① prepare una instancia vacía, ② la pase a __init__ como self, y ③ escriba los argumentos en los atributos de esa instancia, dejándote con un objeto terminado.
class Product:
    def __init__(self, name, price):    # Llamado automáticamente al crear una instancia
        self.name = name
        self.price = price

apple = Product("apple", 150)
banana = Product("banana", 80)

print(apple.name, apple.price)     # apple 150
print(banana.name, banana.price)   # banana 80

# apple y banana son objetos diferentes
print(apple is banana)             # False
Muchas instancias a partir de una sola clase
Product(clase)applename='apple', price=150banananame='banana', price=80orangename='orange', price=120
Cada llamada a Product(...) crea un objeto separado. apple, banana y orange provienen del mismo plano pero son objetos diferentes, cada uno con su propio name / price.

Escribe una clase Product con __init__ y crea múltiples instancias.

① Define class Product:. Dentro de def __init__(self, name, price):, escribe self.name = name y self.price = price.

② Crea dos instancias: apple = Product("apple", 150) y banana = Product("banana", 80).

③ Ejecuta print(apple.name, apple.price) y print(banana.name, banana.price) y confirma que cada una lleva sus propios valores.

(Si lo ejecutas correctamente, aparecerá una explicación.)

Editor Python

Ejecutar el código para ver el resultado

Cómo funcionan los métodos y self

Los atributos por sí solos solo "contienen datos": no muy diferente de un dict simple. El verdadero objetivo de la POO es que también puedes escribir operaciones sobre la instancia junto con los datos. Esas operaciones se llaman métodos.

Las reglas para los métodos y self
class Product:def show(self): ...1er parámetroself (obligatorio)la instanciaque llama se pasaautomáticamenteself.name→ acceso a atributodentrodeclararvalorvía
Una función escrita dentro de una clase con def es un método. El primer parámetro self es obligatorio, y en cada llamada Python lo rellena con la instancia desde la que se llamó al método. Dentro del método, escribe self.name para acceder a los atributos de esa instancia.

Cuando escribes apple.show(), internamente Python ejecuta Product.show(apple): self acaba conteniendo apple.

self siempre apunta a quien llama
Módulo
  • apple y banana son instancias separadas
  • Cuando llamas a apple.show()
frame de show(self)
  • self se rellena con apple automáticamente
  • self.name lee apple.name
  • Para banana.show(), self se convierte en banana
self no es un valor fijo: es la instancia desde la que llamaste al método. Con el mismo método show, llamar desde apple lee el name de apple, llamar desde banana lee el de banana.
class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def show(self):                         # El primer parámetro siempre es self
        print(f"{self.name}: ${self.price}")

apple = Product("apple", 150)
banana = Product("banana", 80)

apple.show()    # apple: $150  internamente igual que Product.show(apple)
banana.show()   # banana: $80   internamente igual que Product.show(banana)
self se decide cuando se llama al método
apple.show()self = appleapple: $150banana.show()self = bananabanana: $80pasasalidapasasalida
Llamar a apple.show() pone apple en self, mientras que llamar a banana.show() pone banana en self. El mismo método show se ejecuta con un self diferente cada vez, según quien lo llame.

Añade un método a Product y llámalo a través de una instancia.

① Define class Product: con __init__(self, name, price) que establece self.name / self.price.

② Dentro de la clase, define def show(self): que imprime f"{self.name}: ${self.price}".

③ Construye apple = Product("apple", 150) y banana = Product("banana", 80), luego llama a apple.show() y banana.show() para confirmar que el mismo método se ejecuta con los valores de cada instancia.

Editor Python

Ejecutar el código para ver el resultado

self es solo una convención

Sintácticamente, el primer parámetro puede ser cualquier cosa: def show(this): también funciona. Pero casi todas las bases de código de Python usan self, así que cíñete a ello. Cualquier otra cosa despista a los lectores.

En este artículo aprendiste los fundamentos de la programación orientada a objetos. Cubriremos las variables y los métodos con más profundidad en artículos posteriores.

QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Cuál de las siguientes es la forma correcta de definir una clase de Python?

Pregunta 2¿Qué se pasa automáticamente al primer parámetro self de un método cuando se le llama?

Pregunta 3¿Qué imprime el siguiente código?
class P:
def __init__(self, x):
self.x = x
a = P(10)
b = P(20)
print(a.x + b.x)