Práctica 2 - Cinemática directa y dinámica de manipuladores

Clases y objetos

En esta segunda práctica nos tomaremos un tiempo para definir un concepto clave de la programación orientada a objetos (POO) util para definir estructuras, metodos especiales aun tipo de datos, herencia, etc.

Un objeto, desde el punto de vista de la POO, es una estructura capaz de contener datos, funciones, etc., tanto públicos como privados.

Un dato público en un objeto, es todo aquel que se puede revisar desde afuera del objeto, por ejemplo:


In [ ]:
class Gato:
    def __init__(self, nom):
        self.nombre = nom

Si usamos esta definición de clase, diseñada para guardar nombres de gatos, podemos guardar nuestro primer gato que se llamará Leonidas.


In [ ]:
gato1 = Gato("Leonidas")

Si ahora, en la siguiente celda, me posiciono con el cursor justo despues de gato1., y presiono la tecla Tabulador, intentará autocompletar con los datos que estan guardados dentro de este objeto, en este caso el nombre; si seleccionamos nombre y ejecutamos esta celda, el resultado será el nombre que le dimos a este primer gato:


In [ ]:
gato1.

Sin embargo darle nombres a gatos no es lo suficientemente util para esta clase, por eso es que nuestro siguiente ejemplo será hacer un recetario de Pizzas!

Pero antes, esta variable que ejecutamos es una variable pública ya que pudimos crear código nuevo afuera de este objetoel cual pudo acceder al nombre del gato.

Todas las variables guardadas en un objeto en Python son públicas, de la misma manera veremos que es el mismo caso para las funciones (métodos).

Revisa la siguiente definición para la clase Pizza:


In [ ]:
class Pizza:
    def __init__(self, nombre, configuracion, tamaño):
        self.nombre = nombre
        if tamaño == "individual":
            self.diam = 5
        if tamaño == "mediana":
            self.diam = 8
        if tamaño == "grande":
            self.diam = 11
        if tamaño == "jumbo":
            self.diam = 15

En esta clase definimos que para inicializar nuestro objeto necesitamos tres datos, el nombre de la pizza, que configuración de pizza es y el tamaño.

Guardamos el nombre en una variable interna llamada self.nombre (como te darás cuenta, todas las variables internas al objeto empiezan con self.) y dependiendo del tamaño que le demos a la pizza, guardaremos el diametro de la pizza; así pues, si definimos una pizza hawaiiana mediana, tendremos que:


In [ ]:
pizza1 = Pizza("Hawaiiana mediana", "H", "mediana")

In [ ]:
pizza1.diam

In [ ]:
pizza1.nombre

Ejercicio

Actualiza la clase definida anteriormente, de tal manera que despues de definirse el diametro de la pizza se calcule el area de la misma.


In [ ]:
class Pizza:
    def __init__(self, nombre, configuracion, tamaño):
        self.nombre = nombre
        if tamaño == "individual":
            self.diam = 5
        if tamaño == "mediana":
            self.diam = 8
        if tamaño == "grande":
            self.diam = 11
        if tamaño == "jumbo":
            self.diam = 15
        # ESCRIBE TU CODIGO AQUI
        raise NotImplementedError

Ejecuta la prueba de abajo para saber si has creado el codigo correcto


In [ ]:
from nose.tools import assert_almost_equal
pizza_de_prueba = Pizza("Hawaiiana individual", "H", "individual")
assert_almost_equal(pizza_de_prueba.area, 19.6349, 3)
print("Sin errores")

Ahora que tenemos el area de la pizza, podemos calcular el número de piezas de condimentos necesarias, dependiendo del tipo de pizza:


In [ ]:
class Pizza:
    def __init__(self, nombre, configuracion, tamaño):
        from numpy import pi, round
        self.nombre = nombre
        if tamaño == "individual":
            self.diam = 5
        if tamaño == "mediana":
            self.diam = 8
        if tamaño == "grande":
            self.diam = 11
        if tamaño == "jumbo":
            self.diam = 15
        self.area = pi*(self.diam/2)**2
        if configuracion == "H":
            self.npiñas = int(round(self.area/3.3))
            self.njamon = int(round(self.area/2.1))
        if configuracion == "P":
            self.npepperoni = int(round(self.area/3.1))

Por lo que ahora, si defino una pizza de pepperoni grande, puedo saber cuantas piezas de pepperoni necesitaré:


In [ ]:
pizza2 = Pizza("Pepperoni grande", "P", "grande")

In [ ]:
pizza2.npepperoni

Hasta el momento solo he guardado datos en variables internas al objeto y accedido a estas, sin embargo tambien puedo definir funciones diseñadas especificamente para interactuar con estos datos internos, por ejemplo, podemos definir una función que nos dara la receta de cada pizza dependiendo del tipo, tamaño y nombre que le guardemos:


In [ ]:
class Pizza:
    def __init__(self, nombre, configuracion, tamaño):
        from numpy import pi, round
        self.nombre = nombre
        self.conf = configuracion
        if tamaño == "individual":
            self.diam = 5
        if tamaño == "mediana":
            self.diam = 8
        if tamaño == "grande":
            self.diam = 11
        if tamaño == "jumbo":
            self.diam = 15
            
        self.area = pi*(self.diam/2)**2
        
        if self.conf == "H":
            self.npiñas = int(round(self.area/3.3))
            self.njamon = int(round(self.area/2.1))
        if self.conf == "P":
            self.npepperoni = int(round(self.area/3.1))
            
    def imp_receta(self):
        if self.conf == "H":
            self.receta = "Para preparar una pizza del tipo "
            self.receta += self.nombre + " es necesario:\n" + "Piña: "
            self.receta += str(self.npiñas) + " piezas\n" + "Jamón: "
            self.receta += str(self.njamon) + " piezas"
            print(self.receta)

Por lo que ahora, si defino una pizza hawaiiana jumbo, puedo obtener su receta, mandando a llamar este método (función interna al objeto):


In [ ]:
pizza3 = Pizza("Hawiana jumbo", "H", "jumbo")

In [ ]:
pizza3.imp_receta()

Ejercicio

Actualiza el código para que pueda imprimir la receta de una pizza de pepperoni e imprime la receta de una pizza de pepperoni individual.


In [ ]:
class Pizza:
    def __init__(self, nombre, configuracion, tamaño):
        from numpy import pi, round
        self.nombre = nombre
        self.conf = configuracion
        if tamaño == "individual":
            self.diam = 5
        if tamaño == "mediana":
            self.diam = 8
        if tamaño == "grande":
            self.diam = 11
        if tamaño == "jumbo":
            self.diam = 15
            
        self.area = pi*(self.diam/2)**2
        
        if self.conf == "H":
            self.npiñas = int(round(self.area/3.3))
            self.njamon = int(round(self.area/2.1))
        if self.conf == "P":
            self.npepperoni = int(round(self.area/3.1))
            
    def imp_receta(self):
        if self.conf == "H":
            self.receta = "Para preparar una pizza del tipo "
            self.receta += self.nombre + " es necesario:\n" + "Piña: "
            self.receta += str(self.npiñas) + " piezas\n" + "Jamón: "
            self.receta += str(self.njamon) + " piezas"
            print(self.receta)
        # ESCRIBE TU CODIGO AQUI
        raise NotImplementedError

In [ ]:
# ESCRIBE TU CODIGO AQUI
raise NotImplementedError
pizza4.imp_receta()

Ejecuta las pruebas de abajo


In [ ]:
from nose.tools import assert_equal
assert_equal(pizza4.receta, "Para preparar una pizza del tipo Pepperoni individual es necesario:\nPepperoni: 6 piezas")
print("Sin errores")