Herramientas Informaticas

Categoría: Pensar como programador Página 2 de 5

6.3. Tablas

Una de las cosas para las que resultan buenos los bucles es para generar datos tabulares. Antes de que los computadores estuvieran disponibles de forma masiva, la gente tenía que calcular a mano logaritmos, senos, cosenos y otras funciones matemáticas. Para facilitarlo, los libros de matemáticas contenían largas tablas donde aparecían los valores de estas funciones. Confeccionar estas tablas era una tarea lenta y pesada, y el resultado estaba lleno de erratas.

Cuando los computadores aparecieron en escena, una de las primeras reacciones fue ¡Que bueno! Podemos usar los computadores para generar las tablas, así no habrá errores”. Resulto cierto (casi), pero no se vio mas allá. Poco después los computadores y las calculadoras científicas se hicieron tan ubicuas que las tablas resultaron obsoletas.

Bueno, casi. Resulta que para ciertas operaciones, los computadores usan tablas para obtener un valor aproximado, y luego ejecutan cálculos para mejorar la aproximación. En algunos casos, ha habido errores en las tablas subyacentes; el mas famoso estaba en la tabla que el Pentium de Intel usaba para llevar a cabo la división de coma flotante.

Aunque una tabla logarítmica ya no es tan útil como lo fuera antaño, todavía constituye un buen ejemplo de iteración. El siguiente programa muestra una secuencia de valores en la columna izquierda y sus logaritmos en la columna derecha:

x = 1.0

while x < 10.0:

    print x, 't', math.log(x)

    x = x + 1.0

    

El nt representa un caracter de tabulacion.

Tal como se van mostrando en la pantalla caracteres y cadenas, un señalador invisible llamado cursor lleva la cuenta de donde ira el proximo caracter. Tras una sentencia print, el cursor va normalmente al principio de la línea siguiente.

El caracter de tabulacion hace que el cursor se desplace a la derecha hasta que alcance uno de los marcadores de tabulacion. Los tabuladores son utiles para alinear columnas de texto, como en la salida del programa anterior:

1.0 0.0
2.0 0.69314718056
3.0 1.09861228867
4.0 1.38629436112
5.0 1.60943791243
6.0 1.79175946923
7.0 1.94591014906
8.0 2.07944154168
9.0 2.19722457734

Si estos valores le parecen raros, recuerde que la funcion log usa como base e.

Debido a que las potencias de dos son muy importantes en las ciencias de la computación, generalmente querremos hallar los logaritmos en relacion con la base dos. Para llevarlo a cabo, podemos usar la siguiente formula:
log2 x =(logex/loge2)
(6.1)

Cambiar la sentencia de salida a:

   1: print x, 't', math.log(x)/math.log(2.0)

devuelve

1.0 0.0
2.0 1.0
3.0 1.58496250072
4.0 2.0
5.0 2.32192809489
6.0 2.58496250072
7.0 2.80735492206
8.0 3.0
9.0 3.16992500144

Podemos ver que 1, 2, 4 y 8 son potencias de dos, porque sus logaritomos de base 2 son numeros enteros. Si quisieramos encontrar los logaritmos de otras potencias de dos, podr³amos modificar el programa de la siguiente manera:

   1: x = 1.0

   2: while x < 100.0:

   3:     print x, 't', math.log(x)/math.log(2.0)

   4:     x = x * 2.0

Ahora, en lugar de añadir algo a x cada vez que atravesamos el bucle, que
devuelve una secuencia aritmetica, multiplicamos x por algo, devolviendo una
secuencia geometrica. El resultado es:
1.0 0.0
2.0 1.0
4.0 2.0
8.0 3.0
16.0 4.0
32.0 5.0
64.0 6.0

Debido a que usamos caracteres de tabulacion entre las columnas, la posicion de la segunda columna no depende del numero de dígitos de la primera columna.

Las tablas logarítmicas quizás ya no sean utiles, pero conocer las potencias de dos no ha dejado de serlo para los científicos informaticos.

Como actividad, modifique el programa para que muestre las potencias de dos hasta 65536 (es decir, 216). Imprímala y memorícela.

El caracter de barra invertida en ‘t’ indica el principio de una secuencia de escape. Las secuencias de escape se usan para representar caracteres invisibles como tabulaciones y retornos de carro. La secuencia n representa un retorno de carro.

Una sentencia de escape puede aparecer en cualquier lugar de una cadena; en el ejemplo, la secuencia de escape del tabulador es la unica de la cadena.
¿Como cree que puede representar una barra invertida en una cadena?

Como ejercicio, escriba un unica cadena que presente esta salida.

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

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.4. Porciones de cadenas

Llamamos porción a un segmento de una cadena. La selección de una porción es similar a la selección de un carácter:

   1: >>> s = "Pedro, Pablo, y María"

   2: >>> print 

   3: s[0:5]

   4: Pedro

   5: >>> print s[7:12]

   6: Pablo

   7: >>> print 

   8: s[15:20]

   9: María

El operador [n:m] devuelve la parte de la cadena desde el enésimo carácter hasta el “enésimo”, incluyendo el primero pero excluyendo el ultimo. Este comportamiento contradice a nuestra intuicion; tiene mas sentido si imagina los índices se~nalando entre los caracteres, como en el siguiente diagrama:

Sin título

Si omite el primer índice (antes de los dos puntos), la porcion comienza al principio de la cadena. Si omite el segundo índice, la porcion llega al final de la cadena. Así:

   1: >>> fruta = "banana"

   2: >>> fruta[:3]

   3: 'ban'

   4: >>> 

   5: fruta[3:]

   6: 'ana'

¿Que cree usted que significa s[:]?

7.5. Comparación de cadenas

Los operadores de comparación trabajan sobre cadenas. Para ver si dos cadenas son iguales:

   1: if palabra == "banana":

   2: print "S³, no tenemos bananas!"

Otras operaciones de comparacion son utiles para poner palabras en orden alfabético:

   1: if palabra < "banana":

   2:     print "Tu palabra," + palabra + ", va antes de banana."

   3: elif palabra > "banana":

   4:     print "Tu palabra," + palabra + ", va despues de banana."

   5: else:

   6:     print "Sí, no tenemos bananas!"

Sin embargo, deber³a usted ser consciente de que Python no maneja las mayúsculas y minusculas como lo hace la gente. Todas las mayusuculas van antes de la minúsculas. Como resultado de ello:

Tu palabra, Zapato, va antes de banana.

Una forma comun de abordar este problema es convertir las cadenas a un formato estandar, como pueden ser las minusculas, antes de realizar la comparacion.

Un problema mayor es hacer que el programa se de cuenta de que los zapatos no son frutas.

8.1. Valores de una lista

Hay varias maneras de crear una nueva lista; la mas sencilla es encerrar sus elementos entre corchetes:

   1: [10, 20, 30, 40]

   2: ["spam", "elastico", "golondrina"]

El primer ejemplo es una lista de cuatro enteros. El segundo es una lista de tres cadenas de texto. Los elementos de una lista no tienen por que ser del mismo tipo. La siguiente lista contiene una cadena, un numero con decimales y un entero, y, maravilla de las maravillas, otra lista:

   1: ["hola", 2.0, 5, [10, 20]]

Se dice que una lista dentro de otra lista esta anidada.

Las listas que contienen numeros enteros consecutivos son comunes, de manera que Python proporciona una manera sencilla de crearlas:

   1: >>> range(1,5)

   2: [1, 2, 3, 4]

La funcion range toma dos argumentos y devuelve una lista que contiene todos los enteros entre el primero y el segundo, ¡incluyendo el primero pero no el segundo!
Hay dos formas alternativas para range. Con un solo argumento, crea una lista que empieza desde 0:

   1: >>> range(10)

   2: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Si hay un tercer argumento, especificara el espacio entre dos valores sucesivos; a esto se le llama paso (step). Este ejemplo cuenta de 1 a 10 de dos en dos (con pasos de 2).

   1: >>> range(1, 10, 2)

   2: [1, 3, 5, 7, 9]

Para terminar, hay una lista especial que no contiene elementos. Se la llama lista vacía y se representa [].
Con todas estas maneras para crear listas, ser³a decepcionante que no pudiéramos asignar valores de listas a variables o pasar listas como parametros a funciones. Por supuesto que podemos.

   1: vocabulario = ["mejorar", "castigar", "defenestrar"]

   2: numeros = [17, 

   3: 123]

   4: vacio = []

   5: print vocabulario, numeros, vacio

   6: ['mejorar', 

   7: 'castigar', 'defenestrar'] [17, 123] []

8.3. Longitud (tamaño) de una lista

La función len toma una lista y devuelve su tamaño. Es una buena idea usar este valor como límite superior de un bucle, en lugar de una constante. De esta manera, si el tamaño de la lista cambia, no habrá que estar haciendo cambios en todos los bucles; funcionaran correctamente con cualquier tamaño de lista.

   1: jinetes = ["guerra", "hambre", "peste", "muerte"]

   2: i = 0

   3: while i < 

   4: len(jinetes):

   5: print jinetes[i]

   6: i = i + 1

La ultima vez que se ejecuta el cuerpo del bucle, i es len(jinetes) – 1, que es el índice del ultimo elemento. Cuando i se iguala a len(jinetes), la condición falla y no se ejecuta el cuerpo, lo que es una cosa buena, ya que len(jinetes)
no es un índice legal.

Aunque una lista puede contener otra lista como elemento, la lista anidada cuenta como un elemento sencillo. El tamaño de esta lista es 4:

   1: ['spam!', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3]]

Como ejercicio, escriba un bucle que recorra la lista anterior e imprima la longitud de cada elemento. }¿que ocurre si envía un entero a len?

8.7. Porciones (slices)

Las operaciones de porciones que vimos en la Sección 7.4 también funcionan en sobre las listas:

   1: >>> lista = ['a', 'b', 'c', 'd', 'e', 'f']

   2: >>> lista[1:3]

   3: ['b', 'c']

   4: >>> lista[:4]

   5: ['a', 'b', 'c', 'd']

   6: >>> lista[3:]

   7: ['d', 'e', 'f']

   8: >>> lista[:]

   9: ['a', 'b', 'c', 'd', 'e', 'f']

8.8. Las listas son mutables

A diferencia de las cadenas, las listas son mutables, lo que significa que podemos cambiar sus elementos. Podemos modificar uno de sus elementos usando el operador corchetes en el lado izquierdo de una asignación:

   1: >>> fruta = ["pl¶atano", "manzana", "membrillo"]

   2: >>> fruta[0] = "pera"

   3: >>> fruta[-1] = "naranja"

   4: >>> print fruta

   5: ['pera', 'manzana', 'naranja']

Con el operador de porción podemos reemplazar varios elementos a la vez:

   1: >>> lista = ['a', 'b', 'c', 'd', 'e', 'f']

   2: >>> lista[1:3] = ['x', 'y']

   3: >>> print lista

   4: ['a', 'x', 'y', 'd', 'e', 'f']

Además, puede eliminar elementos de una lista asignándoles la lista vacía:

   1: >>> lista = ['a', 'b', 'c', 'd', 'e', 'f']

   2: >>> lista[1:3] = []

   3: >>> lista

   4: ['a', 'd', 'e', 'f']

Y puede añadir elementos a la lista embutiéndolos en una porción vacía en la posición deseada:

   1: >>> lista = ['a', 'd', 'f']

   2: >>> lista[1:1] = ['b', 'c']

   3: >>> print lista

   4: ['a', 'b', 'c', 'd', 'f']

   5: >>> lista[4:4] = ['e']

   6: >>> print lista

   7: ['a', 'b', 'c', 'd', 'e', 'f']

Página 2 de 5

Creado con WordPress & Tema de Anders Norén