CC 1002: Introducción a la Programación
Clase 21
Nelson Baloian, José A. Pino
Definición de clase# Campos:
# numerador: int
# denominador: int
class FraccionV1:
# …
• Los campos de una clase son variables de estado que nos permiten almacenar información sobre los objetos de dicha clase.
• Los campos son indicados en la receta de diseño de la clase.
• Después de la especificación de “class”, se debe definir el método constructor de la clase.
Constructor
# Constructor
def __init__ (self, numerador=0, denominador=1):
# Inicializacion de campos
self.numerador = numerador
self.denominador = denominador
__init__ es el nombre del constructor. Sólo uno por clase.Primer parámetro: self: referencia al objeto que se está creando.Al crear un objeto, no se pone nada para el “self”:
f1 = FraccionV1(5, 9) # fracción 5/9
Parámetros “por defecto”:
f2 = FraccionV1() # fracción 0/1
Otro ejemplo
# Campos
# nombre: string
# tipo: string
# edad: int
class Mascota:
def __init__(self, nombre, tipo=“perro”, edad=0)
self.nombre = nombre
self.tipo = tipo
self.edad = edad
p = Mascota(“Fido”)
kitty = Mascota(“Silvestre”, “gato”, 2)
Método suma: dentro de la
clase FraccionV1# suma : fraccion -> fraccion
# devuelve la suma de la fraccion con otra fraccion
def suma (self , fraccion):
num = self.numerador*fraccion.denominador + \
fraccion.numerador*self.denominador
den = self.denominador*fraccion.denominador
return FraccionV1(num, den)
f1 = FraccionV1(1, 2)
f2 = FraccionV1(5, 6)
f3 = f1.suma(f2)
f1 corresponde a self
Métodos accesores y mutadores
• Accesores: no modifican campos del objeto. Ej.: suma
• Mutadores: modifican (o pueden modificar) los valores de los campos de la clase
• Indicar el efecto que puede tener un método mutador sobre los campos
• Ejemplo de método mutador: simplificar una fracción
• Al simplificar (eventualmente) debemos modificar numerador y denominador
• Supongamos que contamos con la función mcd(i1, i2)
Método simplificar (mutador)
# simplificar : None -> Fraccion
# efecto : simplifica la fraccion , puede modificar los
# valores de los campos numerador y denominador
def simplificar ( self ):
valor = mcd(self.numerador, self.denominador)
if valor > 1:
self.numerador = self.numerador/valor
self.denominador = self.denominador/valor
Por convención, a los métodos accesores se les pone nombre que comienza con get.
A los métodos mutadores, se les pone nombre que comienza con set.
Métodos accesores para la clase
FraccionV1Por convención, a los métodos accesores se les pone nombre que comienza con get.
A los métodos mutadores, se les pone nombre que comienza con set.
# getNumerador : None -> int
# devuelve el valor del campo numerador
def getNumerador(self):
return self.numerador
# getDenominador : None -> int
# devuelve el valor del campo denominador
def getDenominador(self):
return self.denominador
Métodos mutadores para la
clase FraccionV1
# setNumerador : int -> None
# efecto : modifica el valor del campo numerador
def setNumerador(self, numerador ):
self.numerador = numerador
# setDenominador : int -> None
# efecto : modifica el valor del campo denominador
def setDenominador(self, denominador ):
self.denominador = denominador
Receta de diseño
• Antes de definir la clase, se identifican los campos y tipos
• La definición de métodos sigue las reglas habituales de la receta de diseño
para funciones, pero los cuerpos de los métodos y los tests correspondientes
quedan pendientes.
• Una vez terminada la definición de métodos, fuera de la clase se implementan
los tests para todos los métodos.
• Se implementan los cuerpos de los métodos.
• Se ejecutan los tests.
• Se itera si es necesario (corrigiendo errores).
Clase FraccionV1 (P.1)
# Campos :
# numerador : int
# denominador : int
class FraccionV1 :
# Constructor
def __init__ (self, numerador = 0, denominador = 1):
# Inicializacion de campos
self.numerador = numerador
self.denominador = denominador
# getNumerador : None -> int
# devuelve el valor del campo numerador
def getNumerador ( self ):
return self.numerador
Clase FraccionV1 (P.2)
# getDenominador : None -> int
# devuelve el valor del campo denominador
def getDenominador (self):
return self.denominador
# setNumerador : int -> None
# efecto : modifica el valor del campo numerador
def setNumerador (self, numerador):
self.numerador = numerador
# setDenominador : int -> None
# efecto: modifica el valor del campo denominador
def setDenominador (self, denominador):
self.denominador = denominador
Clase FraccionV1 (P.3)
# toString : None -> str
# devuelve un string con la fraccion
def toString ( self ):
return str(self.numerador)+"/"+str(self.denominador)
# suma : fraccion -> fraccion
# devuelve la suma de la fraccion con otra fraccion
def suma (self, fraccion):
num = self.numerador*fraccion.denominador + \
fraccion.numerador*self.denominador
den = self.denominador*fraccion.denominador
return FraccionV1(num, den)
Clase FraccionV1 (P.4)
# mcd: int int -> int
# devuelve maximo comun divisor entre numeros x e y
# ejemplo : mcd (12 , 8) devuelve 4
global mcd
def mcd(x, y):
if x == y:
return x
elif x > y:
return mcd (x-y, y)
else :
return mcd (x, y-x)
# Test
assert mcd (12 , 8) == 4
Clase FraccionV1 (P.5)
# simplificar : None -> Fraccion
# efecto : simplifica la fraccion , puede modificar los
# valores de los campos numerador y denominador
def simplificar ( self ):
valor = mcd( self.numerador, self.denominador )
if valor > 1:
self.numerador = self.numerador / valor
self.denominador = self.denominador / valor
# Tests
f1 = FraccionV1(1, 2)
f2 = FraccionV1(5, 6)
# Test de accesores
assert f1.getNumerador() == 1
assert f2.getDenominador() == 6
Clase FraccionV1 (P.6)
# Test de mutadores
f2.setNumerador (3)
f2.setDenominador (4)
assert f2.getNumerador()==3 and f2.getDenominador()==4
# Test de metodo suma
# El siguiente test es incorrecto
# assert f1.suma(f2) == FraccionV1 (10 , 8)
# El siguiente test es correcto
f3 = f1.suma(f2)
assert f3.getNumerador()==10 and f3.getDenominador()==8
# Test de metodo toString
assert f3.toString() == "10/8"
# Test de metodo simplificar
f3.simplificar()
assert f3.getNumerador()==5 and f3.getDenominador()==4
FraccionV2: una versión más
segura• Podemos crear una nueva clase FraccionV2 que no tiene métodos
mutadores.
• Para ello, creamos nuevos métodos accesadores, en donde el resultado se
almacena en un nuevo objeto de la misma clase (y/o se eliminan métodos
mutadores).
• Además, para evitar que un usuario fuera de la clase pueda modificar los
campos de un objeto, en Python se pueden definir con nombres que
comiencen con los caracteres __ (dos caracteres subrayado), y esto los
hace inaccesibles fuera de la clase.
• Si uno intenta modificar un campo que comienza con __, Python arroja el
error AttributeError.
Clase FraccionV2 (P.1)
# Campos :
# numerador : int
# denominador : int
class FraccionV2 :
# Constructor
def __init__(self,numerador=0,denominador=1):
# Inicializacion de campos
# campos invisibles al usuario
self.__numerador = numerador
self.__denominador = denominador
# getNumerador : None -> int
# devuelve el valor del campo numerador
def getNumerador ( self ):
return self.__numerador
Clase FraccionV2 (P.2)
# getDenominador : None -> int
# devuelve el valor del campo denominador
def getDenominador ( self ):
return self.__denominador
# toString : None -> str
# devuelve un string con la fraccion
def toString ( self ):
return str(self.__numerador)+"/"+str(self.__denominador)
# suma : Fraccion -> Fraccion
# devuelve la suma de la fraccion con otra fraccion
def suma(self, fraccion ):
num = self.__numerador*fraccion.__denominador+ \
fraccion.__numerador*self.__denominador
den = self.__denominador*fraccion.__denominador
return FraccionV2(num, den)
Clase FraccionV2 (P.3)
# mcd: int int -> int
# devuelve el maximo comun divisor entre dos numeros x e y
# ejemplo : mcd (12 , 8) devuelve 4
global mcd
def mcd(x, y):
if x == y:
return x
elif x > y:
return mcd (x-y, y)
else :
return mcd (x, y-x)
# Test
assert mcd(12, 8) == 4
Clase FraccionV2 (P.4)
# simplificar : None -> Fraccion
# devuelve la fraccion simplificada
def simplificar ( self ):
valor = mcd(self.__numerador , self.__denominador )
num = self.__numerador / valor
den = self.__denominador / valor
return FraccionV2(num, den )
# Tests
f1 = FraccionV2 (1, 2)
f2 = FraccionV2 (3, 4)
# Test de accesores
assert f1.getNumerador() == 1
assert f2.getDenominador() == 4
#
Clase FraccionV2 (P.5)
# Test de metodo suma
f3 = f1.suma(f2)
assert f3.getNumerador()==10 and f3.getDenominador()==8
# Test de metodo toString
assert f3.toString() == "10/8"
# Test de metodo simplificar
f4 = f3.simplificar()
assert f4.getNumerador()==5 and f4.getDenominador()==4
(martes)
Leer capítulo 16 del apunte
Para la próxima clase