![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Como otro ejemplo de tipo definido por el usuario, definiremos una clase llamada Tiempo que registra el tiempo del día. La definición de clase es:
class Tiempo:
pass
Podemos crear un nuevo objeto Tiempo y asignar atributos para las horas, minutos, y segundos:
tiempo = Tiempo()
tiempo.horas = 11
tiempo.minutos = 59
tiempo.segundos = 30
El diagrama de estados para el objeto Tiempo tiene este formato:

Como ejercicio, escribe una función mostrarTiempo que use un objeto Tiempo como argumento y lo imprima en la forma horas:minutos:segundos.
Como segundo ejercicio, escribe una función booleana despues que use dos objetos Tiempo,t1 y t2, como argumentos, y lo estime como verdadero (1) si t1 sigue a t2 cronológicamente y falso (0) en caso contrario.Comentarios
En las siguientes secciones, escribiremos dos versiones de una función llamada tiempoSuma, que calcula la suma de dos Tiempos. Estas demostrarán dos clases de funciones: funciones puras y modificadores.
La siguiente es una versión preliminar de tiempoSuma:
def tiempoSuma(t1, t2):
suma = Tiempo()
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 Tiempo, establece sus atributos, y estima una referencia para el nuevo objeto. Se conoce como función pura porque no modifica ninguno de los objetos que le son asignados como parámetros y no tiene ningún efecto secundario, tal como la representación de un valor o la aparición del espacio reservado para la entrada de datos del usuario.
A continuación se muestra un ejemplo de cómo usar esta función. Crearemos dos objetos Tiempo : tiempoActual, que represente el tiempo actual; y tiempoPan, que represente la cantidad de tiempo que tarda un panadero en hacer pan. A continuación usaremos la función tiempoSuma para calcular cuándo estará hecho el pan. Si todavía no has terminado de escribir la función mostrarTiempo , echa un vistazo previo a la Sección 14.2 antes de continuar:
>>> tiempoActual = Tiempo()
>>> tiempoActual.horas = 9
>>> tiempoActual.minutos = 14
>>> tiempoActual.segundos = 30
>>> tiempoPan = Tiempo()
>>> tiempoPan.horas = 3
>>> tiempoPan.minutos = 35
>>> tiempoPan.segundos = 0
>>> tiempoConsumido = tiempoSuma(tiempoActual, tiempoPan)
>>> mostrarTiempo(tiempoConsumido )
El resultado de este programa es 12:49:30, que es correcto. No obstante, hay casos donde el resultado no es correcto. ¿Se te ocurre alguno?
El problema es que esta función no trata con casos donde el número de segundos o minutos sumen más de sesenta. Cuando esto sucede, tenemos que "llevar" los segundos suplementarios a la columna de minutos o los minutos suplementarios a la columna de horas.
A continuación se muestra una segunda versión corregida de la función:
def tiempoSuma(t1, t2):
suma= Tiempo()
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, comienza a hacerse compleja. Más tarde propondremos una aproximación alternativa que genera un código más corto. Comentarios
En algunas ocasiones para una función es útil modificar uno o varios de los objetos que recoge como parámetros. Por lo general, la función que llama guarda una referencia de los objetos que itera, por lo que los cambios que realice la función llamada son evidentes para la que llama. Las funciones que operan de esta forma se llaman modificadores.
incremento, añade un número determinado de segundos al objeto Tiempo, se escribiría de forma mucho más natural como modificador. Un borrador de la función tiene el siguiente formato:
def incremento(tiempo, segundos):
tiempo.segundos = tiempo.segundos + segundos
if tiempo.segundos >= 60:
time.segundos = tiempo.segundos - 60
tiempo.minutos = tiempo.minutos + 1
if tiempo.minutos >= 60:
tiempo.minutos = tiempo.minutos - 60
tiempo.horas = tiempo.horas + 1
La primera línea realiza la operación básica; el resto se encarga de los casos especiales que vimos antes.
¿Es correcta la función? ¿Qué pasa si el parámetro segundos es mucho mayor que sesenta? En este caso, no es bastante llevarse decimales de una columna a otra de una sola vez; tenemos que seguir haciéndolo hasta que los segundos sean menos de sesenta. Una solución es sustituir la instrucción if por while:
def incremento(tiempo, segundos):
tiempo.segundos = tiempo.segundos + segundos
while tiempo.segundos >= 60:
tiempo.segundos = tiempo.segundos - 60
tiempo.minutos = tiempo.minutos + 1
while tiempo.minutos >= 60:
tiempo.minutos = tiempo.minutos - 60
tiempo.horas = tiempo.horas + 1
Esta función es ahora correcta, pero no es la solución más eficiente.
Como ejercicio, vuelve a escribir esta función de modo que no tenga bucles.
Como segundo ejercicio, vuelve a escribir incremento como función pura, y escribe llamadas a función para ambas versiones.Comentarios
Cualquier operación que se pueda hacer con modificadores puede hacerse también con funciones puras. De hecho, algunos lenguajes de programación sólo permiten funciones puras. Está demostrado que los programas que usan funciones puras son más rápidos de desarrollar y están menos predispuestos al error que los que usan modificadores. Sin embargo, los modificadores son útiles a veces, y en algunos casos, los programas funcionales son menos eficientes.
En general, le recomendamos que escriba funciones puras siempre que sea sensato hacerlo y recurra a los modificadores sólo si hay una clara ventaja. Este procedimiento podría llamarse estilo de programación funcional. Comentarios
En este capítulo, hemos demostrado una aproximación al desarrollo de programa que llamamos desarrollo de prototipo. En cada caso, escribimos un borrador (o prototipo) que realizó el cálculo básico y luego se probó en varios casos, corrigiendo errores cuando los encontramos.
Aunque este procedimiento pueda ser eficaz, esto puede llevar a escribir código que sea complicado innecesariamente ya que trata con muchos casos especiales y no fiable ya que es difícil de saber si hemos encontrado todos los errores.
Una alternativa es el desarrollo programado, en el cual las ideas brillantes aplicadas al problema pueden hacer la programación mucho más fácil. ¡En este caso, la idea es que un objeto Tiempo es realmente un número de tres dígitos en base 60! El segundo componente es la "columna de unos," el componente minutos es la "columna de sesentas," y el componente horas es la "columna de tres mil seiscientos."
Cuando escribimos tiempoSuma e incremento, de hecho estábamos sumando en base 60, que es la razón de que tuviéramos que llevarnos de una columna a la siguiente.
Esta observación sugiere otra aproximación a la totalidad del problema podemos convertir un objeto Tiempo en un solo número y aprovechar el hecho de que el ordenador sabe hacer cálculos aritméticos con números. La siguiente función convierte un objeto Tiempo en un número entero:
def pasarAsegundos(t):
minutos = t.horas * 60 + t.minutos
segundos = minutos * 60 + t.segundos
return segundos
Ahora, todo lo que necesitamos es un modo de pasar un número entero a un objeto Tiempo:
def hacerTiempo(segundos):
tiempo = Tiempo()
tiempo.horas = segundos/3600
segundos = segundos - tiempo.horas * 3600
tiempo.minutos = segundos/60
segundos = segundos - tiempo.minutos * 60
tiempo.segundos = segundos
return tiempo
A lo mejor deberías reflexionar un momento para convencerte de que esta técnica para pasar de una base a otra es correcta. Suponiendo que estás convencido de ello, puedes usar estas funciones para volver a escribir tiempoSuma:
def tiempoSuma(t1, t2):
segundos = pasarAsegundos(t1) + pasarAsegundos(t2)
return hacerTiempo(segundos)
Esta versión es mucho más corta que la original, y es mucho más fácil demostrar que es correcta (suponiendo, como siempre, que las funciones que calcule sean correctas).
Como ejercicio, vuelve a escribir incremento de la misma forma.Comentarios
De alguna forma, pasar de base 60 a base 10 y volver a base 60 es más difícil que operar sólo con tiempos. La conversión de la base es más abstracta; para operar con tiempos es mejor nuestra propia intuición.
Pero si tenemos la idea de manejar tiempos como números en base 60 y hacer la inversión de escribir las funciones de conversión (pasarAsegundos y hacerTiempo), conseguimos un programa que es más corto, más fácil para leer y depurar, y más fiable.
Además es más fácil añadir las funciones más tarde. Por ejemplo, imagina restar dos Tiempos para encontrar la duración entre ellos. La aproximación inexperta sería poner en práctica la resta con préstamo. La utilización de las funciones de conversión sería más fácil y con mayor probabilidad de ser correcta.
Irónicamente, a veces hacer un problema más difícil (o más general) lo hace más fácil (porque hay menos casos especiales y menos ocasiones para el error). Comentarios
Cuando escribes una solución general para una clase de problemas, a diferencia de una solución específica a un problema determinado, has escrito un algoritmo. Anteriormente mencionamos esta palabra, pero no la definimos con rigor. No es fácil de definir, por lo que intentaremos llevar a cabo un par de aproximaciones.
Primero, considera algo que no es un algoritmo. Cuando aprendiste a multiplicar números de un solo dígito, probablemente memorizaste la tabla de multiplicar. De hecho, memorizaste 100 soluciones específicas. Esa clase de conocimiento no es algorítmica.
Pero si eras "perezoso", probablemente hiciste trampas aprendiendo algunos trucos. Por ejemplo, para encontrar el producto de n y 9, puedes escribir n-1 como primer dígito y 10-n como segundo dígito. Este truco es una solución general para multiplicar cualquier número de un solo dígito por 9. ¡Eso es un algoritmo!
De igual forma, las técnicas que aprendiste para la suma con arrastre, la resta con préstamo, y las divisiones largas son todas algoritmos. Una de las características de los algoritmos es que no necesitan de inteligencia alguna para resolverse. Son procesos mecánicos en los cuales cada paso sigue al anterior de acuerdo a un simple conjunto de normas.
En nuestra opinión, es embarazoso que la gente pase tanto tiempo en la escuela aprendiendo a calcular algoritmos que, literalmente, no requieren de inteligencia alguna.
Por otro lado, el proceso de diseñar algoritmos es interesante, intelectualmente desafiante, y una parte principal de lo que llamamos programación.
Algunas de las cosas que la gente hace de forma natural, sin dificultad o de forma consciente, son las más difíciles de expresar algorítmicamente. El entendimiento del lenguaje de las personas es un buen ejemplo. Todos lo hacemos, pero hasta ahora nadie ha sido capaz de explicar cómo lo hacemos, al menos no en forma de algoritmo. Comentarios
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |