Como muchos saben Python es un lenguaje multiparadigma; Esto quiere decir que podemos realizar con el mismo lenguaje programación estructurada, programación orientada a objetos y programación funcional.
Hasta el momento en el blog solo he usado programación estructurada ya que es mas fácil para realizar programas sencillos como los que he hecho hasta el momento pero me parece oportuno comenzar a practicar la programación orientada a objetos ó OOP por sus siglas en ingles.
Que mejor para desempolvar mis conocimientos sobre el tema que leyendo esta conversación que encontré en un
blog muy interesante.
En la programación orientada a objetos, todo se reduce, como su nombre lo indica, a los objetos y sus relaciones entre ellos.
Los objetos tal como en el mundo real pueden ser, por ejemplo, una lampara, un carro, un perro. En la conversación hacen el ejemplo con un radio.
Un radio tiene, entre otras cosas, algo que permite seleccionar la emisora o frecuencia y algo para modificar el volumen, estas son las propiedades del objeto las cuales básicamente lo definen. Podríamos incluir otras propiedades como el ancho y el alto del radio o el color, la marca, y muchas mas; Pero para este ejemplo esas son las propiedades que nos interesan.
las propiedades tienen un valor. La frecuencia podría ser 97.9, el volumen = 50, el ancho=20 y así con todas las propiedades.
Cuando nosotros cambiamos la frecuencia de un radio o subimos el volumen, normalmente no estamos interesados en lo que ocurre al interior del objeto. Solo nos interesa saber que si presionamos un botón alguna acción va a ocurrir.
Los botones de subir y bajar volumen, o el de modificar la emisora podemos llamarlos como los métodos del objeto. Los métodos son el algo que realiza una tarea sobre el objeto, como modificar sus propiedades. Por ejemplo, Un método del objeto radio podría ser "subir volumen" y lo que hace es modificar la propiedad "volumen".
Los objetos son definidos por medio de clases, Las clases vienen siendo como una plantilla de objetos. Es decir, que si yo tengo la clase radio con sus atributos y métodos puedo crear las radios que quiera con las mismas características.
Vamos a crear nuestra clase radio
class Radio:
def __init__(self):
self.volumen = 10
self.frecuencia = 90
Con esas lineas creamos la clase llamada Radio.
__init__ es un método especial. Este se ejecuta cuando se crea un objeto nuevo. Quiere decir que cuando creemos un objeto desde la clase radio, lo primero que se ejecuta va a ser el método __init__ el cual, a su vez, crea unos atributos llamados volumen y frecuencia y les asigna un valor.
Ahora vamos a crear un objeto. Ponemos el siguiente código:
class Radio:
def __init__(self):
self.volumen = 10
self.frecuencia = 90
mi_radio = Radio()
print mi_radio.volumen
Lo que hicimos fue crear el objeto mi_radio e imprimir el atributo volumen de ese objeto. Como en la clase radio le asigne un valor por defecto a volumen, muy seguramente la salida sera:
>> 10
También podría modificar las propiedades de mi objeto. Por ejemplo:
class Radio:
def __init__(self):
self.volumen = 10
self.frecuencia = 90
mi_radio = Radio()
mi_radio.volumen=45
mi_radio.frecuencia=97.9
print mi_radio.volumen
print mi_radio.frecuencia
y mi salida sera:
>> 45
>> 97.9
En esta caso modificamos las propiedades del objeto pero no tiene sentido modificar el código para modificar un atributo de un objeto. Lo correcto seria crear nuestro primer método que haces las veces de "botón" de nuestro radio. Así que vamos a crear un método que suba el volumen el cual quedaría de la siguiente manera:
class Radio:
def __init__(self):
self.volumen = 10
self.frecuencia = 90
def subir_volumen(self):
self.volumen +=1
mi_radio = Radio()
print mi_radio.volumen
mi_radio.subir_volumen()
print mi_radio.volumen
Esto nos daría como salida:
>> 10
>> 11
Lo cual es justo lo que queríamos En vez de modificar directamente las propiedades, creamos un método que lo hiciera por nosotros.
Si quisiera elegir el volumen y la frecuencia (atributos) al momento de crear mi objeto, mi código seria el siguiente.
class Radio:
def __init__(self,vol,frec):
self.volumen = vol
self.frecuencia = frec
def subir_volumen(self):
self.volumen +=1
mi_radio = Radio(20,94.9)
print mi_radio.volumen
print mi_radio.frecuencia
Mi salida seria:
>> 20
>> 94.9
Es bastante obvio que en el método
__init__ le digo que al momento de crear un objeto Radio le tengo que pasar 2 argumentos tal como hice. Pero si al momento de crear el objeto no le pongo atributos daría un error, por lo que es conveniente ponerle unos valores por defecto a los atributos de la siguiente manera:
class Radio:
def __init__(self,vol=10,frec=97.9):
self.volumen = vol
self.frecuencia = frec
def subir_volumen(self):
self.volumen +=1
mi_radio = Radio()
print mi_radio.volumen
print mi_radio.frecuencia
como no asigne nada a mi_radio = Radio() la salida sera
>> 10
>> 97.9
porque las asigne por defecto en la clase. También podría solo haber pasado un argumento así:
mi_radio = Radio(50)
y mi salida seria
>> 50
>> 97.9
Si quisiera solo asignar la frecuencia y dejar el volumen por defecto tendría que especificar el nombre del atributo
mi_radio = Radio(frec=104.9)
y la salida seria:
>> 10
>> 104.9
Ahora como ejercicio voy a modificar la clase Radio de tal manera que el método
subir_volumen me permita escoger cuanto quiero subir y si no le digo cuanto, me suba 1.
class Radio:
def __init__(self,vol=10,frec=97.9):
self.volumen = vol
self.frecuencia = frec
def subir_volumen(self,aumento=1):
self.volumen +=aumento
mi_radio = Radio()
mi_radio.subir_volumen(10)
print mi_radio.volumen
salida:
>> 20
Ahora vamos a observar otro método especial llamado __str__.
Si hacemos la prueba de imprimir un objeto por medio del siguiente código:
class Radio:
def __init__(self,vol=10,frec=97.9):
self.volumen = vol
self.frecuencia = frec
def subir_volumen(self,aumento=1):
self.volumen +=aumento
mi_radio = Radio()
print mi_radio
nos va a salir esto:
>> <__main__.Radio instance at 0x011F4940>
Esto nos dice que "mi_radio" es una instanciación de la clase Radio.
Mediante el método
__str__ podemos indicar que queremos mostrar en el momento que se le haga un print al objeto mi_radio o a cualquier instancia de la clase Radio.
Voy a poner el mismo ejemplo de la conversación:
class Radio:
def __init__(self,vol=10,frec=97.9):
self.volumen = vol
self.frecuencia = frec
def subir_volumen(self,aumento=1):
self.volumen +=aumento
def __str__(self):
return "Volumen: " + str(self.volumen) + "\nFrecuencia: " + str(self.frecuencia)
mi_radio = Radio()
print mi_radio
Mi salida sera
>>Volumen: 10
>>Frecuencia: 97.9
____________________________________________________________
Vamos a practicar un poco. Voy a realizar una clase que me permita crear un punto con sus correspondientes coordenadas X y Y, si no le paso argumentos al momento de crear el objeto que me de un punto en (0,0). Ademas crear un método
__str__ que me muestre las coordenadas del punto.
Codigo:
class punto:
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return '('+str(self.x)+','+str(self.y)+')'
a=punto(4,3)
print a
Ahora voy le voy a agregar un método que me sume otro punto a mi punto existente.
Codigo:
class punto:
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return '('+str(self.x)+','+str(self.y)+')'
def sumarpuntos(self,b):
return punto(self.x+b.x,self.y+b.y)
a=punto(4,3)
b=punto(5,7)
c=a.sumarpuntos(b)
print c
Podría realizarlo de otra manera usando un método especial llamado __add__
Codigo:
class Punto:
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return '('+str(self.x)+','+str(self.y)+')'
def __add__(self,b):
return Punto(self.x+b.x,self.y+b.y)
a=Punto(4,3)
b=Punto(5,7)
c=a+b
print c
Podría extender el código con una resta usando el método especial __sub__ de la misma manera que uso el __add__
El siguiente y ultimo ejemplo es crear un método que calcule la distancia entre dos puntos
Codigo:
import math
class Punto:
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __str__(self):
return '('+str(self.x)+','+str(self.y)+')'
def __add__(self,b):
return Punto(self.x+b.x,self.y+b.y)
def distancia(self,b):
c=(b.x-self.x,b.y-self.y)
c=(c[0]**2)+(c[1]**2)
c=math.sqrt(c)
return c
a=Punto(4,8)
b=Punto(5,7)
c=a.distancia(b)