POO
Estructura tu código con objetos y clases
Programación Orientada a Objetos en Python
La Programación Orientada a Objetos (POO) es un paradigma de programación que organiza el código en torno a objetos en lugar de funciones y lógica. Python, al ser un lenguaje multiparadigma, ofrece un soporte completo y elegante para la POO. En este tutorial vamos a explorar los conceptos fundamentales de la POO en Python y a entender cómo utilizarlos de forma eficaz en tus programas.
¿Por qué usar la POO?
Antes de entrar en los detalles, es importante entender por qué la POO es tan popular:
- Organización: la POO permite organizar tu código de una manera más estructurada y modular.
- Reutilización: facilita la reutilización del código gracias a la herencia y a la composición.
- Mantenibilidad: un código bien estructurado en objetos suele ser más fácil de mantener y de hacer evolucionar.
- Encapsulación: la POO permite ocultar la complejidad y proteger los datos gracias a la encapsulación.
Clases y objetos
Los dos conceptos fundamentales de la POO son las clases y los objetos.
Clases
Una clase es un modelo o un plano para crear objetos. Define los atributos (variables) y los métodos (funciones) que tendrán los objetos.
Así se define una clase sencilla en Python:
class Personne:
def __init__(self, nom, age):
self.nom = nom
self.age = age
def saluer(self):
return f"Bonjour, je m'appelle {self.nom} et j'ai {self.age} ans."
En este ejemplo:
Personnees el nombre de la clase.__init__es un método especial (constructor) que inicializa un nuevo objeto.selfhace referencia a la instancia del objeto actual.nomyageson atributos.salueres un método.
Objetos
Un objeto es una instancia de una clase. Para crear un objeto, se llama a la clase como si fuera una función:
personne1 = Personne("Alice", 30)
personne2 = Personne("Bob", 25)
print(personne1.saluer()) # Muestra: Bonjour, je m'appelle Alice et j'ai 30 ans.
print(personne2.saluer()) # Muestra: Bonjour, je m'appelle Bob et j'ai 25 ans.
Los objetos personne1 y personne2 son instancias distintas de la clase Personne, cada una con sus propios valores de atributos.
Métodos especiales
Python ofrece varios métodos especiales (también llamados métodos mágicos o métodos dunder, por “double underscore”) que permiten personalizar el comportamiento de los objetos.
class Livre:
def __init__(self, titre, auteur, pages):
self.titre = titre
self.auteur = auteur
self.pages = pages
self.page_actuelle = 0
def __str__(self):
"""Define cómo se representa el objeto como cadena de texto."""
return f"{self.titre} par {self.auteur}"
def __len__(self):
"""Define el comportamiento cuando se aplica la función len() al objeto."""
return self.pages
def __del__(self):
"""Método llamado cuando se elimina el objeto."""
print(f"Le livre {self.titre} a été fermé.")
livre = Livre("Python Facile", "J. Dupont", 200)
print(livre) # Utiliza __str__
print(len(livre)) # Utiliza __len__
del livre # Activa __del__
Herencia
La herencia permite que una clase herede los atributos y métodos de otra clase. Es un concepto fundamental para fomentar la reutilización del código.
class Animal:
def __init__(self, nom):
self.nom = nom
def parler(self):
pass # Método que se sobrescribirá en las clases derivadas
class Chien(Animal):
def parler(self):
return f"{self.nom} dit Woof!"
class Chat(Animal):
def parler(self):
return f"{self.nom} dit Meow!"
animaux = [Chien("Rex"), Chat("Misty")]
for animal in animaux:
print(animal.parler())
En este ejemplo:
Animales la clase base (o clase padre).ChienyChatson clases derivadas (o clases hijas) que heredan deAnimal.- El método
parlerse sobrescribe (se redefine) en cada clase derivada.
Herencia múltiple
A diferencia de otros lenguajes de programación, Python admite la herencia múltiple, lo que permite que una clase herede de varias clases padre.
class A:
def methode_a(self):
return "Méthode de A"
class B:
def methode_b(self):
return "Méthode de B"
class C(A, B): # Hereda de A y B
def methode_c(self):
return "Méthode de C"
objet = C()
print(objet.methode_a()) # Heredado de A
print(objet.methode_b()) # Heredado de B
print(objet.methode_c()) # Definido en C
Encapsulación
La encapsulación es el concepto de agrupar los datos y los métodos que operan sobre ellos, y de restringir el acceso directo a las variables de un objeto.
En Python, la encapsulación se logra por convención más que mediante una aplicación estricta:
class CompteBancaire:
def __init__(self, solde_initial):
self._solde = solde_initial # Convención: atributo protegido (un guion bajo)
self.__compte_id = "123456" # Convención: atributo privado (doble guion bajo)
def deposer(self, montant):
self._solde += montant
def retirer(self, montant):
if montant <= self._solde:
self._solde -= montant
return True
return False
def get_solde(self):
return self._solde
compte = CompteBancaire(1000)
compte.deposer(500)
print(compte.get_solde()) # 1500
print(compte._solde) # Accesible, pero por convención no debería accederse directamente
# print(compte.__compte_id) # Error: renombrado por "name mangling"
print(compte._CompteBancaire__compte_id) # Accesible mediante mangling
En Python:
- Un atributo con un solo guion bajo (
_solde) indica que está protegido (convención, no se aplica). - Un atributo con doble guion bajo (
__compte_id) está sujeto al “name mangling” (renombrado), lo que hace más difícil acceder a él por accidente, pero no es realmente privado.
Polimorfismo
El polimorfismo permite tratar objetos de distintas clases como objetos de una clase común. En Python, el polimorfismo es intrínseco al lenguaje gracias al duck typing.
def faire_parler(animal):
print(animal.parler())
chien = Chien("Rex")
chat = Chat("Misty")
faire_parler(chien) # Rex dit Woof!
faire_parler(chat) # Misty dit Meow!
La función faire_parler funciona con cualquier objeto que tenga un método parler, sin preocuparse de su clase concreta.
Propiedades
Las propiedades permiten controlar el acceso a los atributos de una clase manteniendo una interfaz limpia.
class Temperature:
def __init__(self, celsius=0):
self._celsius = celsius
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("La température ne peut pas être inférieure au zéro absolu.")
self._celsius = value
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
@fahrenheit.setter
def fahrenheit(self, value):
self.celsius = (value - 32) * 5/9
temp = Temperature()
temp.celsius = 25
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")
temp.fahrenheit = 77
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")
Métodos y atributos de clase
A diferencia de los métodos y atributos de instancia, que son propios de cada objeto, los métodos y atributos de clase son compartidos por todas las instancias de la clase.
class Voiture:
# Atributo de clase
nombre_de_voitures = 0
def __init__(self, marque, modele):
self.marque = marque
self.modele = modele
# Incrementar el atributo de clase
Voiture.nombre_de_voitures += 1
@classmethod
def get_nombre_de_voitures(cls):
return cls.nombre_de_voitures
@staticmethod
def est_electrique(marque, modele):
# Un método estático que no depende del estado de la instancia
# Lista ficticia de coches eléctricos
voitures_electriques = [("Tesla", "Model 3"), ("Nissan", "Leaf")]
return (marque, modele) in voitures_electriques
voiture1 = Voiture("Toyota", "Corolla")
voiture2 = Voiture("Honda", "Civic")
print(Voiture.get_nombre_de_voitures()) # 2
print(Voiture.est_electrique("Tesla", "Model 3")) # True
Conclusión
La programación orientada a objetos en Python ofrece una forma potente y flexible de organizar tu código. Te permite crear programas más modulares, reutilizables y mantenibles.
En este tutorial hemos cubierto los conceptos fundamentales de la POO en Python, incluidos las clases, los objetos, la herencia, el polimorfismo y la encapsulación. ¡Pero esto es solo el principio! Existen muchos otros conceptos avanzados y patrones de diseño que pueden ayudarte a sacar el máximo partido a la POO.
En el próximo tutorial exploraremos la gestión de excepciones en Python, un aspecto crucial para escribir programas robustos.
Comentarios
Los comentarios funcionan con GitHub Discussions
Inicia sesión con GitHub para participar en la discusión