POO en Python
Tags: python, spanish
Published: 2023-03-06 03:03:18

La programación orientada a objetos (POO) es un paradigma de programación que se centra en la creación de objetos y clases que contienen datos y funciones para interactuar con esos datos. En Python, POO es una de las características más importantes del lenguaje y se utiliza ampliamente en la creación de aplicaciones y sistemas.

En este artículo, exploraremos la POO en Python en profundidad, cubriendo los conceptos clave de la programación orientada a objetos, incluyendo clases, objetos, herencia, polimorfismo y encapsulamiento. También revisaremos algunos ejemplos prácticos de POO en Python.

## Clases y objetos
En POO, una clase es un plano o modelo para un objeto. Define los atributos y métodos que un objeto puede tener. Un objeto, por otro lado, es una instancia de una clase. Se crea una clase con la palabra clave **class** seguida del nombre de la clase.

```python
class Persona:
    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

    def presentarse(self):
        print(f"Hola, mi nombre es {self.nombre} y tengo {self.edad} años.")
```

En el ejemplo anterior, creamos una clase **Persona** que tiene dos atributos, **nombre** y **edad**, y un método **presentarse** que imprime un saludo con el nombre y la edad de la persona. La función **init** es el constructor de la clase que se llama cuando se crea una nueva instancia de la clase. En este caso, toma dos argumentos, **nombre** y **edad**, y establece los valores correspondientes de los atributos.

Para crear una instancia de la clase **Persona**, simplemente llamamos al nombre de la clase con los argumentos necesarios:

```python
p = Persona("Juan", 30)
p.presentarse()
```

El resultado de esta llamada sería:
`Hola, mi nombre es Juan y tengo 30 años.`

## Herencia
La herencia es una técnica en POO que permite que una clase herede atributos y métodos de una clase padre o superclase. En Python, una clase hereda de otra usando la siguiente sintaxis:

```python
class Empleado(Persona):
    def __init__(self, nombre, edad, salario):
        super().__init__(nombre, edad)
        self.salario = salario

    def presentarse(self):
        super().presentarse()
        print(f"Soy un empleado y mi salario es de {self.salario}.")
```

En este ejemplo, creamos una clase **Empleado** que hereda de la clase **Persona** y agrega un nuevo atributo **salario** y un método **presentarse** modificado que incluye información sobre el salario.

La función super() se utiliza para llamar al método __init__ de la clase padre, que establece los atributos heredados. Luego, se establece el nuevo atributo salario en la clase hija.

## Polimorfismo
El polimorfismo es la capacidad de un objeto de tomar varias formas. En POO, el polimorfismo se logra mediante la sobreescritura de métodos de una superclase en una subclase. En Python, esto se puede hacer fácilmente de la siguiente manera:

```python
class Vehiculo:
    def moverse(self):
        print("El vehículo se está moviendo.")

class Auto(Vehiculo):
    def moverse(self):
        print
```

En este ejemplo, creamos dos clases, **Vehiculo** y **Auto**. La clase Vehiculo tiene un método **moverse**, que imprime un mensaje. La clase Auto hereda de la clase Vehiculo y sobrescribe el método moverse para imprimir un mensaje diferente.

Cuando llamamos al método moverse en una instancia de la clase Auto, se ejecuta el método sobrescrito de la clase Auto en lugar del método de la clase Vehiculo original:

```python
v = Vehiculo()
v.moverse()  # El vehículo se está moviendo.

a = Auto()
a.moverse()  # El auto está en movimiento.
```

## Encapsulamiento
El encapsulamiento es el proceso de ocultar detalles de implementación de un objeto a otros objetos. En Python, esto se logra a través de la convención de nombres. Los atributos y métodos que comienzan con dos guiones bajos "__" se convierten en atributos y métodos privados, lo que significa que solo se pueden acceder desde dentro de la clase.

```python
class CuentaBancaria:
    def __init__(self, nombre, saldo):
        self.__nombre = nombre
        self.__saldo = saldo

    def depositar(self, cantidad):
        self.__saldo += cantidad

    def retirar(self, cantidad):
        if cantidad > self.__saldo:
            print("No hay suficiente saldo en la cuenta.")
        else:
            self.__saldo -= cantidad

    def obtener_saldo(self):
        return self.__saldo
```

En este ejemplo, creamos una clase **CuentaBancaria** que tiene dos atributos privados, __nombre y __saldo. También tiene métodos públicos para depositar, retirar y obtener el saldo de la cuenta.

Cualquier intento de acceder a los atributos privados desde fuera de la clase resultará en un error:

```python
c = CuentaBancaria("Juan", 1000)
print(c.__saldo)  # Error!
```

Para acceder a los atributos privados, es necesario utilizar métodos públicos como **obtener_saldo**:

```python
c = CuentaBancaria("Juan", 1000)
print(c.obtener_saldo())  # 1000
```

## Conclusiones
La POO es una técnica de programación poderosa y versátil que se utiliza ampliamente en Python y otros lenguajes de programación. En Python, las clases y objetos se definen con la palabra clave **class** y se pueden heredar, sobrescribir y encapsular para crear aplicaciones complejas y fáciles de mantener.

En este artículo, hemos revisado los conceptos clave de la POO en Python, incluyendo clases, objetos, herencia, polimorfismo y encapsulamiento. También hemos proporcionado algunos ejemplos prácticos de cómo utilizar estos conceptos en la creación de aplicaciones Python.