# T.1.2.3 Programación orientada a objetos en Python
Como en todos los aspectos de la programación (codigo secuencial, condicional, repetitivo, etc.) es necesario aprender los conceptos de la programación orientada a objetos lo mismo que permita utilizarla de manera efectiva.
En este taller se decriben ejemplos muy básicos de la programación orientado objeto.
## Todo es un objeto
Como se ha descrito el lenguaje de programación Python todo es manejado como un objeto. Copie el siguiente código en nuevo archivo denominado `pooEjemplo1.py` y luego analice su resultado.
A continuación un ejemplo del mismo.
```Python=
cosa = list()
cosa.append('B-datos')
cosa.append('A-datos')
cosa.sort()
print (cosa)
print (cosa[0])
print (cosa.__getitem__(0)) ##tradición verbosa.
```
El resultado se muestra a continuación
```
['A-datos', 'B-datos']
A-datos
A-datos
```
Ahora en la consola de Python digite lo siguiente función:
```powershell
In [1]: dir(cosa)
```
Las salida respectiva muestra las capacidades del objeto cosa y es notable que hereda propiedades y métodos del objeto prinicipal list().
```powershell
Out[37]:
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__gt__',
'__hash__',
'__iadd__',
'__imul__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__rmul__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
```
## Clase vehículo
A continuación se muestra la clase vehículo en donde se específica cada uno de los componentes descritos en clase como son: constructor, métodos, atributos de instancia y atributos de clases. Proceda a crear un nuevo programa y copie el código siguiente y guarde con el nombre `pooClaseVehiculo.py`.
```Python=
class Vehiculo:
ruedas=4
def __init__(self, color, aceleracion):
self.color=color
self.aceleracion=aceleracion
self.velocidad = 0
def acelera(self):
self.velocidad=self.velocidad+self.aceleracion
def frena(self):
v = self.velocidad= self.aceleracion
if v < 0:
v=0
self.velocidad=v
```
Una vez guardado el programa anterior proceda a crear un nuevo programa y escriba un nombre al archivo como por ejemplo: `pooEjemplo2.py` y copie el código siguiente.
```Python=
#primer formato: import file.py
import pooClaseVehiculo
c1 = pooClaseVehiculo.Vehiculo('rojo', 20)
c2 = pooClaseVehiculo.Vehiculo('amarillo', 30)
print(c1.color)
print(c2.color)
# Segundo formato: from file.py import clase
from pooClaseVehiculo import Vehiculo
c1 = Vehiculo('verde', 30)
c2 = Vehiculo('azul', 40)
print(c1.color)
print(c2.color)
# Tercer formato: from file.py import clase as alias
from pooClaseVehiculo import Vehiculo as v
c1 = v('negro', 40)
c2 = v('blanco', 50)
print(c1.color)
print(c2.color)
```
Ejecute el código y verifique que la salida sea similar a la siguiente:
```powershell
In [3]: runfile('F:/MasterIoT/BasicPython/pooEjemplo2.py', wdir='F:/MasterIoT/BasicPython')
Reloaded modules: pooClaseVehiculo
rojo
amarillo
verde
azul
negro
blanco
```
Como pudo notar existen diferentes mecanimos para instanciar la clase previamente definida. En cualquiera de los tres formatos los resultados serán de acuerdo a lo declarado en cada instancia.
## Atributos de clase y de instancia
En una clase existen dos tipos diferentes de atributos de datos: atributos de clase y atributos de instancia.
* Los atributos de clases son variables compartidas por todas las instancias de esa clase.
* Los atributos de instancia, se diferencia de los anteriores porqué son únicos para cada uno de los objetos que pertenecen a dicha clase.
En el ejemplo de la clase "Vehiculo", ruedas se ha definido como un atributo de clase, mientras que color, aceleracion y velocidad son atributos de instancia.
Para referenciar a un atributo de clase se utiliza, generalmente, el nombre de la clase. Al modificar un atributo de este tipo, los cambios se verán reflejados en todas y cada una las instancias. Copie el siguiente código y cree un nuevo programa dicho programa puede ser `pooEjemplo3.py`.
```Python=
from pooClaseVehiculo import vehiculo as v
c1 = v('negro', 15)
c2 = v('blanco', 15)
print(c1.color)
print(c2.color)
print('El atributo de la clase c1 es: ', c1.ruedas)
print('El atributo de la clase c2 es: ', c2.ruedas)
print('--------------------------------------------')
v.ruedas=2
print('El atributo de la clase c1 es: ', c1.ruedas)
print('El atributo de la clase c2 es: ', c2.ruedas)
print('--------------------------------------------')
c2.ruedas=3
print('El atributo de la clase c1 es: ', c1.ruedas)
print('El atributo de la clase c2 es: ', c2.ruedas)
```
Los resultados obtenidos se puede evidenciar en la salida siguiente:
```powershell
In [4] runfile('F:/MasterIoT/BasicPython/pooEjemplo3.py', wdir='F:/MasterIoT/BasicPython')
Reloaded modules: pooClaseVehiculo
negro
blanco
El atributo de la clase c1 es: 4
El atributo de la clase c2 es: 4
--------------------------------------------
El atributo de la clase c1 es: 2
El atributo de la clase c2 es: 2
--------------------------------------------
El atributo de la clase c1 es: 2
El atributo de la clase c2 es: 3
```
El resultado muestra qué la instancia vehículo ha tomado los siguientes comportamientos:
* En la primera parte ambas instancias el atributo rueda es de 4.
* Luego se realiza un cambio y ambas toman un valor 2.
* Finalmente, la instancia número c2 su atributo de instancia ha sido cambiado por 3 para las ruedas.
## Herencia en Python
La herencia es la capacidad de reutilizar una clase extendiendo sus funcionalidad, por lo qué se puede crear una clase a partir de los métodos y propiedades de una clase padre. Además, se puede agregar nuevos métodos o redefinir los ya existentes, y crear nuevos atributos.
A continuación, proceda a crear una nueva clase, esta clase hereda las características y funcionalidades de la clase vehículo. La clase nueva a crear la vamos a llamar `pooClaseVehiculoVolador.py` , y luego copie el siguiente código:
```Python=
from pooClaseVehiculo import Vehiculo
class VehiculoVolador(Vehiculo):
ruedas = 6
def __init__(self, color, aceleracion, esta_volando=False):
super().__init__(color, aceleracion)
self.esta_volando = esta_volando
def vuela(self):
self.esta_volando = True
def aterriza(self):
self.esta_volando = False
```
Como se puede apreciar en la línea número 3 la clase nueva recibe la clase vehículo lo que significa que va a tomar la funcionalidad de dicha clase.
En la línea número 6 al invocar la palabra reservada `super()`. Esta función devuelve un objeto temporal de la superclase que permite invocar a los métodos definidos en la misma. Lo que está ocurriendo es que se está redefiniendo el método __init__() de la clase hija usando la funcionalidad del método de la clase padre. Como la clase `vehiculo` es la que define los atributos color y aceleracion, estos se pasan al constructor de la clase padre y, a continuación, se crea el atributo de instancia `esta_volando` solo para objetos de la clase `VehículoVolador`.
A continuación un ejemplo en donde al utilizar la herencia, los atributos y métodos de la clase padre también pueden ser referenciados por objetos de la clase hija. Por lo contrario, la clase hija al padre no tendría igual comportamiento. Copie el código y cree un nuevo archivo cuyo nombre puede ser `pooEjemplo4.py`.
```Python=
from pooClaseVehiculoVolador import VehiculoVolador as vVolador
c1 = vVolador('rojo', 30)
print("El tipo de vehículo es un Hexacoptero porque tiene = " , c1.ruedas)
c1.vuela()
print("El Hexacoptero se encuentra volando = " , c1.esta_volando)
c1.acelera() #Por herencia accede al método aceleración
print("El Hexacoptero se encuentra acelerando con una velocidad de: " , c1.velocidad)
c1.frena() #Por herencia accede al método de franado "frena()"
print("El Hexacoptero ha frenado y su velocidad es = " , c1.velocidad)
c1.aterriza()
print("El Hexacoptero se encuentra volando = " , c1.esta_volando)
```
El resultado se muestra acontinuación:
```powershell
In [4] =
El tipo de vehículo es un Hexacoptero porque tiene = 6
El Hexacoptero se encuentra volando = True
El Hexacoptero se encuentra acelerando con una velocidad de: 30
El Hexacoptero ha frenado y su velocidad es = 0
El Hexacoptero se encuentra volando = False
```
:::info
:bulb: **Tarea**: Se le solicita que realice dos clases:
1. La primera clase con nombre **Sensors** dicha clase tendrá los métodos que devuelven: temperatura, humedad, y la fecha-hora del sistema. La idea general es que el valor devuelto de temperatura y humedad sean valores randomicos.
1. La segunda clase herera los métodos de la clase **Sensors** y agrega los métodos de latitud y longitud. Esta última clase se la puede llamar **SensorGPS**.
:::
----
```Python=
```
```powershell
In [4]
```