![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Como otro ejemplo de un tipo definido por el usuario, definiremos una clase llamada Hora que registra la hora del d�a. La definici�n de la clase es como sigue:
class Hora:
pass
Podemos crear un nuevo objeto Hora y asignar atributos para contener las horas, minutos y segundos:
hora = Hora()
hora.horas = 11
hora.minutos = 59
hora.segundos = 30
El diagrama de estado del objeto Hora es as�:
A modo de ejercicio, escriba una funci�n imprimeHora que acepte un objeto Hora como argumento y lo imprima en el formato horas:minutos:segundos.
Como un segundo ejercicio, escriba una funci�n booleana despues que tome dos objetos Hora, t1 y t2, como argumentos y devuelva verdadero (1) si t1 sigue cronol�gicamente a t2 y falso (0) en caso contrario.
En las pr�ximas secciones, escribiremos dos versiones de una funci�n llamada sumaHora que calcule la suma de dos Horas. Mostrar�n dos tipos de funciones: funciones puras y modificadores.
�ste es un esbozo de sumaHora:
def sumaHora(t1, t2):
suma = Hora()
suma.horas = t1.horas + t2.horas
suma.minutos = t1.minutos + t2.minutos
suma.segundos = t1.segundos + t2.segundos
return suma
La funci�n crea un nuevo objeto Hora, inicializa sus atributos y devuelve una referencia al nuevo objeto. A esto se le llama funci�n pura porque no modifica ninguno de los objetos que se le pasan y no tiene efectos laterales, como mostrar un valor o tomar una entrada del usuario.
Aqu� tiene un ejemplo de c�mo usar esta funci�n. Crearemos dos objetos Hora: horaActual, que contiene la hora actual, y horaPan, que contiene la cantidad de tiempo que necesita un panadero para hacer pan. Luego usaremos sumaHora para averiguar cu�ndo estar� hecho el pan. Si a�n no ha terminado de escribir imprimeHora, eche un vistazo a la Secci�n 14.2 antes de probar esto:
>>> horaActual = Hora()
>>> horaActual.horas = 9
>>> horaActual.minutos = 14
>>> horaActual.segundos = 30
>>> horaPan = Hora()
>>> horaPan.horas = 3
>>> horaPan.minutos = 35
>>> horaPan.segundos = 0
>>> horaHecho = sumaHora(horaActual, horaPan)
>>> imprimeHora(horaHecho)
La salida de este programa es 12:49:30, lo que es correcto. Por otra parte, hay casos en los que el resultado no es correcto. �Puede imaginar uno?
El problema es que esta funci�n no trata los casos en los que el n�mero de segundos o minutos suma m�s que sesenta. Cuando ocurre eso, debemos "llevar" los segundos sobrantes a la columna de los minutos o los minutos extras a la columna de las horas.
He aqu� una versi�n corregida de la funci�n:
def sumaHora(t1, t2):
suma = Hora()
suma.horas = t1.horas + t2.horas
suma.minutos = t1.minutos + t2.minutos
suma.segundos = t1.segundos + t2.segundos
if suma.segundos >= 60:
suma.segundos = suma.segundos - 60
suma.minutos = suma.minutos + 1
if suma.minutos >= 60:
suma.minutos = suma.minutos - 60
suma.horas = suma.horas + 1
return suma
Aunque esta funci�n es correcta, empieza a ser grande. M�s adelante sugeriremos una aproximaci�n alternativa que nos dar� un c�digo m�s corto.
Hay veces en las que es �til que una funci�n modifique uno o m�s de los objetos que recibe como par�metros. Normalmente, el llamante conserva una referencia a los objetos que pasa, as� que cualquier cambio que la funci�n haga ser� visible para el llamante. Las funciones que trabajan as� se llaman modificadores.
incremento, que a�ade un n�mero dado de segundos a un objeto Hora, se escribir�a de forma natural como un modificador. Un esbozo r�pido de la funci�n podr�a ser �ste:
def incremento(hora, segundos):
hora.segundos = hora.segundos + segundos
if hora.segundos >= 60:
hora.segundos = hora.segundos - 60
hora.minutos = hora.minutos + 1
if hora.minutos >= 60:
hora.minutos = hora.minutos - 60
hora.horas = hroa.horas + 1
La primera l�nea realiza la operaci�n b�sica, las restantes tratan con los casos especiales que vimos antes.
�Es correcta esta funci�n? �Qu� ocurre si el par�metro segundos es mucho mayor que sesenta? En tal caso, no es suficiente con acarrear una vez; debemos seguir haci�ndolo hasta que segundos sea menor que sesenta. Una soluci�n es sustituir las sentencias if por sentencias while:
def incremento(hora, segundos):
hora.segundos = hora.segundos + segundos
while hora.segundos >= 60:
hora.segundos = hora.segundos - 60
hora.minutos = hora.minutos + 1
while hora.minutos >= 60:
hora.minutos = hora.minutos - 60
hora.horas = hroa.horas + 1
Ahora esta funci�n es correcta, pero no es la soluci�n m�s eficiente.
Como ejercicio, reescriba esta funci�n de modo que no contenga tantos bucles.
Como un segundo ejercicio, reescriba incremento como una funci�n pura, y escriba una funci�n que llame a ambas versiones.
Todo lo que se pueda hacer con modificadores puede hacerse tambi�n con funciones puras. En realidad, algunos lenguajes de programaci�n s�lo permiten funciones puras. Hay ciertas evidencias de que los programas que usan funciones puras son m�s r�pidos de desarrollar y menos propensos a los errores que los programas que usan modificadores. Sin embargo, a veces los modificadores son �tiles, y en algunos casos los programas funcionales son menos eficientes.
En general, recomendamos que escriba funciones puras siempre que sea razonable hacerlo as� y recurra a los modificadores s�lo si hay una ventaja convincente. Este enfoque podr�a llamarse estilo funcional de programaci�n.
En este cap�tulo mostramos una aproximaci�n al desarrollo de programas a la que llamamos desarrollo de prototipos. En cada caso, escribimos un esbozo basto (o prototipo) que realizaba el c�lculo b�sico y luego lo probamos sobre unos cuantos casos, corrigiendo los fallos tal como los encontr�bamos.
Aunque este enfoque puede ser efecitvo, puede conducirnos a c�digo que es innecesariamente complicado, ya que trata con muchos casos especiales, y poco fiable, porque es dif�cil saber si encontr� todos los errores.
Una alternativa es el desarrollo planificado, en el que una comprensi�n del problema en profundidad puede hacer la programaci�n mucho m�s f�cil. En este caso, el enfoque es que un objeto Hora es en realidad �un n�mero de tres d�gitos en base 60! El componente segundo es la "columna de unidades", el componente minuto es la "columna de las sesententas" y el componente hora es la "columna de las tresmilseiscentenas".
Cuando escribimos sumaHora e incremento, en realidad est�bamos haciendo una suma en base 60, que es por lo que deb�amos acarrear de una columna a la siguiente.
Esta observaci�n sugiere otro enfoque para el problema. Podemos convertir un objeto Hora en un simple n�mero y sacar provecho del hecho de que la m�quina sabe la aritm�tica necesaria. La siguiente funci�n convierte un objeto Hora en un entero:
def convierteASegundos(t):
minutos = t.horas * 60 + t.minutos
segundos = minutos * 60 + t.segundos
return segundos
Ahora, s�lo necesitamos una forma de convertir un entero en un objeto Hora:
def haceHora(segundos):
hora = Hora()
hora.horas = segundos/3600
segundos = segundos - hora.horas * 3600
hora.minutos = segundos/60
segundos = segundos - hora.minutos * 60
hora.segundos = segundos
return hora
Puede que tenga usted que pensar un poco para convencerse de que esta t�cnica para convertir de una base a otra es correcta. Suponiendo que est� usted convencido, puede usar estas funciones para reescribir sumaHora:
def sumaHora(t1, t2):
segundos = convierteASegundos(t1) + convierteASegundos(t2)
return haceHora(segundos)
Esta versi�n es mucho m�s corta que la original, y es mucho m�s f�cil de demostrar que es correcta (suponiendo, como es habitual, que las funciones a las que llama son correctas).
Como ejercicio, reescriba incremento de la misma forma.
De alg�n modo, convertir de base 60 a base 10 y de vuelta es m�s dif�cil que simplemente manejarse con las horas. La conversi�n de base es m�s abstracta; nuestra intuici�n para tratar con las horas es mejor.
Pero si tenemos la comprensi�n para tratar las horas como n�meros en base 60, y hacer la inversi�n de escribir las funciones de conversi�n (convierteASegundos y haceHora), obtenemos un programa que es m�s corto, m�s f�cil de leer y depurar y m�s fiable.
Tambi�n es m�s f�cil a�adir funcionalidades m�s tarde. Por ejemplo, imagine restar dos Horas para hallar el intervalo entre ellas. La aproximaci�n ingenua ser�a implementar la resta con acarreo. Con el uso de las funciones de conversi�n ser� m�s f�cil y con mayor probabilidad, correcto.
Ir�nicamente, a veces hacer un poblema m�s complejo (o m�s general) lo hace m�s f�cil (porque hay menos casos especiales y menos oportunidades de error).
Cuando escribe una soluci�n general para una clase de problemas, en contraste con una soluci�n espec�fica a un problema concreto, ha escrito un algoritmo. Mencionamos esta palabra antes pero no la definimos con precisi�n. No es f�cil de definir, as� que probaremos un par de enfoques.
Primero, piense en algo que no es un algoritmo. Cuando usted aprendi� a multiplicar n�meros de una cifra, probablemente memoriz� la tabla de multiplicar. En efecto, memoriz� 100 soluciones espec�ficas. Ese tipo de conocimiento no es algor�tmico.
Pero si usted era "harag�n" probablemente hizo trampa aprendiendo algunos trucos. Por ejemplo, para encontrar el producto de n por 9, puede escribir n-1 como el primer d�gito y 10-n como el segundo d�gito. Este truco es una soluci�n general para multiplicar cualquier n�mero de una cifra por 9. �Eso es un algoritmo!
De forma similar, las t�cnicas que aprendi� para la suma y la resta con acarreo y la divisi�n larga son todas algoritmos. Una de las caracter�sticas de los algoritmos es que no requieren inteligencia para llevarse a cabo. Son procesos mec�nicos en los que cada paso sigue al anterior de acuerdo a un conjunto simple de reglas.
En nuestra opini�n, es un poco vergonzoso que los humanos pasen tanto tiempo en la escuela aprendiendo a ejecutar algoritmos que, de forma bastante similar, no exigen inteligencia.
Por otra parte, el proceso de dise�ar algoritmos es interesante, un desaf�o intelectual y una parte primordial de lo que llamamos programar.
Algunas de las cosas que la gente hace naturalmente, sin dificultad ni pensamiento consciente, son las m�s dif�ciles de expresar algor�tmicamente. Entender el lenguaje natural es un buen ejemplo. Todos lo hacemos, pero hasta el momento nadie ha sido capaz de explicar c�mo lo hacemos, al menos no en la forma de un algoritmo.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |