class
crea un nuevo objeto clase y le asigna un nombre. Cuando se corre, genera un nuevo objeto Clase y le asigna el nombre que se encuentra en el header.objeto.nombre
self
en métodos son atributos de instancia. Difieren de una a otra. Dentro de los metodos de la clase, el primer argumento por convención es self
y referencia a la instancia del objeto que esta siendo procesado.Definir una clase Punto
que modele un punto que tiene dos coordenadas x
e y
.
Ademas le podemos pedir que calcule su norma. La norma es la raíz cuadrada de la suma de sus componentes al cuadrado
from math import sqrt
class Punto:
""" Clase que modela a un punto en el plano. """
def __init__(self, x, y):
""" Recibo las coordenadas del punto. """
self.x = x
self.y = y
def obtener_norma(self):
"""Devuelve la distancia al origen."""
return sqrt(self.x**2 + self.y**2)
help(Punto)
Help on class Punto in module __main__: class Punto | Clase que modela a un punto en el plano. | | Methods defined here: | | __init__(self, x, y) | Recibo las coordenadas del punto. | | obtener_norma(self) | Devuelve la distancia al origen.
Veamos un ejemplo en Java
public interface Coloreable {
void colorear(Color color);
}
public class Cuadrado implements Coloreable {
private Color color;
public void colorear(Color color) {
this.color = color;
}
}
class Padre(object):
''' Clase base. '''
pass
class Hijo(Padre):
''' Clase que hereda el comportamiento del padre.'''
pass
Veamos un ejemplo
class Padre(object):
def sobrescrito(self):
print("Padre: método sobrescrito")
def heredado(self):
print("Padre: método heredado.")
def alterado(self):
print("Padre: método alterado.")
class Hijo(Padre):
def sobrescrito(self):
print("Hijo: método sobrescrito.")
def alterado(self):
print("Hijo: método alterado antes de invocar al padre.")
super(Hijo,self).alterado()
print("Hijo: método alterado después de invocar al padre.")
padre = Padre()
hijo = Hijo()
padre.heredado()
Padre: método heredado.
hijo.heredado()
Padre: método heredado.
padre.sobrescrito()
Padre: método sobrescrito
hijo.sobrescrito()
Hijo: método sobrescrito.
padre.alterado()
Padre: método alterado.
hijo.alterado()
Hijo: método alterado antes de invocar al padre. Padre: método alterado. Hijo: método alterado después de invocar al padre.
¿Encapsulamiento?
¡En Python todos los métodos y atributos son públicos!
CONSTANTE_A = 4
CONSTANTE_B = 2
class ClaseDeEjemplo:
''' Clase que sirve de ejemplo. '''
def __init__(self, a = CONSTANTE_A, b = CONSTANTE_B):
self.atributo_publico_a = a
self.atributo_publico_b = b
self.__atributo_privado_c = a + b
def metodo_publico(self):
return self.atributo_publico_a == CONSTANTE_A and \
self.atributo_publico_b == CONSTANTE_A
def __metodo_privado(self):
return self.atributo_publico_a == CONSTANTE_B and \
self.atributo_publico_b == CONSTANTE_A
CONSTANTE_A = 4
class OtraClaseDeEjemplo(object):
def __init__(self, a = CONSTANTE_A):
self.a = a
def atributo_al_cuadrado(self):
return self.a ** 2
clase = OtraClaseDeEjemplo()
print "clase.atributo_al_cuadrado: ", clase.atributo_al_cuadrado()
print "Atributo a:", clase.a # Obtengo atributo a
clase.a = 11 # Seteo atributo a
print "clase.atributo_al_cuadrado: ", clase.atributo_al_cuadrado()
clase.atributo_al_cuadrado: 16 Atributo a: 4 clase.atributo_al_cuadrado: 121
Problema: al hacer clase.a = 11
, si nuestro máximo es 10
no tenemos forma de verificarlo...
get_a
y set_a
¶CONSTANTE_A = 4
MAX_A = 10
class OtraClaseDeEjemplo(object):
def __init__(self, a = CONSTANTE_A):
self.a = a
def get_a(self):
return self.a
def set_a(self, a):
self.a = min(a, MAX_A)
def atributo_al_cuadrado(self):
return self.a ** 2
Problema:
clase.a = 11
, nuevamente tenemos el mismo problema.clase.a
, hay que actualizarlo todo por clase.get_a
. property
¶CONSTANTE_A = 4
MAX_A = 10
class OtraClaseDeEjemplo(object):
def __init__(self, a = CONSTANTE_A):
self.set_a(a) # _a la usamos como atributo privado
def get_a(self):
return self._a
def set_a(self, a):
self._a = min(a, MAX_A)
def atributo_al_cuadrado(self):
return self._a ** 2
a = property(get_a) # a lo usamos como atributo publico
Esto permite que al hacer:
clase.a
se llame a la función fget()
(en este caso get_a
)clase.a = x
se llame a la función fset(x)
(en este caso set_a
)clase = OtraClaseDeEjemplo()
print "clase.atributo_al_cuadrado: ", clase.atributo_al_cuadrado()
print "Atributo a:", clase.a # Obtengo atributo a
clase.a = 11 # Seteo atributo a
print "clase.atributo_al_cuadrado: ", clase.atributo_al_cuadrado()
clase.atributo_al_cuadrado: 16 Atributo a: 4 clase.atributo_al_cuadrado: 100
decorators
¶CONSTANTE_A = 4
MAX_A = 10
class OtraClaseDeEjemplo(object):
def __init__(self, a = CONSTANTE_A):
self.a = a
@property
# @a.getter
def a(self):
return self._a
# a = property(a)
@a.setter
def a(self, a):
self._a = min(a, MAX_A)
def atributo_al_cuadrado(self):
return self.a ** 2
ej1 = OtraClaseDeEjemplo()
ej2 = OtraClaseDeEjemplo()
ej1.a = 30
print ej1.a
10
Es equivalente a la Solusión 3, no requiere definir una variable self._a
Nota: usa decorators, el concepto no entra dentro del scope del curso, si hay tiempo lo vemos al final
clase = OtraClaseDeEjemplo()
print "clase.atributo_al_cuadrado: ", clase.atributo_al_cuadrado()
print "Atributo a:", clase.a # Obtengo atributo a
clase.a = 11 # Seteo atributo a
print "clase.atributo_al_cuadrado: ", clase.atributo_al_cuadrado()
clase.atributo_al_cuadrado: 16 Atributo a: 4 clase.atributo_al_cuadrado: 100
Implementar la clase Vector que reciba en el constructor los valores de las coordenadas e implemente los métodos:
class Vector(object):
''' Clase que modela un vector. '''
def __init__(self, *coordenadas, **lista_coordenadas):
self.coordenadas = \
lista_coordenadas.get("coordenadas", list(coordenadas))
def sumar(self, otro):
''' Suma dos vectores del mismo largo. '''
coord_1 = self.coordenadas
coord_2 = otro.coordenadas
return Vector(coordenadas = \
[ x + y for x, y in zip(coord_1, coord_2) ])
def producto_numero(self, numero):
''' Multiplica al vector por un escalar. '''
return Vector(coordenadas = \
[ x * numero for x in self.coordenadas])
Se invocan automáticamente cuando usamos cierta sintaxis sobre algún tipo que los tenga definidos.
Uso | Sintaxis | Método Mágico |
---|---|---|
Inicializar instancias. | v = Vector(1,2,3) | __init__ |
Representación de impresión. | str(v), print(v) | __str__ |
Representación formal. | repr(v) | __repr__ |
Iterar una secuencia. | iter(secuencia) | __iter__ |
Obtener el siguiente de un iterador. | next(secuencia) | __next__ |
Obtener el largo. | len(secuencia) | __len__ |
Verificar pertenencia. | elemento in secuencia | __contains__ |
Verificar igualdad. | x == y | __eq__ |
Verificar desigualdad. | x != y | __ne__ |
Verificar por menor / menor o igual. | x<y x / <= y | __lt__ / __le__ |
Verificar por mayor / mayor o igual. | x>y x / >= y | __gt__ / __ge__ |
Verificar valor de verdad. | if x: | __bool__ |
Implementar en la clase Vector los métodos de representación, representación en cadena e igualdad y no igualdad
__str__
__repr__
__eq__
__ne__
class Vector:
''' Clase que modela un vector. '''
def __init__(self, a, b):
self.x = a
self.y = b
def __add__(self, otro):
''' Suma dos vectores '''
return Vector(self.x + otro.y, self.y + otro.y)
def __mul__(self, escalar):
''' Multiplica al vector por un escalar. '''
return Vector(self.x * escalar, self.y * escalar)
def __str__(self):
return "("+str(self.x)+","+str(self.y)+")"
def __repr__(self):
return "("+str(self.x)+","+str(self.y)+")"
Uso | Sintaxis | Método Mágico |
---|---|---|
Sumar. | x+y | __add__ |
Restar. | x–y | __sub__ |
Multiplicar. | x*y | __mul__ |
Dividir. | x/y | __truediv__ |
Dividir truncando. | x // y | __floordiv__ |
Sobrecargar los operadores de “+” y “*” de la clase Vector para que implementen la suma y multiplicación respectivamente.
v1 = Vector(1,2)
v2 = Vector(5,6)
print v1 + v2 #(6,8)
print v1 * v2 #(5,12)
class Vector:
''' Clase que modela un vector. '''
def __init__(self, a, b):
self.x = a
self.y = b
def __add__(self, otro):
''' Suma dos vectores '''
return Vector(self.x + otro.x, self.y + otro.y)
def __mul__(self, otro):
''' Multiplica al vector por un escalar. '''
return Vector(self.x * otro.x, self.y * otro.y)
def __str__(self):
return "("+str(self.x)+","+str(self.y)+")"
def __repr__(self):
return "("+str(self.x)+","+str(self.y)+")"
v1 = Vector(1,4)
v2 = Vector(4,3)
print v1 + v2
(5,7)
raise NombreException("mensaje error")
Ej:
raise ValueError("Parametro invalido")
try:
...
except Ex1 as e1:
...
except (Ex2, Ex3):
...
else:
...
finally:
...
BaseException
+-- SystemExit
+-- KeyboardInterrupt +-- GeneratorExit +-- Exception
...
+-- StopIteration +-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError +-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
Implementar en la suma de Vectores la validación de coordenadas, levantando una excepción de tipo ValueError si alguna de las coordenadas del segundo vector es mayor a la del primero.
(1,3)+(2,3) -> ValueError
(1,3)+(1,1) -> (2,4) OK!
import traceback
class Vector:
''' Clase que modela un vector. '''
def __init__(self, a, b):
self.x = a
self.y = b
def __add__(self, otro):
''' Suma dos vectores '''
if(otro.x > self.x or otro.y > self.y):
raise ValueError("No se puede sumar un vector mas grande")
return Vector(self.x + otro.y, self.y + otro.y)
def __mul__(self, escalar):
''' Multiplica al vector por un escalar. '''
return Vector(self.x * escalar, self.y * escalar)
def __str__(self):
return "("+str(self.x)+","+str(self.y)+")"
def __repr__(self):
return "("+str(self.x)+","+str(self.y)+")"
v1 = Vector(1,3)
v2 = Vector(2,3)
v3 = Vector(1,1)
class ExcepcionDeReglaDeNegocio(Exception):
pass
CONSTANTE_A = 4
MAX_A = 10
class OtraClaseDeEjemplo:
def __init__(self, a = CONSTANTE_A):
if a > MAX_A:
raise ExcepcionDeReglaDeNegocio("Valor de 'a' muy grande.")
self._a = a
def atributo_al_cuadrado(self):
return self.a ** 2
Levantan una excepción del tipo AssertionError
si no se cumple una condición.
Se usan para encontrar errores en la etapa de desarrollo de los cuales no se espera recuperar por ejemplo, ruptura de invariantes.
assert expresion
Equivalente a:
if __debug__:
if not expresion:
raise AssertionError
def pedir_numero_positivo():
''' Programa que devuelve un número positivo ingresado por el usuario.'''
numero = int(raw_input("Ingrese un número positivo"))
assert int(numero) > 0
return int(numero)
pedir_numero_positivo()
Ingrese un número positivo-32
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-125-96f2de201bc2> in <module>() ----> 1 pedir_numero_positivo() <ipython-input-123-a5303b5da4e5> in pedir_numero_positivo() 5 6 numero = int(raw_input("Ingrese un número positivo")) ----> 7 assert int(numero) > 0 8 return int(numero) AssertionError:
Fracciones
a) Crear una clase Fraccion, que cuente con dos atributos: dividendo y divisor, que se
asignan en el constructor, y se imprimen como X/Y en el método __str__
.
b) Crear un método sumar __add__
que recibe otra fracción y devuelve una nueva fracción con la
suma de ambas. Ej: f1 + f2
c) Crear un método multiplicar __mul__
que recibe otra fracción y devuelve una nueva fracción con el producto de ambas. Ej: f1 * f2
d) Crear un método simplificar que modifica la fracción actual de forma que los valores del dividendo y divisor sean los menores posibles.
Botella y Sacacorchos
a) Escribir una clase Corcho, que contenga un atributo bodega (cadena con el nombre de la bodega).
b) Escribir una clase Botella que contenga un atributo corcho con una referencia al corcho que la tapa, o None si está destapada.
c) Escribir una clase Sacacorchos que tenga un método destapar que le reciba una botella, le saque el corcho y se guarde una referencia al corcho sacado. Debe lanzar una excepción en el caso en que la botella ya esté destapada, o si el sacacorchos ya contiene un corcho.
d) Agregar un método limpiar, que saque el corcho del sacacorchos, o lance una excepción en el caso en el que no haya un corcho.
Papel, Birome, Marcador
a) Escribir una clase Papel que contenga un texto, un método escribir, que reciba una cadena para agregar al texto, y el método str que imprima el contenido del texto.
b) Escribir una clase Birome que contenga una cantidad de tinta, y un método escribir, que reciba un texto y un papel sobre el cual escribir. Cada letra escrita debe reducir la cantidad de tinta contenida. Cuando la tinta se acabe, debe lanzar una excepción.
c) Escribir una clase Marcador que herede de Birome, y agregue el método recargar, que reciba la cantidad de tinta a agregar.