Herramientas Informaticas

Mes: agosto 2012 Página 6 de 22

6.4. Tablas de dos dimensiones

Una tabla de dos dimensiones es una tabla en la que Usted elige una fila y una columna y lee el valor de la intersección. Un buen ejemplo es una tabla de multiplicar. Supongamos que desea imprimir una tabla de multiplicar para los valores del 1 al 6.

Una buena manera de comenzar es escribir un bucle sencillo que imprima los múltiplos de 2, todos en una l³nea.

   1: i = 1

   2: while i <= 6:

   3:     print 2*i, 't',

   4:     i = i + 1

   5: print

La primera línea inicializa una variable lllamada i, que actuara como contador, o variable de bucle. Conforme se ejecuta el bucle, el valor de i se incrementa de 1 a 6. Cuando i vale 7, el bucle termina. Cada vez que se atraviesa el bucle,

imprimimos el valor 2*i seguido por tres espacios. De nuevo, la coma de la sentencia print suprime el salto de línea. Despues de completar el bucle, la segunda sentencia print crea una línea nueva.

La salida de este programa es:

2     4     6     8     10     12

Hasta ahora, bien. El siguiente paso es encapsular y generalizar.

6.5. Encapsulado y generalización

Por “encapsulado” generalmente se entiende tomar una pieza de código y envolverla en una función, permitiéndole obtener las ventajas de todo aquello para lo que valen las funciones. Hemos visto dos ejemplos de encapsulado, cuando escribimos imprimeParidad en la Sección 4.5 y esDivisible en la Sección 5.4.

Por “generalización” entendemos tomar algo específico, como imprimir los múltiplos de 2, y hacerlo mas general, como imprimir los múltiplos de cualquier entero.

He aquí una función que encapsula el bucle de la sección anterior y la generaliza para imprimir múltiplos de n.
def imprimeMultiplos(n):

   1: i = 1

   2: while i <= 6:

   3:     print n*i, 't',

   4:     i = i + 1

   5: print

Para encapsular, todo lo que hubimos de hacer fue añadir la primera línea, que declara el nombre de la función y la lista de parametros. Para generalizar, todo lo que tuvimos que hacer fue sustituir el valor 2 por el parametro n.

Si llamamos a esta funcion con el argumento 2, obtenemos la misma salida que antes. Con el argumento 3, la salida es:

   1: 3     6     9     12     15     18

y con argumento 4, la salida es

   1: 4     8     12     16     20     24

A estas alturas es probable que haya adivinado como vamos a imprimir una tabla de multiplicacion: llamaremos a imprimeMultiplos repetidamente con diferentes argumentos. De hecho, podemos a usar otro bucle:

   1: i = 1

   2: while i <= 6:

   3:     imprimeMultiplos(i)

   4:     i = i + 1

Observe hasta que punto este bucle es similar al que hay en el interior de imprimeMultiplos. Todo lo que hicimos fue sustituir la sentencia print por una llamada a una función.

La salida de este programa es una tabla de multiplicación:

   1: 1 2 3 4 5 6

   2: 2 4 6 8 10 12

   3: 3 6 9 12 15 18

   4: 4 8 12 16 20 24

   5: 5 10 15 20 25 30 

   6: 6 12 18 24 30 36

6.6. Más encapsulación

Para dar mas ejemplos de encapsulación, tomaremos el código del final de la Sección 6.5 y lo envolveremos en una función:

   1: def imprimeTablaMult():

   2:     i = 1

   3:     while i <= 6:

   4:         imprimeMultiplos(i)

   5:         i = i + 1

   6:         

El proceso que mostramos aquí es un plan de desarrollo habitual. Se desarrolla gradualmente el codigo añadiendo líneas fuera de cualquier funcion o en el interprete. Cuando conseguimos que funcionen, se extraen y se envuelven en una funcion.

Este plan de desarrollo es especialmente si, al comenzar a escribir, no sabe como dividir el programa en funciones. Este enfoque le permite diseñarlo sobre la marcha.

6.7. Variables locales

Quizá se este preguntando como podemos usar la misma variable tanto en imprimeMultiplos como en imprimeTablaMult.

¿No habrá problemas cuando una de las funciones cambie los valores de la variable?

La respuesta es no, ya que la variable i en imprimeMultiplos y la variable i in imprimeTablaMult no son la misma variable.

Las variables creadas dentro de una función son locales. No puede acceder a una variable local fuera de su función “huésped”. Eso significa que es posible tener múltiples variables con el mismo nombre, siempre que no estén en la misma función.

El diagrama de pila de esta función muestra claramente que las dos variables llamadas i no son la misma variable. Pueden referirse a diferentes valores, y cambiar uno no afecta al otro.

Sin título

El valor de i en imprimeTablaMult va desde 1 hasta 6. En el diagrama, resulta ser 3. El próximo recorrido del bucle será 4. En cada recorrido del bucle,imprimeTablaMult llama a imprimeMultiplos con el valor actual de i como argumento. Ese valor se asigna al parámetro n.

Dentro de imprimeMultiplos, el valor de i va desde 1 hasta 6. En el diagrama, resulta ser 2. Los cambios en esta variable no tienen ningún efecto sobre el valor de i en imprimeTablaMult.

Es habitual y perfectamente legal tener diferentes variables locales con el mismo nombre. En especial, los nombres i, j y k se suelen usar como variables de bucle. Si evita usarlas en una función porque las utilizo en algún otro lugar, probablemente consiga que el programa sea mas difícil de leer.

6.8. Más generalización

Como otro ejemplo de generalización, imagine que desea un programa que imprima una tabla de multiplicación de cualquier tamaño, y no solo la tabla de 6×6. Podría añadir un parámetro a imprimeTablaMult:

   1: def imprimeTablaMult(mayor):

   2: i = 1

   3: while i <= 

   4: mayor:

   5: imprimeMultiplos(i)

   6: i = i + 1

Hemos sustituido el valor 6 con el parametro mayor. Si ahora se llama a imprimeTablaMult con el argumento 7, obtenemos:

   1: 1 2 3 4 5 6

   2: 2 4 6 8 10 12

   3: 3 6 9 12 15 18

   4: 4 8 12 16 20 24

   5: 5 10 15 20 25 30

   6: 6 12 18 24 30 36

   7: 7 14 21 28 35 42

lo que es correcto, excepto por el hecho de que seguramente queremos que la tabla este cuadrada, con el mismo numero de filas que de columnas. Para hacerlo, añadimos otro parametro a imprimeMultiplos, a fin de especificar cuantas columnas tendría que tener la tabla.

Solo para fastidiar, llamaremos tambien a este parametro mayor, para demostrar que diferentes funciones pueden tener parametros con el mismo nombre (al igual que las variables locales). Aquí tenemos el programa completo:

   1: def imprimeMultiplos(n, mayor):

   2:     int i = 1

   3:     while i <= mayor:

   4:         print 

   5:         n*i, 't',

   6:         i = i + 1

   7:         print

   8:     def imprimeTablaMult(mayor):

   9:         int i = 

  10:         1

  11:         while i <= mayor:

  12:         imprimeMultiplos(i, mayor)

  13:         i = i + 1

  14:         

Nótese que al añadir un nuevo parametro, tuvimos que cambiar la primera línea de la funcion (el encabezado de la funcion), y tuvimos tambien que cambiar el lugar donde se llama a la función en imprimeTablaMult.

Según lo esperado, este programa genera una tabla cuadrada de 7×7:

   1: 1 2 3 4 5 6 7

   2: 2 4 6 8 10 12 14

   3: 3 6 9 12 15 18 21

   4: 4 8 12 16 20 24 

   5: 28 5 10 15 20 25 30 35

   6: 6 12 18 24 30 36 42

   7: 7 14 21 28 35 42 49

Cuando generaliza correctamente una funcion, a menudo se encuentra con que el programa resultante tiene capacidades que Usted no pensaba. Por ejemplo, quizá observe que la tabla de multiplicacion es simetrica, porque ab = ba, de manera que todas las entradas de la tabla aparecen dos veces. Puede ahorrar tinta imprimiendo solo la mitad de la tabla. Para hacerlo, solo tiene que cambiar una línea de imprimeTablaMult. Cambie imprimeMultiplos(i, mayor) por imprimeMultiplos(i, i) y obtendra

   1: 1

   2: 2 4

   3: 3 6 9

   4: 4 8 12 16

   5: 5 10 15 20 25

   6: 6 12 18 24 30 36

   7: 7 14 21 28 35 42 49

Como actividad, siga o trace la ejecucion de esta nueva version de imprimeTablaMult para hacerse una idea de como funciona.

6.9. Funciones

Hasta el momento hemos mencionado en alguna ocasión “todas las cosas para las que sirven las funciones”. Puede que ya se este preguntando que cosas son exactamente. He aqu³ algunas de las razones por las que las funciones son útiles:

  • Al dar un nombre a una secuencia de sentencias, hace que su programa sea mas fácil de leer y depurar.
  • Dividir un programa largo en funciones le permite separar partes del programa, depurarlas aisladamente, y luego recomponerlas en un todo.
  • Las funciones facilitan tanto la recursividad como la iteración.
  • Las funciones bien dise~nadas son generalmente útiles para mas de un programa. Una vez escritas y depuradas, pueden reutilizarse.

6.10. Glosario

asignación múltiple: Hacer mas de una asignación a la misma variable durante la ejecución de un programa.

iteración: La ejecución repetida de un conjunto de sentencias por medio de una llamada recursiva a una función o un bucle.

bucle: Sentencia o grupo de sentencias que se ejecutan repetidamente hasta que se cumple una condición de terminación.

bucle infinito: Bucle cuya condición de terminación nunca se cumple.

cuerpo: Las sentencias que hay dentro de un bucle.

variable de bucle: Variable que se usa para determinar la condición de terminación de un bucle.

tabulador: Carácter especial que hace que el cursor se mueva hasta la siguiente marca de tabulación en la línea actual.

nueva línea: Un carácter especial que hace que le cursor se mueva al inicio de la siguiente línea.

cursor: Un marcador invisible que sigue el rastro de donde se imprimirá el siguiente carácter.

secuencia de escape: Carácter de escape (n) seguido por uno o mas caracteres imprimibles, que se usan para designar un carácter no imprimible.

encapsular: Dividir un programa largo y complejo en componentes (como las funciones) y aislar los componentes unos de otros (por ejemplo usando variables locales).

generalizar: Sustituir algo innecesariamente específico (como es un valor constante) con algo convenientemente general (como es una variable o parámetro). La generalización hace el código mas versátil, mas apto para reutilizarse y algunas veces incluso mas fácil de escribir.

plan de desarrollo: Proceso para desarrollar un programa. En este capítulo, hemos mostrado un estilo de desarrollo basado en desarrollar código para hacer cosas simples y específicas, y luego encapsularlas y generalizarlas.

Cadenas

7.1. Un tipo de datos compuesto

Hasta el momento hemos visto tres tipos: int, float, y string. Las cadenas son cuantitativamente diferentes de los otros dos porque están hechas de piezas menores: caracteres.

Los tipos que comprenden piezas menores se llaman tipos de datos compuestos. Dependiendo de que estemos haciendo, podemos querer tratar un tipo compuesto como una única cosa o acceder a sus partes. Esta ambigüedad es útil.

El operador corchete selecciona un carácter suelto de una cadena.

   1: >>> fruta = "banana"

   2: >>> letra = fruta[1]

   3: >>> 

   4: print letra

La expresion fruta[1] selecciona el caracter numero 1 de fruta. La variable letra apunta al resultado. Cuando mostramos letra, nos encontramos con una sorpresa: a

La primera letra de “banana” no es a. A no ser que usted sea un programador.

Por perversas razones, los científicos de la computacion siempre empiezan a contar desde cero. La 0-sima letra (“cerosima”) de “banana” es b. La 1-esima (“unesima”) es a, y la 2-esima (dosesima”) letra es n.

Si quiera la cerosima letra de una cadena, simplemente pone 0, o cualquier expresión de valor 0, entre los corchetes:

   1: >>> letra = fruta[0]

   2: >>> print letra

   3: b

A la expresion entre corchetes se le llama índice. Un índice identifica a un miembro de un conjunto ordenado, en este caso el conjunto de caracteres de la cadena. El ³ndice indica cual quiere usted, de ahí el nombre. Puede ser cualquier expresión entera.

7.2. Longitud

La función len devuelve el número de caracteres de una cadena:

   1: >>> fruta = "banana"

   2: >>> len(fruta)

   3: 6

Para obtener la última letra de una cadena puede sentirse tentado a probar algo como esto:

   1: longitud = len(fruta)

   2: ultima = fruta[longitud] # ERROR!

Eso no funcionara. Provoca un error en tiempo de ejecucion IndexError:string index out of range. La razon es que no hay una sexta letra en “banana“. Como empezamos a contar por cero, las seis letras estan numeradas del 0 al 5. Para obtener el ultimo caracter tenemos que restar 1 de longitud:

   1: longitud = len(fruta)

   2: ultima = fruta[longitud-1]

De forma alternativa, podemos usar índices negativos, que cuentan hacia atrás desde el final de la cadena. La expresion fruta[-1] nos da la ultima letra. fruta[-2] nos da la penultima, y así.

7.3. Recorrido y el bucle for

Muchos cálculos incluyen el proceso de una cadena carácter a carácter. A menudo empiezan por el principio, seleccionan cada carácter por turno, hacen algo con el y siguen hasta el final. Este patrón de proceso se llama recorrido. Una forma de codificar un recorrido es una sentencia while:

   1: indice = 0

   2: while indice < len(fruta):

   3:     letra = fruta[indice]

   4:     print 

   5:     letra

   6:     indice = indice + 1

Este bucle recorre la cadena y muestra cada letra en una línea distinta. La condición del bucle es indice < len(fruta), de modo que cuando indice es igual a la longitud de la cadena, la condicion es falsa y no se ejecuta el cuerpo del bucle. El ultimo caracter al que se accede es el que tiene el índice len(fruta)-1, que es el ultimo caracter de la cadena.

Como ejercicio, escriba una función que tome una cadena como argumento y entregue las letras en orden inverso, una por línea.

Es tan habitual usar un índice para recorrer un conjunto de valores que Python facilita una sintaxis alternativa mas simple: el bucle for:

   1: for car in fruta:

   2: print car

Cada vez que recorremos el bucle, se asigna a la variable car el siguiente carácter de la cadena. El bucle continua hasta que no quedan caracteres.

El ejemplo siguiente muestra como usar la concatenacion junto a un bucle for para generar una serie abecedarica. “Abecedarica” es la serie o lista en la que cada uno de los elementos aparece en orden alfabetico. Por ejemplo, en el libro de Robert McCloskey Make Way for Ducklings (Dejad paso a los patitos), los nombres de los patitos son Jack, Kack, Lack, Mack, Nack, Ouack, Pack, y Quack.

Este bucle saca esos nombres en orden:

   1: prefijos = "JKLMNOPQ"

   2: sufijo = "ack"

   3: for letra in prefijos:

   4: print letra 

   5: + sufijo

   6: La salida del programa 

   7: es:

   8: Jack

   9: Kack

  10: Lack

  11: Mack

  12: Nack

  13: Oack

  14: Pack

  15: Qack

Por supuesto, esto no es del todo correcto, porque “Ouack” y “Quack” no están correctamente escritos.

Como ejercicio, modifique el programa para corregir este error.

Página 6 de 22

Creado con WordPress & Tema de Anders Norén