You are on page 1of 92

Parte II

Introduccin a la programacin

CAPTULO

Introduccin a la programacin

2.1.
2.1.1.

Abstraccin de problemas para su programacin. Conceptos fundamentales


Qu es un programa?

La habilidad ms importante del ingeniero es la capacidad para solucionar problemas. La solucin de problemas incluye poder formalizar problemas, pensar en la solucin de manera creativa, y expresar esta solucin en trminos que un ordenador pueda entender. La solucin de problemas mediante el uso del ordenador se consigue a travs de los programas. Denicin Un programa es un texto con una secuencia de instrucciones que un ordenador puede interpretar y ejecutar. Los programas son, por tanto, el medio de comunicacin con el ordenador. Mediante su utilizacin conseguimos que las mquinas aprovechen sus capacidades para resolver los problemas que nos interesan. Sin los programas los ordenadores no son capaces de hacer nada.

2.1.2.

Lenguajes de programacin

Los programas se escriben en lenguajes especializados llamados lenguajes de programacin. Hay muchos lenguajes de programacin, pero para programar no es necesario conocerlos todos. En esencia, la tcnica bsica necesaria para programar es comn a todos los lenguajes. Denicin Un lenguaje de programacin es un idioma formado por un conjunto de smbolos y reglas sintcticas y semnticas que denen la estructura y el signicado de las instrucciones de que consta el lenguaje. Cuando escribimos un programa utilizando un determinado lenguaje de programacin llamamos cdigo fuente, o simplemente cdigo, al texto del programa. Cuando un ordenador lleva a cabo una tarea indicada por un programa, decimos que ejecuta el cdigo. Aunque no vamos a entrar en los detalles de cada uno, es necesario mencionar que a la hora de programar se pueden seguir diversas tcnicas o paradigmas de programacin: programacin

38

Introduccin a la programacin

imperativa, declarativa, estructurada, modular, orientada a objetos, etc. Los lenguajes de programacin suelen soportar varios de estos paradigmas de programacin. Independientemente del lenguaje que se utilice, es importante que el alumno se acostumbre a seguir los principios de la programacin modular, que consiste en dividir un programa en mdulos o subprogramas con el n de hacerlo ms legible y manejable. En general, un problema complejo debe ser dividido en varios subproblemas ms simples, y estos a su vez en otros subproblemas ms simples. Esto debe hacerse hasta obtener subproblemas lo sucientemente simples como para poder ser resueltos fcilmente con algn lenguaje de programacin. En la actualidad los lenguajes de programacin, llamados de alto nivel, estn pensados para que los programas sean comprensibles por el ser humano. Sin embargo, el cdigo fuente de los mismos no es comprendido por el ordenador, ya que ste slo maneja el lenguaje binario o lenguaje mquina. Es necesario hacer una traduccin de los programas escritos en un lenguaje de programacin de alto nivel a lenguaje mquina. Hay dos tipos diferentes de lenguajes dependiendo de la forma de hacer esta traduccin: Lenguajes compilados El Compilador realiza una traduccin completa del programa en lenguaje de alto nivel a un programa equivalente en lenguaje mquina. Este programa resultante, programa ejecutable, se puede ejecutar todas las veces que se quiera sin necesidad de volver a traducir el programa original.

Lenguajes interpretados En este caso, el Intrprete va leyendo el programa en lenguaje de alto nivel instruccin a instruccin, cada una de ellas se traduce y se ejecuta. No se genera un programa directamente ejecutable.

El enfoque compilado genera cdigo ejecutable que utiliza directamente las instrucciones nativas de la CPU. Esto suele implicar que el programa se ejecutar mucho ms velozmente que si se hiciera en un lenguaje interpretado. A cambio, presenta el inconveniente de que el ejecutable resultante de la compilacin slo sirve para ser ejecutado en una CPU concreta y un Sistema Operativo concreto (aquellos para los que se compil), o bien versiones compatibles de la CPU y el operativo, mientras que si se hiciera en un lenguaje interpretado podra ser ejecutado en cualquier arquitectura y operativo para los que exista el intrprete.

2.1 Abstraccin de problemas para su programacin. Conceptos fundamentales

39

2.1.3.

Programas y algoritmos

Cuando se aprende el primer lenguaje de programacin se piensa que la parte difcil de resolver un problema con un ordenador es escribir el programa siguiendo las reglas del lenguaje. Esto es totalmente falso. La parte ms difcil es encontrar el mtodo de resolucin del problema. Una vez encontrado este mtodo, es bastante sencillo traducirlo al lenguaje de programacin necesario: Python, C++, Java o cualquier otro. Denicin Se denomina algoritmo a una secuencia no ambigua, nita y ordenada de instrucciones que han de seguirse para resolver un problema.

Importante Un programa de ordenador es un algoritmo escrito en un lenguaje de programacin. En un algoritmo siempre se deben de considerar tres partes: Entrada: informacin dada al algoritmo. Proceso: operaciones o clculos necesarios para encontrar la solucin del problema. Salida: respuestas dadas por el algoritmo o resultados nales de los procesos realizados. Los algoritmos se pueden expresar de muchas maneras: utilizando lenguajes formales, lenguajes algortmicos (pseudocdigo) o mediante el lenguaje natural (como el castellano). Esta ltima es la forma ms adecuada para la asignatura que nos ocupa. Ejemplo: Algoritmo para calcular el rea de un tringulo 1. Obtener la base del tringulo 2. Obtener la altura del tringulo 3. Hacer la operacin (base altura)/2 4. Mostrar el resultado Este algoritmo de resolucin del rea del tringulo es independiente del lenguaje de programacin que vayamos a utilizar. Cualquier programa que quiera calcular el rea de un tringulo escrito en cualquier lenguaje de programacin debe seguir estos pasos. Terminologa Dos programas distintos codicados en el mismo o en distinto lenguaje de programacin y que resuelven el mismo problema con la misma secuencia de pasos, se dice que son implementaciones del mismo algoritmo.

2.1.4.

Diseo de programas

Aunque el diseo de programas es un proceso creativo, hay que seguir una serie de pasos. Nadie empieza a escribir un programa directamente sin estudiar el problema que se quiere resolver. Todo el proceso de diseo de un programa se puede dividr en dos fases: Fase de resolucin de problemas. El resultado de esta primera fase es un algoritmo, expresado en espaol, para resolver el problema.

40

Introduccin a la programacin Fase de implementacin. A partir del algoritmo obtenido en la fase anterior, se codica y se prueba el programa nal.

Importante Muchos programadores noveles no entienden la necesidad de disear un algoritmo antes de escribir un programa en un lenguaje de programacin. La experiencia ha demostrado que la resolucin de problemas en dos fases da lugar a programas que funcionan correctamente en menos tiempo. Esta forma de disear programas requiere la realizacin de una serie de tareas: Anlisis del problema. A partir de la descripcin del problema, expresado habitualmente en lenguaje natural, es necesario obtener una idea clara sobre qu se debe hacer (proceso), determinar los datos necesarios para conseguirlo (entrada) y la informacin que debe proporcionar la resolucin del problema (salida). Diseo del algoritmo. Se debe identicar las tareas ms importantes para resolver el problema y disponerlas en el orden en el que han de ser ejecutadas. Los pasos en una primera descripcin pueden requerir una revisin adicional antes de que podamos obtener un algoritmo claro, preciso y completo. Transformacin del algoritmo en un programa (codicacin). Solamente despus de realizar las dos etapas anteriores abordaremos la codicacin de nuestro programa en el lenguaje de programacin elegido. Ejecucin y pruebas del programa. Se debe comprobar que el programa resultante est correctamente escrito en el lenguaje de programacin y, ms importante an, que hace lo que realmente debe hacer.

2.1 Abstraccin de problemas para su programacin. Conceptos fundamentales

41

2.1.5.

Python

Python es un lenguaje de alto nivel como pueden ser el C, C++ o el Java. Entonces, por qu hemos escogido precisamente Phyton en este curso? Python presenta una serie de ventajas que lo hacen muy atractivo, tanto para su uso profesional como para el aprendizaje de la programacin. Entre ellas podemos destacar las siguientes: La sintaxis es muy sencilla y cercana al lenguaje natural, lo que facilita tanto la escritura como la lectura de los programas. Es un lenguaje muy expresivo que da lugar a programas compactos, bastante ms cortos que sus equivalentes en otros lenguajes. Es un lenguaje de programacin multiparadigma, que permite al programador elegir entre varios estilos: programacin orientada a objetos, programacin imperativa (y modular) y programacin funcional. Es multiplataforma por lo que podremos utilizarlo tanto en Unix/Linux, Mac/OS o Microsoft Windows. Es un lenguaje interpretado y por tanto interactivo. En el entorno de programacin de Python se pueden introducir sentencias que se ejecutan y producen un resultado visible, que puede ayudarnos a entender mejor el lenguaje y probar los resultados de la ejecucin de porciones de cdigo rpidamente. Python es gratuito, incluso para propsitos empresariales. Es un lenguaje que est creciendo en popularidad. Algunas empresas que utilizan Python son Yahoo, Google, Disney, la NASA, Red Hat, etc. Para saber ms Python es un lenguaje de programacin creado por Guido van Rossum a principios de los aos 90 cuyo nombre est inspirado en el grupo de cmicos ingleses Monty Python. Toda la informacin necesaria sobre el lenguaje la puedes encontrar en http://www. python.org/. Python permite dos modos de interaccin con el lenguaje: 1. Escribir comandos directamente en el intrprete. En este modo, cada lnea que escribimos es ejecutada al pulsar el retorno de carro, y el resultado de la ejecucin se muestra inmediatamente, a continuacin. Es til para probar ejemplos simples y ver inmediatamente el resultado, y para experimentar con diferentes expresiones para comprender mejor sus diferencias y su funcionamiento. El inconveniente es que todo lo que se va escribiendo, se pierde cuando se cierra el intrprete. 2. Escribir un programa completo en un editor de textos, guardar el programa en un chero y despus usar el intrprete para ejecutarlo. En este caso no se ejecuta nada mientras se escribe, sino slo cuando se lanza el intrprete para que ejecute el programa completo que est en el chero. Entonces el intrprete ir leyendo lnea a lnea del chero y las ir ejecutando. No se muestra ningn resultado por pantalla, a menos que el programa contenga la orden print que sirve precisamente para esto (como veremos en su momento).

42

Introduccin a la programacin

A lo largo de este documento, presentaremos ejemplos en ambos formatos. Si se trata de ejemplos muy breves encaminados slo a demostrar alguna caracterstica del lenguaje, usaremos el intrprete directo. Si se trata de ejemplos ms largos que tienen inters suciente para merecer ser guardados en un chero, usaremos el editor. El lector puede diferenciar si usamos el intrprete o el editor, porque el estilo en que se muestra el cdigo es diferente en cada caso. Cuando se usa el intrprete, puede verse el smbolo >>> delante de cada lnea que el usuario teclea, y la respuesta del intrprete en la lnea siguiente:
>>> "Ejemplo ejecutado en el interprete" Ejemplo ejecutado en el iterprete

En cambio, cuando se muestra cdigo para ser escrito en el editor, no se ve el resultado de su ejecucin. Adems las lneas estn numeradas para facilitar el referirse a ellas si es necesario (el alumno no debe copiar estos nmeros cuando escriba el cdigo en el editor).
1 # Ejemplo para ser escrito en el editor 2 print "Ejemplo"

2.2.
2.2.1.

Variables, expresiones, asignacin


Valores

El principal motivo por el que se escriben programas de ordenador es para manipular la informacin de una forma ms eciente y segura. Desde el punto de vista de la informacin, los programas manejan tpicamente los datos del siguiente modo: 1. Reciben datos de entrada por parte de los usuarios, 2. procesan esos datos, haciendo clculos y operaciones con ellos, y 3. producen resultados que son tiles para los usuarios. Los resultados pueden ser tanto valores calculados (por ejemplo, en una aplicacin de clculo de estructuras, obtener las dimensiones que debe tener una viga), como obtener un informe impreso. Aunque la informacin que manejan los programas puede parecer muy amplia, ya que existen aplicaciones informticas para propsitos muy diversos, en realidad la informacin est formada habitualmente por la agregacin de tres tipos de de datos bsicos: nmeros: 7, 3.14165 textos: Juan, Alonso, Universidad de Oviedo valores lgicos: True, False Combinando estos elementos se puede representar la informacin bsica que usan los programas. Por ejemplo, si se quiere hacer una aplicacin para gestionar los datos de cada cliente de un banco, necesitaremos guardar su nombre y apellidos (textos), el saldo de sus cuentas (nmeros) o si el cliente es preferente o no (valor lgico). Los valores lgicos tal vez parezcan menos tiles, sin embargo es casi lo contrario, no solamente permiten representar aquella informacin que puede ser cierta o falsa, sino que adems son los datos fundamentales para controlar el ujo de ejecucin de los programas (como se ver ms adelante, las sentencias condicionales y los bucles se basan en la manipulacin de valores lgicos).

2.2.2.

Tipos

Cada dato o valor que se maneja en un programa es de un tipo. Python detecta de qu tipo es cada dato por su sintaxis. Una secuencia de dgitos que no contenga el punto (.) se considera un entero. Si contiene el punto se considera un real (que python llama float). Una secuencia arbitraria de caracteres delimitados por el carcter de comillas dobles ("), o de comillas simples ()

2.2 Variables, expresiones, asignacin

43

es considerado una cadena de texto1 . Las palabras especiales True y False se consideran datos de tipo booleano. 7 es de tipo int (de integer), es un nmero entero 3.14165 es de tipo float, un nmero en coma otante (real) "Juan", es de tipo str (de string), es una cadena de caracteres True es de tipo bool (de booleano), un valor de verdad Los tipos denen conjuntos de valores que los programas pueden manejar y las operaciones que se pueden hacer con ellos. Por ejemplo, los programas pueden utilizar, gracias al tipo float, el conjunto de los nmeros reales y podemos sumar dos reales. En concreto, el rango de los nmeros reales que se pueden utilizar es de 1.7e308 que viene dado por el nmero de bytes (8) que se utilizan para representarlos2 . Para saber ms Adems del tipo int, python posee otro tipo entero, long. Normalmente se manejan los valores enteros como int ya que este tipo permite representar valores del orden de millones de billones. Si alguna vez un programa necesita guardar un valor entero an mayor, entonces se representar automticamente (sin que el programador deba hacer nada) como un long. La capacidad de representacin de un long est slo limitada por la cantidad de memoria libre, por lo que en la prctica puede representar valores enteros extremadamente grandes. Para saber el tipo de un valor, se puede utilizar la funcin type. Simplemente hay que indicar el valor del que se quiere conocer su tipo:
>>>> type(7) <type int> >>> type(3.1416) <type float> >>> type("Juan") <type str> >>> type(True) <type bool>

Como se puede apreciar, se imprime en la consola el tipo de cada uno de los valores. En realidad esto no es muy til a la hora de escribir un programa, ya que normalmente el programador sabe de qu tipo es cada uno de los datos que el programa maneja.

2.2.3.

Conversiones entre tipos

A veces los programas reciben valores que son de un cierto tipo y necesitan convertirlos en valores de otro tipo antes de hacer operaciones con ellos. Esta situacin se produce, por ejemplo, con datos que se reciben como string pero que representan nmeros; antes de hacer clculos con ellos es necesario convertirlos en un valor numrico. La forma de hacer esas conversiones es bastante sencilla: primero hay que indicar el nombre del tipo al que se quiere convertir el valor, y posteriormente entre parntesis el valor que se quiere convertir. Por ejemplo:
Para delimitar las cadenas se puede usar indistintamente la comilla simple o la doble, pero es forzoso usar el mismo tipo de comilla para abrir y para cerrar. 2 Cuando un nmero real se sale de ese rango se considera
1

44

Introduccin a la programacin

>>> int("7") 7 >>> str(7) 7 >>> float("3.1416") 3.1415999999999999 >>> str(3.1416) 3.1416 >>> int(3.1416) 3 >>> float(7) 7.0

En el primer ejemplo se convierte en int la cadena de caracteres formada solamente por el dgito 7. El valor que se devuelve es el entero 7, que obviamente no es lo mismo la cadena que contiene el dgito 7, ni en cuanto al dato en s mismo, ni sobre todo a las operaciones que se van a poder hacer con l (la cadena con el dgito 7 no se podr dividir por otro valor, mientras que el valor entero s). El ejemplo contrario se da en la siguiente instruccin. En este caso se convierte en cadena (str) el valor entero 7. El valor que se devuelve es ahora una cadena (est entre comillas) formada por el dgito 7. Un caso anlogo se da cuando se convierte nmeros reales en cadenas y viceversa. De nuevo no es lo mismo el nmero real que la cadena formada por los dgitos que componen dicho nmero. En los dos ejemplos nales, se ve cmo se pueden convertir nmeros reales en enteros y al revs. Cuando se convierte un nmero real en entero, se devuelve la parte entera (equivale a truncar) y cuando se convierte un entero en real, la parte decimal vale 0.

2.2.4.

Operadores

Los programas usan los valores que manipulan para hacer clculos y operaciones con ellos. La forma ms sencilla de hacer operaciones con los datos es empleando los operadores del lenguaje. Cada uno de los tipos descritos anteriormente permite hacer operaciones diferentes con sus valores. Antes de estudiar los operadores ms utilizados, es interesante ver unos ejemplos iniciales. En todos estos ejemplos se usan operadores binarios (tienen dos operandos) y su sintaxis es siempre la misma: operando operador operando:
>>> 7 + 4 11 >>> 3.1416 * 2 6.2831999999999999 >>> "Juan" + " Alonso" Juan Alonso >>> True and False False

En las instrucciones anteriores se han usado operadores binarios: el operador suma (+) para sumar dos enteros, el operador producto (*) para multiplicar un real por un entero, de nuevo el operador + para concatenar dos cadenas, y por ltimo el operador y-lgico (and) para hacer dicha operacin entre dos valores lgicos. El primer detalle importante que se debe observar es que todas las operaciones producen un valor: cuando sumamos 7 y 4 el resultado es el valor entero 11, o cuando concatenamos las cadenas Juan y Alonso se produce la cadena Juan Alonso. El segundo aspecto fundamental es entender qu hace cada operador. En los dos ejemplos anteriores el mismo operador + se comporta de manera diferente si se suman enteros que si se utiliza para concatenar cadenas. Por ello, se deben conocer los operadores que existen en el lenguaje y las operaciones que hace cada uno de ellos.

2.2 Variables, expresiones, asignacin

45

Aunque hay ms operadores de los que se van a citar a continuacin, los ms utilizados y con los que se pueden hacer la gran mayora de los programas estn agrupados en tres grandes grupos: Aritmticos: + (suma), - (resta), * (producto), / (divisin), % (resto) y ** (potencia). Tambin hay un operador unario (que acta sobre un solo dato, en lugar de dos) que es el - para cambiar de signo al dato que le siga. Relacionales: == (igual), != (distinto), < (menor que), <= (menor o igual que), > (mayor que) y >= (mayor o igual que) Lgicos: and (y-lgico), or (o-lgico) y not (no-lgico) Los operadores aritmticos se emplean habitualmente con los tipos numricos y permiten hacer las operaciones matemticas tpicas. El nico operador que tiene un comportamiento diferente segn los operandos sean int o float es el operador divisin (/): cuando recibe enteros hace una divisin entera, el cociente ser un valor entero, y con valores reales la divisin es real. Es un buen ejemplo de que el resultado de una expresin que use un operador depende de los operandos que se empleen, en este caso basta con que uno de los dos operandos sea un nmero real para que la divisin sea real. Para saber ms Existen dos variantes del lenguaje Python. La que explicamos en esta asignatura se denomina Python 2, la otra (ms reciente pero an menos extendida) se denomina Python 3. En Python 3, el operador / se comporta de forma diferente a como se ha descrito, ya que siempre realiza la divisin real (otante), incluso si los operandos son enteros. Para el caso en que se quiera realizar la divisin entera se tiene el operador // (que tambin existe en Python 2). Esto suele resultar ms claro para los principiantes. Si quieres que Python 2 se comporte como Python 3 en lo que respecta a la divisin, puedes poner al principio de tus programas una lnea que diga:
1 from __future__ import division

Sin entrar a explicar la curiosa sintaxis de esta lnea, basta saber que si la pones, entonces el operador / realizar siempre la divisin real, al igual que en Python 3. Algunos operadores aritmticos, en concreto el operador + y el operador *, se pueden utilizar tambin con cadenas de caracteres3 . Lo que producen son, respectivamente, la concatenacin de dos cadenas, y la concatenacin de una misma cadena varias veces (luego se ver algn ejemplo de esta operacin). Los operadores relacionales sirven para determinar si es cierta o no una relacin de orden entre dos valores, o si stos son iguales o distintos. Por ejemplo, podemos comprobar si 3 <= 5. Intuitivamente es natural pensar que una relacin de orden o igualdad puede ser cierta o no, es decir, el resultado de esa operacin ser un valor lgico siempre, independientemente de si los valores son nmeros o cadenas de caracteres. Los valores de tipo str tambin se pueden comparar, el valor que se produce depende de su ordenacin alfabtica, distinguindose entre maysculas y minsculas. Por ltimo, se pueden hacer las tpicas operaciones lgicas y, o y no. De nuevo en este caso el valor que se produce es de tipo bool ya que la operacin podr ser cierta o falsa. Estos
3

Tambin con listas, como se indicar en el apartado dedicado a ellas

46

Introduccin a la programacin

operadores se emplean fundamentalmente al escribir las condiciones de las sentencias condicionales y los bucles que se estudiarn ms adelante. La mejor forma de comprender los operadores es jugar con ellos usando el intrprete, introduciendo valores de distintos tipos y viendo el resultado que producen las expresiones resultantes. Algunos ejemplos descriptivos podran ser los siguientes:
>>> 2 / 3 0 >>> 2 % 3 2 >>> 2.0 / 3 0.66666666666666663 >>> 2 ** 3 8 >>>> "Pe" * 4 PePePePe >>> not True False >>> 2 > 3 False >>> 3 <= 3.1416 True >>> 2 == 3 False >>> 2 != 3 True >>> "Antonio" < "Juan" True

En el primer ejemplo se hace una divisin entre dos enteros, el resultado es el cociente, en ese caso 0. Si hacemos el resto ( % ) de esa misma divisin, el valor obtenido es 2. Cuando uno de los operandos es un nmero real, como pasa en el tercer ejemplo, entonces la divisin es real, produciendo un cociente que es un valor float. Aunque en otros lenguajes no existe este operador, en python es posible calcular la potencia de dos nmeros con el operador **. Una operacin ms extraa es la que se muestra en el quinto ejemplo. Se utiliza el operador * con una cadena de caracteres y un nmero entero. Lo que hace es producir una cadena en la que se repite la cadena que acta como primer operando tantas veces como indica el valor entero del segundo operando. En el ejemplo, la cadena Pe se repite 4 veces, produciendo la cadena PePePePe. El resto de operaciones son todas con operadores relacionales y lgicos, y por ello todas producen un valor bool. La primera es la nica que utiliza un operador unario4 , esto es, un operador que solamente necesita un operando. En el ejemplo se hace la operacin not con el valor True, y produce el valor lgico contrario, es decir, False. El resto de operaciones manejan operadores relacionales y producen un resultado cierto o falso en funcin de que la relacin de orden o igualdad se cumpla o no: 2 no es mayor que 3 (falso), 3 s es menor o igual que 3.1426 (cierto), 2 no es igual que 3 (falso) y 2 s es distinto de 3 (cierto). Tambin el orden puede comprobarse entre cadenas, como muestra el ltimo ejemplo. Se trata de un orden alfabtico en este caso, la cadena Antonio va antes, y por tanto es menor que la cadena Juan, si ordenramos ambas cadenas alfabticamente. Importante Todas las operaciones que se hacen con operandos siempre producen un resultado. Ese resultado ser un valor de un cierto tipo. El programador debe conocer siempre el tipo
4

Tambin el operador - puede actuar como operador unario, cambiando el signo del operador numrico que le siga

2.2 Variables, expresiones, asignacin

47

que producir una expresin sabiendo el tipo de sus operandos y la operacin que realiza el operador.

2.2.5.

Variables

Como se dijo al principio de esta seccin, los programas se escriben para, dados unos datos de entrada, hacer clculos con ellos, y producir unos resultados de salida. Para que los programas sean tiles necesitamos un mecanismo que nos permita representar esa informacin que va a cambiar: los datos de entrada que sern diferentes en cada ejecucin y los datos de salida que tomarn valores distintos en funcin de los datos de entrada recibidos. No nos sirve en este caso con usar valores; los valores concretos, como 7 o 3.1416 no cambian. La forma de representar toda esa informacin que vara es a travs de variables. Supongamos que necesitamos hacer un programa que sirva para calcular el rea de un rectngulo, dados los valores de su base y su altura. Sabemos que el clculo del rea de un rectngulo se realiza mediante la ecuacin: area = base altura Los usuarios de nuestro programa quieren poder ejecutarlo las veces que deseen, introducir de alguna forma (generalmente con el teclado) los valores de la base y la altura, y que el programa muestre el resultado del rea. Por ejemplo, si el usuario quiere calcular el rea de un rectngulo de base 5 y altura 4, introducir esos dos datos y nuestro programa debera responder que el rea es 20. Sin embargo, dentro de las instrucciones de nuestro programa no debemos escribir la operacin 5*4 porque no sabemos qu valores va a introducir el usuario cuando lo ejecute. Adems, queremos que nuestro programa calcule el rea de cualquier rectngulo. Si el usuario introdujera 6 y 3, entonces el rea sera 18. La forma de generalizar la operacin de calcular el rea dentro del programa es idntica a la manera en la que se expresa la ecuacin que explica su clculo. En lugar de usar valores concretos, emplearemos nombres de variables para referirnos a esos valores que cambian. Disearemos nuestro programa usando al menos dos variables, base y altura, que tomarn distintos valores en las diferentes ejecuciones, pero la forma de calcular el rea del rectngulo que representan es siempre la misma:
>>> base * altura

cuando base o altura cambien de valor, tambin cambiar el producto de ambas y con ello el valor del rea que calcula nuestro programa. Denicin Una variable es el nombre que se utiliza en un programa para representar un dato o valor que puede cambiar. Veamos el funcionamiento de las variables con un ejemplo prctico. En primer lugar, damos un valor a nuestras dos variables base y altura, en concreto los valores 5 y 4 respectivamente:
>>> base = 5 >>> altura = 4

Hemos usado dos asignaciones. En el siguiente apartado explicaremos con detalle cmo funciona una asignacin. Intuitivamente, lo que hace la asignacin es cambiar el valor de una variable. Es

48

Introduccin a la programacin

decir, ahora en nuestro ejemplo cuando usemos el nombre base, su valor ser 5 y cuando usemos altura 4. Las variables vienen a ser una forma de referirnos a un valor que est en la memoria usando un nombre. En memoria tenemos los valores 5 y 4, el 5 es el valor de la base del rectngulo y el 4 su altura:

base altura

5 4

Memoria

Cuando queremos utilizar estos datos para hacer alguna operacin simplemente tenemos que poner su nombre. As para calcular el rea escribiremos:
>>> base * altura 20

El resultado es naturalmente 20 en funcin del los valores que en ese momento tienen la base y la altura. Sin embargo, a lo mejor el usuario del programa quiere calcular el rea de otro rectngulo distinto, por ejemplo uno que tenga base 5 y altura 2. Cambiaramos el valor de la altura, pero la operacin para calcular el rea sera exactamente la misma, produciendo el resultado deseado:
>>> altura = 2 >>> base * altura 10

El dato altura ha cambiado y con l el resultado del rea. En memoria, la variable altura representa el valor 2 en lugar del valor 4. Ahora nuestro programa est usando los valores 5 y 2, el 4 ya ha dejado de usarse (por eso aparece en gris en la gura siguiente).

base altura

5 4 2

Memoria

Cada vez que se utiliza un valor nuevo en un programa en python, se reserva un nuevo espacio en la memoria para guardarlo. El valor de nuestro dato altura ha cambiado, est en otro sitio en la memoria, pero la forma de referirnos a l es la misma, usando el nombre de la variable. Importante Una variable es un nombre con el que representamos un valor, y por tanto, ser de un tipo. Ese valor adems se guardar en una posicin de la memoria. La variable base representa el valor 5, es de tipo int y dicho valor est en una posicin de la memoria concreta. Con el nombre de la variable podremos acceder al valor tantas veces como queramos y la variable podr cambiar de valor tantas veces como se desee. Para conocer el tipo del

2.2 Variables, expresiones, asignacin

49

valor que representa la variable, algo que habitualmente no es necesario, se puede utilizar la funcin type exactamente como se haca con los valores anteriormente. Para saber ms La posicin de la memoria donde se encuentra el valor que representa una variable es intrascendente para la ejecucin del programa; en ejecuciones distintas, el valor se situar en posiciones de la memoria diferentes. Si se quiere conocer la posicin del valor que representa una variable se debe usar la funcin id, indicando entre parntesis el nombre de la variable, p.e., id(base).

2.2.6.

Asignacin

Una de las instrucciones ms importantes para la construccin de programas es la asignacin. La asignacin es la instruccin que nos permite cambiar el valor de una variable. La sintaxis es sencilla, primero se indica el nombre de la variable, despus el operador = y por ltimo la expresin del valor que se desea asignar: variable = expresin o El efecto que tiene una asignacin es diferente en funcin de cmo sea la expresin que aparece en la parte derecha de la asignacin. Hay dos opciones: 1. si se asigna un valor (o en general, el resultado de una operacin), entonces se reserva un nuevo espacio en la memoria para contenerlo 2. si se asigna otra variable, entonces las dos variables se referirn al mismo valor Es decir, a efectos de la memoria que ocupan los datos del programa hay diferencias entre ambas situaciones. Vamos a verlo con un par de ejemplos, utilizando de nuevo el problema del clculo del rea de un rectngulo, nuestras dos variables base y altura y una nueva variable area con la que guardaremos mediante asignaciones el valor del rea del rectngulo que vayamos calculando. Analicemos en primer lugar las siguiente asignaciones:
>>> >>> >>> >>> 25 base = 5 altura = base area = base * altura area

En la primera de ellas se asigna a la variable base el valor 5. Como se est asignando un nuevo valor, en memoria se reserva el espacio para contener el valor 5, valor al que nos referiremos usando la variable base. A continuacin se asigna a la variable altura la variable base. Ahora estamos en el segundo caso antes descrito, se est asignando una variable. Por tanto, no se reserva un nuevo espacio en memoria, sino que las dos variables se reeren al mismo valor, 5. Por ltimo, a la variable area se le asigna el resultado de calcular el rea del rectngulo, base * altura. Como es una operacin, produce un nuevo valor, 25, y estamos de nuevo en el primer caso. Por ello se crea una nueva posicin de memoria para contener el valor 25. Grcamente la situacin de la memoria tras estas asignaciones sera la siguiente: Supongamos que ahora se hicieran las asignaciones siguientes:

50

Introduccin a la programacin

base altura area

Memoria

25

>>> altura = 4 >>> area = base * altura >>> area 20

En el primer caso, a la variable altura se le asigna el valor 4. Como es un nuevo valor, se crea el espacio de memoria para contenerlo y la variable altura ser el nombre con el que podamos acceder a ese dato. A continuacin, se recalcula el rea del nuevo rectngulo. que en este caso produce el valor 20. Como se asigna un nuevo valor, ste se guarda en una nueva posicin de la memoria, a la que se podra acceder usando la variable area. En esta ocasin el valor 25 ha dejado de ser usado, por lo que aparece en gris en la imagen. Los valores que en ese momento tendra nuestro programa guardados en la memoria seran 5, 4 y 20.

base altura area

5 4 25 20

Memoria

2.2.7.

Otras consideraciones sobre las variables

Hay dos aspectos importantes a la hora de trabajar con las variables que tendrn nuestro programas que a los programadores principiantes les cuesta decidir. La primera es elegir un nombre adecuado para cada variable del programa y la segunda seleccionar qu variables necesitamos usar. El nombre de una variable puede estar formado por letras (a, b, c,. . . ), dgitos (0,1,2,. . . ) y el carcter guin bajo o subrayado (_). Adems deben tenerse en cuenta las siguientes restricciones: el nombre no puede empezar por un dgito el nombre no puede ser igual que una palabra reservada del lenguaje las letras maysculas y minsculas son diferentes Es decir, no podemos usar como nombre de una variable 9numeros ya que empieza por un dgito. Los nombres Numero y numero son diferentes, ya que no es lo mismo la letra N que la n. Y nunca se pueden usar las palabras de las que se compone el lenguaje python y que detallan en

2.2 Variables, expresiones, asignacin

51

el recuadro anexo. Todas estas reglas son bastante similares en cualquier lenguaje de programacin actual. Curiosidad: Palabras reservadas Las palabras reservadas de python son 31. No es necesario memorizarlas, se van aprendiendo a medida que se usan al programar y algunas de ellas no se usarn nunca en los programas de la asignatura. and continue except global lambda raise yield as def exec if not return assert del finally import or try break elif for in pass while class else from is print with

Pero sin duda el aspecto ms importante a la hora de elegir el nombre de una variable es que el nombre sea descriptivo del dato que la variable representa dentro del programa. De esa forma, al leer el programa, tanto por nosotros mismos como autores, como por otros programadores que pudieran leerlo, se entender mejor la utilidad que tiene la variable dentro del programa. Siempre hay que utilizar nombres lo ms descriptivos posibles, aunque sean largos y formados por varias palabras. El convenio que seguiremos en la asignatura es utilizar palabras en minsculas separadas por guiones bajos. Por ejemplo: nombre, velocidad_final, interes, codigo_postal El otro aspecto a tener en cuenta sobre las variables, es cundo hay que usar una variable en un programa? La idea fundamental que se debe tener presente es la siguiente: Importante Las variables son las herramientas que usan los programas para almacenar informacin en la memoria del ordenador. Desde esa perspectiva, siempre que en un programa se desee guardar alguna informacin para luego acceder a ella, entonces es necesario crear una variable. Eso hace que no solamente creemos variables para los datos de entrada y salida del programa, sino tambin para todos aquellos valores intermedios que el programa calcule y de los que queramos mantener el resultado en memoria para acceder a ellos posteriormente. Las variables permiten a los programadores reservar espacio en la memoria para manipular datos. La ventaja de guardar datos calculados previamente es aumentar la velocidad de los programas al no tener que recalcularlos. Otras veces, se guardan datos en memoria desde otros dispositivos como los discos. Por ejemplo, imagina un programa de tratamiento de imgenes que cargue en memoria una imagen desde un archivo. Si la imagen se mantiene en memoria, el programa podr tratarla de forma rpida ya que no necesitar leer su informacin de disco. Los datos que estn en memoria siempre se pueden tratar de una forma ms rpida que si necesitamos acceder a la misma informacin en un dispositivo secundario.

2.2.8.

Expresiones

El objetivo de esta seccin es explicar cmo se ejecutan las operaciones que escribimos en los programas y en las que aparecen valores, variables y operadores, especialmente cuando aparecen varios operadores juntos. Es lo que se denomina una expresin.

52 Denicin

Introduccin a la programacin

Una expresin es una combinacin de operadores y operandos (valores, variables) que produce un resultado (valor) de un cierto tipo.

Varias cosas en esta denicin. Primero, las expresiones se forman al mezclar los operadores con sus operandos. Los operadores son los que denen las operaciones que se van a hacer. En segundo lugar, las expresiones producen siempre un valor. Ese valor ser, como es lgico, de algn tipo. Tanto el valor producido, como su tipo, dependern de los operandos y de los operadores que se usen. La mayor dicultad que entraan las expresiones con varios operadores es saber el orden en que stos se ejecutarn. Eso lo determina lo que se denomina la precedencia de los operadores. La precedencia es la propiedad que sirve para decidir qu operador debe aplicarse primero cuando en una expresin aparecen varios operadores de distintos grupos. Vamos a verlo con dos ejemplos, las expresiones 4+5*7 y (4+5)*7. En ambas aparecen dos operadores, la suma (+) y el producto (*), con los mismos valores, sin embargo el resultado ser diferente por la presencia de los parntesis. En el caso de la expresin 4+5*7, la primera operacin que se hace es el producto ya que el operador * tiene ms precedencia que el operador +. La expresin 5*7 produce el valor 35, al que posteriormente se le suma el valor 4. El resultado nal de la expresin es 39. Grcamente:

4 + 5 * 7 4 + 39
En cambio en la expresin (4+5)*7, tenemos los mismos valores y operadores, pero adems se han incluido unos parntesis que delimitan la operacin de suma. Los parntesis sirven para agrupar las operaciones que se quieren hacer primero. En este caso, lo que se indica es que se debe hacer antes la suma que el producto. Primero se realiza 4+5, produciendo el valor entero 9, y a continuacin se hace el producto de dicho valor por 7, con lo que el resultado nal de la expresin es 63:

35

(4 + 5) * 7 9 * 7 63
Puedes consultar la tabla de precedencia de operadores en python en mltiples pginas web, por ejemplo en http://docs.python.org/reference/expressions.html. Sin embargo

2.3 Uso de entrada/salida por consola

53

memorizarse la tabla es difcil, y en realidad tampoco es necesario. Como se ha visto en los dos ejemplos anteriores, usando los parntesis adecuadamente se pueden cambiar el orden en que se ejecutan los operadores de una expresin. Adems, el uso de los parntesis hace que algunas expresiones se entiendan mejor al leerlas. En todo caso, las tablas de precedencia de todos los lenguajes suelen seguir una serie de reglas que si se conocen pueden permitirnos escribir expresiones complejas sin abusar tanto del uso de los parntesis. Citaremos las cuatro reglas ms bsicas: 1. lo que est entre parntesis se hace primero 2. los operadores aritmticos tienen ms precedencia que los relacionales, y los relacionales ms que los lgicos 3. los operadores unarios de un grupo ms que los binarios de ese mismo grupo 4. ** ms que los multiplicativos (*, /, %), y stos ms que los aditivos (+, -). Esta regla tambin se da con los lgicos (and ms precedencia que or) La primera regla es la ms importante de todas, ya la hemos comentado sucientemente. En el caso de la segunda, se comprende si se piensa en una expresin como x-1<=10. Lo lgico al leer esa expresin en matemticas es que queremos comprobar si al restarle 1 a x el valor resultante es menor o igual que 10. La expresin puede escribirse tal cual, ya que el operador aritmtico (-) tiene ms precedencia que el relacional (<=). La tercera regla se puede entender al analizar una expresin como a*-b. En ese caso lo que se quiere es que se multiplique la variable a por el valor resultante de cambiar el signo de la variable b, esto es, -b. Como el operador - es en este caso unario, se hace antes que el operador *. La nica excepcin a la regla tercera se da en el caso de el operador binario ** que tiene ms precedencia que los operadores unarios aritmticos, como el -, lo que explica que -1**2 de como resultado -1, mientras que (-1)**2 da como resultado 1. Para nalizar, la ltima regla se ha visto en los dos ejemplos utilizados para explicar el concepto de precedencia y el uso de parntesis, las multiplicaciones se hacen antes que las sumas.

2.3.

Uso de entrada/salida por consola

Una caracterstica muy importante de los programas es que sean capaces de interaccionar con el usuario, es decir, que sean capaces de pedir informacin al usario por teclado (entrada estndar) y de mostrar los resultados por pantalla (salida estndar). El siguiente programa en Pyhton calcula el rea de un tringulo, pero la base y la altura siempre son las mismas y no se informa del rea calculada.
1 base=5.0 2 altura=3.0 3 area=(base*altura)/2

Evidentemente, sera mucho ms til si se pudiera aplicar a cualquier tringulo y, por supuesto, si se informa al usuario del resultado nal. Para ello es necesario conocer las operaciones de entrada/salida por consola que nos ofrece Python. Mediante su aplicacin, el programa anterior quedara de la forma siguiente:
1 2 3 4 5

base = float (raw_input("Dame la base:")) altura = float (raw_input("Dame la altura:")) area =(base*altura)/2 print area

54

Introduccin a la programacin

2.3.1.

Entrada por teclado

La forma ms sencilla de obtener informacin por parte del usuario es mediante la funcin raw_input. Esta funcin devuelve una cadena con los caracteres introducidos por el usuario mediante el teclado. Atencin Cuando se llama a esta funcin, el programa se para y espera hasta que el usuario teclea algo. Cuando el usuario presiona Return o Enter, el programa contina y raw_imput retorna lo que ha tecleado el usuario como cadena de caraceteres (string).
>>> entrada = raw_input() _ >>> entrada = raw_input() Hola >>> print entrada Hola

Antes de pedir un dato por teclado al usuario, es una buena idea sacar un mensaje informando de lo que se espera. Por este motivo, raw_input puede llevar como parmetro una cedena de caracteres que se saca por la pantalla justo antes de pedir la entrada al usuario (indicador o prompt en ingls).
>>> entrada = raw_input("Introduce tu nombre: ") Introduce tu nombre: >>> entrada = raw_input("Introduce tu nombre: ") Introduce tu nombre: Jorge Javier >>> print entrada Jorge Javier

Si necesitamos un nmero como entrada, un entero o un otante, en lugar de una cadena, podemos utilizar las funciones int y oat para convertir la cadena al tipo numrico correspondente.
>>> base = float (raw_input("Introduce la base de un tringulo:\n")) Introduce la base de un tringulo: 7

Aunque hay que tener en cuenta que si lo que introduce el usuario no es un nmero vlido se genera un error al no poder realizar la conversin.
>>> base = float (raw_input("Introduce la base de un tringulo:\n")) Introduce la base de un tringulo: A Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for float(): A

Como se comentar mas adelante, el carcter especial \n al nal del mensaje del raw_imput (prompt) causa un salto de lnea.

2.3.2.

Salida por pantalla

La forma ms sencilla de mostrar algo en la salida estndar es mediante el uso de la sentencia print, como hemos visto en varios ejemplos anteriores. En su forma ms bsica a la palabra clave print le sigue una cadena de caracteres, que se mostrar en la pantalla del ordenador al ajecutarse la sentencia. Si se omite la cadena de caracteres se produce un salto de lnea.

2.3 Uso de entrada/salida por consola

55

>>> print >>> print "Hola mundo" Hola mundo

Atencin Las comillas que se usan para identicar una cadena de caracteres no aparecen en la salida por pantalla. Por defecto, la sentencia print muestra algo por la pantalla y se posiciona en la lnea siguiente. Si queremos mostrar ms de un resultado en la misma lnea, basta con separar con comas todos los valores que deseamos mostrar. Esto es debido a que Python interpreta la coma como un espacio de separacin.
>>> print "Hola mundo", "de la programacin" Hola mundo de la programacin

Tambin se puede usar print para imprimir por pantalla valores que no sean cadenas de caracteres, como nmeros enteros o otantes.
>>>print "Te costar entre", 30, "y", 49.5, "euros" Te costar entre 30 y 49.5 euros

Las cadenas de caracteres que muestra la sentencia print pueden contener caracteres especiales. Se trata de caracteres que van precedidos por la barra invertida \ y que tienen un signicado especco. Los ms utilizados son \n, el carcter de nueva lnea, y \t, el de tabulacin. Por ejemplo, la siguiente sentencia imprime la palabra "Hola" seguida de un rengln vaco y en la lnea siguiente (debido a los dos caracteres de nueva lnea, \n) la palabra "mundo" indentada (debido al carcter tabulador, \t).
>>>print "Hola\n\n\tmundo" Hola mundo

2.3.3.

Salida con formato

La sentencia print, o ms bien las cadenas que imprime, permiten tambin utilizar tcnicas avanzadas de formateo de la salida. Veamos un ejemplo bastante simple:
>>>print "Tengo %d aos" % 25 Tengo 25 aos

Lo nuevo de este ejemplo es la utilizacin una secuencia de formato: %d. Las secuencias de formato ms sencillas estn formadas por el smbolo %, llamado operador de formato, seguido de una letra que indica el tipo con el que formatear el valor proporcionado a continuacin: Secuencia %s %d %f Formato Cadena Entero Flotante

56

Introduccin a la programacin

Volvamos al ejemplo anterior. Lo que hace es construir la cadena introduciendo los valores a la derecha del smbolo % (el valor entero 25) en las posiciones indicadas por la secuencia de formato ( %d). Podemos formatear una cadena de carateres utilizando varias secuencias de formato. En este caso, los valores asociados a cada una de las secuencias deben ir entre parntesis separados por comas. El nmero de secuencias de formato y el nmero de valores asociados debe coincidir para que no se produzca un error. Igualmente, los tipos de los valores (o expresiones) deben coincidir con lo que esperan las secuencias de formato. Veamos un ejemplo un poco ms complicado:
>>>print "Tengo %d aos, mido %f m. y soy de %s" % (25, 1.95, "Gijn") Tengo 25 aos, mido 1.950000 m. y soy de Gijn

Cada una de las secuencias de formato se sutituye por los valores que aparecen entre parntesis, tomados de izquierda a derecha:

En el ejemplo anterior se muestra la altura (1.95) con una serie de ceros de ms (1.950000). Esto es debido a que por defecto, el formato para los nmeros de coma otante imprime seis decimales. Sin embargo, para tener ms control sobre el formato de salida, podemos introducir un nmero entre el % y el carcter que indica el tipo al que formatear. Para cadenas y enteros, indica el nmero mnimo de caracteres que queremos que ocupe la cadena generada. Si se precisan menos caracteres de los indicados, se aaden espacios en blanco por la izquierda. En el caso de que el nmero sea negativo, ocurrir exactamente lo mismo, slo que los espacios se aadirn a la derecha de la cadena.
>>>print " %10s mundo" % "Hola" Hola mundo >>>print " %-10s mundo" % "Hola" Hola mundo >>>print "Tengo %5d aos" % 25 Tengo 25 aos -->Se aaden 6 espacios a la izquierda -->Se aaden 6 espacios a la derecha -->Se aaden 3 espacios a la izquierda

Para formatear nmeros otantes, podemos introducir dos nmeros a continuacin del % separados por un .: el primero hace referencia a la longitud total y el segundo a la longitud de la parte decimal (se puede indicar slo la longitud de la parte decimal). A continuacin se presentan varios ejemplos para distintos tipos de datos:
>>>print "Mido %.2f m." Mido 1.95 m. >>>print "Mido %.3f m." Mido 1.950 m. >>>print "Mido %.1f m." Mido 2.0 m. >>>print "Mi coche pesa % 1.95 -->2 cifras decimales % 1.95 -->3 cifras decimales (se rellena con 0) % 1.95 --> 1 cifra decimal (se redondea) %10.2f Kg." % 1324.728

2.4 Manejo de estructuras bsicas de control de ujo


Mi coche pesa 1324.73 -->10 caracateres en total, 2 la parte decimal -->(se aaden 3 espacios y se redondea)

57

Importante Los caracteres especiales y las secuencias de formato no slo se pueden utilizar con la sentencia print, se pueden usar con cualquier variable de tipo cadena.
1 salida = "\nEl area un triangulo de base %d y altura %d es %.2f \n" 2 % (5, 3, (base*altura)/2) 3 print salida

La salida del programa anterior es:


El area un triangulo de base 5 y altura 3 es 7.50

Ahora ya estamos en disposicin de entender, incluso de mejorar, el programa que calcula el rea de un tringulo con el que empezamos esta seccin:
1 2 3 4 5 6

base = float (raw_input("Dame la base:")) altura = float (raw_input("Dame la altura:")) area =(base*altura)/2 salida = "\nEl area un triangulo de base %.1f y altura %.1f es %.2f \n" % (base, altura, area) print salida

2.4.

Manejo de estructuras bsicas de control de ujo


Secuencial (BLOQUE) Aternativa simple Universidad de Oviedodoble (SI-ENTONCES-SI_NO) (SI-ENTONCES) o Fundamentos de Informtica Repetitiva (Existen 2 tipos: MIENTRAS y REPETIR-HASTA) 2.5.1 Estructuras de control fundamentales

Existen 3 estructuras de control fundamentales:

Existen 3 estructuras de control fundamentales: Estas estructuras se representan grcamente en la gura 2.1. Obsrvese que todas ellas tienen un nico punto de entrada y un nico punto de salida marcado con el rectngulo en lnea de trazos, o Secuencial (BLOQUE) lo que permitir ms adelante componer unas con otras, enlazndolas por dichos puntos de entrada o Aternativa (SI-ENTONCES-SI_NO) y salida. o Repetitiva (Existen 2 tipos: MIENTRAS y REPETIR-HASTA)

sent.1 sent. 2

cond.

cond.
V

sent.
F

sent.1 sent. n

sent. 2

sent.

cond.
V

BLOQUE

SI-ENTONCES-SI_NO
Tema 4. Introduccin a la programacin

MIENTRAS

REPETIR-HASTA
4-4

Figura 2.1: Estructuras de control fundamentales

58

Introduccin a la programacin

Bhm y Jacopini demostraron en los aos 60 que todo programa puede realizarse a base de las 3 estructuras anteriores: La secuencial, la alternativa, y una cualquiera de las 2 repetitivas, as como de anidamientos de unas estructuras en otras.

2.4.1.

Estructura secuencial (BLOQUE)

Consiste en ejecutar una sentencia a continuacin de otra. Se pueden agrupar varias sentencias para formar una nica sentencia, denominada sentencia compuesta. En otros lenguajes se usan delimitadores de bloque (p.ej: llaves). Implementacin En Python, lo que delimita el bloque es que todas tengan el mismo nivel de indentacin, es decir, el mismo nmero de espacios por la izquierda. Aunque el nmero de espacios puede ser cualquiera que se desee, ha de ser el mismo para todas las sentencias que componen el bloque secuencial. Es costumbre que este nmero de espacios sea mltiplo de 4. Por ejemplo, en la gura 2.2 se muestra la implementacin en lenguaje Python del bloque correspondiente, asumendo que sent1, sent2, etc. son diferentes sentencias Python, (asignaciones, expresiones, etc).

sent.1 sent. 2
1 sent1 2 sent2 3 ... 4 sentN

sent. n

Figura 2.2: Bloque secuencial Hay que tener en cuenta que el bloque principal en python ha de tener cero espacios de indentacin, y que slo los bloques que aparezcan dentro de otras estructuras de control irn indentados. En los ejemplos que hemos visto hasta este momento, todos los programas tienen un solo bloque, que es el principal y por tanto todos llevan cero espacios de indentacin. En las secciones siguientes en las que usaremos bloques dentro de otras estructuras de control podremos ver ejemplos en los que la indentacin juega su papel fundamental. Se puede usar punto y coma para separar sentencias si estn en la misma lnea, pero en esta asignatura no usaremos esa caracerstica y pondremos siempre cada sentencia en una lnea separada. Hacindolo as, no es necesario poner un punto y coma para separarlas, y en particular no es necesario poner punto y coma al nal de cada lnea (decimos esto porque en otros lenguajes como el C o Java s es obligatorio terminar cada lnea con punto y coma).

2.4.2.

Estructura alternativa

Permite elegir entre dos alternativas, segn sea verdadera o falsa, la condicin que se evala. Existen dos subtipos Aternativa simple (if) Aternativa doble (if-else)

2.4 Manejo de estructuras bsicas de control de ujo

59

En la estructura alternativa simple se proporciona una condicin y una sentencia (o un bloque de ellas). Si la condicin es verdadera se ejecuta la sentencia. Si no, no se ejecuta ninguna accin.

cond

Pseudocdigo:
SI condicin ENTONCES sentencia

sent

Implementacin en python:
1 if cond: 2 sent

Figura 2.3: Estructura alternativa simple (if) Esta estructura de control se puede representar grcamente como se muestra en la gura 2.3. En esta misma gura se muestra cmo leer el grco, en forma de pseudocdigo, y la implementacin en el lenguaje python. Sobre la implementacin, observar los siguientes detalles: La condicin (que se representa por cond en la gura) ser una expresin booleana cuyo resultado ser True o False. La condicin no necesita ir encerrada entre parntesis (a diferencia de otros lenguajes como C o Java). Tras la condicin, se ponen dos puntos (:), nalizando as la lnea. La sentencia a ejecutar (representada por sent en la gura) debe ir indentada, habitualmente cuatro espacios como ya hemos dicho antes. Si se trata de un bloque en lugar de una sola sentencia, todo el bloque ir indentado la misma cantidad de espacios. Aunque el pseudocdigo dice SI . . . ENTONCES, lo cierto es que en la implementacin python se escribe solo if, pero no se escribe then. El papel del then lo hacen los dos puntos. Ejemplo Suponiendo que la variable nota contiene la calicacin de un alumno, el siguiente fragmento de programa determina si ha superado la prueba.
1 # El programa obtiene la nota por algn medio 2 if nota >= 5.0: 3 print "Prueba superada"

En la estructura alternativa doble (if-else) se proporcionan dos posibles sentencias, a elegir una segn el resultado de la condicin, como se muestra en la gura 2.4. Si la condicin es verdadera se ejecuta la sentencia1. Si no, se ejecuta la sentencia2. Sobre la implementacin, observar los siguientes detalles: La condicin sigue las mismas observaciones que para el caso anterior. La sentencia a ejecutar para el caso True (representada por sent1 en la gura) debe ir indentada, habitualmente cuatro espacios como ya hemos dicho antes. Si se trata de un bloque en lugar de una sola sentencia, todo el bloque ir indentado la misma cantidad de espacios.

60

Introduccin a la programacin

Pseudocdigo:
V

cond

SI condicin ENTONCES sentencia1 SI_NO sentencia2

sent1

sent2

Implementacin en python:
1 if cond: 2 sent1 3 else: 4 sent2

Figura 2.4: Estructura alternativa doble (if-else) Lo mismo cabe decir sobre la sentencia (o bloque) para el caso False, representada por sent2 en la gura. La palabra else ha de nalizarse con dos puntos y ha de tener el mismo nivel de indentacin que la palabra if, de este modo se ve a qu if corresponde el else. Ejemplo El siguiente fragmento de programa determina si la variable num de tipo entero contiene un nmero par o impar.
1 # El programa inicializa num por algn medio 2 if num %2 == 0: 3 print "Es par" 4 else: 5 print "Es impar"

Las estructuras alternativas pueden anidarse, esto es, donde debera ir sent1 o sent2 en el diagrama anterior, podemos poner otra estructura alternativa. La gura 2.5 muestra un ejemplo de esto. El anidamiento puede complicarse ms, si en lugar de s1, s2, s3 o s4 en dicha gura, inclumos otra estructura alternativa. El lenguaje no pone lmite al nivel de anidamiento, que puede ser tan profundo como se quiera. En la prctica, sin embargo, utilizar ms de dos niveles resulta difcil de leer, y suele ser un sntoma de que se poda haber diseado el algoritmo de otra forma, o de que parte de l puede ser extrado a una funcin (concepto que veremos ms adelante). Como se ve en la gura, la implementacin en python hace visible el anidamiento de estas estructuras mediante el nivel de indentacin de las lneas. Las lneas que usan el mismo nivel de indentacin, estn al mismo nivel de anidamiento. Es importante que cada else vaya anidado con su if. Finalmente, python proporciona una estructura multialternativa (if-elif-else), que permite elegir entre varias alternativas segn el resultado de diferentes expresiones booleanas. En realidad, puede implementarse mediante una serie de if-else anidados en cascada, pero la sintaxis con if-elif-else resulta ms legible, al reducir el anidamiento. La idea general se leera como si se cumple cond1 haz sent1, si no, si se cumple cond2 haz sent2, si no, si se cumple cond3 haz sent3, etc.. y si no se cumple ninguna, haz sentencia, y la implementacin en Python sera la siguiente:
1 if cond1: 2 sent1 3 elif cond2:

2.4 Manejo de estructuras bsicas de control de ujo

61

c1

Implementacin en python:
1 if c1: 2 if c2: 3 s1 4 else: 5 s2 6 else: 7 if c3: 8 s3 9 else: 10 s4

c2

c3

s1

s2

s3

s4

Figura 2.5: Estructuras alternativas anidadas


4 5 6 7 8 9 10 11

sent2 elif cond3: sent3 ... elif condN: sentN else: sentencia

#cualquier otro caso no contemplado

Observaciones sobre la implementacin: La palabra elif es una contraccin de else if. Cada uno de los elif ha de ir forzosamente alineado con el if inicial, as como el else nal. Se pueden poner tantos elif como se necesiten. El else nal es opcional. Si no se pone, y ninguna de las condiciones se ha cumplido, entonces no se ejecutar ninguna sentencia. Como siempre, cualquiera de las sent del cdigo anterior puede ser un bloque de sentencias. Basta escribir cada una en una lnea y todas con el mismo nivel de indentacin. Ejemplo El siguiente ejemplo pide al usuario una nota numrica y escribe la correspondiente nota con letra. Otro uso tpico de la estructura multialternativa es para crear mens en los que el usuario puede elegir una opcin entre varias que se le presentan.
1 2 3 4 5 6 7 8 9 10 11

nota = int(raw_input("Introduzca la nota del examen: ")) if (nota >= 0) and (nota < 5): print "Suspenso" elif (nota >= 5) and (nota < 7): print "Aprobado" elif (nota >= 7) and (nota < 9): print "Notable" elif (nota >= 9) and (nota <= 10): print "Sobresaliente" else: print "Nota no vlida"

62

Introduccin a la programacin

2.4.3.

Estructuras repetitivas (bucles)

Una estructura repetitiva es un bloque de sentencias (denominado cuerpo del bucle) que se va a ejecutar varias veces. El bucle incluye una condicin, que regula si se seguir repitiendo o no. Las instrucciones dentro del bloque generalmente modican o pueden modicar las condiciones que forman parte de la condicin, haciendo que en algn momento la evaliuacin de esa condicin cambie y por tanto el bucle ya no se repita ms. Dependiendo de si la condicin se evala antes de entrar al bloque, o despus de haber ejecutado el bloque, podemos clasicar los bucles en dos tipos: Bucle con condicin inicial. Bucle con condicin nal. Observar que en el bucle con condicin inicial, si la condicin es falsa de partida, el cuerpo del bucle no se ejecutar ni siquiera una vez. En cambio en los bucles con condicin nal, el cuerpo se ejecutar al menos una vez, antes de evaluar la condicin que regula si se ejcutar ms veces. El bucle con condicin inicial generalmente se denomina MIENTRAS. . . HACER (o en ingls bucle while), se puede representar grcamente como se muestra en la gura 2.6. La condicin es lo primero que se evala y si el resultado es False, se abandona el bucle sin ejecutar su sentencia sent. Si la condicin es True, entonces se ejecuta sent y tras ello se vuelve otra vez a la condicin, para evaluarla de nuevo. Mientras la condicin siga siendo cierta, la sentencia sent se ejecutar una y otra vez. Se entiende que sent modica alguna variable, de modo que cond pueda pasar a ser falsa, y de este modo se terminara el bucle.

cond
V

Pseudocdigo:
MIENTRAS condicin sentencia

sent

Implementacin en python:
1 while cond: 2 sent

Figura 2.6: Estructura repetitiva MIENTRAS (while) Si hubiera ms de una sentencia dentro del bucle, se deber formar una nica sentencia compuesta usando el mismo nivel de indentacin, como se ve en el siguiente ejemplo. Ejemplo El siguiente bucle acumula (calcula) la suma de todos los nmeros introducidos por teclado. Finaliza al meter el cero.
1 2 3 4 5 6

suma = 0 num = int(raw_input("Introduzca un numero (cero para acabar): ")) while num != 0: suma = suma + num num = int(raw_input("Siguiente numero: ")) print "La suma vale ", suma

2.4 Manejo de estructuras bsicas de control de ujo

63

Observar que el bucle while resulta muy adecuado en este caso, ya que no sabemos de antemano cuntos nmeros va a introducir el usuario antes del primer cero. Puede que el cero sea el primer nmero que introduzca, en cuyo caso no hay que calcular nada (el bucle no se ejecutara). Si el primer nmero es distinto de cero, se aadir su valor a lo que haba en suma y se le pide otro. Despus se vuelve a la condicin del while para evaluar de nuevo si este segundo nmero es cero (saldra del bucle), o distinto de cero (lo aadira a suma y pedira otro), etctera. Cuando el usuario introduzca nalmente un cero, la variable suma contendr la suma de todos los nmeros introducidos hasta ese momento. El bucle con condicin nal puede ser de dos tipos: El bucle ha de repetirse mientras que una condicin sea verdadera, y abandonarse cuando la condicin sea falsa. Este tipo de bucle es similar al recin visto while, pero con la condicin al nal. Podramos llamarlo HACER. . . MIENTRAS QUE (do-while). Lo contrario del anterior, es decir, el bucle debe repetirse mientras que una cierta condicin sea falsa, y dejar de repetirse cuando esa condicin pase a ser verdadera. Podramos denominar a este bucle REPETIR. . . HASTA QUE (repeat-until). Algunos lenguajes como el C y Java, tienen palabras reservadas para el primer tipo de bucle (do-while), pero no para el segundo (repeat-until). Otros lenguajes como PASCAL tienen para el segundo tipo, pero no para el primero. En el caso del Python no hay instrucciones especiales para implementar ninguno de estos dos tipos de bucle. Tan slo tiene para el bucle while visto anteriormente en el que la condicin se evala al principio. Sin embargo, veremos en la pgina 63 algunos trucos para implementar en python las estructuras de control do-while y repeat-until. Al margen de que python tenga o no estas estructuras, desde el punto de vista de la algortmica existen por derecho propio, por lo que en las guras 2.7 y 2.8 se muestran sus diagramas de ujo y su pseudocdigo. Observar que el diagrama de ujo es casi idntico, slo que las salidas T y F de la condicin estn intercambiadas.

Pseudocdigo:
sent
V

HACER sentencias MIENTRAS condicin

cond
F

Implementacin:
1 # A diferencia del C, python no tiene el bucle do/while

Figura 2.7: Estructura repetitiva HACER-MIENTRAS (do-while)

2.4.4.

Implementacin en python de las estructuras HACER-MIENTRAS y REPETIRHASTA

Como se ha dicho antes, Python no proporciona niguna construccin especial para este tipo de bucles cuya condicin se evala al nal. Tan slo provee el bucle while visto en la pgina 62 que evala la condicin al principio. Entonces cmo implementar un bucle con condicin al nal?

64

Introduccin a la programacin

Pseudocdigo:
sent
F

REPETIR sentencias HASTA QUE condicion

cond
V

Implementacin en python:
1 # Python no tiene (tampoco) el bucle repeat/until

Figura 2.8: Estructura repetitiva REPETIR-HASTA QUE (repeat-until) Un caso tpico en que se necesita este tipo de bucles es en los programas en los que se tiene una interaccin con el usuario y, una vez nalizada sta, se le pregunta si quiere repetir. Por ejemplo, un juego que una vez terminado le pide al usuario si quiere jugar otra vez o no. Si el usuario responde S, todo lo anterior deber repetirse. Es un caso tpico de bucle con condicin al nal. El caso concreto de bucle (si es HACER-MIENTRAS o REPETIR-HASTA) no importa mucho, ya que podemos expresar la idea de cualquiera de las dos formas. Podemos decir HACER el juego MIENTRAS la respuesta del usuario sea SI, o tambin podemos decir REPETIR el juego HASTA QUE la respuesta del usuario sea NO. Pero lo que s parece claro es que la condicin se debe evaluar al nal, una vez que el usuario ha jugado al menos una vez. En realidad, un bucle con condicin al nal se puede programar tambin como un bucle con condicin al principio, haciendo uso de una variable booleana, que indique si el bucle debe ejecutarse o no, y modicando esa variable al nal del bucle. As, para implementar un bucle HACER-MIENTRAS (do-while) como el que existe en lenguaje C, la solucin sera la siguiente:
1 repetir=True # Indica que el bucle debe ser repetido 2 while repetir: 3 sent1 4 sent2 5 ... 6 sentN 7 if not condicion: # aqui evaluamos realmente la condicion de permanencia 8 repetir=False # si no se cumple, cambiamos la booleana

Es decir, tendramos una variable booleana que inicialmente valdra True, y que se usa como expresin de un bucle while. Tras ejecutar el bucle una vez, al nal del mismo se mira la condicin que causara otra repeticin. Si la condicin no se cumple, la variable booleana se cambia a False. De este modo, cuando python vuelva a la sentencia while para repetir el bucle, al encontrar que la expresin es False, saldr del bucle y no lo repetir ms. Ejemplo El siguiente bucle fuerza al usuario a meter un nmero comprendido entre 1 y 5 (ambos inclusive). Es decir, en pseudocdigo el problema es:
HACER pedir numero al usuario MIENTRAS numero < 1 o numero > 5

2.4 Manejo de estructuras bsicas de control de ujo

65

Traducido a python, necesitamos una variable booleana que se mantenga a True mientras el bucle deba repetirse, es decir, mientras el usuario insista en meter nmeros errneos. Un buen nombre para esta variable puede ser numero_erroneo. Es preferible una nombre as, que expresa el signicado de su cometido, que no un nombre genrico como repetir, o seguir, o similar. Piensa como sera la implementacin en python usando esta idea, y comprueba despus si la solucin que se te ha ocurrido es como esta:
1 numero_erroneo = True # Antes de leer el numero, suponemos que es erroneo 2 while numero_erroneo: # mientras el usuario siga metiendo numeros erroneos 3 num = int(raw_input("Introduzca un numero entre 1 y 5: ") 4 if not (num < 1 or num > 5): 5 numero_erroneo=False

Observar que, en lugar de la expresin if not (num<1 or num>5) podemos usar tambin if num>=1 and num<=5 que es equivalente, y quizs ms fcil de leer y entender. La implementacin del bucle REPETIR-HASTA QUE usa una idea similar, si bien ahora la variable booleana comienza valiendo False y el bucle debe repetirse HASTA QUE se ponga a True. La idea es por tanto:
1 salir=False # Indica si hay que salir del bucle 2 while not salir: # atencion al not 3 sent1 4 sent2 5 ... 6 sentN 7 if condicion: # aqui evaluamos realmente la condicion de permanencia 8 salir=True # si no se cumple, cambiamos la booleana

A la mayora de alumnos les resulta ms fcil pensar en trminos de repetir hasta que, que en trminos de hacer mientras, aunque cualquiera de estos bucles se puede convertir en el otro. Si planteamos de nuevo el problema de pedir al usuario un nmero comprendido entre 1 y 5, pero pensndolo ahora como un repetir hasta que, vemos que la condicin sera ahora la contraria, es decir, en pseudocdigo:
REPETIR pedir numero al usuario HASTA QUE (numero>=1 Y numero<=5)

Para traducirlo a python, pesamos que hay que repetir HASTA QUE el nmero sea correcto, por lo que un buen nombre para la variable booleana seria numero_correcto, que inicializaremos con False y que cambiaremos a True cuando el usuario meta un nmero correcto. Piensa cmo implementaras esto y comprueba tu solucin.
1 numero_correcto = False # Aunque aun no hemos leido el numero, suponemos que es erroneo 2 while not numero_correcto: # mientras el usuario NO meta uno correcto 3 num = int(raw_input("Introduzca un numero entre 1 y 5: ") 4 if num >= 1 and num <=5: 5 numero_correcto = True

Observa cmo el elegir un buen nombre para la variable booleana ayuda mucho a pensar qu condicin debe evaluarse en el if y por qu debe aparecer un not en el while. Mejora del estilo Un detalle de estilo de programacin que ha aparecido en los ejemplos anteriores y que puede mejorarse es el siguiente.

66

Introduccin a la programacin

En lugar de hacer un if en el que se evala una condicin booleana, para seguidamente asignar una variable con el valor True o False, se podra haber asignado directamente a la variable el resultado de la expresin. Es decir, en lugar de:
1 2

if num >=1 and num <=5: numero_correcto = True

podramos haber escrito directamente:


1

numero_correcto = num >=1 and num <=5

Observa que a la derecha de la asignacin hay una expresin booleana, cuyo resultado ser True o False. Si es True, la variable numero_correcto tomar este valor, exactamente igual que en el caso del if. Este estilo no solo es ms conciso (ocupa una lnea, frente a dos), sino tambin ligeramente ms eciente, y hasta ms claro una vez te acostumbres a l.

2.4.5.

El bucle for

Aunque con los tipos de bucle antes vistos se puede implementar ya cualquier algoritmo, es muy frecuente que aparezca la necesidad de realizar un bucle controlado por un contador. Esto es, un bucle en el que una variable vaya tomando valores enteros sucesivos, partiendo de un valor inicial y hasta alcanzar un valor nal. Por ejemplo, si queremos calcular el factorial de un nmero N , necesitamos ir generando los nmeros 1, 2, . . . , N e ir multiplicndolos todos. Obviemos de momento el problema de ir multiplicndolos para obtener el factorial, y centrmonos en el problema de cmo ir generando la secuencia de nmeros 1, 2,. . . , N . De momento, vamos simplemente a escribir esta secuencia de nmeros, uno en cada lnea. Usando la estructura de control MIENTRAS vista anteriormente, el problema se resovera en la forma siguiente. Necesitamos una variable que vaya tomando los valores sucesivos 1, 2, etc. Llamemos a esta variable i (es un nombre habitual, inicial de la palabra index o ndice). Esta variable comenzar con el valor 1. En el bucle se imprimir el valor de esta variable y despus se incrementar en 1, para repetir de nuevo el bucle. Esta repeticin se mantiene MIENTRAS i sea menor o igual que N. El pseudocdigo es por tanto:
i = 1 MIENTRAS i <= N IMPRIMIR el valor de i INCREMENTAR el valor de i

Lo cual se traduce de forma directa al siguiente cdigo en Python, en el cual damos a N un valor de 10, para que se pueda ejecutar.
1 i = 1 2 while i <= 10: 3 print i 4 i = i + 1

Observar que el valor inicial de la i no tiene por qu ser necesariamente 1. De hecho son muy comunes los bucles en los que i comienza con el valor 0. Depende del problema que queramos resolver. Asimismo, el valor que sumamos a i en cada iteracin del bucle no tiene por qu ser 1.

2.4 Manejo de estructuras bsicas de control de ujo

67

Podramos querer contar de 2 en 2, o de 3 en 3, etc. A veces es incluso necesario contar hacia atrs, de modo que la i se va decrementando en cada iteracin del bucle. En este caso el valor inicial sera mayor que el valor nal y la condicin del while sera que i >= valor_final. Como vemos, todas estas variantes se pueden implementar con facilidad modicando ligeramente la estructura while que acabamos de presentar. Sin embargo, ya que este tipo de bucles aparece muy a menudo en todos los programas, la mayora de los lenguajes de programacin incluyen una sintaxis especca para implementarlos, que permite simplicar ligeramente el cdigo y reducir el nmero de lneas necesarias. La mayora de los lenguajes (por ejemplo, C, Java) utilizan la palabra reservada for para este tipo de bucles. En Python tambin existe el bucle for y puede ser usado para implementar esta idea de bucle controlado por contador. Como veremos en la seccin 2.7.4, el for de Python es mucho ms verstil, y puede usarse no solo para hacer que la i vaya tomando el valor de una serie de enteros sucesivos, sino para que vaya tomando una secuencia de valores arbitraria, a travs de las listas. Pero no nos adelantemos. En esta seccin veremos nicamente cmo for puede usarse para implementar el bucle controlado por contador. Para este cometido, Python proporciona la funcin range() que genera una secuencia de enteros entre un valor inicial y nal que se le suministre y separados entre s una cantidad que tambin se le puede suministrar. Es sobre esta secuencia de enteros sobre la que la variable i ir tomando valores. La sintaxis general de range es range(inicial, final, paso), siendo: inicial el valor del primer entero de la secuencia. Puede omitirse, y entonces recibir automticamente el valor cero. nal el valor del primer entero fuera de la secuencia. Este valor ya no formar parte de la secuencia de enteros generada, que se detendr en el entero anterior a ste. paso es la distancia entre los enteros que se van generando. Puede omitirse y entonces recibir automticamente el valor uno. Por ejemplo, si ponemos range(5), estaramos suministrando nicamente el valor nal, por lo que inicial y paso recibiran automticamente los valores 0 y 1 respectivamente, y as se generara la secuencia de cinco enteros empezando en 0 y terminando en 4:
>>> range(5) [0, 1, 2, 3, 4]

Importante observa como en el resultado de range(5) no aparece el 5. La secuencia se detiene en el valor anterior al nal especicado. Si especicamos dos parmetros, se entender que se trata de los valores inicial y nal, aunque al igual que en el caso anterior, el valor nal no estar includo en la secuencia. El paso tomar por defecto el valor 1. Por ejemplo:
>>> range(4,10) [4, 5, 6, 7, 8, 9]

Finalmente, si queremos especicar el paso, necesitamos especicar entonces los tres valores, inicial, nal y paso. La cantidad paso puede ser positiva o negativa, permitiendo as hacer rangos que cuentan hacia adelante o hacia atrs. Un ejemplo de rango ascendente, que recorre los impares menores de 10:
>>> range(1,10,2) [1, 3, 5, 7, 9]

68

Introduccin a la programacin

En el bucle ascendente, el ltimo nmero que se incluye en el rango es el mayor que cumpla ser menor que el valor nal. Es decir, el cuanto se encuentra que el valor es mayor o igual que el valor nal, el rango se detiene y ese ya no sera includo. Qu parmetros tendramos que pasarle a range para generar un rango que incluya los nmeros pares comprendidos entre 1 y 10, incluyendo al 10? Se deja como ejercicio para el lector. Finalmente, si el paso es negativo, el valor inicial tendr que ser mayor que el valor nal, de lo contrario se nos generara un rango vaco. Un par de ejemplos:
>>> range(1,10,-1) [] >>> range(10,1,-1) [10, 9, 8, 7, 6, 5, 4, 3, 2]

Observa como en el primer caso el rango que se obtiene est vaco, debido a que por error hemos puesto un valor inicial que es menor que el valor nal. En el segundo caso el rango se genera correctamente, pero observa que, al igual que en los rangos ascendentes, el valor nal especicado (el 1) no forma parte de la secuencia que se genera. Es decir, en este caso range va generando nmeros hasta que encuentra uno que es menor o igual que el nal especicado y entonces se detiene y este ltimo no forma parte del resultado. Qu parmetros habra que pasarle a range para que genere todos los mltiplos de 3 positivos y menores de 100? Se deja como ejercicio para el lector. Una vez hemos comprendido como range puede usarse para generar listas de nmeros, slo queda decir cmo usar la sintaxis for para hacer que una variable i vaya tomando valores sobre esa lista. La sintaxis es la siguiente:
for i in range(...): sentencia1 sentencia2

Esto crea un bucle formado por sentencia1 y sentencia2 que se repetir un nmero de veces que depende de los parmetros que pongamos en range, y en cada una de esas repeticiones, la variable i va tomando un valor de los generados por range. Por ejemplo, si queremos imprimir los nmeros del 1 al 10:
1 for i in range(1,11): 2 print i

Ya que range(1,11) genera una secuencia de 10 enteros, el bucle se repetir 10 veces. En cada iteracin del bucle la i tendr un valor diferente, que va pasando por la secuencia de valores generada por range. Este bucle por tanto es equivalente al que vimos en la pgina 66, aunque como vemos la sintaxis es mucho ms compacta. Es importante sealar que para que el 10 forme tambin parte de la secuencia, debemos especicar 11 como valor nal. Esto puede resultarte chocante, pero es que, si bien las personas, cuando queremos contar N nmeros solemos hacerlo desde 1 hasta N, ambos inclusives, en informtica sin embargo es mucho ms frecuente el caso de que los N nmeros deban ir desde 0 hasta N-1, lo cual es justamente lo que obtenemos si ponemos range(N). Otra forma de imprimir los nmeros entre 1 y 10, por tanto, podra ser:
1 for i in range(10): 2 print i+1

En ocasiones, los valores que tome la variable i no nos importan. Si queremos, por ejemplo, imprimir una secuencia de 20 asteriscos en pantalla, nos da igual si la i va entre 1 y 20 o entre 0 y

2.4 Manejo de estructuras bsicas de control de ujo

69

19, con tal de que haya 20 repeticiones del bucle. En ese caso range(20) es perfectamente vlido y ms legible incluso que range(1,21). Por ejemplo:
1 for i in range(20): 2 print "*",

# Repetir 20 veces # imprimir asterisco

Ejemplo nal Vamos a escribir un programa que pida al usuario un nmero entero y positivo (debe insistir en que sea positivo, repitiendo la pregunta si el usuario mete uno negativo). Una vez tenemos ese nmero, se calcula el factorial del mismo5 , y se imprime en pantalla el resultado. El cdigo siguiente muestra una posible implementacin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

# Para forzar a que el numero introducido sea positivo, haremos un bucle # REPETIR-HASTA QUE sea positivo es_positivo = False # Inicialmente suponemos que no lo es while not es_positivo: n = int(raw_input("Introduce un numero positivo o cero: ")) if n >= 0: es_positivo = True # # # # Ahora calcularemos el factorial. Para ello hay que multiplicar todos los numeros entre 1 y n. Usaremos una variable "fact" que inicialmente sea 1 y en cada iteracion del bucle multiplique su valor anterior por el i correspondiente a esa iteracion

fact = 1 for i in range(1,n+1): fact = fact * i # Al salir del bucle tenemos la respuesta, la imprimimos print n, "!=", fact

Algunos comentarios sobre el listado anterior: Observa los parmetros que hemos pasado a range(). Para que la i vaya tomando valores entre 1 y n, ambos inclusive, ha sido necesario poner range(1, n+1). Se trata de un bucle ascendente, pero podra haberse implementado tambin en forma de bucle descendente. Intntalo. Qu ocurre si n es cero? Funciona el programa, o se rompe su ejecucin? Y si funciona produce la respuesta correcta? (nota, el factorial de 0 es igual a 1 por denicin). Pongamos por caso que vamos a calcular el factorial de 6. Fijate que en la primera iteracin del bucle, en la que i vale 1 y fact tambin vale 1, estamos haciendo simplemente el producto 1 * 1, lo cual podra haberse omitido. Si en vez de range(1, n+1) ponemos range(2, n+1) nos saltamos esta primera multiplicacin y el algoritmo es un poco ms veloz. Pero seguir funcionando correctamente para n=0 y para n=1? Pinsalo.

2.4.6.

Ejercicios propuestos

1. Se denomina semi-factorial 6 de un entero N , y se denota por N !!, al producto de N por N 2, por N 4, etc. hasta llegar a 2 1.
5

El factorial de N se denota por N ! y se calcula como el producto de todos los enteros positivos menores o iguales En la literatura inglesa es ms frecuente el trmino double factorial, aunque ambos trminos son vlidos.

aN
6

70

Introduccin a la programacin Dicho de otra forma, si N es impar, N !! es el producto de todos los impares menores o iguales que N , mientras que si N es par, N !! es el producto de todos los pares menores o iguales que N. Escribe un programa que pida al usuario el valor de N , forzando a que sea positivo, e imprima el resultado del clculo del semi-factorial. 2. Probablemente para resolver el ejercicio anterior has mirado con un if si N era par o impar, haciendo un bucle diferente en cada caso. Piensa cmo podras calcular N !! con un solo bucle que funcione tanto si N es par como si es impar. Pista: intenta con un bucle descendente.

2.5.

Denicin y uso de subprogramas y funciones. mbito de variables

Podemos pensar que un programa se compone de varias partes, como por ejemplo, obtener los datos de entrada por parte del usuario, realizar ciertos clculos con los mismos y mostrar el resultado de esos clculos en la pantalla. Un buen plan de ataque para realizar un programa consiste en descomponer la tarea a realizar en unas cuantas subtareas, que a su vez pueden descomponerse en subtareas ms pequeas o ms simples y as sucesivamente. Llegar un momento en que dichas subtareas sern lo sucientemente pequeas como para que sea sencillo programarlas. Este mtodo se conoce como diseo descendente y da lugar a la programacin modular. La mayora de los lenguajes de programacin cuentan con recursos que les permiten dividir un programa en partes ms pequeas (subprogramas). En el caso del Python estos subprogramas se conocen como funciones. Importante Un subprograma o funcin es un fragmento de cdigo de un programa que resuelve un subproblema con entidad propia

2.5.1.

Deniciones y uso

En el contexto de la programacin una funcin es una secuencia de sentencias que ejecuta una operacin deseada y tiene un nombre. Esta operacin se especica en una denicin de funcin. La sintaxis para una denicin de funcin en Python es:
def NOMBRE( LISTA DE PARAMETROS ): SENTENCIAS

Sigue la siguiente estructura: 1. Un encabezado, que empieza con una palabra reservada (def), continua con el nombre que se quiere dar a la funcin, sigue con la lista de parmetros entre parntesis y termina con dos puntos. 2. Un cuerpo consistente en una o ms sentencias de Python, cada una de ellas con la misma sangra a partir del margen izquierdo. En esta asignatura usaremos un sangrado estndar de cuatro espacios. Importante Se pueden inventar los nombres que se deseen para las funciones, siguiendo las mismas reglas que para los nombres de variable (vase pgina 50).

2.5 Denicin y uso de subprogramas y funciones. mbito de variables

71

La lista de parmetros especica qu informacin, si es que la hay, se debe proporcionar a n de usar la nueva funcin. La lista de parmetros puede estar vaca o contener un sinnmero de parmetros. Ms adelante se ampliar la informacin acerca de los parmetros. La primera funcin que escribiremos no tiene parmetros, por lo que la implementacin tiene el siguiente aspecto:
1 def nueva_linea(): 2 print # la sentencia print sin parametros muestra una nueva linea

Esta funcin se llama nueva_linea. Los parntesis vacos indican que la funcin no tiene parmetros. Su cuerpo contiene solamente una nica sentencia, cuya salida es una lnea vaca (eso es lo que ocurre cuando se usa la sentencia print sin argumentos). Importante Denir una funcin no hace que la funcin se ejecute. Para que una funcin se ejecute se necesita una llamada a la funcin. Las llamadas a las funciones contienen el nombre de la funcin a ejecutar seguida por la lista, entre parntesis, de los valores que son asignados a los parmetros en la denicin de funcin. Nuestra primera funcin tiene una lista vaca de parmetros, por lo que la llamada a funcin no tiene ningn argumento. Ntese, sin embargo, que en la llamada a la funcin se requieren los parntesis:
1 2 3 4 5 6

def nueva_linea(): print # la sentencia print sin parametros muestra una nueva linea print "Primera Linea." nueva_linea() print "Segunda Linea." Primera Lnea. Segunda Lnea.

El espacio extra entre las dos lneas es el resultado de la llamada a la funcin nueva_linea. Qu pasa si deseamos ms espacio entre las lneas? Podemos llamar la misma funcin repetidamente:
1 2 3 4 5 6 7 8

def nueva_linea(): print # la sentencia print sin parametros muestra una nueva linea print "Primera Linea." nueva_linea() nueva_linea() nueva_linea() print "Segunda Linea." Primera Lnea.

Segunda Lnea.

O podemos escribir una nueva funcin llamada tres_lineas que muestre tres lneas vacas:
1 def nueva_linea(): 2 print # la sentencia print sin parametros muestra una nueva linea

72
3 4 5 6 7 8 9 10 11

Introduccin a la programacin

def tres_lineas(): # llama 3 veces a nueva_linea() nueva_linea() nueva_linea() nueva_linea() print "Primera Linea." tres_lineas() print "Segunda Linea."

Esta funcin contiene tres llamadas a la funcin nueva_linea. Cada una de estas llamadas ejecutar una vez el cdigo asociado a la funcin, con lo que obtendremos la misma salida en este ejemplo que en el anterior. Importante Dentro de una funcin se puede llamar a cualquier otra funcin que haya sido denida previamente. Hasta este punto, puede que no parezca claro por qu hay que tomarse la molestia de crear todas estas funciones. De hecho, hay muchas razones, y el ejemplo que acabamos de ver muestra dos: 1. Crear una nueva funcin nos permite agrupar un cierto nmero de sentencias y darles un nombre. Las funciones pueden simplicar un programa escondiendo un clculo complejo detrs de un nico comando que usa palabras en lenguaje natural. 2. Crear una nueva funcin puede recortar el tamao de un programa eliminando el cdigo repetitivo. Por ejemplo, una forma ms corta de mostrar nueve lneas consecutivas consiste en llamar la funcin tres_lineas tres veces.

2.5.2.

Documentacin de funciones

Las funciones en python se pueden documentar con lo que se conocen como cadenas de documentacin o docstrings. Ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13

def nueva_linea(): """Esta funcion muestra en pantalla una linea vacia""" print # imprime una linea en blanco def tres_lineas(): """Esta funcion muestra en pantalla tres lineas vacia""" nueva_linea() # llama 3 veces a la funcion nueva_linea nueva_linea() nueva_linea() print "Primera Linea." tres_lineas() print "Segunda Linea."

Todo lo que hay entre las comillas es la cadena de documentacin de la funcin, que explica lo que hace sta. Una cadena de documentacin, si existe, debe ser lo primero que se dene en la funcin (es decir, lo primero que aparece tras los dos puntos). No es tcnicamente necesario incluir una cadena de documentacin, pero es recomendable hacerlo siempre. Estas cadenas se estn delimitadas por tres comillas al principio y tres comillas al nal, pudiendo ocupar varias lneas. Muchos entornos de programacin de Python utilizan la cadena de documentacin para proporcionar ayuda sensible al contexto, de modo que cuando se escribe el nombre de una funcin, su

2.5 Denicin y uso de subprogramas y funciones. mbito de variables

73

cadena de documentacin se muestra como ayuda. Otra forma de ver la cadena de documentacin de una funcin es utilizando la funcin help desde el intrprete .
>>> help(nueva_linea) Help on function nueva_linea in module main: nueva_linea() Esta funcion muestra en pantalla una linea vacia

Importante La idea de las cadenas de documentacin es describir el comportamiento externo de la funcin, mientras que el funcionamiento interno se describe utilizando comentarios

Importante Escribir cadenas de documentacin y comentarios es una buena prctica de programacin. Sern ms tiles cuanto mejor expliquen el qu hace la funcin y el cmo lo hace

2.5.3.

Parmetros y argumentos

Ya hemos denido un par de funciones cuyo objetivo es escribir lineas vacas. Estas funciones tienen su utilidad, sin embargo, podra sernos ms til tener un cdigo capaz de escribir una lnea a modo de separador, por ejemplo una lnea con 10 asteriscos: ********** o una lnea con 20 guiones: -------------------Para cubrir esta necesidad, podemos implementar dos funciones: una que imprima 10 asteriscos y otra que imprima 20 guiones. Pero, no sera ms til tener una nica funcin capaz de cubrir las dos necesidades? Para ello podramos implementar la funcin pinta_linea, que se utilizara de la siguiente manera:
>>> pinta_linea(10,"*") ********** >>> pinta_linea(20,"-") --------------------

Podemos observar que el nombre de la funcin es el mismo. Lo que cambia son los argumentos que se pasan a la funcin y, por tanto, el resultado de su ejecucin. Podramos leer el cdigo anterior como "pinta una lnea de 10 asteriscos" y "pinta una lnea de 20 guiones". Veamos cmo se implementara esta funcin:
1 def pinta_linea(veces, car): 2 """Muestra en la pantalla una linea con un determinado numero de caracteres 3 Tiene 2 parametros: 4 - veces, numero de veces que aparecera el caracter en la linea 5 - car, caracter que se quiere mostar""" 6 i=1 7 cadena="" # se crea una cadena vacia 8 while i <= veces: 9 cadena = cadena + car # se aniade un caracter en cada iteracion

74
10 i = i + 1 11 print cadena 12 13 14 pinta_linea(10,"*") 15 pinta_linea(20,"-")

Introduccin a la programacin

Vemos que, en esta ocasin, el espacio dedicado a la lista de parmetros no est vaco. Entre los parntesis se indican dos parmetros: el primero, veces, se utiliza para almacenar el nmero de veces que queremos que aparezca repetido el caracter que se pasa como segundo parmetro el segundo, car, sirve para almacenar el carcter que se quiere mostrar como separador Observa que el orden de los parmetros (en la denicin) se corresponde con el orden de los argumentos (en la llamada a la funcin). Si al llamar a la funcin escribisemos pinta_linea("*",10) no se producira el resultado esperado. Importante A la hora de denir una funcin se debe indicar, entre parntesis, la lista de parmetros (parmetros formales) que esta funcin necesita. Cuando se quiere utilizar una funcin se le pasarn, entre parntesis, los argumentos (parmetros reales) necesarios para su ejecucin.

2.5.4.

Flujo de ejecucin

Con el n de asegurar que una funcin se dena antes de su primer uso es importante conocer el orden en el que las sentencias se ejecutan. Este orden de ejecucin se denomina ujo de ejecucin. La ejecucin siempre empieza con la primera sentencia del programa y las sentencias se ejecutan una a una, desde arriba hacia abajo. Importante Las deniciones de funcin no alteran el ujo de ejecucin del programa, pero recuerda que las sentencias que estn dentro de las funciones no se ejecutan hasta que stas sean llamadas. Las llamadas a funciones son como un desvo en el ujo de ejecucin. En lugar de continuar con la siguiente sentencia, el ujo salta a la primera lnea de la funcin llamada, ejecuta todas las sentencias de la funcin, y regresa para continuar donde estaba previamente. Esto suena sencillo, hasta que tenemos en cuenta que una funcin puede llamar a otra, lo que conllevara un nuevo salto en el ujo de ejecucin hasta el cdigo de la funcin que acaba de ser llamada. Afortunadamente, todos los lenguajes de programacin son capaces de realizar todos estos saltos de forma transparente al programador, as que cada vez que una funcin termina, el programa regresa al punto desde donde fue llamada. Cuando llega al n del programa, la ejecucin termina. Para comprender esto mejor, vamos a continuar con el ejemplo anterior extendindolo para pintar rectngulos. Para ello vamos a denir una nueva funcin pinta_rectangulo que, apoyndose en pinta_linea es capaz de dibujar un rectngulo:
1 def pinta_linea(veces, car): 2 i=1

2.5 Denicin y uso de subprogramas y funciones. mbito de variables


3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

75

cadena="" while i <= veces: cadena = cadena + car i = i + 1 print cadena def pinta_rectangulo(alto, ancho, car): i=1 while i <= alto: pinta_linea(ancho,car) i = i + 1 altura = 5 base = 20 simbolo = "*" pinta_rectangulo(altura,base,simbolo)

La salida de este programa es la siguiente:


******************** ******************** ******************** ******************** ********************

Mediante un diagrama de pila7 podremos observar el valor de cada variable o parmetro y la funcin a la que pertenecen. Veamos cmo se va actualizando el diagrama de pila a medida que se ejecuta el programa anterior. El programa se inicia en la lnea 15 con la creacin de la variable altura, la variable base (lnea 16) y la variable simbolo (lnea 17); en ese momento tendramos el siguiente diagrama de pila:

<module> altura base simbolo

20

"*"

Vemos que el diagrama contiene un recuadro cuyo nombre es <module> y en su interior aparecen las variables base, altura y simbolo apuntando a sus valores correspondientes. <module> es un nombre especial que hace referencia al mdulo que dene el programa, el cdigo que est fuera de todas las funciones. En la lnea 18 se llama a la funcin pinta_rectangulo, con lo que pasa a ejecutarse la lnea 9 (creando los tres parmetros) y la lnea 10 (creando la variable i). En ese momento el diagrama de pila queda de la siguiente manera:
Los diagramas de pila no slo muestran el valor de cada variable, sino que adems muestran la funcin a la cual pertenece cada variable. El funcionamiento de este diagrama es como el de una pila de elementos: si queremos aadir un elemento a la pila, este elemento de aadir en la cima de la pila y si queremos retirar un elemento de la pila, este debe ser necesariamente el de la cima de la pila, ya que si tratsemos de retirar un elemento que no estuviese en la cima, entonces la pila se desmoronara. Pensad en una pila de ropa o una pila de cajas para comprender mejor el funcionamiento de este diagrama. En este caso lo que se apilan son llamadas a funciones.
7

76

Introduccin a la programacin

pinta_rectangulo i 1

alto

ancho

20

car <module> altura base simbolo

"*"

Podemos observar que <module> contina en la pila y sobre l aparece la funcin pinta_rectangulo conteniendo todos los parmetros y variables que se denen en la misma. Los parmetros alto, ancho y car toman, respectivamente, los valores de altura, base y simbolo, mientras que la variable i toma inicialmente el valor 1. Despus se entra en un bucle (lnea 11) que ejecutar alto veces las lneas 12 y 13. La lnea 12 hace una llamada a la funcin pinta_linea. Despus de llamar a esta funcin, se ejecuta la lnea 1, que crea los dos parmetros (veces y car), y las lneas 2 y 3, que crean un par de variables (i y cadena):
pinta_linea cadena i

veces

car "" pinta_rectangulo i 1

alto

ancho

20

car <module> altura base simbolo

"*"

Los parmetros y variables creados en esta funcin apuntan a los valores correspondientes, es decir, veces y car apuntan, respectivamente, a los valores de ancho y car, mientras que la variable i apunta inicialmente al valor 1 y la variable cadena apunta a un str vaco. Se entra entonces en el bucle de la lnea 4 que tendr veces iteraciones. En cada iteracin aadir un carcter a la cadena (lnea 5) e incrementar el valor de la i (lnea 6). Al nalizar el bucle imprimir en la

2.5 Denicin y uso de subprogramas y funciones. mbito de variables

77

pantalla la cadena resultante y la funcin nalizar, pasando a ejecutarse la lnea 13 en la funcin pinta_rectangulo. Cuando una funcin llega a su n se elimina del diagrama de pila. Llegar un momento en que no haya funciones apiladas en el diagrama de pila, es decir, se estar ejecutando el cdigo del mdulo principal <module>. Cuando el cdigo de este mdulo se nalice, el programa nalizar.

2.5.5.

Mensajes de error

Si durante la ejecucin de una funcin ocurriese un error, Python mostrar el nombre de la funcin que ha fallado, de la que la ha llamado y as sucesivamente hasta llegar al mdulo principal. Vamos a modicar el programa anterior introduciendo un error (ponindole como nombre pinta_rect_mal.py) para ver el mensaje que nos muestra en intrprete:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

def pinta_linea(veces, car): i=1 cadena="" while i <= veces: cadena = cadena + car i = i + car # error <- intento sumar a un int un str print cadena def pinta_rectangulo(alto, ancho, car): i=1 while i <= alto: pinta_linea(ancho,car) i = i + 1 altura = 5 base = 20 simbolo = "*" pinta_rectangulo(altura,base,simbolo)

La salida de este programa es la siguiente:


Traceback (most recent call last): File "pinta_rect_mal.py", line 18, in <module> pintar_rectangulo(altura,base,simbolo) File "pinta_rect_mal.py", line 12, in pinta_rectangulo pinta_linea(ancho,car) File "pinta_rect_mal.py", line 6, in pinta_linea i = i + car TypeError: unsupported operand type(s) for +: int and str

En el mensaje de error podemos leer que en la lnea 18 del programa principal (<module>) se llama a la funcin pinta_rectangulo. En la lnea 12, que es una instruccin de esa funcin, se realiza una llamada a la funcin pinta_linea. Finalmente, en la linea 6, en la funcin pinta_linea se ejecuta la instruccin i=i+car, que es la instruccin que produce un error, concretamente: "operador + no soportado para los tipos int y str". Debis prestar atencin al hecho de que en el mensaje de error se nos indican las funciones implicadas en el orden en el que han sido llamadas, es decir, desde la base de la pila hasta la cima de la misma.

2.5.6.

Modicando el valor de los parmetros

Ya sabemos denir parmetros y pasar argumentos a las funciones. Sin embargo, hay un tema que no est claro, qu sucede cuando se modica el valor de un parmetro dentro de una funcin? se modicar el valor de la variable que se utiliza como argumento en la llamada de la funcin? Veamos un ejemplo:

78
1 2 3 4 5 6 7 8

Introduccin a la programacin
def decrementa(val): val = val - 1 print val x = 7 print x decrementa(x) print x

En el cdigo se dene una funcin que decrementa en una unidad el valor que se le pasa como parmetro. Veamos lo que sucede durante la ejecucin del programa. Al ejecutarse la lnea 5 se crea la variable x apuntando al valor 7. En la siguiente lnea se imprime el valor apuntado por la variable.
<module> x 7

En la lnea 7 se llama a la funcin decrementa, con lo que se ejecuta la linea 1 crendose as el parmetro val que apuntar al mismo valor que apunta la variable x:
decrementa val <module> x 7

La ejecucin de la lnea 2 implica que el parmetro val deja de apuntar al 7 pasando a apuntar al 6, con lo que el parmetro val y la variable x quedan desligados. La lnea 3 imprimir un 6, el valor apuntado por val.
decrementa val 6 <module> x 7

Finaliza la funcin y se ejecuta la ltima lnea. La ejecucin completa del programa producir la siguiente salida en la pantalla:
7 6 7

Por tanto, la modicacin de un parmetro (val) dentro de la funcin no afecta al argumento (x) con el que se ha llamado a la funcin. Esto es cierto para todos los tipos de variables que hemos visto hasta el momento, sin embargo, ms adelante, se dedicar una seccin a explicar el tipo de dato lista. Su comportamiento como parmetro de una funcin es diferente y se comentar en la seccin 2.7.5.

2.5 Denicin y uso de subprogramas y funciones. mbito de variables Conclusin Cuando tenemos un parmetro de tipo int, float, str o bool, las modicaciones hechas sobre ese parmetro (parmetro formal) no se ven reejadas en el argumento (parmetro real) que se ha utilizado para llamar a la funcin.

79

2.5.7.

mbito de parmetros y variables

En el ltimo diagrama de la seccin 2.5.4 podemos apreciar cmo cada funcin tiene sus propias variables o parmetros. De esta forma, durante la ejecucin de cada funcin solo se podrn utilizar los identicadores (variables o parmetros) contenidos en su recuadro correspondiente ms los denidos en <module>, que son accesibles desde todas las funciones del propio programa. Cuando se crea una variable dentro de una funcin, esa variable puede ser utilizada nicamente dentro de esa funcin. Lo mismo sucede con los parmetros, solo pueden utilizarse dentro de la funcin donde estn denidos. As, desde la funcin pinta_linea se podr acceder a los identicadores (variables o parmetros) cadena, i, veces, car, altura, base y simbolo. Desde la funcin pinta_rectangulo se podr acceder a los identicadores i, alto, ancho, car, altura, base y simbolo. Finalmente, desde <module> se tendr acceso, nicamente, a altura, base y simbolo. Importante Las variables y parmetros declarados dentro de una funcin se consideran locales, ya que solo se puede acceder a ellos desde la propia funcin. Las variables que estn declaradas fuera de las funciones se consideran globales y se pueden utilizar en todo el programa. A veces nos encontramos en situaciones en las que al utilizar una variable o parmetro puede parecer que hay una ambigedad al haber varias variables con el mismo nombre. Veamos un ejemplo:
1 2 3 4 5 6 7

def decrementa_e_imprime(x): x = x - 1 print x x = 10 y = 1 incrementa_e_imprime(y)

Una variable (x) del programa o mdulo principal tiene el mismo nombre que el parmetro de la funcin. Cuando en la lnea 2 de la funcin se hace x=x-1 a qu valor apunta la x? a 1 o a 10? Vamos a verlo en el diagrama de pila. Al ejecutarse las lneas 5 y 6 se crean las variables x e y que apuntan, respectivamente, a los valores 10 y 1:
<module> y x 1 10

A continuacin se ejecuta la llamada a la funcin decrementa_e_imprime pasndole como argumento la variable y. Como se puede observar en el cdigo, la funcin crea un parmetro llamado x y que, en esta ocasin, apuntar al mismo valor que la y:

80

Introduccin a la programacin

decrementa_e_imprime x <module> y x 1 10

Entonces, nos encontramos en una situacin en la que desde la funcin decrementa_e_imprime tenemos acceso a tres variables: una local (el parmetro x) y dos globales (la x y la y). Como se puede ver, dos de ellas comparten el mismo nombre. Al ejecutar la lnea 2 qu variable se modicar? Puede parecer que existe una ambigedad, sin embargo, tal ambigedad no existe, ya que cuando hay un conicto de este tipo el intrprete entiende que se est haciendo referencia a la variable local. Por tanto, tras ejecutar la lnea 2 estaremos en la siguiente situacin:
decrementa_e_imprime x 0 <module> y x 1 10

y se imprimir un 0 en la pantalla.

2.5.8.

Funciones que retornan valores

Hasta ahora hemos implementado funciones que realizaban unas ciertas acciones que nalizaban mostrando en pantalla el resultado de las mismas: pintar lneas, rectngulos o decrementar un valor y mostrarlo por pantalla. Sin embargo, la verdadera potencia de las funciones radica en el hecho de que el producto de esas acciones o clculos puede ser guardado en una variable y ser usado, a su vez, para realizar clculos ms complejos. Vamos a ver un ejemplo de funcin que retorna algo:
1 def potencia(x,y): 2 return x**y 3 4 resultado = potencia(2,10) 5 print resultado

La funcin potencia retorna x elevado a y. En la lnea 4 vemos que el resultado de la funcin puede ser asignado a una variable y, por tanto, podr ser utilizado para realizar cualquier otra operacin que nos interese. Pero, cul es la diferencia respecto a las funciones que hemos visto hasta el momento? La respuesta es sencilla: la sentencia return. Esta sentencia hace que la funcin nalice en ese mismo instante produciendo como resultado lo que est a continuacin del return. Hay que ser cuidadosos, ya que cualquier instruccin que situemos en las siguientes lneas no se ejecutar si antes se ha ejecutado el return. Importante

2.5 Denicin y uso de subprogramas y funciones. mbito de variables

81

Cuando una funcin ejecuta la sentencia return el ujo de ejecucin vuelve inmediatamente al punto en el que se realiz la llamada a la funcin A estas alturas del curso, todos sabemos que la operacin 10/2 calcula el resultado de la divisin de 10 entre 2. Y tambin sabemos que la operacin 10/0 va a producir un error de divisin por 0:
>>> 10/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: integer division or modulo by zero

Podemos utilizar las funciones como un mecanismo para controlar este tipo de errores. Podramos implementar la funcin divide que al encontrarse con 0 como denominador, no haga la divisin y nos avise de este hecho:
1 2 3 4 5 6 7 8 9 10 11

def divide(num,den): if den == 0: return None else: return num/den resultado = divide(10,0) if resultado == None: print "Hay un 0 en el denominador" else: print "El resultado es:",resultado

None es un valor especial que tiene ciertas utilidades como la que acabamos de ver. Adems, aunque no nos hayamos dado cuenta, todas las funciones retornan algn valor, incluso las que no tienen la sentencia return. Estas funciones retornan, por defecto, None. Funciones que retornan varios valores En ocasiones, puede resultarnos necesaria una funcin que retorne ms de un valor. Por ejemplo, podra resultarnos til una funcin que dados dos nmeros retorne primero el mayor y luego el menor. La implementacin sera tan sencilla como:
1 def max_min(x,y): 2 if x > y: 3 return x, y 4 else: 5 return y, x 6 7 mx, mn = max_min(3,7) 8 9 print "El maximo es el",mx,"y el minimo el",mn

Vemos que lo nico que hay que hacer es colocar a continuacin del return los valores que se deseen retornar. Eso si, cuando se llame a la funcin, se necesitar colocar en la parte izquierda de la asignacin tantas variables como valores se retornen. De esta forma, tras la ejecucin de la funcin max_min, en mx estar almacenado el valor mayor y en mn el menor. Para saber ms En realidad, incluso en este caso en que parece que la funcin puede retornar ms de un valor, est retornando uno solo, si bien es un valor de un tipo de datos que no hemos

82

Introduccin a la programacin

explicado. Se trata del tipo tupla que permite agrupar, separados por comas, varios valores o variables. Por tanto, cuando escribimos return x, y la funcin est retornando una tupla (solo una), que est compuesta por dos variables. Es habitual poner parntesis alrededor de las tuplas, para hacerlas ms evidentes, como por ejemplo return(x, y). En el programa principal, en la lnea 7 en que aparecen dos valores a la izquierda de la asignacin, se trata otra vez de una tupla, formada por dos variables. Por tanto esa asignacin asigna una tupla a otra tupla. Ambas tuplas deben tener el mismo nmero de elementos para que la asignacin funcione.

2.5.9.

Mdulos

A medida que vayamos realizando programas nos iremos dando cuenta de que en muchos de ellos necesitaremos utilizar las mismas funciones. Por ejemplo, la funcin divide podra resultarnos de utilidad en varios programas que no tengan nada en comn. Para tratar de evitar el tener que implementar esta funcin en cada programa podemos utilizar lo que se conoce como mdulos. Importante Un mdulo es un chero que contiene la implementacin de varias funciones. Lo ms razonable es que un mdulo contenga funciones que compartan la misma temtica. La versin de Python que utilizamos ya viene con un montn de mdulos que podemos utilizar. Ms adelante veremos algunos ejemplos. Creacin de mdulos Crear mdulos es muy sencillo. Vamos a meter en el chero mod_pintar.py unas cuantas funciones que pintan en la pantalla:
1 def pinta_linea(veces, car): 2 i=1 3 cadena="" 4 while i <= veces: 5 cadena = cadena + car 6 i = i + 1 7 print cadena 8 9 def pinta_rectangulo(alto, ancho, car): 10 i=1 11 while i <= alto: 12 pinta_linea(ancho,car) 13 i = i + 1 14 15 def pinta_cuadrado(lado, car): 16 pinta_rectangulo(lado,lado,car)

y ya est creado el mdulo! Ahora tenemos que aprender a utilizarlo. Utilizar las funciones de un mdulo Existen varias maneras de importar funciones de un mdulo para poder utilizarlas en nuestro programa. La primera es utilizando simplemente la sentencia import seguida del nombre del mdulo. A partir de ese punto, las funciones del mdulo ya estarn accesibles. No obstante la sintaxis

2.5 Denicin y uso de subprogramas y funciones. mbito de variables

83

para usar esas funciones no es tan directa como cuando estn denidas en el propio programa. Cuando se llama a la funcin, es necesario escribir delante del nombre de la funcin y separado por un punto el nombre del mdulo a que pertenece. Observa el siguiente ejemplo:
>>> import mod_pintar >>> mod_pintar.pinta_linea(10,"*") **********

Despus de la sentencia import se escribe el nombre del mdulo, de forma que se importan todas las funciones contenidas en el mismo. Importante A la hora de importar un mdulo no hay que poner la extensin .py. La extensin del chero no forma parte del nombre mdulo. Para utilizar una funcin del mdulo, fjate en que se debe indicar el nombre del mdulo seguido de un punto y nalmente el nombre de la funcin. Esto puede resultar un poco engorroso cuando se van a utilizar mucho estas funciones, as que tenemos una alternativa:
>>> from mod_pintar import * >>> pinta_linea(10,"*") **********

En este caso tambin se importan todas las funciones, pero ahora, para utilizarlas no es necesario poner el nombre del mdulo ni el punto. Sin embargo, no siempre necesitamos importar todas las funciones de un mdulo, puesto que nuestro programa, seguramente, no va a utilizarlas todas. Cuando estamos en esta situacin, tenemos la opcin de poder elegir las funciones que queremos importar:
>>> from mod_pintar import pinta_linea, pinta_rectangulo >>> pinta_linea(10,"*") ********** >>> pinta_rectangulo(4,10,"*") ********** ********** ********** **********

Como norma general, sin embargo, no se recomienda el uso de from para importar nombres de funcin, como se acaba de ver, sino el uso del import del mdulo aunque despus haya que repetir el nombre del mdulo delante de cada llamada a la funcin. Esto es as por una razn. Es posible que diferentes mdulos implementen funciones con el mismo nombre (aunque hagan diferentes cosas). Por ejemplo, puede haber un mdulo especializado en el procesamiento de cheros con grcos (llammosle el mdulo grafico), y otro para cheros de audio (llammosle el mdulo audio). Es probable que ambos mdulos tengan una funcin cargar para leer del disco datos (imgenes o sonidos, respectivamente). Sin embargo estas funciones son diferentes, ya que una se especializa en formatos grcos y la otra en formatos de audio. Usando la sintaxis modulo.funcion no hay equvoco posible, ya que una se llamara imagenes.cargar y la otra audio.cargar. Curiosidad Cuando importamos un mdulo, el Python crea un chero que se llama como el mdulo pero con la extensin .pyc. Este chero es una versin que python ha creado la primera

84

Introduccin a la programacin

vez que ha cargado ese mdulo, tras comprobar que no contiene errores sintcticos. El chero .pyc contiene un cdigo binario especial, que python puede cargar ms rpidamente pues no necesita comprobar de nuevo la correccin sintctica. Si lo eliminamos no pasar nada y la siguiente vez que se cargue el mdulo se volver a crear. Mdulos existentes Como ya se ha comentado son muchos los mdulos existentes para trabajar en Python. Por ejemplo, el mdulo math contiene las funciones matemticas clsicas, el random funciones que generan nmeros pseudoaleatorios y el string las que trabajan con cadenas de caracteres. Hay otros mdulos que son ms especcos y se centran en problemas concretos, como por ejemplo: Interfaces grcas wxPython, pyGtk, pyQT, . . . Bases de datos MySQLdb, pySQLite, cx_Oracle, . . . Imagen PIL, gdmodule, VideoCapture, . . . Ciencias scipy, numarray, NumPy, . . . Este ltimo, el NumPy lo estudiaremos ms adelante, ya que nos permite trabajar con vectores multidimensionales de una forma muy cmoda Videojuegos Pygame, Soya 3D, pyOpenGL, . . . Sonido pySonic, pyMedia, pyMIDI, . . . Existen tambin mdulos de geolocalizacin, de puertos (USB, serie, paralelo, . . . ), para programacin de dispositivos mviles, Web, programas de mensajera y casi para cualquier cosa que podamos imaginarnos.

2.5.10.

Ejercicios resueltos

[Ejercicio 1] Implementar una funcin que retorne cierto cuando un nmero sea primo y falso en caso contrario.
1 def primo(num): 2 """esta funcion recibe un numero y retorna True si el 3 numero es primo y False si no lo es""" 4 div = 2 5 es_primo = True 6 while div <= num/2 and es_primo: 7 if num % div == 0: # si se encuentra un numero que lo divide 8 es_primo = False # entonces no es primo 9 div = div + 1 10 return es_primo

[Ejercicio 2] Utilizando la funcin implementada en el ejercicio anterior, implementar una funcin que reciba los extremos de un intervalo de nmeros naturales y muestre en pantalla todos los nmeros primos contenidos en ese intervalo. Adems, la funcin retornar la cantidad de nmeros primos que hay en el intervalo o None si el intervalo no es correcto.
1 def muestra_primos(ini, fin): 2 """recibe los extremos de un intervalo de numeros naturales y retorna 3 cantidad de numeros primos contenidos en el intervalo. Ademas, muestra en 4 pantalla los numeros primos encontrados. En caso de que el intervalo no

2.5 Denicin y uso de subprogramas y funciones. mbito de variables


5 6 7 8 9 10 11 12 13 14 15 16

85

este bien definido retornara None""" if ini > fin or ini < 1: return None # si no son naturales o el intervalo no esta bien else: cont = 0 i = ini while i <= fin: # para cada elemento del intervalo if primo(i): # se comprueba si es primo cont = cont + 1 print i i = i + 1 return cont

[Ejercicio 3] Se pide una funcin que, dada la longitud de los tres lados de un tringulo, retorne 1 si es equiltero, 2 si es issceles o 3 si es escaleno.
1 def tipo_triangulo(a,b,c): 2 """dada la longitud de los lados de un triangulo la funcion 3 retorna: 1) si es equilatero 4 2) si es isosceles 5 3) si es escaleno""" 6 if (a==b) and (b==c): 7 return 1 8 elif (a==b) or (a==c) or (b==c): 9 return 2 10 else: 11 return 3

[Ejercicio 4] Implementar una funcin que retorne el factorial de un nmero natural.


1 def factorial(n): 2 """Esta funcion retorna el factorial del numero que se 3 le pasa como parametro""" 4 resultado = 1 5 i = 1 6 while i <= n: 7 resultado = resultado * i 8 i = i + 1 9 return resultado

[Ejercicio 5] Implementar una funcin que calcule el resultado de una divisin por el mtodo de las restas sucesivas. La funcin debe retornar el cociente y el resto de la divisin.
1 def division_por_restas(dividendo,divisor): 2 """"Dados dos numeros naturales, esta funcion calcula el 3 cociente y el resto de la division""" 4 cociente = 0 5 while (dividendo >= divisor): 6 cociente = cociente + 1 7 dividendo = dividendo - divisor 8 return cociente, dividendo # en dividendo est el resto

2.5.11.

Ejercicios

[Ejercicio 1] Implementar una funcin que pinte un rectngulo hueco.


>>> pinta_rectangulo_hueco(4,10,"*") ********** * * * * **********

86

Introduccin a la programacin [Ejercicio 2] Implementar una funcin que calcule el valor absoluto de un nmero.
>>> valor_absoluto(-10) 10

[Ejercicio 3] Implementar una funcin que calcule s =


>>> suma_cuadrados(2,4) 29

m 2 i=n i

[Ejercicio 4] Para calcular el Binomio de Newton se utiliza la siguiente frmula: n k = n! , k!(n k)! por ejemplo 5 3 = 10 (2.1)

implementa una funcin que lo resuelva.


>>> binomio_newton(5,3) 10

[Ejercicio 5] Implementar una funcin que muestre en pantalla la tabla de multiplicar de un determinado nmero.
>>> 3 x 3 x 3 x 3 x 3 x 3 x 3 x 3 x 3 x 3 x tabla_multiplicar(3) 1 = 3 2 = 6 3 = 9 4 = 12 5 = 15 6 = 18 7 = 21 8 = 24 9 = 27 10 = 30

2.6.

Ficheros

Los datos utilizados por los programas que hemos hecho hasta el momento no se conservan indenidamente, sino nicamente durante el tiempo de ejecucin. Cuando termina la ejecucin del intrprete que lee y ejecuta nuestro programa esos datos dejan de existir desde un punto de vista prctico as que, si necesitamos usarlos ms tarde, tendremos que volver a calcularlos de nuevo. Sin embargo, existe la posibilidad de conservar esos datos de forma permanente, incluso tras apagar el ordenador. Para ello los programas pueden hacer uso de cheros que permiten guardar los datos fuera de la memoria del ordenador, tpicamente en un dispositivo como un disco duro, un lpiz de memoria, etc. De esta manera un programa puede salvar los datos que se deban conservar entre ejecuciones, e incluso puede hacer uso de los datos guardados por otros programas; el uso de cheros es una de las formas ms obvias y sencillas de intercambio de informacin entre programas. El lenguaje Python est especializado en el manejo de cheros de texto, es decir, aquellos que contienen la informacin en forma de cadenas de caracteres y que, por tanto, pueden leerse perfectamente en cualquier editor simple de textos, como Textedit, gEdit, o el bloc de notas.

2.6.1.

Apertura y lectura de cheros

Podemos pensar en los cheros como si fuesen cuadernos de notas. As, para poder usar un cuaderno primero lo debemos abrir, a continuacin podemos leer y/o escribir en l y, cuando hayamos terminado, lo debemos cerrar.

2.6 Ficheros

87

De igual forma, para que un programa pueda acceder al contenido de un chero, ste debe ser previamente abierto. Para ello se debe utilizar la funcin open(), a la que hay que suministrar dos parmetros, que sern dos cadenas de caracteres indicando: El nombre del chero al que queremos acceder El modo en el que vamos a abrir el chero. Esta cadena puede tener los siguientes valores "r" para abrir un chero con permiso de lectura. Si el chero no existe se produce un error. "w" para abrir un chero con permiso de escritura. Si el chero no existe se crea uno vaco y si ya existe se reescribe su contenido. "a" para abrir un chero con permiso de escritura, de forma que lo que escriba el programa se aade al contenido previo del chero. Para saber ms. . . Hay ms modos de apertura, como por ejemplo para permitir el acceso de lectura y escritura simultneas a un chero, pero su utilidad excede los requisitos de este curso. Lo que retorna la llamada a la funcin open() debe asociarse a una variable que, en caso de que la operacin de apertura tenga xito, hace referencia al chero recin abierto. Un ejemplo de uso puede verse a continuacin:
>>> f = open("datos.txt","r") Traceback (most recent call last): File "<stdin>", line 1, in <module> IOError: [Errno 2] No such file or directory: datos.txt

En este caso el intrprete muestra un error puesto que el chero que pretendamos abrir para leer no existe. Para poder presentar las operaciones de lectura supongamos que hemos creado con el bloc de notas un chero con el nombre "datos.txt", que contiene un par de lneas de texto tal como muestra la gura.

Una vez creado el chero podemos abrirlo en modo lectura y, a continuacin leer la primera lnea y mostrarla en la consola. Esto es lo que hace el cdigo que se muestra a continuacin:
>>> f = open("datos.txt", "r") >>> lin = f.readline() >>> print "Texto:", lin

88
Texto: En un lugar de la Mancha >>>

Introduccin a la programacin

Con readline() se lee toda una lnea completa del chero, incluyendo el carcter de salto de lnea nal (\n), si existe. Por esa razn al imprimir en consola la cadena asociada a lin aparece a continuacin del texto una lnea en blanco, debida a la impresin del carcter de salto de lnea. Lo que en realidad se est imprimiendo es la cadena "En un lugar de la Mancha\n". Cuando se abre un chero el sistema establece un indicador de posicin que se sita al principio de su contenido. Las sucesivas operaciones de lectura hacen que ese indicador vaya avanzando a medida que se va leyendo el resto de la informacin. As, si repetimos la operacin de lectura con readline() obtenemos la segunda lnea del texto8 :
>>> lin = f.readline() >>> print "Texto:", lin Texto: de cuyo nombre no quiero acordarme >>> f.close() >>>

Finalmente, cerramos el chero con close(), algo que siempre debemos hacer cuando terminamos de usar un chero, de igual forma que cerraramos un cuaderno de notas tras haberlo utilizado. El bucle for para leer cheros por lneas Una forma ms compacta de leer un chero lnea a lnea es mediante la iteracin sobre variable del chero con un bucle for. El cdigo que se muestra a continuacin dene una funcin que, dado un nombre de chero, cuenta y retorna el nmero de lneas en blanco que contiene:
1 def cuenta_lineas_blanco(nombre_fichero): 2 contador = 0 3 f=open(nombre_fichero, "r") 4 for l in f: 5 if len(l.strip()) == 0: 6 contador = contador + 1 7 return contador 8 9 print "Lineas en blanco:", cuenta_lineas_blanco("datos.txt")

El bucle for asigna en cada iteracin una lnea del chero a la variable l. El algoritmo implementado podra leerse como para cada lnea del chero, si su longitud es cero, entonces es que se trata de una lnea en blanco y, por tanto, hay que aumentar en una unidad el contador de lneas en blanco. Como curiosidad cabe destacar que esta funcin contar como lneas en blanco aquellas cuyos nicos caracteres sean espacios, aunque realmente su longitud no sea 0. Esta funcionalidad se consigue utilizando strip() sobre la cadena leda, l, ya que as eliminamos los espacios iniciales y nales, as como el salto de lnea de la cadena (lnea 5). Una vez eliminados, si la longitud es 0 signica que no haba ningn otro carcter y, efectivamente, era una lnea en blanco que debe ser contada. Lectura de caracteres Python dispone de otros mecanismos de lectura que nos permiten dosicar la cantidad de informacin que queremos leer en cada acceso al chero. Para ello podemos utilizar read(), que lleva un parmetro opcional indicando el nmero de caracteres que deseamos leer.
En este ejemplo el ltimo carcter del chero es la letra e, es decir, la ltima lnea del chero no termina con un salto de lnea y por eso no aparece en la consola la lnea en blanco que apareca al imprimir la primera lnea.
8

2.6 Ficheros
1 def cuenta_espacios(fichero): 2 contador = 0 3 f = open(fichero, "r") 4 c = f.read(1) 5 while c != "": 6 if c == " " : 7 contador = contador + 1; 8 c=f.read(1) 9 f.close() 10 return contador 11 12 print "Total:", cuenta_espacios("datos.txt"), "espacios"

89

La funcin cuenta_espacios() lee carcter a carcter el chero cuyo nombre se pasa como parmetro y cada vez que se encuentra un espacio aumenta un contador cuyo valor retorna al nal del proceso. La lectura debe detenerse cuando se llegue al nal del chero, que se detecta porque la funcin de lectura devuelve la cadena vaca (lnea 5). IMPORTANTE Las funciones read() y readline() devuelven la cadena vaca cuando se alcanza el nal del chero. Comprobando el valor que retornan podemos saber cuando hemos recorrido todo el chero. Si se omite el parmetro de read() entonces se obtiene una nica cadena con todo el contenido del chero, tal como muestra el siguiente ejemplo:
>>> >>> >>> En >>> f = open("datos.txt", "r") datos = f.read() datos un lugar de la Mancha\nde cuyo nombre no quiero acordarme

En el ejemplo esa cadena se asocia a la variable datos que, como se puede ver al mostrar su contenido, tiene un salto de lnea entre la palabra Mancha y la palabra de. Si se imprime esta cadena con print el salto de linea se hace efectivo en la consola y podemos ver las dos lneas que contiene el chero.
>>> print "Contenido del fichero:\n", datos Contenido del fichero: En un lugar de la Mancha de cuyo nombre no quiero acordarme >>>

ATENCIN La posibilidad de cargar todo un chero en una sola operacin de lectura debe utilizarse con precaucin ya que, si ste es de gran tamao, se podra sobrepasar la capacidad de almacenamiento en memoria y el programa no funcionara.

2.6.2.

Escritura en cheros

Para escribir texto en un chero necesitamos, en primer lugar, abrir el chero en modo escritura. En este caso, si el chero no existe, se crea uno nuevo, y si ya existe entonces se sobrescribe (por tanto, se pierde) su contenido. A continuacin podemos efectuar operaciones de escritura de cadenas

90

Introduccin a la programacin

de caracteres con write(). Ntese que la operacin de escritura no aade separador de lneas, as que si queremos escribir una lnea completa debemos incluir al nal de la cadena el salto de lnea, tal como se muestra en este ejemplo:
>>> >>> >>> >>> f = open("texto.txt","w") f.write("Esta es la primera\n") f.write("Esta es la segunda\n") f.close()

Dado que los mecanismos de manejo de cheros en Python estn orientados a cheros de cadenas de caracteres, si necesitamos almacenar valores de otro tipo debemos convertirlos previamente a cadenas. Por ejemplo, el programa siguiente pide por teclado nmeros hasta que se escriba la palabra n, y almacena en un chero los pares y en otro los impares:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

def es_par(n): return n % 2 == 0 def pide_numero(): print "Introduce un numero entero (fin para terminar):", n = raw_input() if n == "fin": return None else: return int(n) fpares = open("pares.txt", "w") fimpares = open("impares.txt", "w") n = pide_numero() while (n != None): num_a_cadena = " %d\n" % n if es_par(n): fpares.write(num_a_cadena) else: fimpares.write(num_a_cadena) n = pide_numero() fpares.close() fimpares.close()

En la linea 10, dentro de la funcin pide_numero(), se realiza la conversin a entero de la cadena tecleada por el usuario. Esta conversin es necesaria para luego poder comprobar si el nmero es par o impar. Posteriormente, a la hora de escribir el nmero en el chero correspondiente, tenemos que convertirlo de nuevo en una cadena de caracteres y aadirle el salto de lnea. Esa conversin se realiza en la lnea 16, asignando el resultado a la variable num_a_cadena. Si ahora queremos hacer un programa que lea los dos cheros creados por el programa anterior y que calcule el valor medio de los nmeros pares y de los impares entonces podramos programar lo siguiente:
1 def calcula_media(nombre): 2 suma = 0 3 contador = 0 4 fichero = open(nombre, "r") 5 num_str = fichero.readline() 6 while num_str != "": 7 suma = suma + int(num_str) 8 contador = contador + 1 9 num_str = fichero.readline() 10 fichero.close() 11 return float(suma)/contador

2.6 Ficheros
12 13 print "La media de los pares es", calcula_media("pares.txt") 14 print "La media de los impares es", calcula_media("impares.txt")

91

Observa que tenemos que hacer la conversin a nmero entero de cada uno de los nmeros en formato cadena ledos del chero, tal como se hace en la lnea 7. Este programa hace adems otra conversin necesaria para obtener un resultado correcto, que es la de convertir la variable suma a nmero real, de forma que la divisin de la lnea 11 devuelva un nmero real y no trunque el resultado a un nmero entero.

2.6.3.

Un ejemplo prctico: agenda de direcciones

En esta seccin vamos a presentar una pequea aplicacin en la que usaremos lo aprendido sobre cheros para almacenar una simple agenda de contactos.
1 def nueva_entrada(): 2 """Incorpora una nueva entrada a la agenda con los datos que se 3 piden al usuario por teclado""" 4 print "Nombre:", 5 nombre = raw_input() 6 print "Apellidos:", 7 apellidos = raw_input() 8 print "Tel:", 9 telefono = raw_input() 10 print "Correo electronico:", 11 email = raw_input() 12 # abrimos el fichero para incorporar la nueva entrada 13 agenda = open("agenda.txt", "a") 14 escribir_entrada(agenda, nombre, apellidos, telefono, email) 15 agenda.close() 16 17 def borrar_entrada(): 18 """Pide un nombre y apellidos y crea una nueva agenda a partir de la original 19 en la que se copian todos los contactos excepto ese""" 20 print "Introduce nombre y apellidos del contacto a eliminar" 21 print "Nombre:", 22 nombre_borrar = raw_input() 23 print "Apellidos:", 24 apellidos_borrar = raw_input() 25 # abrimos el fichero para leer las entradas y copiarlas 26 # a otro fichero, excepto la que queremos eliminar 27 agenda = open("agenda.txt", "r") 28 agenda_bis = open("agenda.copia.txt", "w") 29 nombre, apellidos, telefono, email = leer_entrada(agenda) 30 while nombre != "": 31 if nombre == nombre_borrar and apellidos == apellidos_borrar: 32 print "Borrando %s, %s" % (apellidos_borrar, nombre_borrar) 33 else: 34 escribir_entrada(agenda_bis, nombre, apellidos, telefono, email) 35 nombre, apellidos, telefono, email = leer_entrada(agenda) 36 agenda.close() 37 agenda_bis.close() 38 # la copia de la agenda sin la entrada pasa a ser la agenda original 39 copiar_agenda("agenda.copia.txt", "agenda.txt") 40 41 def buscar_entrada(): 42 """Busca una entrada en la agenda cuyo nombre y apellidos coincidan con los que 43 se piden por teclado""" 44 print "Introduce nombre y apellidos del contacto a buscar"

92
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

Introduccin a la programacin
print "Nombre:", nombre_buscar = raw_input() print "Apellidos:", apellidos_buscar = raw_input() agenda = open("agenda.txt", "r") encontrado = False fin_de_fichero = False while not encontrado and not fin_de_fichero: nombre, apellidos, telefono, email = leer_entrada(agenda) encontrado = (nombre == nombre_buscar) and (apellidos == apellidos_buscar) fin_de_fichero = (nombre == "") if nombre == nombre_buscar: imprimir_entrada(nombre, apellidos, telefono, email) else: print "Contacto no encontrado!!" agenda.close() def copiar_agenda(origen, destino): """Copia el fichero cuyo nombre se pasa como primer argumento en otro fichero cuyo nombre se pasa como segundo argumento""" agenda = open(origen, "r") agenda_copia = open(destino, "w") todo = agenda.read() agenda_copia.write(todo) agenda.close() agenda_copia.close() def leer_entrada(agenda): """Lee una entrada del fichero que se le pasa como argumento y devuelve las cadenas sin el salto de linea del final""" nombre = agenda.readline() apellidos = agenda.readline() telefono = agenda.readline() email = agenda.readline() return nombre.strip(), apellidos.strip(), telefono.strip(), email.strip() def con_salto(cadena): """Concatena un salto de linea a la cadena que se le pasa como argumento""" return cadena + "\n" def escribir_entrada(agenda, nombre, apellidos, telefono, email): """Escribe una entrada en el fichero que se le pasa como primer argumento""" agenda.write(con_salto(nombre)) agenda.write(con_salto(apellidos)) agenda.write(con_salto(telefono)) agenda.write(con_salto(email)) def imprimir_entrada(nombre, apellidos, telefono, email): """Imprime una entrada en pantalla""" print "\n\n" print "DATOS DEL CONTACTO" print "==================" print "Nombre:", nombre print "Apellidos:", apellidos print "Telefono:", telefono print "Correo electronico:", email print "\n\n" def menu():

2.6 Ficheros
104 salir = False 105 while not salir: 106 print "\n\n" 107 print "*******************" 108 print "PyAgenda 1.0" 109 print "*******************" 110 print "1) Nueva entrada" 111 print "2) Borrar entrada" 112 print "3) Buscar" 113 print " " 114 print "q) Salir de PyAgenda" 115 print "*******************" 116 opcion = raw_input() 117 if opcion == "1": 118 nueva_entrada() 119 elif opcion == "2": 120 borrar_entrada() 121 elif opcion == "3": 122 buscar_entrada() 123 elif opcion == "q": 124 salir = True 125 else: 126 print "Opcion desconocida!!\n\n" 127 128 129 print "PyAgenda 1.0" 130 menu() 131 print "Adios!"

93

La ejecucin del programa consiste en invocar a la funcin menu(), que muestra las opciones disponibles y, dependiendo de lo que el usuario escoja, llama a la funcin apropiada para aadir, borrar o buscar una entrada en la agenda, o bien abandonar el programa. La funcin nueva_entrada() pide por teclado los datos del nuevo contacto a aadir y, a continuacin, abre el chero en modo aadir ("a") y escribe los campos haciendo uso de una funcin auxiliar, escribir_entrada(), que incluye al nal de cada cadena el salto de lnea necesario para distinguir los campos cuando vayamos a leerlos. La funcin borrar_entrada() pide al usuario el nombre y apellidos del contacto que desea eliminar y luego crea una copia de la agenda en otro chero con todos los contactos excepto el que se desea borrar. Finalmente, el segundo chero que ya no contiene el contacto eliminado, se copia sobre el chero de agenda original. Esta funcin lee una a una las entradas de la agenda mediante la funcin leer_entrada(), que retorna los cuatro campos de un contacto sin el salto de lnea al nal. Esto facilita la comparacin con cadenas introducidas por teclado que no llevan al nal el delimitador y simplica su uso para imprimir mensajes formateados en la consola. Cada una de las entradas ledas se escribe en el chero copia, excepto aquellas cuyo nombre y apellidos coincidan con los indicados por el usuario para ser eliminados. La ltima instruccin de esta funcin es una llamada a la funcin auxiliar copiar_agenda(), que abre el chero cuyo nombre se indica como primer parmetro, carga todo su contenido en una cadena y la vuelca en un segundo chero, con el nombre indicado por el segundo parmetro. La operacin de bsqueda est implementada en la funcin buscar_entrada(), que pide el nombre y apellidos del contacto a buscar y luego abre y recorre cada entrada de la agenda hasta que, o bien se encuentra el contacto, o bien se alcanza el nal del chero. Al abandonar el bucle de bsqueda, si el contacto se ha encontrado se imprimen sus datos por consola, y si no se ha encontrado se muestra un mensaje de aviso.

94

Introduccin a la programacin

2.6.4.

Ejercicios propuestos

[Ejercicio 1] Haz una funcin que tome como parmetros un nombre de chero y una palabra e imprima las lneas de dicho chero que contienen esa palabra. Nota: python dispone del operador booleano in que no se haba explicado. Cuando se aplica entre dos cadenas, produce como resultado True si la primera aparece dentro de la segunda. Por ejemplo "algo"in "algoritmo" es True mientras que "algo"in "ordenador" es False. [Ejercicio 2] Haz una funcin encripta_fichero() que cifre un chero grabando el resultado en otro chero. Los parmetros de la funcin sern el nombre del chero origen y del chero destino. El algoritmo de cifrado ser muy simple: cada carcter se sustituir por el siguiente en la tabla de caracteres. Para ello necesitars hacer uso de las funciones ord(), que retornan la posicin en la tabla de un carcter que se pasa como argumento, y chr(), que retorna el carcter de que ocupa la posicin que se le pasa como argumento. [Ejercicio 3] Haz una funcin desencripta_fichero() capaz de descifrar los cheros encriptados generados por la funcin del ejercicio anterior. [Ejercicio 4] Ampliacin al programa agenda.py: corrige el programa para que cuando se introduzca una entrada ya existente se reemplacen sus datos, en vez de aadir un nuevo contacto. [Ejercicio 5] Ampliacin al programa agenda.py: Mejora la funcin de bsqueda de forma que, cuando el usuario quiera buscar una entrada se le pida el texto a buscar y el programa muestre todas las entradas de la agenda en las que algn campo coincida, aunque sea parcialmente, con el texto introducido (el operador in de cadenas te ser de gran ayuda).

2.7.

Tipos y estructuras de datos bsicas: listas y arrays

La mayor parte de los lenguajes de programacin aparte de trabajar con los tipos bsicos de datos tales como los nmeros, los caracteres, etc., implementan otras estructuras que permiten trabajar con cantidades de informacin ms amplias. En matemticas o en fsica, estamos acostumbrados a tratar con vectores o matrices, que son una coleccin de valores agrupados bajo un solo nombre. Por ejemplo, para representar las coordenadas de un punto en el espacio se suelen usar vectores. v = (3, 4, 0) o para representar los trminos de un sistema de ecuaciones podemos hacer uso de las matrices. 1 3 7 A= 2 1 0 1 3 2 El vector v o la matriz A representan a todo el conjunto de datos, pero tambin se puede referenciar a cada uno de los datos particulares, en este caso, mediante ndices. v2 = 4 , A1,3 = 7

Los lenguajes de programacin modernos implementan varios tipos de estructuras que agrupan colecciones de datos bajo un solo nombre de variable. Las listas, los arrays, las cadenas de texto, los diccionarios o los conjuntos son algunos de los tipos estructurados ms usuales. Las listas de Python engloban conjuntos de datos que pueden ser de distintos tipos (y en este sentido pueden ser usadas de forma similar al tipo de datos denominado estructura o registro en

2.7 Tipos y estructuras de datos bsicas: listas y arrays

95

otros lenguajes, y del que python carece), mientras que los arrays agrupan datos que necesariamente han de ser todos del mismo tipo, y a los que se da el nombre de componentes. Las cadenas, de las que ya hemos visto numerosos ejemplos, por su uso habitual tienen un tratamiento especial en todos los lenguajes. En cuanto a los tipos diccionario y conjunto no se vern en esta asignatura. En python, el tipo lista se denomina list y permite implementar directamente agrupaciones de datos en los que cada dato ocupa una posicin dentro de la agrupacin. Su longitud es variable y de hecho, se pueden aadir o quitar elementos en cualquier momento. Cada elemento de la lista puede ser de cualquier tipo (incluso otras listas). El acceso a cada elemento particular se realiza a travs de ndices (que comienzan en la posicin 0 y no en 1 como es tradicional en fsica o matemticas). Las cadenas tienen su propio tipo asociado str y en python se implementan como un tipo especial de lista, por lo que comparten la mayor parte de sus caractersticas. Los vectores y matrices se representan mediante el tipo ndarray, que viene implementado en la librera numpy. Pueden ser unidimensionales (vectores) o multidimensionales (matrices) aunque en este texto no iremos ms all de la dimensin 2. Su longitud, en cuanto al nmero de elementos, o su forma (nmero de las y/o columnas) es tambin variable. El acceso a los elementos se realiza igualmente a travs de ndices. Veamos con detenimiento estos tres tipos estructurados de datos.

2.7.1.

El tipo list

El tipo list se introduce simplemente encerrando entre corchetes la lista de datos, separados por comas. Por ejemplo
>>> lista = [velocidad, 17, 3.1416]

Esto crea un recipiente al cual se le pone el nombre lista, y en dicho recipiente se reserva espacio para tres datos. En cada uno de los huecos reservados se pone cada uno de los datos, en este caso la cadena velocidad y los nmeros 17 y 3.1416. Tambin es posible representar el vector v anterior mediante una lista. En este caso todos los elementos son del mismo tipo.
>>> v = [3, 4, 0]

Una vez creada qu pondemos hacer con una lista? Algunas de las operaciones bsicas que python trae de fbrica son: Contar cuntos elementos tiene la lista. Basta usar la funcin len
>>> len(lista) 3

Calcular la suma de todos los elementos, usando la funcin sum, si todos los elementos son numricos (enteros o reales):
>>> sum(v) 7

Encontrar el mximo o el mnimo de los elementos (igualmente tiene sentido si todos son numricos). Para ello usamos las funciones max y min:
>>> max(v) 4 >>> min(v) 0

96 Imprimir la lista completa, con print:


>>> print lista [velocidad, 17, 3.1416] >>> print v [3, 4, 0]

Introduccin a la programacin

Ordenar la lista, devolviendo como resultado una nueva lista, que podemos imprimir o almacenar en otra variable (la lista original no se modica, mantendr el orden que tena):
>>> [3, >>> [0, >>> [3, >>> >>> [0, print v 4, 0] print sorted(v) 3, 4] print v 4, 0] v_ordenada = sorted(v) print v_ordenada 3, 4]

Concatenar listas. Si usamos el operador + entre dos listas, lo que ocurre es que se crea una nueva lista concatenando ambas. Esta nueva lista se puede imprimir o asignar a otra variable. Las listas originales no son modicadas. Ejemplo:
>>> [3, >>> [3, >>> >>> [3, >>> [3, print v 4, 0] print v+v 4, 0, 3, 4, 0] otra = v + [100] print otra 4, 0, 100] print v 4, 0]

Observa que en el ejemplo anterior, el valor [100] es otra lista, con un solo elemento, por lo que el operador + concatenar ambas listas. Si hubiramos puesto en cambio v+100 estaramos intentando sumar un tipo lista (la variable v) con un tipo entero (el dato 100). El operador + no funciona si sus dos operandos no son del mismo tipo, por lo que tendamos un error. Asignar otro nombre a la lista, mediante el operador de asignacin =. Al hacer por ejemplo q=v, tendremos dos nombres (q y v) para referirnos a la misma lista:
>>> [3, >>> >>> [3, print v 4, 0] q = v print q 4, 0]

Ms adelante en este tema veremos qu ocurre exactamente con el operador de asignacin y qu consecuencias tiene al tratar con listas. Hay ms operaciones predenidas para listas, pero estas son sucientes. La cuestin es y si queremos hacer algo con los datos de una lista que no puede hacerse con ninguna de las funciones predenidas? Por ejemplo, y si queremos cambiar cada elemento de la lista por su triple? o bien y si queremos calcular la suma de los cuadrados de los elementos? etctera...

2.7 Tipos y estructuras de datos bsicas: listas y arrays

97

La respuesta es que en realidad podemos hacer cualquier cosa con los datos que hay en una lista porque cada uno de esos datos sigue siendo accesible por separado, adems de poder accederse a la lista como un conjunto a travs de su nombre. Veamos esto con detalle.

2.7.2.

Acceso a los elementos individuales de la lista

Cada uno de los elementos de la lista p est accesible a travs de una variable llamada p[i], donde i es el denominado ndice del elemento. Es como cuando en matemticas decimos que un vector v tiene por componentes v1 , v2 , . . . , vi , . . . , vn , siendo n el nmero de componentes del vector. En python, al igual que en la mayora de los lenguajes de programacin (Java, C, etc.), y a diferencia de lo habitual en matemticas, los ndices comienzan a numerarse desde cero, y por tanto los n elementos de la lista p seran accesibles mediante los nombres p[0] (primer elemento), p[1] (segundo elemento), etc... hasta p[n-1] (ltimo elemento). Por ejemplo, considera la asignacin p=[100, 150, 30, 15], que crea una lista con cuatro elementos. La variable p es un nombre para esa lista. Representaremos la situacin mediante la siguiente gura: p
100 150 30 15

Cada uno de los datos a los que apunta p puede ser accedido individualmente mediante la sintaxis p[0], p[1], etc, como muestra la siguiente gura:
p[0] p[1] p[2] p[3]

100 150

30

15

La expresin p[i] puede usarse como parte de cualquier expresin, y as por ejemplo p[0]+p[1]*2 producira el resultado 400, la expresin a=p[2] asignara el entero 30 a la variable a, etc. El tipo de p[i] es el tipo del dato all contenido, de modo que por ejemplo type(p[0]) sera int. Recuerda que en python cada elemento de la lista podra ser de un tipo diferente, aunque en esta asignatura no usaremos mucho esta caracterstica. Observa que si tenemos dos nombres diferentes para una misma lista (por ejemplo, si hacemos q=p, q se convierte en un nuevo nombre para la lista p), entonces podremos usar cualquiera de esos nombres para acceder a los elementos que hay en ella. Es decir, tras la asignacin q=p, tendramos la situacin de la gura:
p[0] p[1] p[2] p[3]

p q
100 150 30 15
q[0] q[1] q[2] q[3]

Por lo que p[1] y q[1] ambos se reeren al mismo dato, el entero 150. Las listas son objetos mutables Esto es muy importante si usamos la expresin p[i] al lado izquierdo de una asignacin, puesto que en este caso estaremos modicando el dato almacenado en esa posicin de la lista. Es decir, si hacemos q[1]=3, estaremos cambiando lo que haba en q[1] (el 150) por un 3. La nueva situacin sera:

98

Introduccin a la programacin
p[0] p[1] p[2] p[3]

p q
100 3 30 15
q[0] q[1] q[2] q[3]

Indirectamente hemos cambiado el valor de p! Si ahora usamos p[1] en cualquier expresin (por ejemplo print p[1]) encontraremos que vale 3. Si lo que queremos es crear una nueva lista q que inicialmente contenga los mismos valores que p, pero que sea un objeto independiente, de modo que podamos modicar q sin afectar a p, una posibilidad para lograrlo es la siguiente:
>>> p = [100, 150, 30, 15] >>> q = list(p) >>> print p [100, 150, 30, 15] >>> print q [100, 150, 30, 15]

La funcin list() crea un nuevo objeto del tipo list, y carga en l los valores iniciales que le pasemos como parmetro, que ha de ser de tipo secuencia. En este caso le estamos pasando una lista p. A la nueva lista que resulta, que es una copia de la que haba en p, le damos el nombre q. Al imprimir ambas vemos que tienen los mismos valores, sin embargo se trata de dos objetos diferentes. La situacin sera la de la gura siguiente:
p[0] p[1] p[2] p[3]

p q

100 150 100 150

30 30

15 15

q[0] q[1] q[2] q[3]

Si ahora modicamos cualquier elemento de q, esto no afecta a los elementos de p, como podemos ver:
>>> q[1] = 3 >>> print p [100, 150, 30, 15] >>> print q [100, 3, 30, 15]

ya que p y q se reeren a diferentes listas.


p[0] p[1] p[2] p[3]

p q

100 150 100 3

30 30

15 15

q[0] q[1] q[2] q[3]

Nota sobre comparacin de listas. Es posible comparar dos listas mediante el operador de igualdad ==. Este comparador lo que har ser en primer lugar comparar la longitud de las listas, y si resultan iguales comparar entonces uno a uno cada elemento. Si todos son iguales, el resultado

2.7 Tipos y estructuras de datos bsicas: listas y arrays

99

ser True. As, si hubiramos mirado si p==q antes de cambiar q[1], el resultado habra sido True, mientras que si lo miramos de nuevo tras cambiarlo (siendo q una copia independiente de q), el resultado sera False. El comparador == por tanto nos dice si dos listas son iguales elemento a elemento, pero no nos dice si son la misma. Puede ser que las dos listas sean iguales porque son en realidad la misma (como ocurra con p y q tras hacer q=p), pero pueden ser iguales tambin si, an siendo diferentes objetos, contienen la misma secuencia de datos. Si queremos descubrir si las listas son en realidad la misma, podemos usar el comparador is, en la expresin p is q. Este operador dar como resultado True slo si ambas variables apuntan al mismo objeto. Si apuntan a objetos diferentes, el resultado ser False, aunque pueda darse el caso de que ambos objetos sean iguales elemento a elemento. Es decir:
>>> p >>> q >>> r >>> p True >>> p True >>> p True >>> p False = [100, 150, 30, 15] = p = list(p) == q == r is q is r

La situacin creada por el cdigo anterior se muestra en la siguiente gura: p q r


100 150 100 150 30 30 15 15

Si en este momento hiciramos la asignacin p[1]=3, intenta adivinar qu resultado daran las comparaciones p is q, p is r, p==q y p==r. Aadir y quitar datos en una lista Supongamos que a la lista p de los ejemplos anteriores le queremos aadir otro dato, por ejemplo el nmero 12. La sintaxis para lograrlo es:
>>> p.append(12)

Esta sintaxis es diferente a lo que vimos hasta ahora. Ocurre que python es un lenguaje orientado a objetos y si bien no vamos a ahondar en esta caracterstica del lenguaje en esta asignatura, s que nos encontraremos en algunos lugares (por ejemplo ahora), con la sintaxis relacionada con el manejo de objetos. En pocas palabras, un objeto es un tipo de dato que agrupa bajo una misma estructura datos y funciones para trabajar sobre esos datos. A los datos se les denomina comunmente atributos, y a las funciones mtodos. Los mtodos son las nicas funciones que tienen va libre para modicar, si se requiere, los atributos. Aunque no lo habamos comentado hasta ahora, todos los datos en Python son objetos (el tipo entero, el oat, las cadenas, las listas, etc.) Para llamar a un mtodo un objeto se usa la sintaxis que acabamos de ver en el ltimo ejemplo, es decir, primero el nombre de la variable que apunta al objeto, despus un punto y despus el nombre del mtodo, seguido de unos parntesis, dentro de los cuales van los parmetros si es que los necesita.

100

Introduccin a la programacin

Como vemos la sintaxis es igual a la vista para llamar a una funcin, slo que delante del nombre de la funcin, separada por un punto, va el nombre de una variable que seala al objeto. En este caso, el objeto de tipo list tiene el mtodo append(12) como una forma de modicar los contenidos de la lista, aadiendo un 12 al nal de los que ya haba. El resultado ser que la lista a la que p se reere habr credido y tendr ahora 5 elementos en lugar de 4. Podemos imprimirla y comprobar su nueva longitud:
>>> print p [100,150,30,15,12] >>> len(p) 5

La situacin, grcamente, es: p q r


100 150 100 150 30 30 15 15 12

Observa que, ya que q se refera a la misma lista que p, cualquier cambio que hagamos en la lista a travs de p se ver reejado tambin cuando la manejemos a travs de q. En concreto len(q) tambin ser 5. En cambio r se refera a una lista diferente (aunque inicialmente tena los mismos datos). El aadido de un dato a travs de p no ha afectado a r, como se ve en la gura. Otro mtodo til que un objeto tipo list tiene es extend(). A travs de este mtodo podemos hacer crecer la lista aadindole varios elementos en lugar de uno solo (como haca append()). Para ello, a extend() se le pasa como parmetro otra lista (o secuencia), conteniendo los elementos que queremos aadir. Por ejemplo:
>>> p.extend([1, 2, 3]) >>> len(p) 8 >>> print p [100, 150, 30, 15, 12, 1, 2, 3]

Adems de poder pasarle una lista de valores directamente, como en el ejemplo anterior, podramos haberlo hecho a travs de otra variable. Por ejemplo, si quisiramos aadir a p los elementos que hay en la lista r, podramos poner p.extend(r). En este caso se crear una copia de la lista r y esa se aadir a p. Si se quieren aadir datos a una lista, pero no en el nal sino en cualquier punto intermedio, se puede conseguir haciendo uso del mtodo insert, que tiene como parmetros la posicin y el elemento que queremos insertar en la lista. Existen otras posibilidades, como el uso de slices, pero su explicacin queda fuera de las pretensiones de esta asignatura. Para eliminar datos de una lista, tenemos dos posibilidades: Si conocemos en qu posicin de la lista est el dato que queremos borrar, usamos el mtodo pop(posicion) de la lista. Recuerda que las posiciones comienzan a numerarse desde 0 y llegan hasta len(lista)-1. Si no se especica la posicin (es decir, usamos simplemente pop() sin parmetros), se eliminar el ltimo de la lista. Adems de eliminar el dato, su valor es retornado, de modo que lo leemos a la vez que lo eliminamos. Por ejemplo:
>>> p = [1, 3, 5, 7, 11, 13] >>> n = p.pop()

2.7 Tipos y estructuras de datos bsicas: listas y arrays


>>> 13 >>> [1, >>> >>> 1 >>> [3, print n print p 3, 5, 7, 11] n = p.pop(0) print n print p 5, 7, 11]

101

Si conocemos el valor del dato, pero no en qu posicin est en la lista, podemos usar el mtodo remove(dato). Si el dato se encuentra, es eliminado (si aparece varias veces, slo se elimina la primera). No obstante el uso de este mtodo es un poco arriesgado, ya que si el dato no estuviera en la lista, se generara una excepcin. Por ejemplo:
>>> p = [1, 3, 5, 7, 11, 13] >>> p.remove(5) >>> print p [1, 3, 7, 11, 13] >>> p.remove(2) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.remove(x): x not in list

Para evitar el error, podramos comprobar si el dato efectivamente est, antes de intentar eliminarlo. Para ello python tiene el operador in que se usa en la expresin booleana: dato in lista, y que devuelve True si el dato est en la lista y False si no. As que si hacemos if 2 in p: antes de intentar p.remove(2), evitaramos que se generase la excepcin.

2.7.3.

Listas que contienen listas

Una lista es una serie de datos, y cada uno de estos datos puede ser de cualquiera de los tipos que ya hemos visto. Por tanto, un dato contenido en una lista podra ser otra lista. Por ejemplo:
>>> p = [100, 200, 300, [1, 2, 3]] >>> print p [100, 200, 300, [1, 2, 3]] >>> print p[0] 100 >>> print p[2] 300 >>> print p[3] [1, 2, 3]

La estructura de datos que hemos creado en el cdigo anterior se puede representar grcamente as:
1 2 3

100 200 300

Qu valor crees que obtendremos al hacer len(p)? Comprubalo en el intrprete. Como vemos, el ltimo elemento de p no contiene un dato propiamente dicho, sino una referencia hacia otro dato que es la lista [1, 2, 3]. Esta lista de alguna forma es annima en el

102

Introduccin a la programacin

sentido de que no tiene nombre (no hay una variable que se reera a ella). Si quisiramos entonces modicar el 1 que hay en ella y cambiarlo por un 5 cmo podramos lograrlo? Pinsalo un poco antes de continuar leyendo. Hemos dicho que no hay una variable que se reera a la lista [1,2,3], pero esto no es del todo cierto. En realidad p[3] es un nombre que se reere a esa lista, como hemos visto al hacer print p[3]. Y si p[3] es una lista, podremos aplicarle las mismas operaciones que a cualquier otra lista. Por ejemplo, podemos hacer len(p[3]) (qu valor devolvera?). Y en particular, tambin podemos poner unos corchetes tras su nombre y acceder as a cualquiera de sus elementos. De modo que para cambiar el 1 por un 5 la sintaxis sera:
>>> p[3][0] = 5 >>> print p [100, 200, 300, [5, 2, 3]]

Observa que en el ejemplo anterior, la lista [1, 2, 3] slo puede ser accedida a travs de p[3], ya que no tenemos ninguna otra variable que se reera a esa lista. Pero podramos tenerla. Considera el siguiente cdigo:
>>> q = p[3]

Tras la asignacin anterior, q se convierte en otro nombre para la lista [1, 2, 3], como reeja la siguiente gura: q p
100 200 300 5 2 3

A partir de esta gura, se comprende que si hacemos por ejemplo q[1]=27 estaremos modicando indirectamente el valor de p[3][1], lo cual se manifestar al imprimir p.
>>> q[1] = 27 >>> print q [5, 27, 3] >>> print p [100, 200, 300, [5, 27, 3]]

A la misma situacin de la gura anterior habramos llegado tambin si hubieramos inicializado p y q de este otro modo:
>>> q = [5, 2, 3] >>> p = [100, 200, 300, q] >>> print p [100, 200, 300, [5, 2, 3]]

Fjate que al dar la lista de valores de p hemos usado q como uno de ellos. El efecto es que dentro de p[3] se almacena una referencia a la misma lista a la que se reere q. Es decir, la misma situacin de la gura anterior. Las modicaciones que hagamos a travs de q tendrn efecto en p. Si hubiramos querido tener en p[3] una referencia a una copia de q, en lugar de una referencia a la misma lista que q) una forma de lograrlo habra sido:
>>> q = [5, 2, 3] >>> p = [100, 200, 300] >>> p.append(q) >>> print p [100, 200, 300, [5, 2, 3]]

2.7 Tipos y estructuras de datos bsicas: listas y arrays Aunque el resultado parece el mismo, la situacin ahora sera la de la gura siguiente: q p
5 2 3 5 2 3

103

100 200 300

2.7.4.

Bucles para recorrer listas

Como hemos dicho antes, python trae algunas funciones tiles para realizar clculos elementales sobre listas. Por ejemplo, la funcin sum(lista) nos devuelve la suma de todos los elementos de una lista. Sin embargo, hay otras muchas operaciones que podramos necesitar, y que no vienen con el lenguaje. Por ejemplo, y si quisiramos calcular la suma de los cuadrados? O crear una nueva lista cuyos elementos sean las races cuadradas de los elementos de la lista dada? etctera... Obviamente la solucin consiste en implementar nosotros mismos los clculos requeridos en un bucle. En cada iteracin (repeticin) del bucle, obtendremos un elemento de la lista a procesar, con el que realizaremos nuestros clculos. Ya hemos visto que cada elemento de la lista es accesible a travs de un ndice, que va desde 0 hasta len(lista)-1, por lo que una estrategia directa es utilizar un bucle for sobre una variable i que recorra el rango 0 a len(lista)-1, y dentro de l usar esa variable como ndice para acceder a lista[i]. Precisamente este rango es el que obtenemos mediante range(len(lista)), por lo que una implementacin directa de estas ideas sera la siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

# Inicializamos la lista p con una serie de numeros p = [4, 9, 27, 100, 110] # Calculemos la suma de los cuadrados suma_2 = 0 # de momento vale cero for i in range(len(p)): suma_2 = suma_2 + p[i]**2 print "Lista p =", p print "La suma de los cuadrados vale", suma_2 # Creemos ahora una nueva lista que contenga las raices cuadradas de cada # uno de los datos de la lista p # Para calcular raices cuadradas necesitamos la funcion sqrt del modulo math import math # La nueva lista con los resultados, inicialmente vacia: raices_cuadradas = [] # Rellenemos la lista anterior, mediante un bucle for i in range(len(p)): raices_cuadradas.append(math.sqrt(p[i])) print "Raices cuadradas:", raices_cuadradas

El resultado de ejecutar el cdigo anterior sera:


Lista p = [4, 9, 27, 100, 110] La suma de los cuadrados vale 22926 Raices cuadradas: [2.0, 3.0, 5.196152422706632, 10.0, 10.488088481701515]

Esta forma de acceder a cada elemento de una lista, a travs de su ndice, es la forma que permiten casi todos los lenguajes de programacin (C, C++, java, etc.). Python proporciona otra forma an ms breve para recorrer los elementos de una lista. Se trata de usar la sintaxis siguiente:

104
1 for variable in lista: 2 sentencia1 3 sentencia2 4 etc...

Introduccin a la programacin

Lo que ocurre es que la variable variable va pasando por todos los valores de la lista, por orden. En la primera iteracin del bucle variable toma el valor de lista[0], en la siguiente iteracin toma el valor de lista[1] y as sucesivamente hasta agotar todos los valores de la lista. Observa que con esta sintaxis no se requieren ndices ni corchetes. Usemos esta sintaxis para implementar de nuevo el clculo de la suma de los cuadrados y la lista con las races cuadradas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

# Inicializamos la lista p con una serie de numeros p = [4, 9, 27, 100, 110] # Calculemos la suma de los cuadrados suma_2 = 0 # de momento vale cero for dato in p: suma_2 = suma_2 + dato**2 print "Lista p =", p print "La suma de los cuadrados vale", suma_2 # Creemos ahora una nueva lista que contenga las raices cuadradas de cada # uno de los datos de la lista p # Para calcular raices cuadradas necesitamos la funcion sqrt del modulo math import math # La nueva lista con los resultados, inicialmente vacia: raices_cuadradas = [] # Rellenemos la lista anterior, mediante un bucle for dato in p: raices_cuadradas.append(math.sqrt(dato)) print "Raices cuadradas:", raices_cuadradas

Como ves, esta sintaxis es ms clara, pero ten en cuenta que es una caracterstica que en otros lenguajes puede no estar presente (el ejemplo ms notable es el C). Para saber ms En realidad, la sintaxis for variable in lista no es una sintaxis alternativa para el for, sino la nica que python tiene. Lo que ocurre es que la funcin range() que usbamos hasta ahora, crea una lista que contiene una serie de nmeros en secuencia, sobre la cual despus el bucle for itera. Puedes comprobar esto con el intrprete:
>>> numeros = range(10) >>> type(numeros) <type list> >>> print numeros [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for i in numeros: ... print i, ... 0 1 2 3 4 5 6 7 8 9 >>>

2.7 Tipos y estructuras de datos bsicas: listas y arrays

105

2.7.5.

Listas y funciones

Una funcin puede recibir como parmetro una lista, y tambin devolver una lista como resultado. As, por ejemplo, podemos convertir en una funcin uno de los ejemplos antes vistos, el que calcula la suma de los cuadrados de los elementos de una lista.
1 2 3 4 5 6 7 8 9 10 11 12 13 14

def suma_de_los_cuadrados(lista): """Dada una lista como parametro, que contiene una serie de numeros, la funcion retorna la suma de los cuadrados""" suma_2 = 0 # De momento la suma es cero for dato in lista: suma_2 = suma_2 + dato**2 # Al salir del bucle tenemos el resultado, que retornamos return suma_2 # Para probar el ejemplo anterior, creare una lista p = [1, 2, 3, 4] resultado = suma_de_los_cuadrados(p) print "La lista es:", p print "La suma de los cuadrados es", resultado

Al ejecutar el programa anterior, el resultado ser 30. Si necesitramos una funcin que en lugar de la suma de los cuadrados hiciera la suma de los cubos, bastara cambiar el **2 de la lnea 6 por un **3. Esto nos lleva a plantearnos la siguiente generalizacin: Escribe una funcin llamada suma_de_las_potencias que, dada una lista {xi } calcule xn , siendo n otro valor que se le i pasa como parmetro. Se deja este problema como ejercicio para el lector. Como hemos dicho antes, una funcin tambin puede retornar una lista como resultado. Gracias a esto tambin podemos convertir en funcin el otro ejemplo antes visto, que a partir de una lista dada crea otra lista que contiene las races cuadradas de cada elemento de la lista original. La solucin sera la siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

import math

# Para poder usar la funcion sqrt

def raices_cuadradas(lista): """Dada una lista como parametro, que contiene una serie de numeros, la funcion retorna otra lista que contiene las raices cuadradas de esos numeros""" lista_resultado = [] # De momento esta vacia for dato in lista: lista_resultado.append(math.sqrt(dato)) # Al salir del bucle tenemos la lista_resultado rellena return lista_resultado

# Para probar el ejemplo anterior, creare una lista p = [4, 25, 16, 9] resultado = raices_cuadradas(p) print "La lista es:", p print "Las raices cuadradas son:", resultado

Retornar una lista como resultado puede usarse para crear funciones que retornen varios resultados, como un mecanismo alternativo al que se mostr en la seccin 2.5.8. Por ejemplo, una funcin que dado un par de enteros retorna el cociente y el resto de su divisin. Podemos retornar una lista cuyo primer elemento sea el cociente, y el segundo sea el resto, como se muestra en el listado siguiente
1 def cociente_y_resto(a, b): 2 """Dados dos enteros, a y b, la funcion retorna una lista

106
3 4 5 6 7 8 9 10 11 12 13

Introduccin a la programacin
cuyo primer elemento es el cociente entero a/b y cuyo segundo elemento es el resto de dicha division""" cociente=a/b resto=a %b return [cociente, resto] # Probemos la funcion con un par de numeros que nos de el usuario numero1=int(raw_input("Dame un entero: ")) numero2=int(raw_input("Dame otro: ")) resultado=cociente_y_resto(numero1, numero2) print "El cociente es", resultado[0], "y el resto", resultado[1]

Un par de observaciones sobre el programa anterior. En primer lugar, la funcin es tan simple que su cdigo podra haberse acortado hasta dejarla en una sola lnea, simplemente si no hacemos uso de las variables intermedias cociente y resto, sino que ponemos directamente las expresiones a/b y a %b en los valores a retornar. As (he omitido aqu la documentacin de la funcin, que sera la misma que en el listado anterior):
1 def cociente_y_resto(a, b): 2 return [a/b, a %b]

En segundo lugar, cuando llamamos a la funcin y recogemos el valor retornado, lo hacemos sobre una variable llamada resultado, y despus necesitamos acceder a resultado[0] para obtener el cociente y a resultado[1] para obtener el resto. Esto es poco legible y puede mejorarse gracias a una caracterstica del lenguaje python, que nos permite asignar las listas del mismo modo que se mostr en la pgina 81 para las tulas. Si al lado izquierdo de una asignacin, en lugar de una variable hay una lista de variables, y al lado derecho de la asignacin hay una lista de valores o expresiones, entonces primero se evalan las expresiones del lado de la derecha, y despus cada una de las variables de la izquierda recibir cada uno de los resultados. Esto es:
>>> >>> 8 >>> 15 >>> 5 >>> [x, y, z] = [8, 3*5, 10/2] x y z [a, b, z] = [z, y, x]

Puedes adivinar qu valor tomarn las variables a, b y z tras esta ltima asignacin? Para que este tipo de asignacin funcione, la lista de la izquierda ha de tener la misma longitud que la lista de la derecha, y la lista de la izquierda ha de estar compuesta exclusivamente por nombres de variables. La lista de la derecha podra ser cualquier cosa. Incluso el resultado de llamar a una funcin! Esto nos permitira hacer, por ejemplo:
1 [cociente, resto] = cociente_y_resto(10, 3) 2 print "Cociente=", cociente, "Resto=", resto

Es decir, hemos usado [cociente, resto] en vez de resultado, por lo que despus tenemos nombres para el cociente y para el resto en lugar de tener que acceder a ellos con la sintaxis menos legible resultado[0], resultado[1]. En todo caso, el mtodo estndar para que una funcin retorne varios resultados es el mostrado en la seccin 2.5.8. El que se pueda hacer de forma similar con listas es una mera curiosidad. La funcin puede cambiar elementos en la lista que recibe como parmetro Una consecuencia directa de que las listas son objetos mutables, y del funcionamiento del paso de parmetros y la asignacin en python, es que, a diferencia de lo visto hasta ahora, una funcin

2.7 Tipos y estructuras de datos bsicas: listas y arrays

107

puede recibir un parmetro de tipo lista y devolver la misma modicada. Ya hemos visto en el tema de funciones que el paso de parmetros no es ms que una asignacin, en la que se asigna a los parmetros formales (los declarados en la implementacin de la funcin) los valores que tienen los parmetros reales (los que se ponen en la llamada a la funcin). Teniendo esta idea clara, veamos qu pasa cuando una funcin intenta modicar el valor del parmetro que ha recibido. Considera el siguiente ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

def intenta_modificar(x): print " x vale", x x = [0, 0, 0] # Hemos cambiado el valor de x? print " Ahora x vale", x # Vamos a crear una variable a con una lista a = [1, 2, 3] print "a vale", a # Llamamos a la funcion intenta_modificar, pasandole a intenta_modificar(a) # Habra cambiado el valor de a? print "Ahora a vale", a

Qu crees que saldr por pantalla al ejecutar este programa? Pinsalo un instante antes de leer la respuesta.
a vale [1, 2, 3] x vale [1, 2, 3] Ahora x vale [0, 0, 0] Ahora a vale [1, 2, 3]

Como puedes ver, la funcin ha cambiado el valor de x, pero eso no ha afectado al valor de a. Si no comprendes por qu, los siguientes esquemas pueden ayudarte a claricar la situacin.

Instruccin a = [1, 2, 3]

Explicacin Crea una nueva lista que contiene los datos 1, 2 y 3, y hace que la variable a apunte (se reera) a dicha lista. Se imprime el valor de a y obviamente sale [1, 2, 3] Durante la llamada a la funcin, se realiza la asignacin al parmetro formal, es decir x=a, lo cual crea un nuevo nombre para la misma lista Se imprime el valor de x que obviamente es el mismo que el de a. Se crea una nueva lista que contiene tres ceros, y se modica x para que ahora apunte a esta nueva lista. Eso no afecta a a que sigue apuntando a la antigua.

Diagrama a
1 2 3

print a intenta_modificar(a)

x a
1 2 3

print x x = [0, 0, 0]

0 2

0 3

x a
1

108

Introduccin a la programacin

print x (return implcito)

Se imprime el valor de x y ahora salen tres ceros La funcin retorna, esto hace que x deje de existir. Ya que niguna otra variable apunta a la lista [0,0,0], esta lista tambin ser destruida por python en algn momento, de forma automtica. Se imprime el valor de a y como se ve del ltimo diagrama, sigue apuntando a la lista original, por lo que de nuevo sale [1, 2, 3]
0 0 2 0 3

x a
1

print a

Cabe destacar que todo lo explicado en este ejemplo en el que a y x son variables de tipo list, es igualmente cierto y aplicable a cualquier otro tipo de datos en python. En particular, esto mismo sucede si a y x son de tipo entero. En general, sea cual sea el tipo del parmetro de una funcin, una asignacin que se haga a ese parmetro causa que se modique slo esa variable (haciendola apuntar a otro lugar) y sin afectar a la variable que era el parmetro real. Sin embargo. . . qu pasa si dentro de la funcin hacemos x[0]=0, por ejemplo? Es decir, qu imprimira el cdigo siguiente?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

def intenta_modificar2(x): print " x vale", x x[0] = 0 # Hemos cambiado el valor de x? print " Ahora x vale", x # Vamos a crear una variable a con una lista a = [1, 2, 3] print "a vale", a # Llamamos a la funcion intenta_modificar, pasandole a intenta_modificar2(a) # Habra cambiado el valor de a? print "Ahora a vale", a

Si te jas, este ejemplo es idntico al anterior, salvo por la lnea 3, que antes haca x=[0,0,0] y ahora hace x[0]=0 (bueno, y tambin que hemos renombrado la funcin a intenta_modificar2, pero esto es irrelevante). Si esperabas que al ejecutar este cdigo la variable a no se viera afectada, es que no lo has pensado bien. Mira el resultado:
a vale [1, 2, 3] x vale [1, 2, 3] Ahora x vale [0, 2, 3] Ahora a vale [0, 2, 3]

Al cambiar el primer elemento de x y poner all un cero, hemos afectado indirectamente a la variable a del programa principal, que ahora tambin tiene un cero en su primer elemento! En realidad, si has comprendido el caso del ejemplo anterior, este tiene tambin perfecto sentido. La siguiente tabla lo explica paso a paso:

2.7 Tipos y estructuras de datos bsicas: listas y arrays

109

Instruccin a = [1, 2, 3]

Explicacin Crea una nueva lista que contiene los datos 1, 2 y 3, y hace que la variable a apunte (se reera) a dicha lista. Se imprime el valor de a y obviamente sale [1, 2, 3] Durante la llamada a la funcin, se realiza la asignacin al parmetro formal, es decir x=a, lo cual crea un nuevo nombre para la misma lista Se imprime el valor de x que obviamente es el mismo que el de a. Se modica el primer elemento de la lista apuntada por x. Ya que es la misma lista a la que apuntaba a, estamos modicando a! Se imprime el valor de x y ahora sale [0,2,3] La funcin retorna, esto hace que x deje de existir. La lista a la que apuntaba x no se destruye, porque todava tenemos a a apuntando a ella. Se imprime el valor de a y evidentemente sale [0, 2, 3]

Diagrama a
1 2 3

print a intenta_modificar2(a)

x a
1 2 3

print x x[0] = 0

x a
0 2 3

print x (return implcito)

print a

Por tanto cuando se pasa una lista a una funcin, esta funcin puede modicar los elementos almacenados en esa lista, si la funcin usa los corchetes para acceder a un elemento de la lista y le asigna otro valor. Esto es posible slo con listas (en general, con cualquier objeto en python que sea mutable). Si x fuese un entero, no hay forma de hacer x[0]=0 (si lo intentas dar un error, porque el operador [] slo tiene sentido sobre listas). Y si lo que hacemos es x=0 ya hemos visto que eso simplemente cambia la x para que apunte a un cero, sin modicar el valor al que apuntaba a. De modo que es posible escribir funciones que modiquen una lista in situ, es decir, sin crear una lista nueva a partir de ella. As, podramos hacer una funcin raices_cuadradas_lista que en lugar de crear una nueva lista con los valores de las raices cuadradas y retornar esa nueva lista, lo que haga sea ir modicando la lista original sustituyendo cada elemento por su raz cuadrada. Sera como sigue:
1 import math # Para poder usar la funcion sqrt 2 3 def raices_cuadradas_in_situ(lista): 4 """Dada una lista como parametro, que contiene una serie de 5 numeros, la funcion MODIFICA esa lista cambiando cada elemento

110
6 7 8 9 10 11 12 13 14 15 16

Introduccin a la programacin
por su raiz cuadrada""" for i in range(len(lista)): lista[i] = math.sqrt(lista[i]) # No es necesario retornar ningun valor, ya estan todos en la lista # Para probar el ejemplo anterior, creare una lista p = [4, 25, 16, 9] print "Antes de llamar, la lista es:", p resultado = raices_cuadradas_in_situ(p) print "Despues de llamar, la lista es:", p print "El valor retornado por la funcion es", resultado

Observa que la funcin no contiene sentencia return (aunque de todas formas har un return implcito cuando salga del bucle, ya que no hay ms instrucciones para ejecutar en la funcin). La forma de llamar a esta funcin por tanto es distinta a la del ejemplo con raices_cuadradas, donde hacamos resultado=raices_cuadradas(p). En aquel ejemplo la lista con las races cuadradas era diferente de la lista p, y la variable resultado serva para apuntar a la nueva lista. En cambio ahora la lista con las races es la propia p (sus valores originales se pierden), y la funcin no retorna nada, por lo que asignar a resultado como hace el programa anterior no tiene sentido. Bastaba llamar a la funcin sin asignar su resultado a ninguna variable. No obstante, si lo asignamos como se ve en el ejemplo anterior, encontraremos que la variable resultado toma el valor especial None, que es el valor que python usa para representar nada. La funcin no ha retornado nada. Al ejecutar ese cdigo veremos en pantalla:
Antes de llamar, la lista es: [4, 25, 16, 9] Despues de llamar, la lista es: [2.0, 5.0, 4.0, 3.0] El valor retornado por la funcion es None

Para terminar, indicar que es posible escribir programas que nunca hagan uso de esta caracterstica. Es decir, cualquier problema computacional se puede resolver haciendo uso de funciones que nunca modiquen los valores de los parmetros que reciben, sino que en vez de ello creen otros datos nuevos y los retornen.

2.7.6.

Listas y cadenas

La cadena es un tipo especial de lista Una cadena de caracteres es un tipo especial de lista, en la que cada elemento es un caracter, esto es, una letra, un dgito, un signo de puntuacin o un carcter de control. Por tanto, podemos usar los mecanismos que conocemos de las listas para iterar sobre sus elementos, calcular su longitud, concatenarlas, etc. Por ejemplo, el siguiente cdigo cuenta cuntas letras vocales hay en la frase escrita por el usuario:
1 2 3 4 5 6 7 8 9 10 11 12 13

# Pedir al usuario un texto texto = raw_input("Escribe una frase: ") vocales = 0 # Contador de vocales halladas # Recorrer letra a letra el texto for letra in texto: # Comprobar si es una vocal # Es sencillo gracias al operador "in" ya visto para listas # que tambien es aplicable a cadenas if letra in "aeiouAEIOU": vocales = vocales + 1 print "Tu frase tiene", len(texto), "letras"

2.7 Tipos y estructuras de datos bsicas: listas y arrays


14 print "de las cuales", vocales, "son vocales."

111

Sin embargo hay una diferencia fundamental entre las cadenas y las listas. Las cadenas son inmutables, lo que signica que no podemos alterar ninguno de sus caracteres. Si bien podemos consultar el valor de texto[i] para ver qu letra es, no podemos en cambio asignar nada a la variable texto[i]. Si lo intentamos, obtendremos un error en tiempo de ejecucin. Imagina que queremos programar una funcin que recibe como parmetro una cadena y queremos que se ocupe de cambiar todas las vocales que aparezcan en dicha cadena por el signo _. Es decir, si la cadena que recibe contiene el mensaje "Hola Mundo", el resultado debera ser "H_l_ m_nd_". Si intentamos una versin de la funcin que modique la cadena in situ, fracasar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

def cambiar_vocales(texto): """Esta funcion recibe una cadena de texto como parametro e intenta cambiar todas las vocales que contiene por el signo _. Sin embargo, ya que las cadenas son inmutables, producira un error.""" # Recorremos todos los indices para acceder a cada letra for i in range(len(texto)): # Miramos si es una vocal if texto[i] in "aeiouAEIOU": # Si lo es, la cambiamos. Esto es lo que dara error texto[i] = "_" # Para probar la funcion anterior creo un mensaje mensaje = "Mensaje de prueba" # Intento "borrar" sus vocales cambiar_vocales(mensaje) # Imprimo el resultado (en realidad esto nunca llegara a ejecutarse # porque el programa "rompe" antes con un error) print mensaje

Al ejecutar el programa anterior obtendremos un error:


Traceback (most recent call last): File "funcion-sustituir-vocales-mal.py", line 17, in <module> cambiar_vocales(mensaje) File "funcion-sustituir-vocales-mal.py", line 11, in cambiar_vocales texto[i] = "_" TypeError: str object does not support item assignment

La solucin consiste en hacer una funcin que, en lugar de modicar la cadena, crea una cadena nueva que va construyendo letra a letra, copiando cada letra de la cadena original, salvo si es una vocal en cuyo caso inserta el carcter "_". Pero aparentemente esto tampoco puede hacerse, ya que al ser las cadenas datos inmutables, carecen tambin del mtodo .append() para poder ir aadiendo caracteres. Entonces? La respuesta es que, aunque efectivamente no puedo aadir caracteres a una cadena dada, s puedo crear una nueva cadena como la suma de dos (concatenacin), y asignar el resultado de esta concatenacin a la misma variable. Por ejemplo:
>>> texto="Prueba" >>> texto Prueba >>> texto = texto + "s" >>> texto Pruebas

112

Introduccin a la programacin

Puede parecer que hemos aadido una letra "s" a la cadena. En realidad lo que ha ocurrido es que hemos creado una cadena nueva, que contiene "Pruebas", pero sin afectar a la cadena original que sigue conteniendo "Prueba". Despus hacemos que la variable texto se reera a esta nueva cadena. La cadena original ya no tiene variable que se reera a ella y python la destruir. Usando este enfoque, la funcin que cambia vocales por subrayados quedara as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

def cambiar_vocales(texto): """Esta funcion recibe una cadena de texto como parametro y retorna otra cadena que es una copia de la recibida, salvo por que todas las vocales han sido sustituidas por el signo _""" resultado = "" # De momento no tenemos letras en el resultado # Recorremos todos los indices para acceder a cada letra for letra in texto: # Miramos si es una vocal if letra in "aeiouAEIOU": # Si lo es, concatenamos "_" al resultado resultado = resultado + "_" else: # Si no, concatenamos la letra en cuestion resultado = resultado + letra # Una vez salimos del bucle, tenemos la cadena formada # No olvidarse de retornarla! return resultado # Para probar la funcion anterior creo un mensaje mensaje = "Mensaje de prueba" # Borramos sus vocales, pero debo recoger el resultado en otra variable cambiado = cambiar_vocales(mensaje) # Imprimir cadena original y cambiada: print mensaje print cambiado

Para saber ms El mtodo usado en la funcin anterior para ir haciendo crecer una cadena, se considera mala prctica entre los programadores expertos de python. La razn es que ese cdigo es muy ineciente, ya que cada vez que hacemos texto=texto+algo, se est creando una nueva cadena en memoria, copiando a ella todos los caracteres concatenados de texto y algo, reasignando la variable texto para que apunte a esa nueva cadena, y destruyendo la cadena anterior (si no hay ya variables que apunten a ella). Si este tipo de crecimiento de cadenas se usa dentro de un bucle que se repite muchas veces, para crear cadenas muy largas, el programa puede empezar a ir ms lento de lo deseable. En nuestro caso, con cadenas tan cortas, preocuparse por la eciencia no es necesario. No obstante, si quisieras hacerlo bien, lee el recuadro Para saber ms de la pgina 116, que muestra como usar la operacin join() (que se describe ms adelante) para crear cadenas que se componen de ir agregando muchas otras cadenas, y de forma eciente. Convertir una cadena en una lista A menudo se tiene una cadena de texto que contiene una serie de palabras, separadas mediante algn smbolo separador especial. Por ejemplo, al exportar una hoja de clculo EXCEL en el formato

2.7 Tipos y estructuras de datos bsicas: listas y arrays

113

denominado csv (comma separated values) lo que hace excel es escribir un chero en el que cada lnea representa una la de la tabla, y los contenidos de cada celda se escriben todos en la misma lnea, usando el punto y coma (;) como separador de columnas. Por ejemplo, considera una tabla excel que contenga la siguiente informacin, sobre los apellidos ms frecuentes: Apellido GARCIA GONZALEZ RODRIGUEZ FERNANDEZ LOPEZ Frecuencia 1.483.939 935.135 932.924 928.618 879.145 Por 1000 31,6 19,9 19,8 19,7 18,7

Si exportamos esta hoja al formato csv, el chero resultante se podra abrir en el bloc de notas (contiene solo texto) y veramos lo siguiente:
Apellido;Frecuencia;Por 1000 GARCIA;1.483.939;31,6 GONZALEZ;935.135;19,9 RODRIGUEZ;932.924;19,8 FERNANDEZ;928.618;19,7 LOPEZ;879.145;18,7

Si leyeramos ese chero desde un programa en python, la funcin readline nos dara una lnea completa, y sera interesante poder romper esa lnea en tres trozos y as poder recuperar el apellido, la frecuencia y el tanto por 1000 almacenado en cada lnea. Pues bien, las cadenas de texto tienen entre sus mtodos uno llamado split() que sirve justamente para este propsito. Este mtodo espera un parmetro que es el carcter (o en realidad la sub-cadena) que se usar como separador. En nuestro ejemplo se tratara del punto y coma. El resultado del mtodo es una lista, en la cual cada elemento es una cadena que ha resultado de romper la cadena original. En nuestro ejemplo, la lista tendra tres elementos correspondientes a los tres trozos. Por ejemplo:
>>> linea = "GARCIA;1.483.939;31,6" >>> trozos=linea.split(";") >>> len(trozos) 3 >>> trozos[0] GARCIA >>> trozos[1] 1.483.939 >>> trozos[2] 31,6

Convirtiendo datos desde excel Lo que leemos del archivo csv son cadenas de texto. Al partirlo en trozos con split() cada trozo sigue siendo una cadena de texto. Si queremos manejar un trozo como si fuera un valor numrico (para sumarlos, compararlos o lo que sea), sera necesario convertirlo al tipo apropiado (int o float). Sin embargo hay un problema adicional y es que Excel ha metido como parte del nmero otros smbolos que confundirn a python. Por ejemplo, en los enteros de ms de 3 cifras

114

Introduccin a la programacin

mete un punto como separador de miles, que python podra tomar como el separador de decimales. Y en los reales que tienen parte fraccin usa la coma como separador, en lugar del punto Si queremos tratar esas cadenas como nmeros, antes habra que convertirlas a una forma apropiada, antes de pasarlas a int() o float(). Esto implica procesar la cadena, eliminando cada . innecesario, y cambiando la , separadora de decimales por el punto. Aunque el procesamiento de cadenas se sale de los objetivos de la asignatura, por su utilidad en este caso particular, daremos cmo se hara, a modo de receta. La siguiente funcin recibir una cadena de caracteres como las que Excel genera para representar un nmero, y devuelve un dato python de tipo int o float con el valor representado en dicha cadena. Puedes copiar esta funcin tal cual aparece aqu y usarla en tus programas si la necesitas.
1 def interpreta_cadena_excel(dato): 2 """Recibe un dato que es una cadena de texto formateada en el estilo 3 en que excel formatea los numeros, es decir, usando coma para separar 4 los decimales, y usando punto como separador de millares, millones, etc 5 La funcion retorna un dato tipo int o float que contiene el valor 6 representado por la cadena que ha recibido""" 7 8 # Lo primero quitarle al dato todos los puntos (.) que tenga 9 # El metodo replace() cambia un texto por otro dentro de la cadena 10 # En esta ocasion lo usamos para cambiar el punto por una cadena vacia 11 # con lo que lo borramos. 12 dato = dato.replace(".", "") 13 14 # Seguidamente cambiar las comas que contenga por puntos 15 dato = dato.replace(",", ".") 16 17 # Ya esta listo para ser procesado por python. El resultado 18 # sera un float si contiene el caracter punto "." o un entero 19 # si no lo contiene 20 if "." in dato: 21 resultado = float(dato) 22 else: 23 resultado = int(dato) 24 return resultado

Otra forma de convertir una cadena en una lista es usar la funcin list() pasndole una cadena. El resultado ser una lista en la que cada elemento es una letra de la cadena original. Esto tiene en general poca utilidad, y no lo usaremos en esta asignatura. Convertir una lista en una cadena Podemos convertir una lista que contenga valores de cualquier tipo en una cadena, que sera la misma que veramos en pantalla al hacer un print de la lista. Para ello basta pasar dicha lista a la funcin str(). Pero esto en general no es muy til:
>>> >>> [1, >>> >>> lista = [1, 2.3, 5] lista 2.2999999999999998, 5] cadena = str(lista) cadena

2.7 Tipos y estructuras de datos bsicas: listas y arrays


[1, 2.2999999999999998, 5]

115

Otro caso mucho ms til es aquel en el que tenemos una lista cuyos elementos son cadenas, y queremos concatenar todos juntos estos elementos, posiblemente insertando entre ellos algn tipo de separador. Por ejemplo, tenemos la lista semana que contiene como elementos ["lunes", "martes", "miercoles", "jueves", "viernes", "sabado", "domingo"] y queremos construir una cadena que contenga el texto "lunes, martes, miercoles, jueves, viernes, sabado, domingo".Como ves, se trata de concatenar las palabras que haba en la lista, poniendo una coma y un espacio (", ") entre ellas. Con lo que sabemos hasta ahora, esto podra hacerse de diferentes formas. La ms directa (y la peor), podra ser simplemente sumar (concatenar) los 7 elementos de la lista a mano.
1 cadena = semana[0] + ", " + semana[1] + ", " + semana[2] + ", " + 2 semana[3] + ", " + semana[4] + ", " + semana[5] + ", " + 3 semana[6]

Ni que decir tiene que el cdigo anterior es una barbaridad. Adems de lo torpe que resulta tener que repetir tantas veces la misma expresin, ni siquiera es una solucin genrica. Habra que cambiarlo si la lista que quiero concatenar tiene ms o menos elementos. Para esto estn los bucles! En una solucin con bucles, comenzaramos con una cadena vaca (que contenga "") e iramos sumndole a dicha cadena cada elemento de semana, ms la cadena ", ", hasta llegar al ltimo.
1 cadena="" # Inicialmente vaca 2 for texto in semana: 3 cadena = cadena + texto + ", "

Sin embargo el cdigo anterior no hace exactamente lo que queramos, ya que aparecera una coma tambin despus del ltimo da de la semana, y en ese caso no la queremos. El ultimo caso es excepcional y para manejar ese caso tenemos que afear un poco la solucin anterior. Tenemos dos formas, la primera sera comprobar dentro del bucle si estamos en el ltimo elemento, y si no estamos, aadir la coma separadora. Sera as:
1 cadena="" # Inicialmente vaca 2 ultimo_indice = len(semana) - 1 3 for i in range(len(semana)): 4 cadena = cadena + semana[i] # Aadir el dato 5 if i != ultimo_indice: # y si no es el ultimo 6 cadena = cadena + ", " # aadir tambin la coma

La segunda forma es hacer que el bucle se recorra para todos los elementos salvo el ltimo, y tratar este despus, fuera del bucle. Sera as:
1 2 3 4 5 6

cadena="" # Inicialmente vaca ultimo_indice = len(semana) - 1 for i in range(ultimo_indice): cadena = cadena + semana[i] + ", " # Ahora aadir el ultimo elemento cadena = cadena + semana[ultimo_indice]

# Aadir dato con su coma # sin coma detras

Cualquiera de estas soluciones es buena. Ambas funcionan para listas de cualquer longitud, salvo para listas vacas, en las que la segunda solucin fallara. Si quisiramos hacerlo totalmente genrico habra que comprobar en el segundo caso si la lista tiene longitud cero, en cuyo caso no habra que hacer nada ms sobre cadena. Este es el problema que intentamos resolver, y aunque ya hemos dado con una solucin para l, resulta conveniente saber que python ya vena con una solucin pre-programada para este problema. Se trata de un mtodo llamado .join() que tienen las cadenas.

116

Introduccin a la programacin

La sintaxis de este mtodo es un poco extraa y de alguna forma parece estar al revs de lo que uno esperara. El mtodo se invoca sobre una cadena que contenga el separador a insertar (en nuestro caso, la cadena ", "), y se le pasa como parmetro la lista que contiene los datos a concatenar. El resultado de la llamada es la cadena concatenada como queramos. Para el ejemplo anterior la llamada sera por tanto:
1 cadena = ", ".join(semana)

En casos excepcionales podemos querer concatenar todos los elementos de la lista sin ningn tipo de separador intermedio. Por ejemplo, en el caso en que cada elemento de la lista sea un solo carcter y queramos juntarlos todos para formar una palabra o cadena. Esto tambin puede hacerlo join(), basta usar una cadena vaca ("") en la llamada. Por ejemplo:
>>> letras = ["H", "o", "l", "a"] >>> palabra = "".join(letras) >>> palabra Hola

Para saber ms: Uso para crear cadenas letra a letra En la pgina 2.7.6 vimos una funcin que sustitua las vocales de una cadena dada por otro carcter. Dentro de la funcin la cadena resultado se iba creando letra a letra, por el mtodo de ir concatenando cada letra a lo que haba previamente. Se coment all que el mtodo era ineciente porque para cada concatenacin se creaba una cadena nueva. El mtodo eciente de lograr el mismo resultado consiste en crear una lista con las letras de la nueva cadena. Para ir aadiendo cada nueva letra a la lista se usa el mtodo .append() de la lista, en lugar de concatenar como en las cadenas. Esto modica siempre la misma lista, hacindola crecer, en lugar de crear listas nuevas para cada letra que se aade, y por tanto es ms eciente. Como paso nal, una vez tenemos la lista con todas las letras que la componen, se crea una cadena juntando todas ellas, con el mtodo visto en el ltimo ejemplo de uso de join(). El cdigo que implementa esta idea sera:
1 # coding=latin1 2 def cambiar_vocales(texto): 3 """Esta funcion recibe una cadena de texto como parametro 4 y retorna otra cadena que es una copia de la recibida, salvo 5 por que todas las vocales han sido sustituidas por el 6 signo _""" 7 # El resultado sera una lista, en lugar de una cadena 8 resultado = [ ] # De momento no tenemos letras en el resultado 9 # Recorremos todas las letras de la cadena original 10 for letra in texto: 11 # Miramos si es una vocal 12 if letra in "aeiouAEIOU": 13 # Si lo es, metemos "_" en el resultado 14 resultado.append("_") 15 else: 16 # Si no, metemos la letra en cuestion 17 resultado.append(letra) 18 # Una vez salimos del bucle, tenemos una lista con todas 19 # las letras del resultado. Lo convertimos en una cadena 20 # concatenando todas esas letras sin separador, y retornamos 21 # el resultado

2.7 Tipos y estructuras de datos bsicas: listas y arrays

117

22 23 24 25 26 27 28 29 30 31 32

return "".join(resultado) # Para probar la funcion anterior creo un mensaje mensaje = "Mensaje de prueba" # Borramos sus vocales, pero debo recoger el resultado en otra variable cambiado = cambiar_vocales(mensaje) # Imprimir cadena original y cambiada: print mensaje print cambiado

2.7.7.

Arrays

Numpy es un paquete de Python que reune tipos de datos y funciones para el clculo cientco. Proporciona, entre otras cosas, el tipo ndarray, til para la representacin de vectores y matrices multidimensionales, as como importantes funciones de lgebra lineal, tales como diversas operaciones con matrices, el clculo de la inversa o la resolucin de un sistema de ecuaciones. Un array es una secuencia ordenada9 , de elementos del mismo tipo, agrupados en distintas dimensiones. Si es nica la dimensin, hablamos de vectores. Si son varias, de matrices. El nmero de dimensiones de una matriz (o nmero de ejes) no se limita a dos. Esta circunstancia permite disponer de un tipo de dato adecuado para representar, por ejemplo, las propiedades de un objeto tridimensional. Los atributos ms tiles de un ndarray son: ndim, devuelve el nmero de dimensiones de un array. shape, devuelve el tamao del array en cada una de sus dimensiones size, devuelve el nmero de elementos totales del array, es decir, el producto de su extensin en cada una de sus dimensiones. Para poder utilizar numpy en un programa o en modo interactivo, es necesario cargar el mdulo, lo cual se hace con import como ya sabemos:
import numpy

En este curso, para crear un array se utilizar uno de estos mtodos: 1. Conversin desde otras estructuras de datos de Python (usualmente listas). 2. Creacin intrnseca de arrays con llamadas a funciones que devuelven arrays. 3. Lectura de arrays desde cheros. Conversin desde otras estructuras de datos La funcin array(secuencia, dtype=tipo) permite convertir una secuencia en un array de elementos del tipo especcado. Si este ltimo no se detalla la funcin usa el tipo ms genrico encontrado en la secuencia. Veamos unos ejemplos de conversin de listas numricas en arrays. Despus de crear cada array podemos escribir su nombre y a continuacin pulsar return para ver su contenido o bien hacer uso de la funcin print.
>>> a=numpy.array([7,23,4,.5]) >>> a En el sentido de que posee un orden interno, es decir, que cada elemento puede ser accedido mediante uno o ms subndices
9

118

Introduccin a la programacin
array([ 7. , 23. , 4. , 0.5]) >>> b=numpy.array([[7,2,3.5],[3.1,2.2,0]]) >>> b array([[ 7. , 2. , 3.5], [ 3.1, 2.2, 0. ]]) >>> c=numpy.array([[0,1.7,1.1],[1.3,1.5,2]], dtype=int) >>> c array([[ 0, 1, 1], [ 1, 1, 2]]) >>> d=numpy.array((b,c)) >>> d array([[[ 7. , 2. , 3.5], [ 3.1, 2.2, 0. ]], [[ 0. , [ 1. , 1. , 1. , 1. ], 2. ]]])

En la sucesin de ejemplos anteriores, a es un array de una dimensin, b y c son arrays de dos dimensiones y d es un array de tres dimensiones. Como podemos observar la matriz c se ha creado especicando el tipo int por lo que los datos reales se han convertido a enteros truncando su valor. Cuando no se especica el tipo y aparecen en los datos elementos de tipo entero y real, se toma por defecto el tipo real como bsico, ya que es el ms genrico. A continuacin se muestra el valor de los atributos ndim, shape y size de las matrices y vectores denidos. En este caso hemos usado las funciones con los mismos nombres que nos devuelven el mismo valor.
>>> numpy.ndim(a) 1 >>> numpy.ndim(b) 2 >>> numpy.shape(a) (4,) >>> numpy.shape(b) (2, 3) >>> numpy.size(a) 4 >>> numpy.size(b) 6 >>> numpy.size(c) 6 >>> numpy.shape(c) (2, 3) >>> numpy.shape(d) (2, 2, 3) >>> numpy.size(d) 12 >>> numpy.ndim(c) 2 >>> numpy.ndim(d) 3

Para saber ms Una curiosidad: Vemos que el shape o forma del vector unidimensional a es (4,). En python dicha funcin retorna una tupla. El problema es que la tupla (4) se confunde con la expresin numrica que representa al 4. Para que no haya confusin python representa

2.7 Tipos y estructuras de datos bsicas: listas y arrays

119

una tupla con un nico valor as: (valor,). La coma indica que detrs debera haber ms elementos (aunque se omitan) y que por tanto no es una expresin numrica simple. Alguno puede pensar que an as, un vector puede ser considerado como una matriz de una sla la y tantas columnas como la dimensin del vector. Para que python piense lo mismo, el vector unidimensional debera haberse denido as: a=numpy.array([[1,2,3,4]]). En este caso el nmero de corchetes igual a dos indica que es una matriz, y ahora s, la funcin shape() devuelve el valor (1,4). Todo lo cual, efectivamente, tiene su lgica.

Creacin intrnseca de arrays La creacin intrnseca de arrays consiste en crearlos utilizando alguna de las funciones que devuelven arrays. He aqu las ms tpicas. arange(), tiene la misma funcionalidad que el range() que ya conocemos, pero en lugar de devoler una lista (tipo list) devuelve un vector (tipo ndarray). Posee los mismos parmetros que la funcin range. No lo usaremos en esta asignatura.
>>> numpy.arange(10) array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> numpy.arange(0,1,0.1) array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5,

0.6,

0.7,

0.8,

0.9])

zeros(), devuelve un ndarray con el atributo shape que se le pase como parmetro, inicializando a cero cada elemento. El atributo shape se indica entre parntesis (adems de los parntesis que ya tenamos por ser un parmetro, es decir, doble parntesis).
>>> a=numpy.zeros((2,3)) >>> a array([[ 0., 0., 0.], [ 0., 0., 0.]])

En el ejemplo anterior se ha creado un ndarray de tamao 2 3 ones(), devuelve un ndarray con el atributo shape que se le pase como parmetros (que ha de ir entre parntesis, como en zeros()), inicializando a uno cada elemento.
>>> a=numpy.ones((2,3)) >>> a array([[ 1., 1., 1.], [ 1., 1., 1.]])

Indexado Es posible acceder a cada valor almacenado en un ndarray, utilizando tantos ndices como corresponda a su atributo ndim, es decir, uno para los de una dimensin, dos para los de dos, etc. El rango de valores para esos ndices viene determinado por los valores correspondientes del atributo shape, desde cero hasta ese valor menos uno. Por ejemplo, a es un array de una sola dimension (ndim=1), por lo tanto slo es necesario un ndice para acceder a sus elementos. Por otra parte, el valor de shape es (4,), por lo tanto los ndices vlidos para a son {0,1,2,3}.

120

Introduccin a la programacin

>>> a[0] 7.0 >>> a[1] 23.0 >>> a[2] 4.0 >>> a[3] 0.5

Anlogamente, b es un array bidimensional (ndim vale 2), de modo que son necesarios dos ndices para acceder individualmente a cada elemento. El atributo shape vale (2, 3), de modo que los valores vlidos para el primer ndice son {0,1} y para el segundo {0,1,2}. Convencionalmente se suele decir que el primero determina la la y el segundo la columna.
>>> b[0,0] 7.0 >>> b[0,1] 2.0 >>> b[1,2] 0.0

Para saber ms Es posible especicar rangos de ndices separando el inicio y el n del rango mediante :, al igual que sucede con otras secuencias en Python. Recurdese que la secuencia de ndices obtenida contiene el inicio del rango pero no el ltimo, termina con el penltimo. De esta forma 3:7 representa 3,4,5,6. Por ejemplo, para un ndarray de una dimensin:
>>> a=numpy.array([ 1, >>> a[3:7] array([7, 4, 8, 9]) 5, 2, 7, 4, 8, 9, 10, 3, 2, 5, 4])

En el caso de los ndarray de ms de una dimensin, los rangos pueden especicarse en una o ms de sus dimensiones. Si no se especican el inicio y el n pero s los : entonces el rango abarca todos los ndices vlidos de esa dimenesin. Por ejemplo si se tiene el siguiente ndarray:
>>> b=numpy.array(([4,5,2,1,6,4],[3,3,6,7,8,1],[7,7,8,9,1,2],[1,2,2,3,1,1])) >>> b array([[4, 5, 2, 1, 6, 4], [3, 3, 6, 7, 8, 1], [7, 7, 8, 9, 1, 2], [1, 2, 2, 3, 1, 1]])

La segunda columna sera:


>>> b[:,2] array([2, 6, 8, 2])

La submatriz obtenida a partir de los elementos comprendidos ente la la 1 y la tres y las columnas 2 y 5 seran:
>>> b[1:3,2:5] array([[6, 7, 8], [8, 9, 1]])

2.7 Tipos y estructuras de datos bsicas: listas y arrays Cambios en la forma de un ndarray

121

Es posible cambiar la forma de un ndarray, es decir, distribuir de forma distinta los elementos que lo componen, resultando en un ndarray con el mismo nmero total de elementos pero un nmero distinto de las, columnas, etc. Entre las funciones disponibles en numpy estn las siguientes: transpose, transpone una matriz.
>>> c=numpy.transpose(b) >>> c array([[5, 5, 1, 6], [2, 1, 1, 8], [4, 2, 5, 2]])

ravel, convierte un ndarray en otro de una sola dimensin.


>>> d=numpy.ravel(c) >>> d array([5, 5, 1, 6, 2, 1, 1, 8, 4, 2, 5, 2])

Para saber ms Otra operacin de cambio de forma de un ndarray que puede ser til es la siguiente: reshape, cambia el atributo shape de un ndarray al valor especicado. Si uno de los valores del atributo es -1, se calcula a partir de los dems para que se cumpla que size no cambie.
>>> a=numpy.array([[5,2,4,5],[1,2,1,1],[5,6,8,2]]) >>> a array([[5, 2, 4, 5], [1, 2, 1, 1], [5, 6, 8, 2]]) >>> b=numpy.reshape(a,(2,6)) >>> b array([[5, 2, 4, 5, 1, 2], [1, 1, 5, 6, 8, 2]]) >>> b=numpy.reshape(a,(-1,3)) >>> b array([[5, 2, 4], [5, 1, 2], [1, 1, 5], [6, 8, 2]])

2.7.8.

Operaciones bsicas con arrays

Las operaciones aritmticas sobre ndarray se efectan elemento a elemento, esto es de especial importancia en el caso del producto: a*b no representa el producto de matrices al uso sino que denota una operacin en la que el elemento a[i,j] se multiplica por el b[i,j], para los valores de i y j vlidos segn el atributo shape de ambos ndarray. Cuando las operaciones ser realizan entre dos o ms ndarray, sus atributos shape deben de ser idnticos, de lo contrario se produce un error. Cuando las operaciones se realizan con un escalar, la operacin se realiza entre cada elemento del ndarray y ese escalar.

122

Introduccin a la programacin

>>> a=numpy.array(([7,3,1],[5,6.5,1])) >>> a array([[ 7. , 3. , 1. ], [ 5. , 6.5, 1. ]]) >>> b=numpy.array(([3.1,0,-2],[1.3,3,0])) >>> a+b array([[ 10.1, 3. , -1. ], [ 6.3, 9.5, 1. ]]) >>> a*b array([[ 21.7, 0. , -2. ], [ 6.5, 19.5, 0. ]]) >>> a<b array([[False, False, False], [False, False, False]], dtype=bool) >>> a+1 array([[ 8. , 4. , 2. ], [ 6. , 7.5, 2. ]]) >>> a**2 array([[ 49. , 9. , 1. ], [ 25. , 42.25, 1. ]]) >>> a==1 array([[False, False, True], [False, False, True]], dtype=bool)

El producto matricial se representa mediante la funcin dot. Como es de esperar, el nmero de columnas de la primera matriz ha de ser igual al nmero de las de la segunda matriz. A modo de ejemplo se muestra el producto de a por la transpuesta de b.
>>> numpy.dot(a,numpy.transpose(b)) array([[ 19.7, 18.1], [ 13.5, 26. ]])

Las funciones universales, sin, cos, exp, etc., tambin se aplican elemento a elemento.
>>> c=numpy.array(([3.1415926535897931,3.1415926535897931/2], [3.1415926535897931/3,3.1415926535897931/4])) >>> c array([[ 3.14159265, 1.57079633], [ 1.04719755, 0.78539816]]) >>> numpy.cos(c) array([[ -1.00000000e+00, 6.12323400e-17], [ 5.00000000e-01, 7.07106781e-01]])

Las operaciones unarias (se aplican a ndarray pero devuelven un slo valor) por defecto se aplican elemento a elemento como si los valores del ndarray se almacenasen en una lista, sin importar el valor del atributo shape.
>>> numpy.min(a) 1.0 >>> numpy.max(a) 7.0 >>> numpy.sum(a) 23.5

2.7 Tipos y estructuras de datos bsicas: listas y arrays Para saber ms Si se desea operar sobre una dimensin o eje en concreto (las o columnas, por ejemplo) y producir un valor distinto para cada uno de los valores de ndice posibles para ese eje, se especica mediante el parametro axis. Por ejemplo, la suma de las las por un lado y de las columnas por otro de un ndarray de dos dimensiones sera:
>>> numpy.sum(a,axis=1) array([ 11. , 12.5]) >>> numpy.sum(a,axis=0) array([ 12. , 9.5, 2. ])

123

Las funciones max y min tambin se pueden usar de la misma forma:


>>> numpy.min(a,axis=0) array([ 5., 3., 1.]) >>> numpy.min(a,axis=1) array([ 1., 1.]) >>> a array([[ 7. , 3. , 1. ], [ 5. , 6.5, 1. ]])

La inversa y del determinante de una matriz (que cumpla, obviamente, los requisitos para que se puedan calcular esos valores) se representamn mediante las funciones linalg.inv y linalg.det, respectivamente.
>>> coef array([[ 7. , 3. ], [ 5. , 6.5]]) >>> numpy.linalg.det(coef) 30.500000000000004 >>> numpy.linalg.inv(coef) array([[ 0.21311475, -0.09836066], [-0.16393443, 0.2295082 ]])

La funcin solve calcula la solucin de un sistema lineal de ecuaciones denido mediante su matriz de coecientes y los trminos independientes correspondientes. Por ejemplo, el sistema de ecuaciones: 7x + 3y = 1 5x + 6.5y = 2

se resuelve as:
>>> y=numpy.array([1,2]) >>> numpy.linalg.solve(coef,y) array([ 0.01639344, 0.29508197])

2.7.9.

Copia de arrays

La asignacin se comporta con los ndarray de la misma forma que con cualquier otro objeto en Python, en esencia se trata de dar un nombre alternativo a un objeto existente. Por ese motivo, cualquier accin que se realice sobre un objeto obtiene el mismo resultado independientemente del

124

Introduccin a la programacin

nombre que se utilice. En el siguiente ejemplo al cambiar el elemento 0,0 de y cambia tambin el elemento 0,0 de x, porque es el mismo objeto.
>>> x=numpy.array(([4,3],[1,6])) >>> x array([[4, 3], [1, 6]]) >>> y=x >>> y[0,0]=1 >>> x array([[1, 3], [1, 6]])

Si por el motivo que sea se necesita copiar un objeto de tipo ndarray en otro, se utiliza la funcin copy. En el siguiente ejemplo se ha asignado a y una copia de x, de modo que al cambiar el elemento y[0,0], no cambiar el correspondiente elemento de x.
>>> x=numpy.array(([4,3],[1,6])) >>> x array([[4, 3], [1, 6]]) >>> y=x.copy() >>> y[0,0]=1 >>> x array([[4, 3], [1, 6]]) >>> y array([[1, 3], [1, 6]])

2.7.10.

Recorrido de arrays

El tipo ndarray est concebido para ser muy eciente cuando las operaciones sobre ste se realizan sin utilizar bucles. Sin embargo en algunas ocasiones puede ser necesario utilizar bucles para aplicar ciertas operaciones a todos o parte de los elementos de un ndarray. Adems, en muchos lenguajes de programacin, el tipo equivalente al ndarray no est diseado para trabajar de la misma forma, ms bien al contrario. Por este motivo se van a dar aqu unas indicaciones sobre el uso de objetos de tipo ndarray mediante bucles. Por defecto, la iteracin sobre un array se realiza sobre el primero de los ndices, el nico ndice de un array de una dimensin, convencionalmente las las en un array bidimensional. En el siguiente ejemplo, como z es un array de una dimensin, la iteracin se produce sobre los elementos del array, que estn indexados por el primer y nico ndice del mismo.
>>> z=numpy.array([3,6,4,6,8,5,6,7,8,9]) >>> for elemento in z: ... print elemento, ... 3 6 4 6 8 5 6 7 8 9

Sin embargo, si se itera sobre un array bidimensional, se itera sobre las las, que estn indexadas por el primer ndice
>>> a array([[ 7. , 3. , [ 5. , 6.5, >>> for fila in a: ... print fila 1. ], 1. ]])

2.7 Tipos y estructuras de datos bsicas: listas y arrays


... [ 7. [ 5.

125

3. 1.] 6.5 1. ]

Evidentemente, en el caso anterior, cada la a su vez puede ser recorrida como en el primero de los ejemplos, en ese caso se utilizaran dos bucles anidados, el ms externo recorrera las las y el ms interno las columnas dentro da cada la para acceder al valor de cada elemento.
>>> for fila in a: ... for elemento in fila: ... print elemento, ... 7.0 3.0 1.0 5.0 6.5 1.0

En algunos lenguajes de programacin no existe una construccin equivalente a las anteriores, de modo que en esos casos se usan de forma explcita los valores de los ndices en todas las dimensiones posibles para acceder a los elementos individuales de las estructuras de datos anlogas a ndarray. Python tambin admite esta forma de trabajo; a continuacin se detalla esta tcnica que habitualmente se llama recorrido. En primer lugar es necesario generar una secuencia que contenga todos los valores vlidos para los ndices que se utilicen en cada dimensin del ndarray. Una forma prctica es utilizar range pasando como parmetro el elemento correspondiente del atributo shape que contenga el nmero de elementos en la dimensin en cuestin. El primer elemento de shape es el nmero de elementos en la primera dimensin, el segundo el nmero de elementos en la segunda dimensin, etc. En el caso particular de los ndarray unidimensionales, size devuelve el nmero de elementos que, evidentemente, coincide con el nmero de elementos que hay en la nica dimensin del ndarray. En los ejemplos que van a continuacin, los ndarray utilizados son los denidos en los ejemplos precedentes. En el siguiente ejemplo se obtiene el nmero de elementos de z usando shape. Aunque este atributo tenga un slo elemento, es necesario escribir una pareja de corchetes indicando el ndice correspondiente. El nmero de elementos, que es 10, se asigna a nelementos. Despus se utiliza este objeto como parametro en range, de modo que se generar la secuencia 0,1,2,...,9. En el bucle for se utiliza esta secuencia para que i tome sucesivamente esos valores en orden creciente. En cada iteracin del bucle for, se muestra el contenido del elemento de z indexado por i.
>>> nelementos=numpy.shape(z)[0] >>> for i in range(nelementos): ... print z[i], ... 3 6 4 6 8 5 6 7 8 9

En el caso de los ndarray bidimensionales, shape contiene dos valores: el primero es el nmero de las y el segundo el nmero de columnas. Cada uno de estos valores se asigna a un objeto adecuado (filas y columnas en el ejemplo). Al igual que en el ejemplo anterior, esos dos objetos se utilizan en sendas llamadas a range para generar las secuencias que contienen los valores de ndices vlidos para cada dimensin. Estas secuencias se utilizan en dos bucles for anidados, de modo que, dentro del bucle ms interno, i y j adoptan todos los valores del producto cartesiano de las dos secuencias. En otras palabras, todas las posibles parejas de ndices vlidos para el objeto ndarray en cuestin. Como se deduce de la salida por pantalla del fragmento de cdigo que se muestra, en este caso la matriz se recorre por las, es decir, en primer lugar se accede a los elementos de la primera la, desde el primero al ltimo, en ese orden. Despus los de la segunda en ese mismo orden. Si hubiese ms las se continuara de la misma forma.

126

Introduccin a la programacin

>>> >>> >>> ... ... ... 7.0

filas=numpy.shape(a)[0] columnas=numpy.shape(a)[1] for i in range(filas): for j in range(columnas): print a[i,j], 3.0 1.0 5.0 6.5 1.0

Es posible alterar este esquema de recorrido y realizarlo por columnas, sin ms que intercambiar los bucles de posicin dentro del cdigo. En el siguiente ejemplo se puede observar como se ha accedido a los elementos de la matriz mostrando en primer lugar los elementos de la primera columna, despus los de la segunda.
>>> for j in range(columnas): ... for i in range(filas): ... print a[i,j], ... 7.0 5.0 3.0 6.5 1.0 1.0

Es posible invertir el orden del recorrido dentro de una o ms dimensiones de un ndarray, es decir, hacer que la secuencia sea por ejemplo 9,8,...,1,0 en lugar de 0,1,...,8,9, para lo que se puede usar range con un incremento negativo, o la funcin reversed que da la vuelta al resultado de un range normal. En el siguiente ejemplo se muestra como recorrer el vector unidimensional z desde el ltimo elemento al primero.
>>> for i in reversed(range(nelementos)): ... print z[i], ... 9 8 7 6 5 8 6 4 6 3

Alternativamente se podra haber utilizado como ndice de z una expresin que tomase los valores 9,8,...,1,0, construida a partir de i (que ira normalmente de 0 a 9, en orden creciente). En este caso, la expresin sera nelementos-1-i.
>>> for i in range(nelementos): ... print z[nelementos-1-i], ... 9 8 7 6 5 8 6 4 6 3

De la misma forma es posible invertir el orden del recorrido de las las o columnas de un ndarray bidimensional.

You might also like