Temario
- ¿Qué es la P.O.O?
- Características de la P.O.O
- Algunos Lenguajes Orientados a Objetos
- Ventajas y desventajas de este paradigma
- Ejemplos
- Ejercicios
¿Qué es la Programación Orientada a Objetos?
¿Qué es un objeto?
Ahora hablemos un poco que es la Programación Orientada a Objetos o P.O.O(abrevación), es muy parecida a la programación estructurada, es decir aquí se rescataran muchos conceptos que ya vimos en el capítulo anterior.
Algo de historia
El primer lenguaje P.O.O se llamo simula 67 y fue desarollado por Krinsten Nygaard y Ole-Johan, la invención de este lenguaje era simplificar la gran cantidad de código que se usaba en el paradigma estructurado.
Aun que este paradigma empezo a ganar mucha popularidad cuando en la decada de 1980-1990 los laboratirios de AT&T ampliarón el lenguajes c a C++ el cual ya permitia tener objetos.
Pero es hasta la decada de los 1990 a 2000 que este paradigma se consolido como un paradigma, de hecho en esta decada salierón 3 de los lenguajes orientados a objetos más importantes.
- Java (1995)
- python (1991)
- PHP (1995)
Pero aquí habra nuevos conceptos los cuales hablaremos en más detalle en Características de la P.O.O, por el momento solo los mencionaremos.
¿Por qué son importantes estos conceptos?
Recordemos que en el paradigma estructurado el código se leía de arriba abajo, lo cual estaba perfecto cuando se hacian códigos muy pequeños, sin emargo a medida que el código se expande, la tarea de darle mantenimiento se vuelve muy complicada, debido a la cantidad de lineas que se tienen que revisar y a la gran catidad de funciones que se tiene que revisar.
La solución que se propuso con la P.O.O es dividir todo en diferentes objetos para que asi consulten los atributos y métodos lo cual resulta mucho más fácil que buscar funciones en especifico en un código de más de mil lineas, pero ¿Qué les parece si definimos de mejor manera? cada uno de los conceptos.
Caracteristicas de la P.O.O
Constructor
Ahora veamos como se vería una clase en python, describiendo a una Persona.
##Ejemplo de una clase persona
class Persona:
def __init__(self,nombre,edad,identificacion):
"""
Metodo constuctor muy importante
self es un parametro obligatoro en este lenguaje, y hace referencia al objeto
nombre es un String
edad es un numero entero positivo
identificacion es un String
"""
self.nombre=nombre ###Estos son los atributos de la clase
self.edad=edad
self.identificacion=identificacion
def masEdad(self):
"""
Metodo que nos permite aumentar la edad de una persona
no regresa nada
"""
nuevaEdad=self.edad+1
self.edad=nuevaEdad
def setNombre(self,name):
"""
Metodo que nos permite cambiar el nombre de una persona
"""
self.nombre=name
def setIdentificacion(self, x):
"""
Mertodo que nos permite cambiar la identificación
"""
self.identificacion=x
def verificaPersona(self, codigo):
"""
Metodo que le pasas un codigo y te dice si es el de la persona o no
"""
return self.identificacion== codigo
def __str__(self):
"""
Metodo que nos permite imprimir nuestros objetos, aqui lo unico que debemos escribir es
una cadena de como queremos que se vea en pantalla nuestro objeto
"""
return "El nombre de la persona es " + str(self.nombre) + " su edad es " + str(self.edad) + " su identificacion es " + str(self.identificacion)
Ahora hagamos una lista de sus métodos y de sus atributos
Atributos
- Nombre
- Edad
- Identificación
Métodos
- init()
- másEdad
- setNombres
- setIdentificacion
- verificarPersona
- str()
Revisando los métodos nos podemos dar cuenta por que necesitamos crear objetos, ya que para que nuestros métodos funcionen requerimos de ciertas condiciones, en otras palabras necesitamos poder asegurar que se puedan obtener los datos del nombre, los datos de la identificación y los datos de la edad respectivamente.
Además hay algunos métodos que son particularmente importantes cuando trabajamos con P.O.O
Pero, ahora ¿cómo podemos usar estos métodos que creamos en nuestro código pyhton?, por que para algo los creamos y esto se logra atravez de crear los objetos pero ¿Qué es un objeto?
¿Cómo utilizamos un objeto en python?, muy fácil veamos como podemos crear uno
###Ejemplo de objeto
if __name__ == "__main__": ##Ponemos el main por buena educacion
persona1= Persona("juan",25,"juanito25")##Escribimos el nombre del objeto y entre parentesis
print(persona1)
##Usemos sus metodos
persona1.setIdentificacion("Juanito27")##Modificamos el valor de la identificacion juanito
print (persona1)
for i in range(0,5):
persona1.masEdad()##Aumentamos su edad
print(persona1)
Otro ejemplo :)
class Jugete :
def __init__(self,nombre,marca,precio,fechaLazamiento):
self.nombre=nombre
self.marca=marca
self.precio=precio
self.fechaLazamiento=fechaLazamiento
def jugar(self):
print("jugando")
print("El jugete " + str(self.nombre) + " se siente feliz")
def aumentarPrecio(self,aumento):
print ("El precio aumento en " + str(aumento) )
self.precio+=int(aumento)
def setNombre(self,nuevo):
print("El nombre se actualizo por " + str(nuevo))
self.nombre=nuevo
def getNombre(self):
return self.nombre
def jugeteMasCaro(self, juguete2):
if self.precio < juguete2.precio:
print("El jugete " + str(juguete2.nombre) + " Es mas barato " )
if self.precio == juguete2.precio:
print ("El Precio es igual")
else :
print ("EL juguete " + self.nombre + "es más barato " )
Ahora veamos que la clase juguete y la clase Persona tienen un método que tiene el mismo nombre, esto es muy normal cuando trabajamos con la P.O.O.
Así que tendremos que tener mucho cuidado cuando pase esto debido a que en este caso ambos metodos hacen exactamente lo mismo existiran otros casos donde los código haga cosas totalmente diferentes.
Ejercicio*
- Identifique los atributos y métodos de la clase juguete
- Documente el codigo de la clase juguete
- Haga un método que permita verificar si un juguete es de una determinada marca o no
- Haga un main donde almenos utilize 3 métodos de la clase juguete
Hablemos de otros temas muy importantes para la P.O.O que son 2 de los grandes pilares de la P.O.O que son la herencia y el polimorfismo ambos conceptos son muy parecidos sin embargo este conceptos son muy diferentes como veremos a continuación
Primero hablaremos de la Herencia, existen 2 tipos de herencia, la múltiple y la simple en este curso únicamente abarcaremos herencia simple pero ¿Qué es la herencia?
Tipos de herencia
Ahora veamos un ejemplo practico de como usara, supongamos que tenemos 3 Objetos, un disco común un disco, un disco de música y un disco de Videjuegos veamos como podemos usar la herencia.
class Disco :
def __init__(self,nombre,empresa):
self.nombre=nombre
self.empresa=empresa
def getEmpresa(self):
return self.empresa
def setEmpresa(self,nuevo):
self.empresa=nuevo
def getNombre(self):
return self.nombre
def setNombre(self,nuevo):
self.nombre=nuevo
def empezar(self):
print ("El disco va a empezar a reproducirse")
def __str__(self):
return "El nombre es " + str(self.nombre) + " producido por la empresa " + str(self.empresa)
class Videojuego(Disco) :
def __init__(self,nombre,empresa,consolas,clasificacion, genero):
Disco.__init__(self,nombre,empresa)
self.consolas=consolas
self.clasificacion=clasificacion
self.genero=genero
def jugar(self):
print("Esta jugando el juego " + str (self.nombre) )
print("Piu,Piu , Piu ")
print("Gano yeii")
def getConsola(self):
return self.consolas
def setConsola(self,x):
self.consolas=x
def getClacificacion(self):
return self.clasificacion
def setClacificacion(self,x):
self.clasificacion=x
def getGenero(self):
return self.genero
def setGenero(self,x):
self.genero=x
def __str__(self):
return super().__str__() + " La consolas son " + str(self.consolas) + " Su clacificacion es " + self.clasificacion + " Su genero es " + str(self.genero)
class Musica(Disco):
def __init__(self, nombre, empresa,numCaciones,album):
Disco.__init__(self,nombre, empresa)
self.numCanciones=numCaciones
self.album=album
def reproducir(self):
print("Se esta reproducciendo el album " + str (self.album))
def getNumcaciones(self):
return self.numCanciones
def setNumcaciones(self,num):
self.numCanciones=num
def getAlbum(self):
return self.album
def setAlbum(self,album):
self.album= album
def __str__(self):
return super().__str__() + " El album es " + str(self.album) + " tiene " + str(self.getNumcaciones() )+ " Canciones"
Ahora, tal vez te estes preguntando ¿qué significa el método super()? que aparece en el método __str()__ es una Palabra reservada que indica que el método que estas buscando, no se encuentra dentro de la clase, que el método en cuestion esta siendo heredado por algunos de sus ancetros, en otras palabras se le esta indicando que el método esta siendo heredado por la clase padre.
Aquí, estamos viendo un clase de herencia simple
Donde claramente la clase Padre es Disco y tiene 2 clases hijas cada una independiente sin embargo cada clase hija podría heredar a otra clase y así convertirce en una clase padre como por ejemplo
Se deja como ejercicio hacer las 3 clases hijas de videojuego como ejercicio.
Polimorfismo
Ahora hablemos un concepto que esta muy relacionado con la herencia que se conoce como polimorfismo. Primero recordaremos el sistema de tipos.
Python es un lenguaje débilmente tipado, esto es que no necesitamos declarar el tipo que van a guardar nuestras variables, por ejemplo, en el siguiente código creamos una variable a y le asignamos un valor de tipo entero, y luego un valor de tipo String. Y python va a impirmir ambos valores sin problemas.
¿Qué pasa en otros lenguajes? Por ejemplo C es un lenguaje fuertemente tipado, esto quiere decir que una vez que creamos una variable, esta guarda un valor de un tipo y este no puede cambiar. Por ejemplo si declaramos una variable que guarde el número 10, haríamos algo como: int a = 10; en C y si luego queremos (Como en el ejemplo de abajo) que esta ahora guarde una cadena, tendríamos un error de tipos y el compilador se quejaría-
a = 10
print(a)
a = "Hola"
print(a)
El sistema de tipos entonces, nos importa porque con el polimorfismo, lo relajamos, esto quiere decir, si antes una variable solo podía guardar cosas de un cierto objeto, ahora, una variable puede guardar cosas de ese mismo objeto y de los objetos generados por clases que heredan a nuestro primer objeto
Ahora, la implicación practica de este concepto es poder usar con diferentes objetos el mismo método o poder usar un método con el mismo nombre en diferentes objetos y puedan hacer cosas distintas veamos un ejemplo práctico a continuación
## Ejemplo de polimorfismo
musica1=Musica("MagoOZ","WarnerBros",21,"Ilusia")
juego2=Videojuego("Mario Bros","Nintendo", "Switch","E", "Plataforma")
##Aqui
musica1.empezar()
juego2.empezar()
Hay que notar que si una de las clases Musica o Videojuego tuvieran implementado un método empezar, entonces al momento de mandarlo a llamar, el método que se usaría, sería el que está implementado.
Encapsulamiento
El encapsulamiento de datos consisten en proteger “del exterior” datos que una clase tiene, estos datos pueden ser desde atributos a métodos. En python no existe, pero se puede simular poniendo antes del nombre de los métodos o atributos __, de esta manera indicamos que son especiales.
class A:
__privado__a = "atributo privado"
def __metodo__privado(self, s):
return "privado ", s
Si intentamos llamar a el atributo o al método como lo haríamos normalmente:
a = A()
print(a.__privado_a)
a.__metodo_privado("A")
Nos mandaría un error python diciendo que la clase A no cuenta con ese método ni con ese atributo. ¿Cómo haríamos para llamarlos? Pues necesitamos un método publico dentro de la clase, que nos permita interactuar con los datos (atributos o métodos) privados. por ejemplo hagamos otra clase:
class B:
__privado_b = "atributo privado de B"
def __metodo_privado(self, s):
return "privado de", s
def metodo_publico(self,s):
return self.__metodo_privado(s)
def atributo(self):
return self.__privado_b
En este caso, tenemos dos métodos, uno que llama al atributo y otro que llama al método privado, probemos para ver cómo es que python ahora nos regresa el valor del atributo y también cómo puede mandar a llamar a un método privado desde el método público.
b = B()
print(b.atributo())
print(b.metodo_publico("B"))
En otros lenguajes por ejemplo Java, podríamos ver el hecho de crear un método público que interactúe con atributos privados como getters y setters y usando palabras reservadas.
Ahora veamos un ejemplo de una calculadora básica, la cuál contendrá un atributo privado que será una constante. Nuetras operaciones con la calculadora tendrán que ver con esa constante, es decir, si queremos sumar dos números, entonces sumamos la constante (Que es el atributo privado) y el argumento que pasamos.
class CalcCons:
__constante = 0
constante_pub = 1
def cambia_constante(self, n):
self.__constante = n
def constante(self):
return self.__constante
def suma(self,n):
return self.__constante + n
calculadora = CalcCons()
a = calculadora.constante() # debería regresar 0
print(a)
a = calculadora.suma(9) # debería regresar 9
print(a)
calculadora.cambia_constante(9)
a = calculadora.constante() # debería regresar 9
print(a)
a = calculadora.suma(9) # debería regresar 18
print(a)
Nota que si tenemos un atributo que no comienza con __, entonces podemos acceder a él desde la creación del objeto, y accediendo con el operador ‘.’ (punto) para actualizarlo, por ejemplo, si quisiéramos cambiar la variable ‘constante_pub’, bastaría con hacer lo siguiente:
print(calculadora.constante_pub)
calculadora.constante_pub = 8
print(calculadora.constante_pub)
Ejercicios
- Crea una clase ‘A’ que tenga el método =__init__= tenga 2 argumentos.
- Crea una clase ‘B’ que herede de la clase ‘A’ y reciba más argumentos, usa la herencia para usar 2 de esos argumentos en el constructor de la clase ‘A’
- Crea un método ‘a1’ en la clase ‘A’ que tome dos argumentos y haga algo con ellos (puede ser una suma, una concatenación, etc).
-
Cuando crees un objeto instancia de la clase ‘B’, manda a llamar al método ‘a1’ con este, ¿Qué pasa?
-
Crea una clase ‘C’ que herede de la clase ‘B’ ¿Como harías que el constructor herede de la clase B?. ¿Puedes mandar a llamar al método ‘a1’ con una instancia de la clase ‘C’?
- Crea un método ‘a2’ en la clase ‘A’ y un método ‘a2’ en la clase ‘B’, mánda a llamar al método ‘a2’ desde la clase ‘C’. ¿Cuál método es el que se ejecuta?