• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Ippython
 

Ippython

on

  • 303 views

un buen manual de Python

un buen manual de Python

Statistics

Views

Total Views
303
Views on SlideShare
303
Embed Views
0

Actions

Likes
0
Downloads
3
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Ippython Ippython Document Transcript

    • Introducción a la programación con Python Andrés Marzal Isabel Gracia Departamento de lenguajes y sistemas informáticos Codis d’assignatura II04 i IG04 Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9  Introducción a la programación con Python - UJI
    • Introducci´n a la programaci´n o o con Python Andr´s Marzal e Isabel Gracia Departamento de Lenguajes y Sistemas Inform´ticos a Universitat Jaume I Edita: Publicacions de la Universitat Jaume I. Servei de Comunicació i Publicacions Campus del Riu Sec. Edifici Rectorat i Serveis Centrals. 12071 Castelló de la Plana http://www.tenda.uji.es e-mail: publicacions@uji.es Col·lecció Sapientia, 23 www.sapientia.uji.es ISBN: 978-84-692-5869-9 Aquest text està subjecte a una llicència Reconeixement-NoComercial-CompartirIgual de Creative Commons, que permet copiar, distribuir i comunicar públicament l’obra sempre que especifique l’autor i el nom de la publicació i sense objectius comercials, i també permet crear obres derivades, sempre que siguen distribuïdes amb aquesta mateixa llicència. http://creativecommons.org/licenses/by-nc-sa/2.5/es/deed.ca Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 II Introducción a la programación con Python - UJI
    • Prefacio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 III 1 Introducción a la programación con Python - UJI
    • Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 IV Introducción a la programación con Python - UJI
    • Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9  Introducción a la programación con Python - UJI
    • Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 VI Introducción a la programación con Python - UJI
    • Prefacio ˂˂Introducci´n a la programaci´n con Python˃˃ e ˂˂Introducci´n a la programaci´n con C˃˃ o o o o desarrollan el temario de la asignatura ˂˂Metodolog´ y tecnolog´ de la programaci´n˃˃ de ıa ıa o las titulaciones de Ingenier´ Inform´tica e Ingenier´ T´cnica en Inform´tica de Gesti´n ıa a ıa e a o de la Universitat Jaume I. En ella se pretende ense˜ar a programar y, a diferencia de lo n que es usual en cursos introductorios a la programaci´n, se propone el aprendizaje con o dos lenguajes de programaci´n: Python y C. o ¿Por qu´ dos lenguajes de programaci´n? Python y C son bien diferentes. El primero e o es un lenguaje de muy alto nivel que permite expresar algoritmos de forma casi directa (ha llegado a considerarse ˂˂pseudoc´digo ejecutable˃˃) y hemos comprobado que se trata o de un lenguaje particularmente adecuado para la ense˜anza de la programaci´n. Esta n o impresi´n se ve corroborada por la adopci´n de Python como lenguaje introductorio en o o otras universidades. El lenguaje C exige una gran atenci´n a multitud de detalles que o dificultan la implementaci´n de algoritmos a un estudiante que se enfrenta por primera o vez al desarrollo de programas. No obstante, C sigue siendo un lenguaje de programaci´n o de referencia y debe formar parte del curr´ ıculum de todo inform´tico: su proximidad al a computador nos permite controlar con gran precisi´n el consumo de recursos computacioo nales. Aprender Python antes que C permite estudiar las estructuras de control y de datos b´sicas con un alto nivel de abstracci´n y, as´ entender mejor qu´ supone, exactamente, a o ı, e la mayor complejidad de la programaci´n en C y hasta qu´ punto es mayor el grado o e de control que nos otorga. Por ejemplo, una vez se han estudiado listas en Python, su implementaci´n en C permite al estudiante no perder de vista el objetivo ultimo: conso ´ truir una entidad con cierto nivel de abstracci´n usando unas herramientas concretas (los o punteros). De ese modo se evita una desafortunada confusi´n entre estructuras din´micas o a y punteros que es frecuente cuando ´stas se estudian unicamente a la luz de un lenguaje e ´ como C. En cierto modo, pues, Python y C se complementan en el aprendizaje y ofrecen una visi´n m´s rica y completa de la programaci´n. Las similitudes y diferencias entre o a o ambos permiten al estudiante inferir m´s f´cilmente qu´ es fundamental y qu´ accesorio a a e e o accidental al dise˜ar programas en un lenguaje de programaci´n cualquiera. n o ¿Y por qu´ otro libro de texto introductorio a la programaci´n? Ciertamente hay muchos e o libros que ense˜an a programar desde cero. Creemos que estos dos libros de texto se n diferencia de ellos tanto en el hecho de estudiar secuencialmente dos lenguajes como en la forma en que se exponen y desarrollan los conocimientos. Hemos procurado adoptar siempre el punto de vista del estudiante y presentar los conceptos y estrategias para dise˜ar programas b´sicos paso a paso, incrementalmente. La experiencia docente nos ha n a ido mostrando toda una serie l´ ıneas de razonamiento inapropiadas, errores y vicios en los que caen muchos estudiantes. El texto trata de exponer, con mayor o menor fortuna, esos razonamientos, errores y vicios para que el estudiante los tenga presentes y procure evitarlos. As´ en el desarrollo de algunos programas llegamos a ofrecer versiones err´neas ı, o para, acto seguido, estudiar sus defectos y mostrar una versi´n corregida. Los apuntes o est´n repletos de cuadros que pretenden profundizar en aspectos marginales, llamar la a atenci´n sobre alg´n extremo, ofrecer algunas pinceladas de historia o, sencillamente, o u desviarse de lo sustancial con alguna digresi´n que podr´ resultar motivadora para el o ıa Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 1  Introducción a la programación con Python - UJI
    • estudiante. Hemos de recalcar que este libro pretende ense˜ar a programar y no es un manual n exhaustivo sobre el lenguaje de programaci´n Python. Son particularmente rese˜ables o n dos omisiones: los diccionarios y las clases. No forman parte de esta edici´n (aunque o posiblemente se incluir´n en otra posterior) porque hemos preferido centrarnos en aquellos a aspectos que tanto Python como C presentan en com´n. La orientaci´n a objetos se puede u o tratar a partir del material expuesto en estos vol´menes, pero hubiera resultado dif´ u ıcil incluir estos contenidos en el volumen de Python y no poder tratarlos adecuadamente en el volumen dedicado a C. Queremos aprovechar para dar un consejo a los estudiantes que no nos cansamos de repetir: es imposible aprender a programar limit´ndose a leer unos apuntes o a seguir a pasivamente una explicaci´n en clase (especialmente si el per´ o ıodo de estudio se concentra en una o dos semanas). Programar al nivel propio de un curso introductorio no es particularmente dif´ pero constituye una actividad intelectual radicalmente nueva para ıcil, los estudiantes. Es necesario darse una oportunidad para ir asentando los conocimientos y las estrategias de dise˜o de programas (y as´ superar el curso). Esa oportunidad n ı, requiere tiempo para madurar. . . y trabajo, mucho trabajo; por eso el texto ofrece m´s de a cuatrocientos ochenta ejercicios. S´lo tras haberse enfrentado a buena parte de ellos se o estar´ preparado para demostrar que se ha aprendido lo necesario. a Hay centenares de diferencias entre las dos primeras ediciones (publicadas como apuntes en la Universidad Jaume I y en formato electr´nico en Internet) y ´sta. No s´lo o e o hemos corregido erratas (y errores), hemos a˜adido tambi´n nuevos ejemplos, modificado n e otros, preparado nuevos ejercicios, reubicado ejercicios para que aparezcan en lugares que hemos juzgado m´s apropiados, etc. Los programas se presentan con una tipograf´ a ıa que, creemos, facilita notablemente la lectura. El documento PDF ofrece, adem´s, la a posibilidad de descargar c´modamente el texto de los programas (que se pueden descargar o de http://ocw.uji.es). Esperamos que esta posibilidad se traduzca en un mayor animo ´ del estudiante para experimentar con los programas. Convenios tipogr´ficos a Hemos tratado de seguir una serie de convenios tipogr´ficos a lo largo del texto. Los a programas, por ejemplo, se muestran con fondo gris, as´ ı: print ’ Hola,␣mundo!’ ! 1 Por regla general, las l´ ıneas del programa aparecen numeradas a mano izquierda. Esta numeraci´n tiene por objeto facilitar la referencia a puntos concretos del programa y no o debe reproducirse en el fichero de texto si se copia el programa. Cuando se quiere destacar el nombre del fichero en el que reside un programa, se dispone este en una barra encima del c´digo: o hola mundo.py print ’ Hola,␣mundo!’ ! 1 Si se trabaja con la versi´n electr´nica del libro en formato PDF (disponible en la o o p´gina web http://ocw.uji.es) es posible acceder c´modamente al texto de los proa o gramas. Para ello, basta con desempaquetar el fichero programas.tgz (o programas.zip) en el mismo directorio en el que est´ ubicado el documento PDF. Los programas accesibles e tienen un icono que representa un documento escrito en la esquina superior izquierda. Junto al icono aparece el nombre real del fichero: como ofrecemos varias versiones de un mismo programa, nos hemos visto obligados a seguir un esquema de numeraci´n que modio fica el propio nombre del fichero. La primera versi´n de un fichero llamado hola mundo.py o es hola mundo 1.py, la segunda hola mundo 2.py, y as´ sucesivamente. ı Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o  2 Introducción a la programación con Python - c UJI UJI
    • hola mundo.py hola mundo 1.py print ’ Hola,’, ’mundo!’ ! 1 Si, aunque haya varias versiones, no aparece un n´mero al final del nombre del fichero u descargable, se entiende que esa es la versi´n definitiva. o hola mundo.py hola mundo.py print ’ Hola,␣mundo!’ ! 1 Al pinchar en el icono, se abre un fichero de texto con el navegador web o editor de textos que se indique en las preferencias del visualizador de documentos PDF. Cuando el programa contiene alg´n error grave, aparecen un par de rayos flanqueando u al nombre del programa: E hola mundo.py E rint ’ Hola,␣mundo!’ ! 1 Algunos programas no est´n completos y, por ello, presentan alguna deficiencia. No a obstante, hemos optado por no marcarlos como err´neos cuando ´stos evolucionaban en o e el curso de la exposici´n. o La informaci´n que se muestra por pantalla aparece siempre recuadrada. El resultado o de ejecutar hola mundo.py se mostrar´ as´ a ı: ! Hola, mundo! En ocasiones mostraremos las ´rdenes que deben ejecutarse en un int´rprete de o e o e a ımbolo de d´lar: o ´rdenes Unix. El prompt del int´rprete se representar´ con un s´ ↱ $ python hola_mundo.py Hola, mundo! ! La parte que debe teclear el usuario o el programador se muestra siempre con un fondo gris. El retorno de carro se representa expl´ ıcitamente con el s´ ımbolo . Las sesiones interactivas del int´rprete de Python tambi´n se muestran recuadradas. e e El prompt primario del int´rprete Python se muestra con los caracteres ˂˂>>>˃˃ y el e secundario con ˂˂...˃˃. Las expresiones y sentencias que teclea el programador se destacan con fondo gris. ↱ ↱ >>> ’Hola,’ + ’␣’ + ’mundo!’ ’ Hola, mundo!’ >>> if ’Hola’ == ’mundo’: ... print ’si’ ... else: ... print ’no’ ... no ↱ ! ↱ ↱ ↱ ↱ Agradecimientos Este texto es fruto de la experiencia docente de todo el profesorado de las asignaturas de ˂˂Metodolog´ y tecnolog´ de la programaci´n˃˃ y se ha enriquecido con las aportaciones, ıa ıa o comentarios y correcciones de muchos profesores del departamento de Lenguajes y Sistemas Inform´ticos de la Universitat Jaume I de Castell´: Juan Pablo Aibar Ausina, Rafael a o Berlanga Llavor´ Antonio Castellanos L´pez, Pedro Garc´ Sevilla, Mar´ Dolores Llid´ ı, o ıa ıa o Escriv´, David Llorens Pi˜ana, Jos´ Luis Llopis Borr´s, Juan Miguel Vilar Torres, V´ a n e a ıctor Manuel Jim´nez Pelayo y Ram´n Mollineda C´rdenas. Para todos ellos, nuestro agradee o a cimiento. El agradecimiento a David Llorens Pi˜ana es doble por desarrollar, adem´s, el n a Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 3 Introducción a la programación con Python - UJI c UJI
    • entorno de programaci´n PythonG. Finalmente, agradecemos la colaboraci´n de cuantos o o nos han hecho llegar sugerencias o han detectado erratas. Castell´ de la Plana, a 8 de octubre de 2009. o Andr´s Marzal Var´ e Isabel Gracia Luengo. e o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 4  Introducción a la programación con Python - cUJI UJI
    • Cap´ ıtulo 1 Introducci´n o ¿Qu´ sabes de este asunto? pregunt´ el Rey a Alicia. e o Nada dijo Alicia. ¿Absolutamente nada? insisti´ el Rey. o Absolutamente nada dijo Alicia. Esto es importante dijo el Rey, volvi´ndose hacia los jurados. e LEWIS CARROLL, Alicia en el pa´ de la maravillas. ıs El objetivo de este curso es ense˜arte a programar, esto es, a dise˜ar algoritmos y expren n sarlos como programas escritos en un lenguaje de programaci´n para poder ejecutarlos o en un computador. Seis t´rminos t´cnicos en el primer p´rrafo. No est´ mal. Vayamos paso a paso: e e a a empezaremos por presentar en qu´ consiste, b´sicamente, un computador. e a 1.1. Computadores El diccionario de la Real Academia define computador electr´nico como ˂˂M´quina electr´o a o nica, anal´gica o digital, dotada de una memoria de gran capacidad y de m´todos de trao e tamiento de la informaci´n, capaz de resolver problemas matem´ticos y l´gicos mediante o a o la utilizaci´n autom´tica de programas inform´ticos.˃˃ o a a La propia definici´n nos da indicaciones acerca de algunos elementos b´sicos del o a computador: la memoria, y alg´n dispositivo capaz de efectuar c´lculos matem´ticos y l´gicos. u a a o La memoria es un gran almac´n de informaci´n. En la memoria almacenamos todo tipo e o de datos: valores num´ricos, textos, im´genes, etc. El dispositivo encargado de efectuar e a operaciones matem´ticas y l´gicas, que recibe el nombre de Unidad Aritm´tico-L´gica a o e o (UAL), es como una calculadora capaz de trabajar con esos datos y producir, a partir de ellos, nuevos datos (el resultado de las operaciones). Otro dispositivo se encarga de transportar la informaci´n de la memoria a la UAL, de controlar a la UAL para que efect´e o u las operaciones pertinentes y de depositar los resultados en la memoria: la Unidad de Control. El conjunto que forman la Unidad de Control y la UAL se conoce por Unidad Central de Proceso (o CPU, del ingl´s ˂˂Central Processing Unit˃˃). e Podemos imaginar la memoria como un armario enorme con cajones numerados y la CPU como una persona que, equipada con una calculadora (la UAL), es capaz de buscar operandos en la memoria, efectuar c´lculos con ellos y dejar los resultados en la memoria. a Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 5  Introducción a la programación con Python - UJI
    • 1 2 3 4 . . . Memoria Unidad Central de Proceso Unidad de Control Unidad Aritm´tico-L´gica e o Utilizaremos un lenguaje m´s t´cnico: cada uno de los ˂˂cajones˃˃ que conforman la a e memoria recibe el nombre de celda (de memoria) y el n´mero que lo identifica es su u posici´n o direcci´n, aunque a veces usaremos estos dos t´rminos para referirnos tambi´n o o e e a la correspondiente celda. Cada posici´n de memoria permite almacenar una secuencia de unos y ceros de o tama˜o fijo. ¿Por qu´ unos y ceros? Porque la tecnolog´ actual de los computadores n e ıa se basa en la sencillez con que es posible construir dispositivos binarios, es decir, que pueden adoptar dos posibles estados: encendido/apagado, hay corriente/no hay corriente, cierto/falso, uno/cero. . . ¿Es posible representar datos tan variados como n´meros, textos, u im´genes, etc. con s´lo unos y ceros? La respuesta es s´ (aunque con ciertas limitaciones). a o ı Para entenderla mejor, es preciso que nos detengamos brevemente a considerar c´mo se o representa la informaci´n con valores binarios. o 1.2. Codificaci´n de la informaci´n o o Una codificaci´n asocia signos con los elementos de un conjunto a los que denominamos o significados. En occidente, por ejemplo, codificamos los n´meros de cero a nueve con u el conjunto de signos {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}. Al hacerlo, ponemos en correspondencia estos s´ ımbolos con cantidades, es decir, con su significado: el s´ ımbolo ˂˂6˃˃ representa a la cantidad seis. El conjunto de signos no tiene por qu´ ser finito. Podemos combinar e los d´ ıgitos en secuencias que ponemos en correspondencia con, por ejemplo, los n´meros u naturales. La sucesi´n de d´ o ıgitos ˂˂99˃˃ forma un nuevo signo que asociamos a la cantidad noventa y nueve. Los ordenadores s´lo tienen dos signos b´sicos, {0, 1}, pero se pueden o a combinar en secuencias, as´ que no estamos limitados a s´lo dos posibles significados. ı o Una variable que s´lo puede tomar uno de los dos valores binarios recibe el nombre o de bit (acr´nimo del ingl´s ˂˂binary digit˃˃). Es habitual trabajar con secuencias de bits o e de tama˜o fijo. Una secuencia de 8 bits recibe el nombre de byte (aunque en espa˜ol el n n t´rmino correcto es octeto, ´ste no acaba de imponerse y se usa la voz inglesa). Con una e e secuencia de 8 bits podemos representar 256 (28 ) significados diferentes. El rango [0, 255] de valores naturales comprende 256 valores, as´ que podemos representar cualquiera de ı ellos con un patr´n de 8 bits. Podr´ o ıamos decidir, en principio, que la correspondencia entre bytes y valores naturales es completamente arbitraria. As´ podr´ ı, ıamos decidir que la secuencia 00010011 representa, por ejemplo, el n´mero natural 0 y que la secuencia u 01010111 representa el valor 3. Aunque sea posible esta asociaci´n arbitraria, no es o deseable, pues complica enormemente efectuar operaciones con los valores. Sumar, por ejemplo, obligar´ a tener memorizada una tabla que dijera cu´l es el resultado de efectuar ıa a la operaci´n con cada par de valores, ¡y hay 65536 pares diferentes! o Los sistemas de representaci´n posicional de los n´meros permiten establecer esa o u asociaci´n entre secuencias de bits y valores num´ricos naturales de forma sistem´tica. o e a Centramos el discurso en secuencias de 8 bits, aunque todo lo que exponemos a continuaci´n es v´lido para secuencias de otros tama˜os1 . El valor de una cadena de bits o a n b7 b6 b5 b4 b3 b2 b1 b0 es, en un sistema posicional convencional, 7 bi ·2i . As´ la secuencia ı, i=0 de bits 00001011 codifica el valor 0·27 +0·26 +0·25 +0·24 +1·23 +0·22 +1·21 +1·20 = 8 + 2 + 1 = 11. El bit de m´s a la izquierda recibe el nombre de ˂˂bit m´s significativo˃˃ a a y el bit de m´s a la derecha se denomina ˂˂bit menos significativo˃˃. a Ocho bits ofrecen un rango de valores muy limitado. Es habitual en los ordenadores modernos trabajar con grupos de 4 bytes (32 bits) u 8 bytes (64 bits). 1 Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o  6 Introducción a la programación con Python - UJI c UJI
    • . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 1 ¿Cu´l es el m´ximo valor que puede representarse con 16 bits y un sistema de a a representaci´n posicional como el descrito? ¿Qu´ secuencia de bits le corresponde? o e · 2 ¿Cu´ntos bits se necesitan para representar los n´meros del 0 al 18, ambos inclua u sive? .................................................................................. El sistema posicional es especialmente adecuado para efectuar ciertas operaciones aritm´ticas. Tomemos por caso la suma. Hay una ˂˂tabla de sumar˃˃ en binario que te e mostramos a continuaci´n: o sumandos 0 0 1 1 0 1 0 1 suma 0 1 1 0 acarreo 0 0 0 1 El acarreo no nulo indica que un d´ ıgito no es suficiente para expresar la suma de dos bits y que debe a˜adirse el valor uno al bit que ocupa una posici´n m´s a la izquierda. n o a Para ilustrar la sencillez de la adici´n en el sistema posicional, hagamos una suma de o dos n´meros de 8 bits usando esta tabla. En este ejemplo sumamos los valores 11 y 3 en u su representaci´n binaria: o + 00001011 00000011 Empezamos por los bits menos significativos. Seg´n la tabla, la suma 1 y 1 da 0 con u acarreo 1: Acarreo + 1 00001011 00000011 0 El segundo d´ ıgito empezando por derecha toma el valor que resulta de sumar a 1 y 1 el acarreo que arrastramos. O sea, 1 y 1 es 0 con acarreo 1, pero al sumar el acarreo que arrastramos de la anterior suma de bits, el resultado final es 1 con acarreo 1: Acarreo + 1 1 00001011 00000011 10 Ya te habr´s hecho una idea de la sencillez del m´todo. De hecho, ya lo conoces bien, a e pues el sistema de numeraci´n que aprendiste en la escuela es tambi´n posicional, s´lo o e o que usando diez d´ ıgitos diferentes en lugar de dos, as´ que el procedimiento de suma es ı esencialmente id´ntico. He aqu´ el resultado final, que es la secuencia de bits 00001110, e ı o sea, el valor 14: Acarreo + 1 1 00001011 00000011 00001110 La circuiter´ electr´nica necesaria para implementar un sumador que act´e como el ıa o u descrito es extremadamente sencilla. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 3 Calcula las siguientes sumas de n´meros codificados con 8 bits en el sistema u posicional: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o  7 Introducción a la programación con Python - UJIUJI c
    • a) 01111111 + 00000001 b) 01010101 + 10101010 c) 00000011 + 00000001 .................................................................................. Debes tener en cuenta que la suma de dos n´meros de 8 bits puede proporcionar una u cantidad que requiere 9 bits. Suma, por ejemplo, las cantidades 255 (en binario de 8 bits es 11111111) y 1 (que en binario es 00000001): Acarreo 1 1 1 1 1 1 1 11111111 + 00000001 (1)00000000 El resultado es la cantidad 256, que en binario se expresa con 9 bits, no con 8. Decimos en este caso que la suma ha producido un desbordamiento. Esta anomal´ debe ser tenida ıa en cuenta cuando se usa o programa un ordenador. Hasta el momento hemos visto c´mo codificar valores positivos. ¿Podemos representar o tambi´n cantidades negativas? La respuesta es s´ Consideremos brevemente tres formas e ı. de hacerlo. La primera es muy intuitiva: consiste en utilizar el bit m´s significativo para a codificar el signo; si vale 0, por ejemplo, el n´mero expresado con los restantes bits es u positivo (con la representaci´n posicional que ya conoces), y si vale 1, es negativo. Por o ejemplo, el valor de 00000010 es 2 y el de 10000010 es −2. Efectuar sumas con valores positivos y negativos resulta relativamente complicado si codificamos as´ el signo de un ı n´mero. Esta mayor complicaci´n se traslada tambi´n a la circuiter´ necesaria. Mala u o e ıa cosa. Una forma alternativa de codificar cantidades positivas y negativas es el denominado ˂˂complemento a uno˃˃. Consiste en lo siguiente: se toma la representaci´n posicional de o un n´mero (que debe poder expresarse con 7 bits) y se invierten todos sus bits si es u negativo. La suma de n´meros codificados as´ es relativamente sencilla: se efect´a la u ı u suma convencional y, si no se ha producido un desbordamiento, el resultado es el valor que se deseaba calcular; pero si se produce un desbordamiento, la soluci´n se obtiene o sumando el valor 1 al resultado de la suma (sin tener en cuenta ya el bit desbordado). Ve´moslo con un ejemplo. Sumemos el valor 3 al valor −2 en complemento a uno: a Acarreo 1 1 1 1 1 1 1 00000011 + 11111101 (1)00000000 ↓ 00000000 + 00000001 00000001 La primera suma ha producido un desbordamiento. El resultado correcto resulta de sumar una unidad a los 8 primeros bits. La codificaci´n en complemento a uno tiene algunas desventajas. Una de ellas es que o hay dos formas de codificar el valor 0 (con 8 bits, por ejemplo, tanto 00000000 como 11111111 representan el valor 0) y, por tanto, s´lo podemos representar 255 valores o ([−127, 127]), en lugar de 256. Pero el principal inconveniente es la lentitud con que se realizan operaciones como la suma: cuando se produce un desbordamiento se han de efectuar dos adiciones, es decir, se ha de invertir el doble de tiempo. Una codificaci´n alternativa (y que es la utilizada en los ordenadores) es la denominao da ˂˂complemento a dos˃˃. Para cambiar el signo a un n´mero hemos de invertir todos sus u bits y sumar 1 al resultado. Esta codificaci´n, que parece poco natural, tiene las ventajas o de que s´lo hay una forma de representar el valor nulo (el rango de valores representados o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 8  Introducción a la programación con Python - cUJI UJI
    • es [−128, 127]) y, principalmente, de que una sola operaci´n de suma basta para obtener o el resultado correcto de una adici´n. Repitamos el ejemplo anterior. Sumemos 3 y −2, o pero en complemento a dos: Acarreo 1 1 1 1 1 1 00000011 + 11111110 (1)00000001 Si ignoramos el bit desbordado, el resultado es correcto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 4 Codifica en complemento a dos de 8 bits los siguientes valores: a) 4 ·5 b) −4 c) 0 d) 127 e) 1 b) −4 + 3 c) 127 − 128 d) 128 − 127 e) 1 − 1 f) −1 Efect´a las siguientes sumas y restas en complemento a dos de 8 bits: u a) 4 + 4 f) 1 − 2 .................................................................................. Bueno, ya hemos hablado bastante acerca de c´mo codificar n´meros (aunque m´s o u a adelante ofreceremos alguna reflexi´n acerca de c´mo representar valores con parte fraco o cional). Preocup´monos por un instante acerca de c´mo representar texto. Hay una tabla e o que pone en correspondencia 127 s´ ımbolos con secuencias de bits y que se ha asumido como est´ndar. Es la denominada tabla ASCII, cuyo nombre son las siglas de ˂˂American a Standard Code for Information Interchange˃˃. La correspondencia entre secuencias de bits y caracteres determinada por la tabla es arbitraria, pero aceptada como est´ndar. La letra a ˂˂a˃˃, por ejemplo, se codifica con la secuencia de bits 01100001 y la letra ˂˂A˃˃ se codifica con 01000001. En el ap´ndice A se muestra esta tabla. El texto se puede codificar, pues, e como una secuencia de bits. Aqu´ tienes el texto ˂˂Hola˃˃ codificado con la tabla ASCII: ı 01001000 01101111 01101100 01100001 Pero, cuando vemos ese texto en pantalla, no vemos una secuencia de bits, sino la letra ˂˂H˃˃, seguida de la letra ˂˂o˃˃,. . . Lo que realmente vemos es un gr´fico, un patr´n de a o p´ ıxeles almacenado en la memoria del ordenador y que se muestra en la pantalla. Un bit de valor 0 puede mostrarse como color blanco y un bit de valor 1 como color negro. La letra ˂˂H˃˃ que ves en pantalla, por ejemplo, es la visualizaci´n de este patr´n de bits: o o 01000010 01000010 01000010 01111110 01000010 01000010 01000010 En la memoria del ordenador se dispone de un patr´n de bits para cada car´cter2 . o a Cuando se detecta el c´digo ASCII 01001000, se muestra en pantalla el patr´n de bits o o correspondiente a la representaci´n gr´fica de la ˂˂H˃˃. Truculento, pero eficaz. o a No s´lo podemos representar caracteres con patrones de p´ o ıxeles: todos los gr´ficos a de ordenador son simples patrones de p´ ıxeles dispuestos como una matriz. Como puedes ver, basta con ceros y unos para codificar la informaci´n que manejamos o en un ordenador: n´meros, texto, im´genes, etc. u a 2 La realidad es cada vez m´s compleja. Los sistemas modernos almacenan los caracteres en memoria de a otra forma, pero hablar de ello supone desviarnos mucho de lo que queremos contar. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o  9 Introducción a la programación con Python - UJIUJI c
    • 1.3. Programas y lenguajes de programaci´n o Antes de detenernos a hablar de la codificaci´n de la informaci´n est´bamos comentando o o a que la memoria es un gran almac´n con cajones numerados, es decir, identificables con e valores num´ricos: sus respectivas direcciones. En cada caj´n se almacena una secuencia e o de bits de tama˜o fijo. La CPU, el ˂˂cerebro˃˃ del ordenador, es capaz de ejecutar acciones n especificadas mediante secuencias de instrucciones. Una instrucci´n describe una acci´n o o muy simple, del estilo de ˂˂suma esto con aquello˃˃, ˂˂multiplica las cantidades que hay en tal y cual posici´n de memoria˃˃, ˂˂deja el resultado en tal direcci´n de memoria˃˃, ˂˂haz o o una copia del dato de esta direcci´n en esta otra direcci´n˃˃, ˂˂averigua si la cantidad o o almacenada en determinada direcci´n es negativa˃˃, etc. Las instrucciones se representan o mediante combinaciones particulares de unos y ceros (valores binarios) y, por tanto, se pueden almacenar en la memoria. Combinando inteligentemente las instrucciones en una secuencia podemos hacer que la CPU ejecute c´lculos m´s complejos. Una secuencia de instrucciones es un programa. a a Si hay una instrucci´n para multiplicar pero ninguna para elevar un n´mero al cubo, poo u demos construir un programa que efect´e este ultimo c´lculo a partir de las instrucciones u a ´ disponibles. He aqu´ grosso modo, una secuencia de instrucciones que calcula el cubo a ı, partir de productos: 1. Toma el n´mero y multipl´ u ıcalo por s´ mismo. ı 2. Multiplica el resultado de la ultima operaci´n por el n´mero original. o u ´ Las secuencias de instrucciones que el ordenador puede ejecutar reciben el nombre de programas en c´digo de m´quina, porque el lenguaje de programaci´n en el que est´n o a o a expresadas recibe el nombre de c´digo de m´quina. Un lenguaje de programaci´n es o a o cualquier sistema de notaci´n que permite expresar programas. o 1.3.1. C´digo de m´quina o a El c´digo de m´quina codifica las secuencias de instrucciones como sucesiones de unos o a y ceros que siguen ciertas reglas. Cada familia de ordenadores dispone de su propio repertorio de instrucciones, es decir, de su propio c´digo de m´quina. o a Un programa que, por ejemplo, calcula la media de tres n´meros almacenados en las u posiciones de memoria 10, 11 y 12, respectivamente, y deja el resultado en la posici´n o de memoria 13, podr´ tener el siguiente aspecto expresado de forma comprensible para ıa nosotros: 1 2 3 4 Memoria Sumar contenido de direcciones 10 y 11 y dejar resultado en direcci´n 13 o Sumar contenido de direcciones 13 y 12 y dejar resultado en direcci´n 13 o Dividir contenido de direcci´n 13 por 3 y dejar resultado en direcci´n 13 o o Detener En realidad, el contenido de cada direcci´n estar´ codificado como una serie de unos o ıa y ceros, as´ que el aspecto real de un programa como el descrito arriba podr´ ser ´ste: ı ıa e 1 2 3 4 . . . Memoria 10101011 00001010 00001011 00001101 10101011 00001101 00001100 00001101 00001110 00001101 00000011 00001101 00000000 00000000 00000000 00000000 Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o Unidad Central de Proceso (CPU) Unidad de Control 10 10 Unidad Aritm´tico-L´gica e o Introducción a la programación con Python - UJI c UJI
    • La CPU es un ingenioso sistema de circuitos electr´nicos capaz de interpretar el o significado de cada una de esas secuencias de bits y llevar a cabo las acciones que codifican. Cuando la CPU ejecuta el programa empieza por la instrucci´n contenida en o la primera de sus posiciones de memoria. Una vez ha ejecutado una instrucci´n, pasa a o la siguiente, y sigue as´ hasta encontrar una instrucci´n que detenga la ejecuci´n del ı o o programa. Supongamos que en las direcciones de memoria 10, 11 y 12 se han almacenado los valores 5, 10 y 6, respectivamente. Representamos as´ la memoria: ı 1 2 3 4 .. . 10 11 12 .. . Memoria Sumar contenido de direcciones 10 y 11 y dejar resultado en direcci´n 13 o Sumar contenido de direcciones 13 y 12 y dejar resultado en direcci´n 13 o Dividir contenido de direcci´n 13 por 3 y dejar resultado en direcci´n 13 o o Detener .. . 5 10 6 .. . Naturalmente, los valores de las posiciones 10, 11 y 12 estar´n codificados en binario, a aunque hemos optado por representarlos en base 10 en aras de una mayor claridad. La ejecuci´n del programa procede del siguiente modo. En primer lugar, se ejecuta la o instrucci´n de la direcci´n 1, que dice que tomemos el contenido de la direcci´n 10 (el o o o valor 5), lo sumemos al de la direcci´n 11 (el valor 10) y dejemos el resultado (el valor 15) o en la direcci´n de memoria 13. Tras ejecutar esta primera instrucci´n, la memoria queda o o as´ ı: Memoria 1 2 3 4 .. . 10 11 12 13 .. . Sumar contenido de direcciones 10 y 11 y dejar resultado en direcci´n 13 o Sumar contenido de direcciones 13 y 12 y dejar resultado en direcci´n 13 o Dividir contenido de direcci´n 13 por 3 y dejar resultado en direcci´n 13 o o Detener .. . 5 10 6 15 .. . 1 2 3 4 .. . 10 11 12 13 .. . Sumar contenido de direcciones 10 y 11 y dejar resultado en direcci´n 13 o Sumar contenido de direcciones 13 y 12 y dejar resultado en direcci´n 13 o Dividir contenido de direcci´n 13 por 3 y dejar resultado en direcci´n 13 o o Detener .. . 5 10 6 21 .. . A continuaci´n, se ejecuta la instrucci´n de la direcci´n 2, que ordena que se tome el o o o contenido de la direcci´n 13 (el valor 15), se sume al contenido de la direcci´n 12 (el o o valor 6) y se deposite el resultado (el valor 21) en la direcci´n 13. La memoria pasa a o quedar en este estado. Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Memoria 11 11 Introducción a la programación con Python - cUJI UJI
    • Ahora, la tercera instrucci´n dice que hemos de tomar el valor de la direcci´n 13 (el valor o o 21), dividirlo por 3 y depositar el resultado (el valor 7) en la direcci´n 13. Este es el o estado en que queda la memoria tras ejecutar la tercera instrucci´n: o 1 2 3 4 .. . 10 11 12 13 .. . Memoria Sumar contenido de direcciones 10 y 11 y dejar resultado en direcci´n 13 o Sumar contenido de direcciones 13 y 12 y dejar resultado en direcci´n 13 o Dividir contenido de direcci´n 13 por 3 y dejar resultado en direcci´n 13 o o Detener .. . 5 10 6 7 .. . Y finalmente, la CPU detiene la ejecuci´n del programa, pues se encuentra con la inso trucci´n Detener en la direcci´n 4. o o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 6 Ejecuta paso a paso el mismo programa con los valores 2, −2 y 0 en las posiciones de memoria 10, 11 y 12, respectivamente. · 7 Dise˜a un programa que calcule la media de cinco n´meros depositados en las n u posiciones de memoria que van de la 10 a la 14 y que deje el resultado en la direcci´n o ¯ de memoria 15. Recuerda que la media x de cinco n´meros x1 , x2 , x3 , x4 y x5 es u ¯ x= 5 i=1 xi 5 = x1 + x2 + x3 + x4 + x5 . 5 · 8 Dise˜a un programa que calcule la varianza de cinco n´meros depositados en las n u posiciones de memoria que van de la 10 a la 14 y que deje el resultado en la direcci´n o de memoria 15. La varianza, que se denota con σ 2 , es σ2 = 5 i=1 (xi 5 ¯ − x )2 , ¯ donde x es la media de los cinco valores. Sup´n que existe una instrucci´n ˂˂Multiplicar el o o contenido de direcci´n a por el contenido de direcci´n b y dejar el resultado en direcci´n o o o c˃˃. .................................................................................. ¿Qu´ instrucciones podemos usar para confeccionar programas? Ya hemos dicho que e el ordenador s´lo sabe ejecutar instrucciones muy sencillas. En nuestro ejemplo, s´lo o o hemos utilizado tres instrucciones distintas: una instrucci´n de suma de la forma ˂˂Sumar contenido de direcciones p y o q y dejar resultado en direcci´n r˃˃; o una instrucci´n de divisi´n de la forma ˂˂Dividir contenido de direcci´n p o o o por q y dejar resultado en direcci´n r˃˃; o y una instrucci´n que indica que se ha llegado al final del programa: Detener. o ¡Pocos programas interesantes podemos hacer con tan s´lo estas tres instrucciones! Nao turalmente, en un c´digo de m´quina hay instrucciones que permiten efectuar sumas, o a restas, divisiones y otras muchas operaciones. Y hay, adem´s, instrucciones que permiten a escoger qu´ instrucci´n se ejecutar´ a continuaci´n, bien directamente, bien en funci´n e o a o o de si se cumple o no determinada condici´n (por ejemplo, ˂˂Si el ´ltimo resultado o u es negativo, pasar a ejecutar la instrucci´n de la posici´n p˃˃). o o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 12 12 Introducción a la programación con Python - UJIUJI c
    • 1.3.2. Lenguaje ensamblador En los primeros tiempos de la inform´tica los programas se introduc´ en el ordenador a ıan directamente en c´digo de m´quina, indicando uno por uno el valor de los bits de cada una o a de las posiciones de memoria. Para ello se insertaban manualmente cables en un panel de conectores: cada cable insertado en un conector representaba un uno y cada conector sin cable representaba un cero. Como puedes imaginar, programar as´ un computador ı resultaba una tarea ardua, extremadamente tediosa y propensa a la comisi´n de errores. o El m´s m´ a ınimo fallo conduc´ a un programa incorrecto. Pronto se dise˜aron notaciones ıa n que simplificaban la programaci´n: cada instrucci´n de c´digo de m´quina se representaba o o o a mediante un c´digo mnemot´cnico, es decir, una abreviatura f´cilmente identificable con o e a el prop´sito de la instrucci´n. o o Por ejemplo, el programa desarrollado antes se podr´ representar como el siguiente ıa texto: SUM #10, #11, #13 SUM #13, #12, #13 DIV #13, 3, #13 FIN En este lenguaje la palabra SUM representa la instrucci´n de sumar, DIV la de dividir y o FIN representa la instrucci´n que indica que debe finalizar la ejecuci´n del programa. La o o almohadilla (#) delante de un n´mero indica que deseamos acceder al contenido de la u posici´n de memoria cuya direcci´n es dicho n´mero. Los caracteres que representan el o o u programa se introducen en la memoria del ordenador con la ayuda de un teclado y cada letra se almacena en una posici´n de memoria como una combinaci´n particular de unos o o y ceros (su c´digo ASCII, por ejemplo). o Pero, ¿c´mo se puede ejecutar ese tipo de programa si la secuencia de unos y ceros o que la describe como texto no constituye un programa v´lido en c´digo de m´quina? Con a o a la ayuda de otro programa: el ensamblador. El ensamblador es un programa traductor que lee el contenido de las direcciones de memoria en las que hemos almacenado c´digos o mnemot´cnicos y escribe en otras posiciones de memoria sus instrucciones asociadas en e c´digo de m´quina. o a El repertorio de c´digos mnemot´cnicos traducible a c´digo de m´quina y las reglas o e o a que permiten combinarlos, expresar direcciones, codificar valores num´ricos, etc., recibe e el nombre de lenguaje ensamblador, y es otro lenguaje de programaci´n. o 1.3.3. ¿Un programa diferente para cada ordenador? Cada CPU tiene su propio juego de instrucciones y, en consecuencia, un c´digo de o maquina y uno o m´s lenguajes ensambladores propios. Un programa escrito para una a CPU de la marca Intel no funcionar´ en una CPU dise˜ada por otro fabricante, como a n Motorola3 . ¡Incluso diferentes versiones de una misma CPU tienen juegos de instrucciones que no son totalmente compatibles entre s´ los modelos m´s evolucionados de una familia ı!: a de CPU pueden incorporar instrucciones que no se encuentran en los m´s antiguos4 . a Si queremos que un programa se ejecute en m´s de un tipo de ordenador, ¿habr´ que a a escribirlo de nuevo para cada CPU particular? Durante mucho tiempo se intent´ definir o alg´n tipo de ˂˂lenguaje ensamblador universal˃˃, es decir, un lenguaje cuyos c´digos u o A menos que la CPU se haya dise˜ado expresamente para reproducir el funcionamiento de la primera, n como ocurre con los procesadores de AMD, dise˜ados con el objetivo de ejecutar el c´digo de m´quina de n o a los procesadores de Intel. 4 Por ejemplo, a˜adiendo instrucciones que faciliten la programaci´n de aplicaciones multimedia (como n o ocurre con los Intel Pentium MMX y modelos posteriores) impensables cuando se dise˜´ la primera CPU de no la familia (el Intel 8086). 3 Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 13 13 Introducción a la programación con Python - UJI c UJI
    • ¡Hola, mundo! Nos gustar´ mostrarte el aspecto de los programas escritos en lenguajes ensambladores ıa reales con un par de ejemplos. Es una tradici´n ilustrar los diferentes lenguajes de o programaci´n con un programa sencillo que se limita a mostrar por pantalla el mensaje o ˂˂Hello, World!˃˃ (˂˂¡Hola, mundo!˃˃), as´ que la seguiremos. He aqu´ ese programa escrito ı ı en los lenguajes ensambladores de dos CPU distintas: a mano izquierda, el de los procesadores 80x86 de Intel (cuyo ultimo representante por el momento es el Pentium ´ 4) y a mano derecha, el de los procesadores de la familia Motorola 68000 (que es el procesador de los primeros ordenadores Apple Macintosh). start: .data move.l #msg,-(a7) msg: .string "Hello, World!n" move.w #9,-(a7) trap #1 len: addq.l #6,a7 .long . - msg move.w #1,-(a7) .text trap #1 .globl _start addq.l #2,a7 _start: clr -(a7) push $len trap #1 push $msg msg: dc.b "Hello, World!",10,13,0 push $1 movl $0x4, %eax call _syscall addl $12, %esp push $0 movl $0x1, %eax call _syscall _syscall: int $0x80 ret Como puedes ver, ambos programas presentan un aspecto muy diferente. Por otra parte, los dos son bastante largos (entre 10 y 20 l´ ıneas) y de dif´ comprensi´n. ıcil o mnemot´cnicos, sin corresponderse con los del c´digo de m´quina de ning´n ordenador e o a u concreto, fuesen f´cilmente traducibles al c´digo de m´quina de cualquier ordenador. a o a Disponer de dicho lenguaje permitir´ escribir los programas una sola vez y ejecutarlos ıa en diferentes ordenadores tras efectuar las correspondientes traducciones a cada c´digo o de m´quina con diferentes programas ensambladores. a Si bien la idea es en principio interesante, presenta serios inconvenientes: Un lenguaje ensamblador universal no puede tener en cuenta c´mo se dise˜ar´n oro n a denadores en un futuro y qu´ tipo de instrucciones soportar´n, as´ que posiblemente e a ı quede obsoleto en poco tiempo. Programar en lenguaje ensamblador (incluso en ese supuesto lenguaje ensamblador universal) es complicad´ ısimo por los numerosos detalles que deben tenerse en cuenta. Adem´s, puestos a dise˜ar un lenguaje de programaci´n general, ¿por qu´ no utilizar a n o e un lenguaje natural, es decir un lenguaje como el castellano o el ingl´s? Programar un e computador consistir´ simplemente, en escribir (¡o pronunciar frente a un micr´fono!) ıa, o un texto en el que indic´semos qu´ deseamos que haga el ordenador usando el mismo a e lenguaje con que nos comunicamos con otras personas. Un programa inform´tico podr´ a ıa encargarse de traducir nuestras frases al c´digo de m´quina, del mismo modo que un o a programa ensamblador traduce lenguaje ensamblador a c´digo de m´quina. Es una idea o a atractiva, pero que queda lejos de lo que sabemos hacer por varias razones: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 14 14 Introducción a la programación con Python - cUJI UJI
    • La complejidad intr´ ınseca de las construcciones de los lenguajes naturales dificulta enormemente el an´lisis sint´ctico de las frases, es decir, comprender su estructura a a y c´mo se relacionan entre s´ los diferentes elementos que las constituyen. o ı 1.3.4. El an´lisis sem´ntico, es decir, la comprensi´n del significado de las frases, es a a o a´n m´s complicado. Las ambig¨edades e imprecisiones del lenguaje natural hacen u a u que sus frases presenten, f´cilmente, diversos significados, aun cuando las podaa mos analizar sint´cticamente. (¿Cu´ntos significados tiene la frase ˂˂Trabaja en un a a banco.˃˃?) Sin una buena comprensi´n del significado no es posible efectuar una o traducci´n aceptable. o Lenguajes de programaci´n de alto nivel o Hay una soluci´n intermedia: podemos dise˜ar lenguajes de programaci´n que, sin ser tan o n o potentes y expresivos como los lenguajes naturales, eliminen buena parte de la complejidad propia de los lenguajes ensambladores y est´n bien adaptados al tipo de problemas e que podemos resolver con los computadores: los denominados lenguajes de programaci´n o de alto nivel. El calificativo ˂˂de alto nivel˃˃ se˜ala su independencia de un ordenador n concreto. Por contraposici´n, los c´digos de m´quina y los lenguajes ensambladores se o o a denominan lenguajes de programaci´n de bajo nivel. o He aqu´ el programa que calcula la media de tres n´meros en un lenguaje de alto ı u nivel t´ ıpico (Python): a = 5 b = 10 c = 6 media = (a + b + c) / 3 Las tres primeras l´ ıneas definen los tres valores y la cuarta calcula la media. Como puedes ver, resulta mucho m´s legible que un programa en c´digo de m´quina o en un lenguaje a o a ensamblador. Para cada lenguaje de alto nivel y para cada CPU se puede escribir un programa que se encargue de traducir las instrucciones del lenguaje de alto nivel a instrucciones de c´digo de m´quina, con lo que se consigue la deseada independencia de los programas con o a respecto a los diferentes sistemas computadores. S´lo habr´ que escribir una versi´n del o a o programa en un lenguaje de programaci´n de alto nivel y la traducci´n de ese programa o o al c´digo de m´quina de cada CPU se realizar´ autom´ticamente. o a a a 1.3.5. Compiladores e int´rpretes e Hemos dicho que los lenguajes de alto nivel se traducen autom´ticamente a c´digo de a o m´quina, s´ pero has de saber que hay dos tipos diferentes de traductores dependiendo a ı, de su modo de funcionamiento: compiladores e int´rpretes. e Un compilador lee completamente un programa en un lenguaje de alto nivel y lo traduce en su integridad a un programa de c´digo de m´quina equivalente. El programa o a de c´digo de m´quina resultante se puede ejecutar cuantas veces se desee, sin necesidad o a de volver a traducir el programa original. Un int´rprete act´a de un modo distinto: lee un programa escrito en un lenguaje de e u alto nivel instrucci´n a instrucci´n y, para cada una de ellas, efect´a una traducci´n a o o u o las instrucciones de c´digo de m´quina equivalentes y las ejecuta inmediatamente. No o a hay un proceso de traducci´n separado por completo del de ejecuci´n. Cada vez que o o ejecutamos el programa con un int´rprete, se repite el proceso de traducci´n y ejecuci´n, e o o ya que ambos son simult´neos. a Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 15 15 Introducción a la programación con Python - UJI c UJI
    • Compiladores e int´rpretes. . . de idiomas e Puede resultarte de ayuda establecer una analog´ entre compiladores e int´rpretes de ıa e lenguajes de programaci´n y traductores e int´rpretes de idiomas. o e Un compilador act´a como un traductor que recibe un libro escrito en un idioma u determinado (lenguaje de alto nivel) y escribe un nuevo libro que, con la mayor fidelidad posible, contiene una traducci´n del texto original a otro idioma (c´digo de m´quina). o o a El proceso de traducci´n (compilaci´n) tiene lugar una sola vez y podemos leer el libro o o (ejecutar el programa) en el idioma destino (c´digo de m´quina) cuantas veces queramos. o a Un int´rprete de programas act´a como su hom´nimo en el caso de los idiomas. Sup´n e u o o que se imparte una conferencia en ingl´s en diferentes ciudades y un int´rprete ofrece e e su traducci´n simult´nea al castellano. Cada vez que la conferencia es pronunciada, o a el int´rprete debe realizar nuevamente la traducci´n. Es m´s, la traducci´n se produce e o a o sobre la marcha, frase a frase, y no de un tir´n al final de la conferencia. Del mismo modo o act´a un int´rprete de un lenguaje de programaci´n: traduce cada vez que ejecutamos u e o el programa y adem´s lo hace instrucci´n a instrucci´n. a o o Por regla general, los int´rpretes ejecutar´n los programas m´s lentamente, pues e a a al tiempo de ejecuci´n del c´digo de m´quina se suma el que consume la traducci´n o o a o simult´nea. Adem´s, un compilador puede examinar el programa de alto nivel abarcando a a m´s de una instrucci´n cada vez, por lo que es capaz de producir mejores traducciones. a o Un programa interpretado suele ser mucho m´s lento que otro equivalente que haya sido a compilado (¡t´ ıpicamente entre 2 y 100 veces m´s lento!). a Si tan lento resulta interpretar un programa, ¿por qu´ no se usan unicamente compie ´ ladores? Es pronto para que entiendas las razones, pero, por regla general, los int´rpretes e permiten una mayor flexibilidad que los compiladores y ciertos lenguajes de programaci´n o de alto nivel han sido dise˜ados para explotar esa mayor flexibilidad. Otros lenguajes n de programaci´n, por contra, sacrifican la flexibilidad en aras de una mayor velocidad o de ejecuci´n. Aunque nada impide que compilemos o interpretemos cualquier lenguaje de o programaci´n, ciertos lenguajes se consideran apropiados para que la traducci´n se lleve o o a cabo con un compilador y otros no. Es m´s apropiado hablar, pues, de lenguajes de a programaci´n t´ o ıpicamente interpretados y lenguajes de programaci´n t´ o ıpicamente compilados. Entre los primeros podemos citar Python, BASIC, Perl, Tcl, Ruby, Bash, Java o Lisp. Entre los segundos, C, C#, Pascal, C++ o Fortran. En este curso aprenderemos a programar usando dos lenguajes de programaci´n diso tintos: uno interpretado, Python, y otro compilado, C. Este volumen se dedica al lenguaje de programaci´n con Python. Otro volumen de la misma colecci´n se dedica al estudio o o de C, pero partiendo de la base de que ya se sabe programar con Python. 1.3.6. Python Existen muchos otros lenguajes de programaci´n, ¿por qu´ aprender Python? Python o e presenta una serie de ventajas que lo hacen muy atractivo, tanto para su uso profesional como para el aprendizaje de la programaci´n. Entre las m´s interesantes desde el punto o a de vista did´ctico tenemos: a Python es un lenguaje muy expresivo, es decir, los programas Python son muy compactos: un programa Python suele ser bastante m´s corto que su equivalente a en lenguajes como C. (Python llega a ser considerado por muchos un lenguaje de programaci´n de muy alto nivel.) o Python es muy legible. La sintaxis de Python es muy elegante y permite la escritura de programas cuya lectura resulta m´s f´cil que si utiliz´ramos otros lenguajes de a a a programaci´n. o Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 16 16 Introducción a la programación con Python - c UJI UJI
    • Python ofrece un entorno interactivo que facilita la realizaci´n de pruebas y ayuda o a despejar dudas acerca de ciertas caracter´ ısticas del lenguaje. El entorno de ejecuci´n de Python detecta muchos de los errores de programaci´n o o que escapan al control de los compiladores y proporciona informaci´n muy rica o para detectarlos y corregirlos. Python puede usarse como lenguaje imperativo procedimental o como lenguaje orientado a objetos. Posee un rico juego de estructuras de datos que se pueden manipular de modo sencillo. Estas caracter´ ısticas hacen que sea relativamente f´cil traducir m´todos de c´lculo a a e a programas Python. Python ha sido dise˜ado por Guido van Rossum y est´ en un proceso de continuo n a desarrollo por una gran comunidad de desarrolladores. Aproximadamente cada seis meses se hace p´blica una nueva versi´n de Python. ¡Tranquilo! No es que cada medio a˜o se u o n cambie radicalmente el lenguaje de programaci´n, sino que ´ste se enriquece manteniendo o e en lo posible la compatibilidad con los programas escritos para versiones anteriores. Nosotros utilizaremos caracter´ ısticas de la versi´n 2.3 de Python, por lo que deber´s o a utilizar esa versi´n o una superior. o Una ventaja fundamental de Python es la gratuidad de su int´rprete. Puedes descare gar el int´rprete de la p´gina web http://www.python.org. El int´rprete de Python e a e tiene versiones para pr´cticamente cualquier plataforma en uso: sistemas PC bajo Linux, a sistemas PC bajo Microsoft Windows, sistemas Macintosh de Apple, etc. Para que te vayas haciendo a la idea de qu´ aspecto presenta un programa completo e en Python, te presentamos uno que calcula la media de tres n´meros que introduce por u teclado el usuario y muestra el resultado por pantalla: a = float(raw_input(’Dame un n´mero:’)) u b = float(raw_input(’Dame otro n´mero:’)) u c = float(raw_input(’Y ahora, uno m´s:’)) a media = (a + b + c) / 3 print ’La media es’, media En los ultimos a˜os Python ha experimentado un important´ n ısimo aumento del n´mero u ´ de programadores y empresas que lo utilizan. Aqu´ tienes unas citas que han encabezado ı durante alg´n tiempo la web oficial de Python (http://www.python.org): u Python ha sido parte importante de Google desde el principio, y lo sigue siendo a medida que el sistema crece y evoluciona. Hoy d´ docenas de ıa, ingenieros de Google usan Python y seguimos buscando gente diestra en este lenguaje. PETER NORVIG, director de calidad de b´squedas de Google Inc. u Python juega un papel clave en nuestra cadena de producci´n. Sin ´l, un proo e yecto de la envergadura de ˂˂Star Wars: Episodio II˃˃ hubiera sido muy dif´ ıcil de sacar adelante. Visualizaci´n de multitudes, proceso de lotes, composici´n o o de escenas. . . Python es lo que lo une todo. TOMMY BRUNETTE, director t´cnico senior de Industrial Light & Magic . e Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 17 17 Introducción a la programación con Python - UJI c UJI
    • Python est´ en todas partes de Industrial Light & Magic. Se usa para extender a la capacidad de nuestras aplicaciones y para proporcionar la cola que las une. Cada imagen generada por computador que creamos incluye a Python en alg´n punto del proceso. u PHILIP PETERSON, ingeniero principal de I+D de Industrial Light & Magic. 1.3.7. C El lenguaje de programaci´n C es uno de los m´s utilizados en el mundo profesional. La o a mayor´ de las aplicaciones comerciales y libres se han desarrollado con el lenguaje de ıa programaci´n C. El sistema operativo Linux, por ejemplo, se ha desarrollado en C en su o pr´ctica totalidad. a ¿Por qu´ es tan utilizado el lenguaje C? C es un lenguaje de prop´sito general e o que permite controlar con gran precisi´n los factores que influyen en la eficiencia de o los programas. Pero esta capacidad de control ˂˂fino˃˃ que ofrece C tiene un precio: la escritura de programas puede ser mucho m´s costosa, pues hemos de estar pendientes a de numerosos detalles. Tan es as´ que muchos programadores afirman que C no es un ı lenguaje de alto nivel, sino de nivel intermedio. ¡Hola de nuevo, mundo! Te presentamos los programas ˂˂¡Hola, mundo!˃˃ en Python (izquierda) y C (derecha). print ’Hello, world!’ #include <stdio.h> int main(void) { printf("Hello, world!n"); return 0; } Como puedes comprobar, Python parece ir directamente al problema: una sola l´ ınea. Empezaremos aprendiendo Python. Aqu´ tienes una version en C del c´lculo de la media de tres n´meros le´ ı a u ıdos por teclado: #include <stdio.h> int main(void) { double a, b, c, media; printf("Dame un n´mero: "); u scanf("%lf", &a); printf("Dame otro n´mero: "); u scanf("%lf", &b); printf("Y ahora, uno m´s: "); a scanf("%lf", &c); media = (a + b + c) / 3; printf("La media es %fn", media); return 0; } C ha sufrido una evoluci´n desde su dise˜o en los a˜os 70. El C, tal cual fue concebido o n n por sus autores, Brian Kernighan y Dennis Ritchie, de la compa˜´ norteamericana de nıa Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 18 18 Introducción a la programación con Python - UJI c UJI
    • telecomunicaciones AT&T, se conoce popularmente por K&R C y est´ pr´cticamente en a a desuso. En los a˜os 80, C fue modificado y estandarizado por el American National n Standards Institute (ANSI), que dio lugar al denominado ANSI C y que ahora se conoce como C89 por el a˜o en que se public´. El est´ndar se revis´ en los a˜os 90 y se n o a o n incorporaron nuevas caracter´ ısticas que mejoran sensiblemente el lenguaje. El resultado es la segunda edici´n del ANSI C, m´s conocida como C99. Esta es la versi´n que o a o estudiaremos en este curso. En la asignatura utilizaremos un compilador de C gratuito: el gcc en su versi´n 3.2 o o superior. Inicialmente se denomin´ a gcc as´ tomando las siglas de GNU C Compiler. o ı GNU es el nombre de un proyecto que tiene por objeto ofrecer un sistema operativo ˂˂libre˃˃ y todas las herramientas que es corriente encontrar en una plataforma Unix. Hoy d´ se ıa ha popularizado enormemente gracias a la plataforma GNU/Linux, que se compone de un n´cleo de sistema operativo de la familia del Unix (Linux) y numerosas herramientas u desarrolladas como parte del proyecto GNU, entre ellas gcc. La versi´n de gcc que o usaremos no soporta a´n todas las caracter´ u ısticas de C99, pero s´ las que aprenderemos ı en el curso. Cualquier distribuci´n reciente de Linux5 incorpora la versi´n de gcc que utilio o zaremos o una superior. Puedes descargar una versi´n de gcc y las utilidades asoo ciadas para Microsoft Windows en http://www.delorie.com/djgpp. En la p´gina a http://www.bloodshed.net/devcpp.html encontrar´s un entorno integrado (editor a de texto, depurador de c´digo, compilador, etc.) que tambi´n usa el compilador gcc. o e ¡Ojo!, no todos los compiladores soportan algunas caracter´ ısticas de la ultima versi´n o ´ de C, as´ que es posible que experimentes alg´n problema de compatibilidad si utilizas ı u un compilador diferente del que te recomendamos. 1.4. M´s all´ de los programas: algoritmos a a Dos programas que resuelven el mismo problema expresados en el mismo o en diferentes lenguajes de programaci´n pero que siguen, en lo fundamental, el mismo procedimieno to, son dos implementaciones del mismo algoritmo. Un algoritmo es, sencillamente, una secuencia de pasos orientada a la consecuci´n de un objetivo. o Cuando dise˜amos un algoritmo podemos expresarlo en uno cualquiera de los nun merosos lenguajes de programaci´n de prop´sito general existentes. Sin embargo, ello o o resulta poco adecuado: no todos los programadores conocen todos los lenguajes y no hay consenso acerca de cu´l es el m´s adecuado para expresar las soluciones a los diferentes problemas, a a cualquiera de los lenguajes de programaci´n presenta particularidades que pueden o interferir en una expresi´n clara y concisa de la soluci´n a un problema. o o Podemos expresar los algoritmos en lenguaje natural, pues el objetivo es comunicar un procedimiento resolutivo a otras personas y, eventualmente, traducirlos a alg´n lenguaje u de programaci´n. Si, por ejemplo, deseamos calcular la media de tres n´meros le´ o u ıdos de teclado podemos seguir este algoritmo: 1. solicitar el valor del primer n´mero, u 2. solicitar el valor del segundo n´mero, u 3. solicitar el valor del tercer n´mero, u 5 En el momento en que se redact´ este texto, las distribuciones m´s populares y recientes de Linux eran o a SuSE 8.2, RedHat 9, Mandrake 9.1 y Debian Woody. Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 19 19 Introducción a la programación con Python - c UJI UJI
    • La torre de Babel Hemos dicho que los lenguajes de programaci´n de alto nivel pretend´ entre otros o ıan, objetivos, paliar el problema de que cada ordenador utilice su propio c´digo de m´quina. o a Puede que, en consecuencia, est´s sorprendido por el n´mero de lenguajes de prograe u maci´n citados. Pues los que hemos citado son unos pocos de los m´s utilizados: ¡hay o a centenares! ¿Por qu´ tantos? e El primer lenguaje de programaci´n de alto nivel fue Fortran, que se dise˜´ en los o no primeros a˜os 50 (y a´n se utiliza hoy d´ aunque en versiones evolucionadas). Fortran n u ıa, se dise˜´ con el prop´sito de traducir f´rmulas matem´ticas a c´digo de m´quina (de heno o o a o a cho, su nombre proviene de ˂˂FORmula TRANslator˃˃, es decir, ˂˂traductor de f´rmulas˃˃). o Pronto se dise˜aron otros lenguajes de programaci´n con prop´sitos espec´ n o o ıficos: Cobol (Common Business Oriented Language), Lisp (List Processing language), etc. Cada uno de estos lenguajes hac´ f´cil la escritura de programas para solucionar problemas de ıa a ambitos particulares: Cobol para problemas de gesti´n empresarial, Lisp para ciertos o ´ problemas de Inteligencia Artificial, etc. Hubo tambi´n esfuerzos para dise˜ar lenguajes e n de ˂˂prop´sito general˃˃, es decir, aplicables a cualquier dominio, como Algol 60 (Algoo rithmic Language). En la d´cada de los 60 hicieron su aparici´n nuevos lenguajes de e o programaci´n (Algol 68, Pascal, Simula 67, Snobol 4, etc.), pero quiz´ lo m´s notable o a a de esta d´cada fue que se sentaron las bases te´ricas del dise˜o de compiladores e e o n int´rpretes. Cuando la tecnolog´ para el dise˜o de estas herramientas se hizo accesible e ıa n a m´s y m´s programadores hubo un aut´ntico estallido en el n´mero de lenguajes de a a e u programaci´n. Ya en 1969 se hab´ dise˜ado unos 120 lenguajes de programaci´n y se o ıan n o hab´ implementado compiladores o int´rpretes para cada uno de ellos. ıan e La existencia de tant´ ısimos lenguajes de programaci´n cre´ una situaci´n similar a o o o la de la torre de Babel: cada laboratorio o departamento inform´tico usaba un lenguaje a de programaci´n y no hab´ forma de intercambiar programas. o ıa Con los a˜os se ha ido produciendo una selecci´n de aquellos lenguajes de progran o maci´n m´s adecuados para cada tipo de tarea y se han dise˜ado muchos otros que o a n sintetizan lo aprendido de lenguajes anteriores. Los m´s utilizados hoy d´ son C, C++ a ıa , Java, Python, Perl y PHP. Si tienes curiosidad, puedes ver ejemplos del programa ˂˂Hello, world!˃˃ en m´s de a 100 de lenguajes de programaci´n diferentes (y m´s de 400 dialectos) visitando la p´gina o a a http://www.uni-karlsruhe.de/˜uu9r/lang/html/lang-all.en.html 4. sumar los tres n´meros y dividir el resultado por 3, u 1. poner aceite en una sart´n, e 3. calentar el aceite, 5. mostrar el resultado. Como puedes ver, esta secuencia de operaciones define exactamente el proceso que nos permite efectuar el c´lculo propuesto y que ya hemos implementado como programas en a Python y en C. Los algoritmos son independientes del lenguaje de programaci´n. Describen un proo cedimiento que puedes implementar en cualquier lenguaje de programaci´n de prop´sito o o general o, incluso, que puedes ejecutar a mano con l´piz, papel y, quiz´, la ayuda de una a a calculadora. ¡Ojo! No es cierto que cualquier procedimiento descrito paso a paso pueda considerarse un algoritmo. Un algoritmo debe satisfacer ciertas condiciones. Una analog´ con ıa recetas de cocina (procedimientos para preparar platos) te ayudar´ a entender dichas a restricciones. Estudia esta primera receta: 2. encender el fuego, Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 20 20 Introducción a la programación con Python - cUJI UJI
    • 4. 5. 6. coger un huevo, romper la c´scara, a verter el contenido del huevo en la sart´n, e 7. aderezar con sal, 8. esperar a que tenga buen aspecto. En principio ya est´: con la receta, sus ingredientes y los utiles necesarios somos capaces a ´ de cocinar un plato. Bueno, no del todo cierto, pues hay unas cuantas cuestiones que no quedan del todo claras en nuestra receta: ¿Qu´ tipo de huevo utilizamos?: ¿un huevo de gallina?, ¿un huevo de rana? e ¿Cu´nta sal utilizamos?: ¿una pizca?, ¿un kilo? a ¿Cu´nto aceite hemos de verter en la sart´n?: ¿un cent´ a e ımetro c´bico?, ¿un litro? u ¿Cu´l es el resultado del proceso?, ¿la sart´n con el huevo cocinado y el aceite? a e En una receta de cocina hemos de dejar bien claro con qu´ ingredientes contamos y e cu´l es el resultado final. En un algoritmo hemos de precisar cu´les son los datos del a a problema (datos de entrada) y qu´ resultado vamos a producir (datos de salida). e Esta nueva receta corrige esos fallos: Ingredientes: 10 cc. de aceite de oliva, una gallina y una pizca de sal. M´todo: e 1. esperar a que la gallina ponga un huevo, 2. poner aceite en una sart´n, e 3. encender el fuego, 4. calentar el aceite, 5. coger el huevo, 6. romper la c´scara, a 7. verter el contenido del huevo en la sart´n, e 8. aderezar con sal, 9. esperar a que tenga buen aspecto. Presentaci´n: depositar el huevo frito, sin aceite, en un plato. o Pero la receta a´n no est´ bien del todo. Hay ciertas indefiniciones en la receta: u a 1. ¿Cu´n caliente ha de estar el aceite en el momento de verter el huevo?, ¿humeando?, a ¿ardiendo? 2. 3. ¿Cu´nto hay que esperar?, ¿un segundo?, ¿hasta que el huevo est´ ennegrecido? a e Y a´n peor, ¿estamos seguros de que la gallina pondr´ un huevo? Podr´ ocurrir u a ıa que la gallina no pusiera huevo alguno. Para que la receta est´ completa, deber´ e ıamos especificar con absoluta precisi´n cada o uno de los pasos que conducen a la realizaci´n del objetivo y, adem´s, cada uno de ellos o a deber´ ser realizable en tiempo finito. ıa No basta con decir m´s o menos c´mo alcanzar el objetivo: hay que decir exactamente a o c´mo se debe ejecutar cada paso y, adem´s, cada paso debe ser realizable en tiempo o a finito. Esta nueva receta corrige algunos de los problemas de la anterior, pero presenta otros de distinta naturaleza: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 21 21 Introducción a la programación con Python - cUJI UJI
    • Ingredientes: 10 cc. de aceite de oliva, un huevo de gallina y una pizca de sal. M´todo: e 1. poner aceite en una sart´n, e 2. encender el fuego a medio gas, 3. calentar el aceite hasta que humee ligeramente, 4. coger un huevo, 5. romper la c´scara con el poder de la mente, sin tocar el huevo, a 6. 7. 8. verter el contenido del huevo en la sart´n, e aderezar con sal, esperar a que tenga buen aspecto. Presentaci´n: depositar el huevo frito, sin aceite, en un plato. o El quinto paso no es factible. Para romper un huevo has de utilizar algo m´s que ˂˂el a poder de la mente˃˃. En todo algoritmo debes utilizar unicamente instrucciones que pueden ´ llevarse a cabo. He aqu´ una receta en la que todos los pasos son realizables: ı Ingredientes: 10 cc. de aceite de oliva, un huevo de gallina y una pizca de sal. M´todo: e 1. poner aceite en una sart´n, e 4. echar una partida al solitario, 2. sintonizar una emisora musical en la radio, 3. encender el fuego a medio gas, 5. calentar el aceite hasta que humee ligeramente, 6. coger un huevo, 7. romper la c´scara, a 8. verter el contenido del huevo en la sart´n, e 9. aderezar con sal, 10. esperar a que tenga buen aspecto. Presentaci´n: depositar el huevo frito, sin aceite, en un plato. o En esta nueva receta hay acciones que, aunque expresadas con suficiente precisi´n y o siendo realizables, no hacen nada util para alcanzar nuestro objetivo (sintonizar la radio ´ y jugar a cartas). En un algoritmo, cada paso dado debe conducir y acercarnos m´s a la a consecuci´n del objetivo. o Hay una consideraci´n adicional que hemos de hacer, aunque en principio parezca o una obviedad: todo algoritmo bien construido debe finalizar tras la ejecuci´n de un n´mero o u finito de pasos. Aunque todos los pasos sean de duraci´n finita, una secuencia de instrucciones puede o requerir tiempo infinito. Piensa en este m´todo para hacerse millonario: e 1. comprar un n´mero de loter´ v´lido para el pr´ximo sorteo, u ıa a o 2. esperar al d´ de sorteo, ıa 3. cotejar el n´mero ganador con el nuestro, u Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 22 22 Introducción a la programación con Python - cUJI UJI
    • 4. si son diferentes, volver al paso 1; en caso contrario, somos millonarios. Como ves, cada uno de los pasos del m´todo requiere una cantidad finita de tiempo, pero e no hay ninguna garant´ de alcanzar el objetivo propuesto. ıa En adelante, no nos interesar´n m´s las recetas de cocina ni los procedimientos para a a enriquecerse sin esfuerzo (¡al menos no como objeto de estudio de la asignatura!). Los algoritmos en los que estaremos interesados son aquellos que describen procedimientos de c´lculo ejecutables en un ordenador. Ello limitar´ el ambito de nuestro estudio a la a a ´ manipulaci´n y realizaci´n de c´lculos sobre datos (num´ricos, de texto, etc.). o o a e Abu Ja‘far Mohammed ibn Mˆsˆ Al-Khowˆrizm y Euclides u a a La palabra algoritmo tiene origen en el nombre de un matem´tico persa del siglo IX: Abu a Ja‘far Mohammed ibn Mˆsˆ Al-Khowˆrizm (que significa ˂˂Mohammed, padre de Ja‘far, u a a hijo de Moises, nacido en Khowˆrizm˃˃). Al-Khowˆrizm escribi´ tratados de aritm´tica a a o e y algebra. Gracias a los textos de Al-Khowˆrizm se introdujo el sistema de numeraci´n a o ´ hind´ en el mundo arabe y, m´s tarde, en occidente. u a ´ En el siglo XIII se publicaron los libros Carmen de Algorismo (un tratado de aritm´tica e ¡en verso!) y Algorismus Vulgaris, basados en parte en la Aritm´tica de Al-Khowˆrizm. e a Al-Khowˆrizm escribi´ tambi´n el libro ˂˂Kitab al jabr w’al-muqabala˃˃ (˂˂Reglas de a o e restauraci´n y reducci´n˃˃), que dio origen a una palabra que ya conoces: ˂˂´lgebra˃˃. o o a Abelardo de Bath, uno de los primeros traductores al lat´ de Al-Khowˆrizm, emın a pez´ un texto con ˂˂Dixit Algorismi. . . ˃˃ (˂˂Dijo Algorismo. . . ˃˃), popularizando as´ el o ı t´rmino algorismo, que pas´ a significar ˂˂realizaci´n de c´lculos con numerales hindoe o o a ar´bigos˃˃. En la edad media los abaquistas calculaban con abaco y los algorismistas a ´ con ˂˂algorismos˃˃. En cualquier caso, el concepto de algoritmo es muy anterior a Al-Khowˆrizm. En el a siglo III a.C., Euclides propuso en su tratado ˂˂Elementos˃˃ un m´todo sistem´tico para e a el c´lculo del M´ximo Com´n Divisor (MCD) de dos n´meros. El m´todo, tal cual fue a a u u e propuesto por Euclides, dice as´ ˂˂Dados dos n´meros naturales, a y b, comprobar si ı: u ambos son iguales. Si es as´ a es el MCD. Si no, si a es mayor que b, restar a a el ı, valor de b; pero si a es menor que b, restar a b el valor de a. Repetir el proceso con los nuevos valores de a y b˃˃. Este m´todo se conoce como ˂˂algoritmo de Euclides˃˃, e aunque es frecuente encontrar, bajo ese mismo nombre, un procedimiento alternativo y m´s eficiente: ˂˂Dados dos n´meros naturales, a y b, comprobar si b es cero. Si es as´ a u ı, a es el MCD. Si no, calcular c, el resto de dividir a entre b. Sustituir a por b y b por c y repetir el proceso˃˃. 1. 2. Un algoritmo debe poseer las siguientes caracter´ ısticas: Ha de tener cero o m´s datos de entrada. a Debe proporcionar uno o m´s datos de salida como resultado. a 3. Cada paso del algoritmo ha de estar definido con exactitud, sin la menor ambig¨edad. u 5. Debe ser efectivo, es decir, cada uno de sus pasos ha de poder ejecutarse en tiempo finito con unos recursos determinados (en nuestro caso, con los que proporciona un sistema computador). 4. Ha de ser finito, es decir, debe finalizar tras la ejecuci´n de un n´mero finito de o u pasos, cada uno de los cuales ha de ser ejecutable en tiempo finito. Adem´s, nos interesa que los algoritmos sean eficientes, esto es, que alcancen su a objetivo lo m´s r´pidamente posible y con el menor consumo de recursos. a a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 9 Dise˜a un algoritmo para calcular el area de un c´ n ırculo dado su radio. (Recuerda ´ que el area de un c´ ırculo es π veces el cuadrado del radio.) ´ Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 23 23 Introducción a la programación con Python - UJIUJI c
    • · 10 Dise˜a un algoritmo que calcule el IVA (16%) de un producto dado su precio de n venta sin IVA. · 11 ¿Podemos llamar algoritmo a un procedimiento que escriba en una cinta de papel todos los n´meros decimales de π? u .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 24 24 Introducción a la programación con Python - UJIUJI c
    • Cap´ ıtulo 2 Una calculadora avanzada ¿Sabes sumar? le pregunt´ la Reina Blanca. ¿Cu´nto es uno m´s uno o a a m´s uno m´s uno m´s uno m´s uno m´s uno m´s uno m´s uno m´s uno m´s a a a a a a a a a uno? No lo s´ dijo Alicia. Perd´ la cuenta. e ı No sabe hacer una adici´n le interrumpi´ la Reina Roja. o o LEWIS CARROLL, Alicia a trav´s del espejo. e El objetivo de este tema es que te familiarices con el entorno interactivo de Python, que aprendas a construir expresiones aritm´ticas almacenando los resultados en variae bles mediante asignaciones y que conozcas los tipos de datos b´sicos del lenguaje de a programaci´n Python. o 2.1. Sesiones interactivas Cuando programamos utilizamos un conjunto de herramientas al que denominamos entorno de programaci´n. Entre estas herramientas tenemos editores de texto (que nos permiten o escribir programas), compiladores o int´rpretes (que traducen los programas a c´digo e o de m´quina), depuradores (que ayudan a detectar errores), analizadores de tiempo de a ejecuci´n (para estudiar la eficiencia de los programas), etc. o Los lenguajes interpretados suelen ofrecer una herramienta de ejecuci´n interactiva. o Con ella es posible dar ´rdenes directamente al int´rprete y obtener una respuesta ino e mediata para cada una de ellas. Es decir, no es necesario escribir un programa completo para empezar a obtener resultados de ejecuci´n, sino que podemos ˂˂dialogar˃˃ con el o int´rprete de nuestro lenguaje de programaci´n: le pedimos que ejecute una orden y nos e o responde con su resultado. El entorno interactivo es de gran ayuda para experimentar con fragmentos de programa antes de incluirlos en una versi´n definitiva. En esta secci´n o o veremos c´mo realizar sesiones de trabajo interactivo con Python.1 o Si hemos instalado Python en nuestro ordenador podemos iniciar una sesi´n de o trabajo escribiendo python en la l´ ınea de ´rdenes Unix.2 El sistema nos responder´ o a dando un mensaje informativo sobre la versi´n de Python que estamos utilizando (y o cu´ndo fue compilada, con qu´ compilador, etc.) y, a continuaci´n, mostrar´ el prompt: a e o a ↱ $ python Python 2.3 (#1, Aug 2 2003, 12:14:49) 1 Abusando del lenguaje, llamaremos indistintamente Python al entorno de programaci´n, al int´rprete o e del lenguaje y al propio lenguaje de programaci´n. o 2 En el entorno Microsoft Windows puedes arrancar el int´rprete interactivo activando el icono correspone diente (que es una caricatura de una serpiente pit´n) o seleccionando el programa desde el men´ ˂˂Inicio˃˃. o u Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 25 25 Introducción a la programación con Python - UJI
    • [GCC 3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> El prompt es la serie de caracteres ˂˂>>>˃˃ que aparece en la ultima l´ ınea. El prompt ´ indica que el int´rprete de Python espera que nosotros introduzcamos una orden utilie zando el teclado. La orden Unix python Hemos invocado el entorno interactivo escribiendo python en la l´ ınea de ´rdenes Unix o y pulsando el retorno de carro. Al hacer esto, el entorno de ejecuci´n de ´rdenes Unix o o (al que se suele denominar shell) busca en el ordenador una aplicaci´n llamada python o y la ejecuta. Esa aplicaci´n es un programa que lee una l´ o ınea introducida por teclado, la interpreta como si fuera un fragmento de programa Python y muestra por pantalla el resultado obtenido. (En realidad hace m´s cosas. Ya las iremos viendo.) a Por regla general, la aplicaci´n python reside en /usr/local/bin/ o en o /usr/bin/. Son directorios donde normalmente el shell busca programas. Si al escribir python y dar al retorno de carro no arranca el int´rprete, aseg´rate de que est´ e u a instalado el entorno Python. Si es as´ puedes intentar ejecutar el entorno dando la ruta ı, completa hasta el programa: por ejemplo /usr/local/bin/python. Escribamos una expresi´n aritm´tica, por ejemplo ˂˂2+2˃˃, y pulsemos la tecla de retorno o e de carro. Cuando mostremos sesiones interactivas destacaremos el texto que teclea el usuario con texto sobre fondo gris representaremos con el s´ ımbolo ˂˂ ˃˃ la pulsaci´n de o la tecla de retorno de carro. Python eval´a la expresi´n (es decir, obtiene su resultado) u o y responde mostrando el resultado por pantalla. ↱ ↱ $ python Python 2.3 (#1, Aug 2 2003, 12:14:49) [GCC 3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> 2+2 4 >>> ↱ La ultima l´ ınea es, nuevamente, el prompt: Python acab´ de ejecutar la ultima orden o ´ ´ (evaluar una expresi´n y mostrar el resultado) y nos pide que introduzcamos una nueva o orden. Si deseamos acabar la sesi´n interactiva y salir del int´rprete Python, debemos o e introducir una marca de final de fichero, que en Unix se indica pulsando la tecla de control y, sin soltarla, tambi´n la tecla d. (De ahora en adelante representaremos una e combinaci´n de teclas como la descrita as´ C-d.) o ı: 2.1.1. Los operadores aritm´ticos e Las operaciones de suma y resta, por ejemplo, se denotan con los s´ ımbolos u operadores + y -, respectivamente, y operan sobre dos valores num´ricos (los operandos). Probemos e algunas expresiones formadas con estos dos operadores: ↱ ↱ ↱ >>> 1 + 2 3 >>> 1 + 2 + 3 6 >>> 1 - 2 + 3 2 Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 26 26 Introducción a la programación con Python - UJI c UJI
    • Final de fichero La ˂˂marca de final de fichero˃˃ indica que un fichero ha terminado. ¡Pero nosotros no trabajamos con un fichero, sino con el teclado! En realidad, el ordenador considera al teclado como un fichero. Cuando deseamos ˂˂cerrar el teclado˃˃ para una aplicaci´n, o enviamos una marca de final de fichero desde el teclado. En Unix, la marca de final de fichero se env´ pulsando C-d; en MS-DOS o Microsoft Windows, pulsando C-z. ıa Existe otro modo de finalizar la sesi´n; escribe o ↱ >>> from sys import exit >>> exit() ↱ En ingl´s, ˂˂exit˃˃ significa ˂˂salir˃˃. S´ pero, ¿qu´ significa ˂˂from sys import exit˃˃ y e ı e por qu´ hay un par de par´ntesis detr´s de la palabra ˂˂exit˃˃ en la segunda l´ e e a ınea? M´s a adelante lo averiguaremos. Observa que puedes introducir varias operaciones en una misma l´ ınea o expresi´n. o El orden en que se efect´an las operaciones es (en principio) de izquierda a derecha. u La expresi´n 1 - 2 + 3, por ejemplo, equivale matem´ticamente a ((1 − 2) + 3); por ello o a decimos que la suma y la resta son operadores asociativos por la izquierda. Podemos representar gr´ficamente el orden de aplicaci´n de las operaciones utilia o zando arboles sint´cticos. Un arbol sint´ctico es una representaci´n gr´fica en la que a a o a ´ ´ disponemos los operadores y los operandos como nodos y en los que cada operador est´ a conectado a sus operandos. El arbol sint´ctico de la expresi´n ˂˂1 - 2 + 3˃˃ es ´ste: a o e ´ + 3 1 2 El nodo superior de un arbol recibe el nombre de nodo ra´ Los nodos etiquetados ız. ´ con operadores (representados con c´ ırculos) se denominan nodos interiores. Los nodos interiores tienen uno o m´s nodos hijo o descendientes (de los que ellos son sus resa pectivos nodos padre o ascendientes). Dichos nodos son nodos ra´ de otros (sub)´rboles ız a sint´cticos (¡la definici´n de arbol sint´ctico es auto-referencial!). Los valores resultantes a o a ´ de evaluar las expresiones asociadas a dichos (sub)´rboles constituyen los operandos de a la operaci´n que representa el nodo interior. Los nodos sin descendientes se denomio nan nodos terminales u hojas (representados con cuadrados) y corresponden a valores num´ricos. e La evaluaci´n de cada operaci´n individual en el arbol sint´ctico ˂˂fluye˃˃ de las hojas o o a ´ hacia la ra´ (el nodo superior); es decir, en primer lugar se eval´a la subexpresi´n ˂˂1 - 2˃˃, ız u o que corresponde al sub´rbol m´s profundo. El resultado de la evaluaci´n es −1: a a o + −1 1 3 2 A continuaci´n se eval´a la subexpresi´n que suma el resultado de evaluar ˂˂1 - 2˃˃ al o u o valor 3: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 27 27 Introducción a la programación con Python - cUJI UJI
    • 2 + −1 - 3 1 2 As´ se obtiene el resultado final: el valor 2. ı Si deseamos calcular (1−(2+3)) podemos hacerlo a˜adiendo par´ntesis a la expresi´n n e o aritm´tica: e ↱ >>> 1 - (2 + 3) -4 El arbol sint´ctico de esta nueva expresi´n es a o ´ - 1 + 2 3 En este nuevo arbol, la primera subexpresi´n evaluada es la que corresponde al sub´rbol o a ´ derecho. Observa que en el arbol sint´ctico no aparecen los par´ntesis de la expresi´n. El arbol a e o ´ ´ sint´ctico ya indica el orden en que se procesan las diferentes operaciones y no necesita a par´ntesis. La expresi´n Python, sin embargo, necesita los par´ntesis para indicar ese e o e mismo orden de evaluaci´n. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 12 ¿Qu´ expresiones Python permiten, utilizando el menor n´mero posible de par´ntesis, e u e efectuar en el mismo orden los c´lculos representados con estos arboles sint´cticos? a a ´ + 4 - 2 1 + 3 + 1 + 1 a) 2 + 2 3 + 3 4 b) 4 c) · 13 Dibuja los arboles sint´cticos correspondientes a las siguientes expresiones arita ´ m´ticas: e a) 1 + 2 + 3 + 4 b) 1 - 2 - 3 - 4 c) 1 - (2 - (3 - 4) + 1) .................................................................................. Los operadores de suma y resta son binarios, es decir, operan sobre dos operandos. El mismo s´ ımbolo que se usa para la resta se usa tambi´n para un operador unario, es decir, e un operador que act´a sobre un unico operando: el de cambio de signo, que devuelve el u ´ valor de su operando cambiado de signo. He aqu´ algunos ejemplos: ı Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 2828 Introducción a la programación con Python - UJIUJI c
    • Espacios en blanco Parece que se puede hacer un uso bastante liberal de los espacios en blanco en una expresi´n. o 10 + 20 + 30 +20 + 30 ↱ 10+ 20+30 ↱ 10 ↱ 10+20+30 ↱ >>> 60 >>> 60 >>> 60 >>> 60 Es as´ Has de respetar, no obstante, unas reglas sencillas: ı. No puedes poner espacios en medio de un n´mero. u ↱ >>> 10 + 2 0 + 30 Los espacios en blanco entre el 2 y el 0 hacen que Python no lea el n´mero 20, u sino el n´mero 2 seguido del n´mero 0 (lo cual es un error, pues no hay operaci´n u u o alguna entre ambos n´meros). u No puedes poner espacios al principio de la expresi´n. o 10 + 20 + 30 ↱ >>> Los espacios en blanco entre el prompt y el 10 provocan un error. A´n es pronto u para que conozcas la raz´n. o ↱ ↱ >>> -3 -3 >>> -(1 + 2) -3 >>> --3 3 ↱ He aqu´ los arboles sint´cticos correspondientes a las tres expresiones del ejemplo: ı a ´ + 3 1 - 2 3 Existe otro operador unario que se representa con el s´ ımbolo +: el operador identidad. El operador identidad no hace nada ˂˂´til˃˃: proporciona como resultado el mismo n´mero u u que se le pasa. ↱ ↱ >>> +3 3 >>> +-3 -3 Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 29 29 Introducción a la programación con Python - UJI c UJI
    • El operador identidad s´lo sirve para, en ocasiones, poner ´nfasis en que un n´mero o e u es positivo. (El ordenador considera tan positivo el n´mero 3 como el resultado de evaluar u +3.) Los operadores de multiplicaci´n y divisi´n son, respectivamente, * y /: o o 12 / 3 * 2 ↱ 3*4/2 ↱ 4/2 ↱ 2*3 ↱ >>> 6 >>> 2 >>> 6 >>> 8 Observa que estos operadores tambi´n son asociativos por la izquierda: la expresi´n e o 3·4 ˂˂3 * 4 / 2˃˃ equivale a ((3 · 4)/2) = 2 , es decir, tiene el siguiente arbol sint´ctico: a ´ / 2 * 3 4 12 3 y la expresi´n 12 / 3 * 2 equivale a ((12/3) · 2) = o * 2 / 12 · 2, o sea, su arbol sint´ctico es: a ´ 3 ¿Qu´ pasa si combinamos en una misma expresi´n operadores de suma o resta con e o operadores de multiplicaci´n o divisi´n? F´ o o ıjate en que la regla de aplicaci´n de operadores o de izquierda a derecha no siempre se observa: ↱ ↱ >>> 2 * 4 + 5 13 >>> 2 + 4 * 5 22 En la segunda expresi´n, primero se ha efectuado el producto 4 * 5 y el resultado o se ha sumado al valor 2. Ocurre que los operadores de multiplicaci´n y divisi´n son o o prioritarios frente a los de suma y resta. Decimos que la multiplicaci´n y la divisi´n o o tienen mayor nivel de precedencia o prioridad que la suma y la resta. El arbol sint´ctico de 2 * 4 + 5 es: a ´ + 5 * 2 y el de 2 + 4 * 5 es: Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 4 30 30 Introducción a la programación con Python - UJI c UJI
    • + 2 * 4 5 Pero, ¡atenci´n!, el cambio de signo tiene mayor prioridad que la multiplicaci´n y la o o divisi´n: o ↱ ↱ >>> -2 * 2 -4 >>> --2 * 2 4 Los arboles sint´cticos correspondientes a estas dos expresiones son, respectivamente: a ´ * - * 2 - 2 2 2 Si los operadores siguen unas reglas de precedencia que determinan su orden de aplicaci´n, ¿qu´ hacer cuando deseamos un orden de aplicaci´n distinto? Usar par´ntesis, o e o e como hacemos con la notaci´n matem´tica convencional. o a La expresi´n 2 * (4 + 5), por ejemplo, presenta este arbol sint´ctico: o a ´ * 2 + 4 5 Comprob´moslo con el int´rprete: e e ↱ >>> 2 * (4 + 5) 18 Existen m´s operadores en Python. Tenemos, por ejemplo, el operador m´dulo, que a o se denota con el s´ ımbolo de porcentaje % (aunque nada tiene que ver con el c´lculo a de porcentajes). El operador m´dulo devuelve el resto de la divisi´n entera entre dos o o operandos. ↱ ↱ >>> 27 % 5 2 >>> 25 % 5 0 El operador % tambi´n es asociativo por la izquierda y su prioridad es la misma que e la de la multiplicaci´n o la divisi´n. o o El ultimo operador que vamos a estudiar es la exponenciaci´n, que se denota con dos o ´ asteriscos juntos, no separados por ning´n espacio en blanco: **. u Lo que en notaci´n matem´tica convencional expresamos como 23 se expresa en Pyo a thon con 2 ** 3. Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 31 31 Introducción a la programación con Python - UJI c UJI
    • ↱ >>> 2 ** 3 8 Pero, ¡ojo!, la exponenciaci´n es asociativa por la derecha. La expresi´n 2 ** 3 ** o o (32 ) = 29 = 512, y no a (23 )2 = 82 = 64, o sea, su arbol sint´ctico es: 2 equivale a 2 a ´ ** 2 ** 3 2 Por otra parte, la exponenciaci´n tiene mayor precedencia que cualquiera de los otros o operadores presentados. He aqu´ varias expresiones evaluadas con Python y sus correspondientes arboles ı ´ sint´cticos. Est´dialos con atenci´n: a u o + ↱ >>> 2 + 3 ** 2 * 5 47 2 * 5 ** 3 + ↱ >>> 2 + ((3 ** 2) * 5) 47 2 2 * 5 ** 3 + ↱ >>> 2 + 3 ** (2 * 5) 59051 2 2 ** 3 * 2 - ↱ >>> -3 ** 2 -9 ** 3 Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 5 32 32 2 c UJI Introducción a la programación con Python - UJI
    • - ↱ >>> -1 -1 1 La tabla 2.1 resume las caracter´ ısticas de los operadores Python: su aridad (n´mero u de operandos), asociatividad y precedencia. Operaci´n o Operador Aridad Asociatividad Precedencia Exponenciaci´n o ** Binario Por la derecha 1 ............................................................................ Identidad + Unario  2 Cambio de signo Unario  2 ............................................................................ Multiplicaci´n o * Binario Por la izquierda 3 Divisi´n o / Binario Por la izquierda 3 M´dulo (o resto) o % Binario Por la izquierda 3 ............................................................................ Suma + Binario Por la izquierda 4 Resta Binario Por la izquierda 4 Tabla 2.1: Operadores para expresiones aritm´ticas. El nivel de precedencia 1 es el de e mayor prioridad y el 4 el de menor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 14 ¿Qu´ resultados se obtendr´n al evaluar las siguientes expresiones Python? e a Dibuja el arbol sint´ctico de cada una de ellas, calcula a mano el valor resultante de a ´ cada expresi´n y comprueba, con la ayuda del ordenador, si tu resultado es correcto. o a) 2 + 3 + 1 + 2 c) (2 + 3) * 1 + 2 b) 2 + 3 * 1 + 2 d) (2 + 3) * (1 + 2) a) 2 + (3 · (6/2)) e) +---6 f) -+-+6 c) (4/2)5 · 15 Traduce las siguientes expresiones matem´ticas a Python y eval´alas. Trata de a u utilizar el menor n´mero de par´ntesis posible. u e b) 4+6 2+3 e) (−3)2 d) (4/2)5+1 f) −(32 ) (Nota: El resultado de evaluar cada expresi´n es: a) 11; b) 2; c) 32; d) 64; e) 9; f) −9.) o .................................................................................. 2.1.2. Errores de tecleo y excepciones Cuando introducimos una expresi´n y damos la orden de evaluarla, es posible que nos o equivoquemos. Si hemos formado incorrectamente una expresi´n, Python nos lo indicar´ o a con un mensaje de error. El mensaje de error proporciona informaci´n acerca del tipo de o error cometido y del lugar en el que ´ste ha sido detectado. Aqu´ tienes una expresi´n e ı o err´nea y el mensaje de error correspondiente: o ↱ >>> 1 + 2) File "<stdin>", line 1 1 + 2) Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 3333 Introducción a la programación con Python - UJIUJI c
    • ˆ SyntaxError: invalid syntax En este ejemplo hemos cerrado un par´ntesis cuando no hab´ otro abierto previae ıa mente, lo cual es incorrecto. Python nos indica que ha detectado un error de sintaxis (SyntaxError) y ˂˂apunta˃˃ con una flecha (el car´cter ˆ) al lugar en el que se encuentra. a (El texto ˂˂File "<stdin> ", line 1˃˃ indica que el error se ha producido al leer de teclado, esto es, de la entrada est´ndar stdin es una abreviatura del ingl´s ˂˂standard a e input˃˃, que se traduce por ˂˂entrada est´ndar˃˃.) a En Python los errores se denominan excepciones. Cuando Python es incapaz de analizar una expresi´n, produce una excepci´n. Cuando el int´rprete interactivo detecta o o e la excepci´n, nos muestra por pantalla un mensaje de error. o Veamos algunos otros errores y los mensajes que produce Python. ↱ >>> 1 + * 3 File "<stdin>", line 1 1 + * 3 ˆ SyntaxError: invalid syntax >>> 2 + 3 % File "<stdin>", line 1 2 + 3 % ˆ SyntaxError: invalid syntax >>> 1 / 0 Traceback (innermost last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo ↱ ↱ En el ejemplo, el ultimo error es de naturaleza distinta a los anteriores (no hay ´ un car´cter ˆ apuntando a lugar alguno): se trata de un error de divisi´n por cero a o (ZeroDivisionError), cuando los otros eran errores sint´cticos (SyntaxError). La cantia dad que resulta de dividir por cero no est´ definida y Python es incapaz de calcular un a valor como resultado de la expresi´n 1 / 0. No es un error sint´ctico porque la expresi´n o a o est´ sint´cticamente bien formada: el operador de divisi´n tiene dos operandos, como a a o toca. Edici´n avanzada en el entorno interactivo o Cuando estemos escribiendo una expresi´n puede que cometamos errores y los deteco temos antes de solicitar su evaluaci´n. A´n estaremos a tiempo de corregirlos. La tecla o u de borrado, por ejemplo, elimina el car´cter que se encuentra a la izquierda del cursor. a Puedes desplazar el cursor a cualquier punto de la l´ ınea que est´s editando utilizando a las teclas de desplazamiento del cursor a izquierda y a derecha. El texto que teclees se insertar´ siempre justo a la izquierda del cursor. a Hasta el momento hemos tenido que teclear desde cero cada expresi´n evaluada, aun o cuando muchas se parec´ bastante entre s´ Podemos teclear menos si aprendemos a ıan ı. utilizar algunas funciones de edici´n avanzadas. o Lo primero que hemos de saber es que el int´rprete interactivo de Python memoe riza cada una de las expresiones evaluadas en una sesi´n interactiva por si deseamos o recuperarlas m´s tarde. La lista de expresiones que hemos evaluado constituye la hisa toria de la sesi´n interactiva. Puedes ˂˂navegar˃˃ por la historia utilizando la teclas o de desplazamiento de cursor hacia arriba y hacia abajo. Cada vez que pulses la tecla de desplazamiento hacia arriba recuperar´s una expresi´n m´s antigua. La tecla de a o a desplazamiento hacia abajo permite recuperar expresiones m´s recientes. La expresi´n a o recuperada aparecer´ ante el prompt y podr´s modificarla a tu antojo. a a Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 34 34 Introducción a la programación con Python - UJI c UJI
    • 2.2. Tipos de datos Vamos a efectuar un experimento de resultado curioso: ↱ >>> 3 / 2 1 ¡El resultado de dividir 3 entre 2 no deber´ ser 1, sino 1.5!3 ¿Qu´ ha pasado? ¿Se ha ıa e equivocado Python? No. Python ha actuado siguiendo unas reglas precisas en las que participa un nuevo concepto: el de tipo de dato. 2.2.1. Enteros y flotantes Cada valor utilizado por Python es de un tipo determinado. Hasta el momento s´lo hemos o utilizado datos de tipo entero, es decir, sin decimales. Cuando se efect´a una operaci´n, u o Python tiene en cuenta el tipo de los operandos a la hora de producir el resultado. Si los dos operandos son de tipo entero, el resultado tambi´n es de tipo entero, as´ que la e ı divisi´n entera entre los enteros 3 y 2 produce el valor entero 1. o Si deseamos obtener resultados de tipo real, deberemos usar operandos reales. Los operandos reales deben llevar, en principio, una parte decimal, aunque ´sta sea nula. e ↱ >>> 3.0 / 2.0 1.5 Hay diferencias entre enteros y reales en Python m´s all´ de que los primeros no a a tengan decimales y los segundos s´ El n´mero 3 y el n´mero 3.0, por ejemplo, son ı. u u indistinguibles en matem´ticas, pero s´ son diferentes en Python. ¿Qu´ diferencias hay? a ı e Los enteros suelen ocupar menos memoria. Las operaciones entre enteros son, generalmente, m´s r´pidas. a a As´ pues, utilizaremos enteros a menos que de verdad necesitemos n´meros con decimales. ı u Hemos de precisar algo respecto a la denominaci´n de los n´meros con decimales: o u el t´rmino ˂˂reales˃˃ no es adecuado, ya que induce a pensar en los n´meros reales de e u las matem´ticas. En matem´ticas, los n´meros reales pueden presentar infinitos decimaa a u les, y eso es imposible en un computador. Al trabajar con computadores tendremos que conformarnos con meras aproximaciones a los n´meros reales. u Recuerda que todo en el computador son secuencias de ceros y unos. Deberemos, pues, representar internamente con ellos las aproximaciones a los n´meros reales. Para u facilitar el intercambio de datos, todos los computadores convencionales utilizan una misma codificaci´n, es decir, representan del mismo modo las aproximaciones a los n´meros o u reales. Esta codificaci´n se conoce como ˂˂IEEE Standard 754 floating point˃˃ (que se pueo de traducir por ˂˂Est´ndar IEEE 754 para coma flotante˃˃), as´ que llamaremos n´meros a ı u en formato de coma flotante o simplemente flotantes a los n´meros con decimales que u podemos representar con el ordenador. Un n´mero flotante debe especificarse siguiendo ciertas reglas. En principio, consta u de dos partes: mantisa y exponente. El exponente se separa de la mantisa con la letra ˂˂e˃˃ (o ˂˂E˃˃). Por ejemplo, el n´mero flotante 2e3 (o 2E3) tiene mantisa 2 y exponente 3, u y representa al n´mero 2 · 103 , es decir, 2000. u Una advertencia sobre convenios tipogr´ficos. En espa˜ol, la parte fraccionaria de un n´mero se separa a n u de la parte entera por una coma, y no por un punto. Sin embargo, la norma anglosajona indica que debe utilizarse el punto. Python sigue esta norma, as´ que el n´mero que en espa˜ol se denota como 1,5 debe ı u n escribirse como 1.5 para que Python lo interprete correctamente. En aras de evitar confusiones, utilizaremos siempre el punto como car´cter de separaci´n entre parte entera y fraccionaria de un n´mero. a o u 3 Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 35 35 Introducción a la programación con Python - UJI c UJI
    • El exponente puede ser negativo: 3.2e-3 es 3.2·10−3 , o sea, 0.0032. Ten en cuenta que si un n´mero flotante no lleva exponente debe llevar parte fraccionaria. ¡Ah! Un par de u reglas m´s: si la parte entera del n´mero es nula, el flotante puede empezar directamente a u con un punto, y si la parte fraccionaria es nula, puede acabar con un punto. Veamos un par de ejemplos: el n´mero 0.1 se puede escribir tambi´n como .1; por otra parte, el n´mero u e u 2.0 puede escribirse como 2., es decir, en ambos casos el cero es opcional. ¿Demasiadas reglas? No te preocupes, con la pr´ctica acabar´s record´ndolas. a a a IEEE Standard 754 Un n´mero en coma flotante presenta tres componentes: el signo, la mantisa y el exu ponente. He aqu´ un n´mero en coma flotante: −14.1 × 10−3 . El signo es negativo, la ı u mantisa es 14.1 y el exponente es −3. Los n´meros en coma flotante normalizada preu sentan una mantisa menor o igual que 10. El mismo n´mero de antes, en coma flotante u normalizada, es −1.41×10−2. Una notaci´n habitual para los n´meros en coma flotante o u sustituye el producto (×) y la base del exponente por la letra ˂˂e˃˃ o ˂˂E˃˃. Notar´ ıamos con -1.41e-2 el n´mero del ejemplo. u Los flotantes de Python siguen la norma IEEE Standard 754. Es una codificaci´n o binaria y normalizada de los n´meros en coma flotante y, por tanto, con base 2 para u el exponente y mantisa de valor menor que 2. Usa 32 bits (precisi´n simple) o 64 o bits (precisi´n doble) para codificar cada n´mero. Python utiliza el formato de doble o u precisi´n. En el formato de precisi´n doble se reserva 1 bit para el signo del n´mero, 11 o o u para el exponente y 52 para la mantisa. Con este formato pueden representarse n´meros u tan pr´ximos a cero como 10−323 (322 ceros tras el punto decimal y un uno) o de valor o absoluto tan grande como 10308 . No todos los n´meros tienen una representaci´n exacta en el formato de coma flou o tante. Observa qu´ ocurre en este caso: e ↱ >>> 0.1 0.10000000000000001 La mantisa, que vale 1/10, no puede representarse exactamente. En binario obtenemos la secuencia peri´dica de bits o 0.0001100110011001100110011001100110011001100110011. . . No hay, pues, forma de representar 1/10 con los 52 bits del formato de doble precisi´n. o En base 10, los 52 primeros bits de la secuencia nos proporcionan el valor 0.1000000000000000055511151231257827021181583404541015625. Es lo m´s cerca de 1/10 que podemos estar. En pantalla, Python s´lo nos muestra sus a o primeros 17 decimales (con el redondeo correspondiente). Una peculiaridad adicional de los n´meros codificados con la norma IEEE 754 es u que su precisi´n es diferente seg´n el n´mero representado: cuanto m´s pr´ximo a ceo u u a o ro, mayor es la precisi´n. Para n´meros muy grandes se pierde tanta precisi´n que o u o no hay decimales (¡ni unidades, ni decenas. . . !). Por ejemplo, el resultado de la suma 100000000.0+0.000000001 es 100000000.0, y no 100000000.000000001, como cabr´ ıa esperar. A modo de conclusi´n, has de saber que al trabajar con n´meros flotantes es posible o u que se produzcan peque˜os errores en la representaci´n de los valores y durante los n o c´lculos. Probablemente esto te sorprenda, pues es vox populi que ˂˂los ordenadores a nunca se equivocan˃˃. Es posible mezclar en una misma expresi´n datos de tipos distintos. o ↱ >>> 3.0 / 2 1.5 Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 36 36 Introducción a la programación con Python - UJI c UJI
    • Python sigue una regla sencilla: si hay datos de tipos distintos, el resultado es del tipo ˂˂m´s general˃˃. Los flotantes son de tipo ˂˂m´s general˃˃ que los enteros. a a ↱ ↱ >>> 1 + 2 + 3 + 4 + 5 + 6 + 0.5 21.5 >>> 1 + 2 + 3 + 4 + 5 + 6 + 0.0 21.0 Pero, ¡atenci´n!, puede parecer que la regla no se observa en este ejemplo: o ↱ >>> 1.0 + 3 / 2 2.0 El resultado debiera haber sido 2.5, y no 2.0. ¿Qu´ ha pasado? Python eval´a la e u expresi´n paso a paso. Analicemos el arbol sint´ctico de esa expresi´n: o a o ´ flotante 2.0 + 1.0 entero 1 / 3 2 La divisi´n es prioritaria frente a la suma, por lo que ´sta se lleva a cabo en primer lugar. o e La divisi´n tiene dos operandos, ambos de tipo entero, as´ que produce un resultado de o ı tipo entero: el valor 1. La suma recibe, pues, un operando flotante (el de su izquierda) de valor 1.0, y otro entero (el que resulta de la divisi´n), de valor 1. El resultado es un o flotante y su valor es 2.0. ¿Qu´ pasar´ si ejecut´ramos 1 + 3 / 2.0? e ıa a ↱ >>> 1 + 3 / 2.0 2.5 El arbol sint´ctico es, en este caso, a ´ flotante 2.5 + 1 / 3 flotante 1.5 2.0 As´ pues, la divisi´n proporciona un resultado flotante, 1.5, que al ser sumado al entero ı o 1 de la izquierda proporciona un nuevo flotante: 2.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 16 ¿Qu´ resultar´ de evaluar las siguientes expresiones? Presta especial atenci´n e a o al tipo de datos que resulta de cada operaci´n individual. Haz los c´lculos a mano o a ayud´ndote con arboles sint´cticos y comprueba el resultado con el ordenador. a a ´ a) 1 / 2 / 4.0 f) 4.0 ** (1 / 2) b) 1 / 2.0 / 4.0 g) 4.0 ** (1 / 2) + 1 / 2 d) 1.0 / 2 / 4 i) 3e3 / 10 c) 1 / 2.0 / 4 e) 4 ** .5 Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o h) 4.0 ** (1.0 / 2) + 1 / 2.0 j) 10 / 5e-3 37 37 Introducción a la programación con Python - UJIUJI c
    • k) 10 / 5e-3 + 1 l) 3 / 2 + 1 .................................................................................. 2.2.2. Valores l´gicos o 2.3. Operadores l´gicos y de comparaci´n o o Desde la versi´n 2.3, Python ofrece un tipo de datos especial que permite expresar o s´lo dos valores: cierto y falso. El valor cierto se expresa con True y el valor falso con o False. Son los valores l´gicos o booleanos. Este ultimo nombre deriva del nombre de un o ´ matem´tico, Boole, que desarroll´ un sistema algebraico basado en estos dos valores y a o tres operaciones: la conjunci´n, la disyunci´n y la negaci´n. Python ofrece soporte para o o o estas operaciones con los operadores l´gicos. o Hay tres operadores l´gicos en Python: la ˂˂y l´gica˃˃ o conjunci´n (and), la ˂˂o l´gica˃˃ o o o o o disyunci´n (or) y el ˂˂no l´gico˃˃ o negaci´n (not). o o o El operador and da como resultado el valor cierto si y s´lo si son ciertos sus dos o operandos. Esta es su tabla de verdad: and operandos izquierdo derecho True True False False True False True False resultado True False False False El operador or proporciona True si cualquiera de sus operandos es True, y False s´lo o cuando ambos operandos son Falses. Esta es su tabla de verdad: or operandos izquierdo derecho True True False False True False True False resultado True True True False El operador not es unario, y proporciona el valor True si su operando es False y viceversa. He aqu´ su tabla de verdad: ı not operando True False resultado False True Podemos combinar valores l´gicos y operadores l´gicos para formar expresiones o o l´gicas. He aqu´ algunos ejemplos: o ı Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 38 38 Introducción a la programación con Python - c UJI UJI
    • ↱ >>> True and False False >>> not True False >>> (True and False) or True True >>> True and True or False True >>> False and True or True True >>> False and True or False False ↱ ↱ ↱ ↱ ↱ Has de tener en cuenta la precedencia de los operadores l´gicos: o Operaci´n o Operador Aridad Asociatividad Precedencia Negaci´n o not Unario  alta ............................................................................ Conjunci´n o and Binario Por la izquierda media ............................................................................ Disyunci´n o or Binario Por la izquierda baja Tabla 2.2: Aridad, asociatividad y precedencia de los operadores l´gicos. o Del mismo modo que hemos usado arboles sint´cticos para entender el proceso de a ´ c´lculo de los operadores aritm´ticos sobre valores enteros y flotantes, podemos recurrir a e a ellos para interpretar el orden de evaluaci´n de las expresiones l´gicas. He aqu´ el o o ı arbol sint´ctico de la expresi´n True or False and not False: a o ´ or True True and False False not True False Hay una familia de operadores que devuelven valores booleanos. Entre ellos tenemos a los operadores de comparaci´n, que estudiamos en este apartado. Uno de ellos es el o operador de igualdad, que devuelve True si los valores comparados son iguales. El operador de igualdad se denota con dos iguales seguidos: ==. Ve´moslo en funcionamiento: a ↱ >>> 2 == 3 False >>> 2 == 2 True >>> 2.1 == 2.1 True >>> True == True True >>> True == False False >>> 2 == 1+1 True ↱ ↱ ↱ ↱ ↱ Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 39 39 c UJI Introducción a la programación con Python - UJI
    • Observa la ultima expresi´n evaluada: es posible combinar operadores de comparaci´n o o ´ y operadores aritm´ticos. No s´lo eso, tambi´n podemos combinar en una misma expresi´n e o e o operadores l´gicos, aritm´ticos y de comparaci´n: o e o ↱ >>> (True or (2 == 1 + 2)) == True True Este es el arbol sint´ctico correspondiente a esa expresi´n: a o ´ booleano True == or booleano True True True booleano False == 2 entero 3 + 1 2 Hemos indicado junto a cada nodo interior el tipo del resultado que corresponde a su sub´rbol. Como ves, en todo momento operamos con tipos compatibles entre s´ a ı. Antes de presentar las reglas de asociatividad y precedencia que son de aplicaci´n o al combinar diferentes tipos de operador, te presentamos todos los operadores de comparaci´n en la tabla 2.3 y te mostramos algunos ejemplos de uso4 : o operador == != < <= > >= <1 >1 igual que distinto de menor que menor o igual que mayor que mayor o igual que ↱ >5 es es es es es es Tabla 2.3: Operadores de comparaci´n. o ↱ ↱ <2 ↱ >= 1 ↱ >= 5 ↱ != 1 ↱ != 0 ↱ >>> 2 False >>> 1 True >>> 5 True >>> 5 True >>> 5 False >>> 5 True >>> 1 True >>> 1 comparaci´n o Hay una forma alternativa de notar la comparaci´n ˂˂es distinto de˃˃: tambi´n puedes usar el s´ o e ımbolo <>. La comparaci´n de desigualdad en el lenguaje de programaci´n C se denota con != y en Pascal con <>. o o Python permite usar cualquiera de los dos s´ ımbolos. En este texto s´lo usaremos el primero. o 4 Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 40 40 Introducción a la programación con Python - UJI c UJI
    • ↱ False >>> -2 <= 2 True Es hora de que presentemos una tabla completa (tabla 2.4) con todos los operadores que conocemos para comparar entre s´ la precedencia de cada uno de ellos cuando aparece ı combinado con otros. Operaci´n o Operador Aridad Asociatividad Precedencia Exponenciaci´n o ** Binario Por la derecha 1 ...................................................................... Identidad + Unario  2 Cambio de signo Unario  2 ...................................................................... Multiplicaci´n o * Binario Por la izquierda 3 Divisi´n o / Binario Por la izquierda 3 M´dulo (o resto) o % Binario Por la izquierda 3 ...................................................................... Suma + Binario Por la izquierda 4 Resta Binario Por la izquierda 4 ...................................................................... Igual que == Binario  5 Distinto de != Binario  5 Menor que < Binario  5 Menor o igual que <= Binario  5 Mayor que > Binario  5 Mayor o Igual que >= Binario  5 ...................................................................... Negaci´n o not Unario  6 ...................................................................... Conjunci´n o and Binario Por la izquierda 7 ...................................................................... Disyunci´n o or Binario Por la izquierda 8 Tabla 2.4: Caracter´ ısticas de los operadores Python. El nivel de precedencia 1 es el de mayor prioridad. En la tabla 2.4 hemos omitido cualquier referencia a la asociatividad de los comparadores de Python, pese a que son binarios. Python es un lenguaje peculiar en este sentido. Imaginemos que fueran asociativos por la izquierda. ¿Qu´ significar´ esto? El operae ıa dor suma, por ejemplo, es asociativo por la izquierda. Al evaluar la expresi´n aritm´tica o e 2 + 3 + 4 se procede as´ primero se suma el 2 al 3; a continuaci´n, el 5 resultante se ı: o suma al 4, resultando un total de 9. Si el operador < fuese asociativo por la izquierda, la expresi´n l´gica 2 < 3 < 4 se evaluar´ as´ primero, se compara el 2 con el 3, resultando el o o ıa ı: valor True; a continuaci´n, se compara el resultado obtenido con el 4, pero ¿qu´ significa o e la expresi´n True < 4? No tiene sentido. o Cuando aparece una sucesi´n de comparadores como, por ejemplo, 2 < 3 < 4, Python o la eval´a igual que (2 < 3) and (3 < 4). Esta soluci´n permite expresar condiciones comu o plejas de modo sencillo y, en casos como el de este ejemplo, se lee del mismo modo que se leer´ con la notaci´n matem´tica habitual, lo cual parece deseable. Pero ¡ojo! Python ıa o a permite expresiones que son m´s extra˜as; por ejemplo, 2 < 3 > 1, o 2 < 3 == 5. a n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 17 ¿Qu´ resultados se muestran al evaluar estas expresiones? e Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 4141 Introducción a la programación con Python - UJIUJI c
    • Una rareza de Python: la asociatividad de los comparadores Algunos lenguajes de programaci´n de uso com´n, como C y C++, hacen que sus o u operadores de comparaci´n sean asociativos, por lo que presentan el problema de que o expresiones como 2 < 1 < 4 producen un resultado que parece il´gico. Al ser asociativo o por la izquierda el operador de comparaci´n <, se eval´a primero la subexpresi´n 2 < o u o 1. El resultado es falso, que en C y C++ se representa con el valor 0. A continuaci´n se o eval´a la comparaci´n 0 < 4, cuyo resultado es. . . ¡cierto! As´ pues, para C y C++ es u o ı cierto que 2 < 1 < 4. Pascal es m´s r´ a ıgido a´n y llega a prohibir expresiones como 2 < 1 < 4. En Pascal u hay un tipo de datos denominado boolean cuyos valores v´lidos son true y false. a Pascal no permite operar entre valores de tipos diferentes, as´ que la expresi´n 2 < 1 ı o se eval´a al valor booleano false, que no se puede comparar con un entero al tratar u de calcular el valor de false < 4. En consecuencia, se produce un error de tipos si intentamos encadenar comparaciones. La mayor parte de los lenguajes de programaci´n convencionales opta por la soluci´n o o del C o por la soluci´n del Pascal. Cuando aprendas otro lenguaje de programaci´n, te o o costar´ ˂˂deshabituarte˃˃ de la elegancia con que Python resuelve los encadenamientos a de comparaciones. ↱ ↱ True == True != False 1<2<3<4<5 (1 < 2 < 3) and (4 < 5) 1<2<4<3<5 (1 < 2 < 4) and (3 < 5) ↱ ↱ ↱ >>> >>> >>> >>> >>> .................................................................................. 2.4. Variables y asignaciones En ocasiones deseamos que el ordenador recuerde ciertos valores para usarlos m´s adea lante. Por ejemplo, supongamos que deseamos efectuar el c´lculo del per´ a ımetro y el area ´ de un c´ ırculo de radio 1.298373 m. La f´rmula del per´ o ımetro es 2πr, donde r es el radio, y la f´rmula del area es πr 2 . (Aproximaremos el valor de π con 3.14159265359.) Podemos o ´ realizar ambos c´lculos del siguiente modo: a ↱ ↱ >>> 2 * 3.14159265359 * 1.298373 8.1579181568392176 >>> 3.14159265359 * 1.298373 ** 2 5.2960103355249037 Observa que hemos tenido que introducir dos veces los valores de π y r por lo que, al tener tantos decimales, es muy f´cil cometer errores. Para paliar este problema podemos a utilizar variables: ↱ >>> pi = 3.14159265359 >>> r = 1.298373 >>> 2 * pi * r 8.1579181568392176 >>> pi * r ** 2 5.2960103355249037 ↱ ↱ ↱ En la primera l´ ınea hemos creado una variable de nombre pi y valor 3.14159265359. A continuaci´n, hemos creado otra variable, r, y le hemos dado el valor 1.298373. El acto o de dar valor a una variable se denomina asignaci´n. Al asignar un valor a una variable o Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 42 42 Introducción a la programación con Python - UJI c UJI
    • que no exist´ Python reserva un espacio en la memoria, almacena el valor en ´l y crea ıa, e una asociaci´n entre el nombre de la variable y la direcci´n de memoria de dicho espacio. o o Podemos representar gr´ficamente el resultado de estas acciones as´ a ı: pi 3.14159265359 r 1.298373 A partir de ese instante, escribir pi es equivalente a escribir 3.14159265359, y escribir r es equivalente a escribir 1.298373. Podemos almacenar el resultado de calcular el per´ ımetro y el area en sendas variables: ´ ↱ pi = 3.14159265359 r = 1.298373 perimetro = 2 * pi * r area = pi * r**2 ↱ ↱ ↱ >>> >>> >>> >>> pi 3.14159265359 r 1.298373 perimetro 8.1579181568392176 area 5.2960103355249037 La memoria se ha reservado correctamente, en ella se ha almacenado el valor correspondiente y la asociaci´n entre la memoria y el nombre de la variable se ha establecido, o pero no obtenemos respuesta alguna por pantalla. Debes tener en cuenta que las asignaciones son ˂˂mudas˃˃, es decir, no provocan salida por pantalla. Si deseamos ver cu´nto a vale una variable, podemos evaluar una expresi´n que s´lo contiene a dicha variable: o o ↱ >>> area 5.2960103355249037 As´ pues, para asignar valor a una variable basta ejecutar una sentencia como ´sta: ı e variable = expresi´n o Ten cuidado: el orden es importante. Hacer ˂˂expresi´n = variable˃˃ no es equivalente. o Una asignaci´n no es una ecuaci´n matem´tica, sino una acci´n consistente en (por este o o a o orden): 1. 2. evaluar la expresi´n a la derecha del s´ o ımbolo igual (=), y guardar el valor resultante en la variable indicada a la izquierda del s´ ımbolo igual. Se puede asignar valor a una misma variable cuantas veces se quiera. El efecto es que la variable, en cada instante, s´lo ˂˂recuerda˃˃ el ultimo valor asignado. . . hasta que o ´ se le asigne otro. a=1 2*a ↱ ↱ a=2 a*a ↱ ↱ a+2 ↱ >>> >>> 2 >>> 3 >>> >>> 4 Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 43 43 Introducción a la programación con Python - UJI c UJI
    • == no es = (comparar no es asignar) Al aprender a programar, muchas personas confunden el operador de asignaci´n, =, con o el operador de comparaci´n, ==. El primero se usa exclusivamente para asignar un valor o a una variable. El segundo, para comparar valores. Observa la diferente respuesta que obtienes al usar = y == en el entorno interactivo: ↱ ↱ >>> a = 10 >>> a 10 >>> a == 1 False >>> a 10 ↱ ↱ Una asignaci´n no es una ecuaci´n o o Hemos de insistir en que las asignaciones no son ecuaciones matem´ticas, por mucho a que su aspecto nos recuerde a ´stas. F´ e ıjate en este ejemplo, que suele sorprender a aquellos que empiezan a programar: ↱ ↱ >>> x = 3 >>> x = x + 1 >>> x 4 ↱ La primera l´ ınea asigna a la variable x el valor 3. La segunda l´ ınea parece m´s a complicada. Si la interpretas como una ecuaci´n, no tiene sentido, pues de ella se o concluye absurdamente que 3 = 4 o, sustrayendo la x a ambos lados del igual, que 0 = 1. Pero si seguimos paso a paso las acciones que ejecuta Python al hacer una asignaci´n, la cosa cambia: o 1. 2. Se eval´a la parte derecha del igual (sin tener en cuenta para nada la parte u izquierda). El valor de x es 3, que sumado a 1 da 4. El resultado (el 4), se almacena en la variable que aparece en la parte izquierda del igual, es decir, en x. As´ pues, el resultado de ejecutar las dos primeras l´ ı ıneas es que x vale 4. El nombre de una variable es su identificador. Hay unas reglas precisas para construir identificadores. Si no se siguen, diremos que el identificador no es v´lido. Un identifia cador debe estar formado por letras5 min´sculas, may´sculas, d´ u u ıgitos y/o el car´cter de a subrayado (_), con una restricci´n: que el primer car´cter no sea un d´ o a ıgito. Hay una norma m´s: un identificador no puede coincidir con una palabra reservada o a palabra clave. Una palabra reservada es una palabra que tiene un significado predefinido y es necesaria para expresar ciertas construcciones del lenguaje. Aqu´ tienes una lista ı con todas las palabras reservadas de Python: and, assert, break, class, continue, def, del, elif, else, except, exec, finally, for, from, global, if, import, in, is, lambda, not, or, pass, print, raise, return, try, while y yield. Por ejemplo, los siguientes identificadores son v´lidos: h, x, Z , velocidad, aceleracion, a x, fuerza1, masa_ 2, _a, a_ , prueba_ 123, desviacion_tipica. Debes tener presente que Python distingue entre may´sculas y min´sculas, as´ que area, Area y AREA son tres u u ı Exceptuando los s´ ımbolos que no son propios del alfabeto ingl´s, como las vocales acentuadas, la letra e ‘˜’, la letra ‘c’, etc.. n ¸ 5 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 44 44 Introducción a la programación con Python - cUJI UJI
    • identificadores v´lidos y diferentes. a Cualquier car´cter diferente de una letra, un d´ a ıgito o el subrayado es inv´lido en un a identificador, incluyendo el espacio en blanco. Por ejemplo, edad media (con un espacio en medio) son dos identificadores (edad y media), no uno. Cuando un identificador se forma con dos palabras, es costumbre de muchos programadores usar el subrayado para separarlas: edad_media; otros programadores utilizan una letra may´scula para la inicial u de la segunda: edadMedia. Escoge el estilo que m´s te guste para nombrar variables, a pero permanece fiel al que escojas. Dado que eres libre de llamar a una variable con el identificador que quieras, hazlo con clase: escoge siempre nombres que guarden relaci´n con los datos del problema. Si, o por ejemplo, vas a utilizar una variable para almacenar una distancia, llama a la variable distancia y evita nombres que no signifiquen nada; de este modo, los programas ser´n a m´s legibles. a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 18 ¿Son v´lidos los siguientes identificadores? a a) Identificador g) desviaci´n o m) UnaVariable c) Dos palabras i) from n) 12 ˜ b) Indicedos d) __ e) 12horas f) hora12 h) a˜o n j) var! k) ’var’ l) import_from n) a(b) s) area-rect o) uno.dos u) ________ 1 q) π w) x_x p) x · 19 ¿Qu´ resulta de ejecutar estas tres l´ e ıneas? t) x_______ 1 v) _x_ ↱ ↱ >>> x = 10 >>> x = x * 10 >>> x r) area ´ ↱ · 20 Eval´a el polinomio x 4 + x 3 + 2x 2 − x en x = 1.1. Utiliza variables para evitar u teclear varias veces el valor de x. (El resultado es 4.1151.) · 21 Eval´a el polinomio x 4 + x 3 + 1 x 2 − x en x = 10. Aseg´rate de que el resultado u u 2 sea un n´mero flotante. (El resultado es 11040.0.) u .................................................................................. 2.4.1. Asignaciones con operador F´ ıjate en la sentencia i = i + 1: aplica un incremento unitario al contenido de la variable i. Incrementar el valor de una variable en una cantidad cualquiera es tan frecuente que existe una forma compacta en Python. El incremento de i puede denotarse as´ ı: ↱ >>> i += 1 (No puede haber espacio alguno entre el + y el =.) Puedes incrementar una variable con cualquier cantidad, incluso con una que resulte de evaluar una expresi´n: o a=3 b=2 a += 4 * b a ↱ ↱ ↱ ↱ >>> >>> >>> >>> 11 Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 45 45 Introducción a la programación con Python - UJIUJI c
    • z z z z z z Todos los operadores aritm´ticos tienen su asignaci´n con operador asociada. e o += 2 *= 2 /= 2 -= 2 %= 2 **= 2 Hemos de decirte que estas formas compactas no aportan nada nuevo. . . salvo comodidad, as´ que no te preocupes por tener que aprender tantas cosas. Si te vas a sentir ı inc´modo por tener que tomar decisiones y siempre est´s pensando ˂˂¿uso ahora la forma o a normal o la compacta?˃˃, es mejor que ignores de momento las formas compactas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 22 ¿Qu´ resultar´ de ejecutar las siguientes sentencias? e a ↱ ↱ ↱ =2 += 2 += 2 - 2 *= 2 *= 1 + 1 /= 2 %= 3 /= 3 - 1 -= 2 + 1 -= 2 **= 3 ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ z z z z z z z z z z z z ↱ >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> .................................................................................. 2.4.2. Variables no inicializadas En Python, la primera operaci´n sobre una variable debe ser la asignaci´n de un valor. o o No se puede usar una variable a la que no se ha asignado previamente un valor: ↱ >>> a + 2 Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name ’a’ is not defined Como puedes ver, se genera una excepci´n NameError, es decir, de ˂˂error de nombre˃˃. o El texto explicativo precisa a´n m´s lo sucedido: ˂˂name ’a’ is not defined˃˃, es decir, u a ˂˂el nombre a no est´ definido˃˃. a La asignaci´n de un valor inicial a una variable se denomina inicializaci´n de la o o variable. Decimos, pues, que en Python no es posible usar variables no inicializadas. 2.5. El tipo de datos cadena Hasta el momento hemos visto que Python puede manipular datos num´ricos de dos tipos: e enteros y flotantes. Pero Python tambi´n puede manipular otros tipos de datos. Vamos a e estudiar ahora el tipo de datos que se denomina cadena. Una cadena es una secuencia de caracteres (letras, n´meros, espacios, marcas de puntuaci´n, etc.) y en Python se u o distingue porque va encerrada entre comillas simples o dobles. Por ejemplo, ’cadena’, ’otro␣ejemplo’, "1,␣2␣1o␣3", ’ Si!’, "...Python" son cadenas. Observa que los ! Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 46 46 Introducción a la programación con Python - UJIUJI c
    • ¡M´s operadores! a S´lo te hemos presentado los operadores que utilizaremos en el texto y que ya est´s o a preparado para manejar. Pero has de saber que hay m´s operadores. Hay operadores, a por ejemplo, que est´n dirigidos a manejar las secuencias de bits que codifican los a valores enteros. El operador binario & calcula la operaci´n ˂˂y˃˃ bit a bit, el operador o binario | calcula la operaci´n ˂˂o˃˃ bit a bit, el operador binario ˆ calcula la ˂˂o exclusiva˃˃ o (que devuelve cierto si y s´lo si los dos operandos son distintos), tambi´n bit a bit, y o e el operador unario ˜ invierte los bits de su operando. Tienes, adem´s, los operadores a binarios << y >>, que desplazan los bits a izquierda o derecha tantas posiciones como le indiques. Estos ejemplos te ayudar´n a entender estos operadores: a En decimal Expresi´n Resultado o 5 & 12 5 | 12 5 ˆ 12 ˜5 5 << 1 5 << 2 5 << 3 5 >> 1 4 13 9 -6 10 20 40 2 En binario Expresi´n o Resultado 00000101 & 00001100 00000101 | 00001100 00000101 ˆ 00001100 ˜00000101 00000101 << 00000001 00000101 << 00000010 00000101 << 00000011 00000101 >> 00000010 00000100 00001101 00001001 11111010 00001010 00010100 00101000 00000010 ¡Y estos operadores presentan, adem´s, una forma compacta con asignaci´n: <<=, |=, a o etc.! M´s adelante estudiaremos, adem´s, los operadores is (e is not) e in (y not in), los a a operadores de indexaci´n, de llamada a funci´n, de corte. . . o o espacios en blanco se muestran as´ en este texto: ˂˂␣˃˃. Lo hacemos para que resulte f´cil ı a contar los espacios en blanco cuando hay m´s de uno seguido. Esta cadena, por ejemplo, a est´ formada por tres espacios en blanco: ’␣␣␣’. a Las cadenas pueden usarse para representar informaci´n textual: nombres de personas, o nombres de colores, matr´ ıculas de coche... Las cadenas tambi´n pueden almacenarse en e variables. ↱ >>> nombre = ’Pepe’ >>> nombre ’Pepe’ ↱ nombre ’Pepe’ Es posible realizar operaciones con cadenas. Por ejemplo, podemos ˂˂sumar˃˃ cadenas a˜adiendo una a otra. n ↱ >>> ’a’ + ’b’ ’ab’ >>> nombre = ’Pepe’ >>> nombre + ’Cano’ ’PepeCano’ >>> nombre + ’␣’ + ’Cano’ ’Pepe Cano’ >>> apellido = ’Cano’ >>> nombre + ’␣’ + apellido ’Pepe Cano’ ↱ ↱ ↱ ↱ ↱ Hablando con propiedad, esta operaci´n no se llama suma, sino concatenaci´n. El o o s´ ımbolo utilizado es +, el mismo que usamos cuando sumamos enteros y/o flotantes; pero Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 47 47 Introducción a la programación con Python - UJI c UJI
    • Una cadena no es un identificador Con las cadenas tenemos un problema: muchas personas que est´n aprendiendo a proa gramar confunden una cadena con un identificador de variable y viceversa. No son la misma cosa. F´ ıjate bien en lo que ocurre: ↱ >>> a = 1 >>> ’a’ ’a’ >>> a 1 ↱ ↱ La primera l´ ınea asigna a la variable a el valor 1. Como a es el nombre de una variable, es decir, un identificador, no va encerrado entre comillas. A continuaci´n hemos o escrito ’a’ y Python ha respondido tambi´n con ’a’: la a entre comillas es una cadena e formada por un unico car´cter, la letra ˂˂a˃˃, y no tiene nada que ver con la variable a. a ´ A continuaci´n hemos escrito la letra ˂˂a˃˃ sin comillas y Python ha respondido con el o valor 1, que es lo que contiene la variable a. Muchos estudiantes de programaci´n cometen errores como estos: o Quieren utilizar una cadena, pero olvidan las comillas, con lo que Python cree que se quiere usar un identificador; si ese identificador no existe, da un error: ↱ >>> Pepe Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name ’Pepe’ is not defined Quieren usar un identificador pero, ante la duda, lo encierran entre comillas: ↱ >>> ’x’ = 2 SyntaxError: can’t assign to literal Recuerda: s´lo se puede asignar valores a variables, nunca a cadenas, y las cadenas no o son identificadores. aunque el s´ ımbolo sea el mismo, ten en cuenta que no es igual sumar n´meros que u concatenar cadenas: ↱ >>> ’12’ + ’12’ ’1212’ >>> 12 + 12 24 ↱ Sumar o concatenar una cadena y un valor num´rico (entero o flotante) produce un e error: ↱ >>> ’12’ + 12 Traceback (innermost last): File "<stdin>", line 1, in ? TypeError: illegal argument type for built-in operation Y para acabar, hay un operador de repetici´n de cadenas. El s´ o ımbolo que lo denota es *, el mismo que hemos usado para multiplicar enteros y/o flotantes. El operador de repetici´n necesita dos datos: uno de tipo cadena y otro de tipo entero. El resultado es la o concatenaci´n de la cadena consigo misma tantas veces como indique el n´mero entero: o u ↱ >>> ’Hola’ * 5 ’HolaHolaHolaHolaHola’ Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 48 48 Introducción a la programación con Python - UJI c UJI
    • ↱ >>> ’-’ * 60 ’------------------------------------------------------------’ >>> 60 * ’-’ ’------------------------------------------------------------’ ↱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 23 Eval´a estas expresiones y sentencias en el orden indicado: u a) a = ’b’ b) a + ’b’ c) a + ’a’ d) a * 2 + ’b’ * 3 e) 2 * (a + ’b’) · 24 ¿Qu´ resultados se obtendr´n al evaluar las siguientes expresiones y asignaciones e a Python? Calcula primero a mano el valor resultante de cada expresi´n y comprueba, con o la ayuda del ordenador, si tu resultado es correcto. a) ’a’ * 3 + ’/*’ * 5 + 2 * ’abc’ + ’+’ b) palindromo = ’abcba’ (4 * ’<’ + palindromo + ’>’ * 4) * 2 c) subcadena = ’=’ + ’-’ * 3 + ’=’ ’10’ * 5 + 4 * subcadena d) 2 * ’12’ + ’.’ + ’3’ * 3 + ’e-’ + 4 * ’76’ · 25 Identifica regularidades en las siguientes cadenas, y escribe expresiones que, partiendo de subcadenas m´s cortas y utilizando los operadores de concatenaci´n y a o repetici´n, produzcan las cadenas que se muestran. Introduce variables para formar las o expresiones cuando lo consideres oportuno. a) ’%%%%%./././<-><->’ b) ’(@)(@)(@)======(@)(@)(@)======’ c) ’asdfasdfasdf=-=-=-=-=-=-=-??????asdfasdf’ d) ’........*****---*****---........*****---*****---’ .................................................................................. El concepto de comparaci´n entre n´meros te resulta familiar porque lo has estudiado o u antes en matem´ticas. Python extiende el concepto de comparaci´n a otros tipos de datos, a o como las cadenas. En el caso de los operadores == y != el significado est´ claro: dos a cadenas son iguales si son iguales car´cter a car´cter, y distintas en caso contrario. a a Pero, ¿qu´ significa que una cadena sea menor que otra? Python utiliza un criterio de e comparaci´n de cadenas muy natural: el orden alfab´tico. En principio, una cadena es o e menor que otra si la precede al disponerlas en un diccionario. Por ejemplo, ’abajo’ es menor que ’arriba’. ¿Y c´mo se comparan cadenas con caracteres no alfab´ticos? Es decir, ¿es ’@@’ o e menor o mayor que ’abc’? Python utiliza los c´digos ASCII de los caracteres para o decidir su orden alfab´tico (ver tablas en ap´ndice A). Para conocer el valor num´rico e e e que corresponde a un car´cter, puedes utilizar la funci´n predefinida ord, a la que le has a o de pasar el car´cter en cuesti´n como argumento. a o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 49 49 Introducción a la programación con Python - UJIUJI c
    • Otros tipos de datos Python posee un rico conjunto de tipos de datos. Algunos, como los tipos de datos estructurados, se estudiar´n con detalle m´s adelante. Sin embargo, y dado el car´cter a a a introductorio de este texto, no estudiaremos con detalle otros dos tipos b´sicos: los a n´meros enteros ˂˂largos˃˃ y los n´meros complejos. Nos limitaremos a presentarlos u u sucintamente. El rango de los n´meros flotantes puede resultar insuficiente para ciertas aplicaciou nes. Python ofrece la posibilidad de trabajar con n´meros con un n´mero de cifras arbiu u trariamente largo: los enteros ˂˂largos˃˃. Un entero largo siempre acaba con la letra L. He aqu´ algunos ejemplos de enteros largos: 1L, -52L, 1237645272817635341571828374645L. ı Los n´meros enteros promocionan autom´ticamente a enteros largos cuando es necesario. u a ↱ >>> 2**30 1073741824 >>> 2**31 2147483648L ↱ Observa la ˂˂L˃˃ que aparece al final del segundo resultado: aunque 2 y 31 son n´meros enteros ˂˂normales˃˃, el resultado de evaluar 2**31 es un entero largo. Esto es u as´ porque los enteros normales se codifican en complemento a 2 de 32 bits, y 2**31 ı no puede representarse en complemento a 2 de 32 bits. Si bien los enteros largos resultan c´modos por no producir nunca errores de desboro damiento, debes tener presente que son muy ineficientes: ocupan (mucha) m´s memoria a que los enteros normales y operar con ellos resulta (mucho) m´s lento. a Finalmente, Python tambi´n ofrece la posibilidad de trabajar con n´meros complejos. e u √ Un n´mero complejo puro finaliza siempre con la letra j, que representa el valor −1. u Un n´mero complejo con parte real se expresa sumando la parte real a un complejo puro. u He aqu´ ejemplos de n´meros complejos: 4j, 1 + 2j, 2.0 + 3j, 1 - 0.354j. ı u ↱ >>> ord(’a’) 97 La funci´n inversa (la que pasa un n´mero a su car´cter equivalente) es chr. o u a ↱ >>> chr(97) ’a’ La tabla ASCII presenta un problema cuando queremos ordenar palabras: las letras may´sculas tienen un valor num´rico inferior a las letras min´sculas (por lo que ’Zapata’ u e u precede a ’ajo’) y las letras acentuadas son siempre ˂˂mayores˃˃ que sus equivalentes sin acentuar (’abanico’ es menor que ’´baco’). Hay formas de configurar el sistema operativo a para que tenga en cuenta los criterios de ordenaci´n propios de cada lengua al efectuar o comparaciones, pero esa es otra historia. Si quieres saber m´s, lee el cuadro titulado a ˂˂C´digo ASCII y c´digo IsoLatin-1˃˃ y consulta el ap´ndice A. o o e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 26 ¿Qu´ resultados se muestran al evaluar estas expresiones? e ↱ ↱ ↱ ’abalorio’ < ’abecedario’ ’abecedario’ < ’abecedario’ ’abecedario’ <= ’abecedario’ ’Abecedario’ < ’abecedario’ ’Abecedario’ == ’abecedario’ 124 < 13 ’124’ < ’13’ ’␣a’ < ’a’ ↱ ↱ ↱ ↱ ↱ >>> >>> >>> >>> >>> >>> >>> >>> Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 50 50 Introducción a la programación con Python - UJIUJI c
    • C´digo ASCII y c´digo IsoLatin-1 o o En los primeros d´ de los computadores, los caracteres se codificaban usando 6 o ıas 7 bits. Cada ordenador usaba una codificaci´n de los caracteres diferente, por lo que o hab´ problemas de compatibilidad: no era f´cil transportar datos de un ordenador a ıa a otro. Los estadounidenses definieron una codificaci´n est´ndar de 7 bits que asignaba o a un car´cter a cada n´mero entre 0 y 127: la tabla ASCII (de American Standard Code a u for Information Interchange). Esta tabla (que puedes consultar en un ap´ndice) s´lo e o conten´ los caracteres de uso com´n en la lengua inglesa. La tabla ASCII fue enriquecida ıa u posteriormente definiendo un c´digo de 8 bits para las lenguas de Europa occidental: o la tabla IsoLatin-1, tambi´n conocida como ISO-8859-1 (hay otras tablas para otras e lenguas). Esta tabla coincide con la tabla ASCII en sus primeros 128 caracteres y a˜ade n todos los s´ ımbolos de uso com´n en las lenguas de Europa occidental. Una variante u estandarizada es la tabla ISO-8859-15, que es la ISO-8859-1 enriquecida con el s´ ımbolo del euro. . . . (Nota: .el. c´digo. ASCII. del .car´.cter . ’␣’. es. 32,. .y. .el . del. .car´.cter .’a’ . es .97.) . . . . . . . . . . . . . . . . o. . . . . . . . . . . . . . .a . . . . . . . . . . . . .. ..a ... ... .. ... . 2.6. Funciones predefinidas Hemos estudiado los operadores aritm´ticos b´sicos. Python tambi´n proporciona funcioe a e nes que podemos utilizar en las expresiones. Estas funciones se dice que est´n predefia nidas.6 La funci´n abs, por ejemplo, calcula el valor absoluto de un n´mero. Podemos usarla o u como en estas expresiones: ↱ >>> abs(-3) 3 >>> abs(3) 3 ↱ El n´mero sobre el que se aplica la funci´n se denomina argumento. Observa que el u o argumento de la funci´n debe ir encerrado entre par´ntesis: o e ↱ >>> abs(0) 0 >>> abs 0 File "<stdin>", line 1 abs 0 ˆ SyntaxError: invalid syntax ↱ Existen muchas funciones predefinidas, pero es pronto para aprenderlas todas. Te resumimos algunas que ya puedes utilizar: float: conversi´n a flotante. Si recibe un n´mero entero como argumento, devuelve o u el mismo n´mero convertido en un flotante equivalente. u 6 ↱ >>> float(3) 3.0 La funci´n float tambi´n acepta argumentos de tipo cadena. Cuando se le pasa una o e cadena, float la convierte en el n´mero flotante que ´sta representa: u e Predefinidas porque nosotros tambi´n podemos definir nuestras propias funciones. Ya llegaremos. e Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 51 51 Introducción a la programación con Python - UJI c UJI
    • ↱ ↱ >>> float(’3.2’) 3.2 >>> float(’3.2e10’) 32000000000.0 Pero si la cadena no representa un flotante, se produce un error de tipo ValueError, es decir, ˂˂error de valor˃˃: ↱ >>> float(’un␣texto’) Traceback (innermost last): File "<stdin>", line 1, in ? ValueError: invalid literal for float(): un texto Si float recibe un argumento flotante, devuelve el mismo valor que se suministra como argumento. int: conversi´n a entero. Si recibe un n´mero flotante como argumento, devuelve el o u entero que se obtiene eliminando la parte fraccionaria.7 ↱ >>> int(2.1) 2 >>> int(-2.9) -2 ↱ Tambi´n la funci´n int acepta como argumento una cadena: e o ↱ >>> int(’2’) 2 Si int recibe un argumento entero, devuelve el argumento tal cual. str: conversi´n a cadena. Recibe un n´mero y devuelve una representaci´n de ´ste o u o e como cadena. ↱ ↱ >>> str(2.1) ’2.1’ >>> str(234E47) ’2.34e+49’ La funci´n str tambi´n puede recibir como argumento una cadena, pero en ese caso o e devuelve como resultado la misma cadena. round: redondeo. Puede usarse con uno o dos argumentos. Si se usa con un s´lo o argumento, redondea el n´mero al flotante m´s pr´ximo cuya parte decimal sea u a o nula. ↱ >>> round(2.1) 2.0 >>> round(2.9) 3.0 >>> round(-2.9) -3.0 >>> round(2) 2.0 ↱ ↱ ↱ El redondeo de int puede ser al alza o a la baja seg´n el ordenador en que lo ejecutes. Esto es as´ porque u ı int se apoya en el comportamiento del redondeo autom´tico de C (el int´rprete de Python que usamos est´ a e a escrito en C) y su comportamiento est´ indefinido. Si quieres un comportamiento homog´neo del redondeo, a e pues usar las funciones round, floor o ceil, que se explican m´s adelante. a 7 Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 52 52 c UJI Introducción a la programación con Python - UJI
    • (¡Observa que el resultado siempre es de tipo flotante!) Si round recibe dos argumentos, ´stos deben ir separados por una coma y el segundo indica el n´mero de e u decimales que deseamos conservar tras el redondeo. ↱ ↱ ↱ >>> round(2.1451, 2) 2.15 >>> round(2.1451, 3) 2.145 >>> round(2.1451, 0) 2.0 Estas funciones (y las que estudiaremos m´s adelante) pueden formar parte de exa presiones y sus argumentos pueden, a su vez, ser expresiones. Observa los siguientes ejemplos: ↱ >>> abs(-23) % int(7.3) 2 >>> abs(round(-34.2765,1)) 34.3 >>> str(float(str(2) * 3 + ’.123’)) + ’321’ 222.123321 ↱ ↱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 27 Calcula con una unica expresi´n el valor absoluto del redondeo de −3.2. (El o ´ resultado es 3.0.) · 28 Convierte (en una unica expresi´n) a una cadena el resultado de la divisi´n o o ´ 5011/10000 redondeado con 3 decimales. str(2.1) + str(1.2) int(str(2) + str(3)) str(int(12.3)) + ’0’ int(’2’+’3’) str(2 + 3) str(int(2.1) + float(3)) ↱ ↱ ↱ ↱ >>> >>> >>> >>> >>> >>> ¿Qu´ resulta de evaluar estas expresiones? e ↱ ↱ · 29 .................................................................................. 2.7. Funciones definidas en m´dulos o 2.7.1. El m´dulo math o Python tambi´n proporciona funciones trigonom´tricas, logaritmos, etc., pero no est´n e e a directamente disponibles cuando iniciamos una sesi´n. Antes de utilizarlas hemos de o indicar a Python que vamos a hacerlo. Para ello, importamos cada funci´n de un m´dulo. o o Empezaremos por importar la funci´n seno (sin, del ingl´s ˂˂sinus˃˃) del m´dulo matem´tico o e o a (math): ↱ >>> from math import sin Ahora podemos utilizar la funci´n en nuestros c´lculos: o a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 53 53 Introducción a la programación con Python - UJIUJI c
    • ↱ >>> sin(0) 0.0 >>> sin(1) 0.841470984808 ↱ Observa que el argumento de la funci´n seno debe expresarse en radianes. o Inicialmente Python no ˂˂sabe˃˃ calcular la funci´n seno. Cuando importamos una funo ci´n, Python ˂˂aprende˃˃ su definici´n y nos permite utilizarla. Las definiciones de funciones o o residen en m´dulos. Las funciones trigonom´tricas residen en el m´dulo matem´tico. Por o e o a ejemplo, la funci´n coseno, en este momento, es desconocida para Python. o ↱ >>> cos(0) Traceback (innermost last): File "<stdin>", line 1, in ? NameError: cos Antes de usarla, es necesario importarla del m´dulo matem´tico: o a ↱ >>> from math import cos >>> cos(0) 1.0 ↱ En una misma sentencia podemos importar m´s de una funci´n. Basta con separar a o sus nombres con comas: ↱ >>> from math import sin, cos Puede resultar tedioso importar un gran n´mero de funciones y variables de un m´dulo. u o Python ofrece un atajo: si utilizamos un asterisco, se importan todos los elementos de un m´dulo. Para importar todas las funciones del m´dulo math escribimos: o o ↱ >>> from math import * As´ de f´cil. De todos modos, no resulta muy aconsejable por dos razones: ı a Al importar elemento a elemento, el programa gana en legibilidad, pues sabemos de d´nde proviene cada identificador. o Si hemos definido una variable con un nombre determinado y dicho nombre coincide con el de una funci´n definida en un m´dulo, nuestra variable ser´ sustituida por la o o a funci´n. Si no sabes todos los elementos que define un m´dulo, es posible que esta o o coincidencia de nombre tenga lugar, te pase inadvertida inicialmente y te lleves una sorpresa cuando intentes usar la variable. He aqu´ un ejemplo del segundo de los problemas indicados: ı ↱ >>> pow = 1 >>> from math import * >>> pow += 1 Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: unsupported operand type(s) for +=: ’builtin_function_or_method’ and ’int’ ↱ ↱ Python se queja de que intentamos sumar un entero y una funci´n. Efectivamente, o hay una funci´n pow en el m´dulo math. Al importar todo el contenido de math, nuestra o o variable ha sido ˂˂machacada˃˃ por la funci´n. o Te presentamos algunas de las funciones que encontrar´s en el m´dulo matem´tico: a o a Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 54 54 c UJI Introducción a la programación con Python - UJI
    • Evitando las coincidencias Python ofrece un modo de evitar el problema de las coincidencias: importar s´lo el o m´dulo. o ↱ >>> import math De esta forma, todas las funciones del m´dulo math est´n disponibles, pero usando o a el nombre del m´dulo y un punto como prefijo: o ↱ sin(x) cos(x) tan(x) exp(x) ceil(x) floor(x) log(x) log10(x) sqrt(x) ↱ >>> import math >>> print math.sin(0) 0.0 Seno de x, que debe estar expresado en radianes. Coseno de x, que debe estar expresado en radianes. Tangente de x, que debe estar expresado en radianes. El n´mero e elevado a x. u Redondeo hacia arriba de x (en ingl´s, ˂˂ceiling˃˃ significa techo). e Redondeo hacia abajo de x (en ingl´s, ˂˂floor˃˃ significa suelo). e Logaritmo natural (en base e) de x. Logaritmo decimal (en base 10) de x. Ra´ cuadrada de x (del ingl´s ˂˂square root˃˃). ız e En el m´dulo matem´tico se definen, adem´s, algunas constantes de inter´s: o a a e ↱ >>> from math import pi, e >>> pi 3.1415926535897931 >>> e 2.7182818284590451 ↱ ↱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 30 ¿Qu´ resultados se obtendr´n al evaluar las siguientes expresiones Python? Cale a cula primero a mano el valor resultante de cada expresi´n y comprueba, con la ayuda del o ordenador, si tu resultado es correcto. a) int(exp(2 * log(3))) b) round(4*sin(3 * pi / 2)) c) abs(log10(.01) * sqrt(25)) d) round(3.21123 * log10(1000), 3) .................................................................................. 2.7.2. Otros m´dulos de inter´s o e Existe un gran n´mero de m´dulos, cada uno de ellos especializado en un campo de apliu o caci´n determinado. Precisamente, una de las razones por las que Python es un lenguaje o potente y extremadamente util es por la gran colecci´n de m´dulos con que se distribuye. o o ´ Hay m´dulos para el dise˜o de aplicaciones para web, dise˜o de interfaces de usuao n n rio, compresi´n de datos, criptograf´ multimedia, etc. Y constantemente aparecen nuevos o ıa, m´dulos: cualquier programador de Python puede crear sus propios m´dulos, a˜adiendo o o n Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 55 55 Introducción a la programación con Python - UJIUJI c
    • Precisi´n de los flotantes o Hemos dicho que los argumentos de las funciones trigonom´tricas deben expresarse en e radianes. Como sabr´s, sen(π) = 0. Veamos qu´ opina Python: a e ↱ >>> from math import sin, pi >>> sin(pi) 1.2246063538223773e-16 ↱ El resultado que proporciona Python no es cero, sino un n´mero muy pr´ximo a cero: u o 0.00000000000000012246063538223773. ¿Se ha equivocado Python? No exactamente. Ya dijimos antes que los n´meros flotantes tienen una precisi´n limitada. El n´mero π est´ u o u a definido en el m´dulo matem´tico como 3.1415926535897931, cuando en realidad posee o a un n´mero infinito de decimales. As´ pues, no hemos pedido exactamente el c´lculo del u ı a seno de π, sino el de un n´mero pr´ximo, pero no exactamente igual. Por otra parte, el u o m´dulo matem´tico hace c´lculos mediante algoritmos que pueden introducir errores en o a a el resultado. as´ funciones que simplifican la programaci´n en un ambito cualquiera y poni´ndolas ı o e ´ a disposici´n de otros programadores. Nos limitaremos a presentarte ahora unas pocas o funciones de un par de m´dulos interesantes. o Vamos con otro m´dulo importante: sys (sistema), el m´dulo de ˂˂sistema˃˃ (sys es o o una abreviatura del ingl´s ˂˂system˃˃). Este m´dulo contiene funciones que acceden al e o sistema operativo y constantes dependientes del computador. Una funci´n importante es o exit, que aborta inmediatamente la ejecuci´n del int´rprete (en ingl´s significa ˂˂salir˃˃). o e e La variable maxint, tambi´n definida en sys, contiene el n´mero entero m´s grande con e u a el que se puede trabajar, y la variable version, indica con qu´ versi´n de Python estamos e o trabajando: ↱ >>> from sys import maxint, version >>> maxint 2147483647 >>> version ’2.3 (#1, Aug 2 2003, 09:00:57) n[GCC 3.3]’ ↱ ↱ ¡Ojo! Con esto no queremos decirte que la funci´n version o el valor predefinido maxint o sean importantes y que debas aprender de memoria su nombre y cometido, sino que los m´dulos de Python contienen centenares de funciones utiles para diferentes cometidos. Un o ´ buen programador Python sabe manejarse con los m´dulos. Existe un manual de referencia o que describe todos los m´dulos est´ndar de Python. Lo encontrar´s con la documentaci´n o a a o Python bajo el nombre ˂˂Library reference˃˃ (en ingl´s significa ˂˂referencia de biblioteca˃˃) e y podr´s consultarla con un navegador web.8 . a 2.8. M´todos e Los datos de ciertos tipos permiten invocar unas funciones especiales: los denominados ˂˂m´todos˃˃. De los que ya conocemos, s´lo las cadenas permiten invocar m´todos sobre e o e ellas. Un m´todo permite, por ejemplo, obtener una versi´n en min´sculas de la cadena e o u sobre la que se invoca: 8 En una instalaci´n Linux lo encontrar´s en file:/usr/doc/python/html/index.html (aunque dio a ferentes distribuciones lo pueden albergar en otro lugar). Si est´s trabajando en un ordenador con acceso a a Internet, prueba con http://www.python.org/python/doc/2.3/lib/lib.html. Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 56 56 Introducción a la programación con Python - UJI c UJI
    • ↱ >>> cadena = ’Un␣EJEMPLO␣de␣Cadena’ >>> cadena.lower() ’un ejemplo de cadena’ >>> ’OTRO␣EJEMPLO’.lower() ’otro ejemplo’ ↱ ↱ La sintaxis es diferente de la propia de una llamada a funci´n convencional. Lo primero o que aparece es el propio objeto sobre el se efect´a la llamada. El nombre del m´todo se u e separa del objeto con un punto. Los par´ntesis abierto y cerrado al final son obligatorios. e Existe otro m´todo, upper (˂˂uppercase˃˃, en ingl´s, significa ˂˂may´sculas˃˃), que pasa e e u todos los caracteres a may´sculas. u ↱ >>> ’Otro␣ejemplo’.upper() ’OTRO EJEMPLO’ Y otro, title que pasa la inicial de cada palabra a may´sculas. Te preguntar´s para qu´ u a e puede valer esta ultima funci´n. Imagina que has hecho un programa de recogida de datos o ´ que confecciona un censo de personas y que cada individuo introduce personalmente su nombre en el ordenador. Es muy probable que algunos utilicen s´lo may´sculas y otros o u may´sculas y min´sculas. Si aplicamos title a cada uno de los nombres, todos acabar´n u u a en un formato unico: ´ ↱ >>> ’PEDRO␣F.␣MAS’.title() ’Pedro F. Mas’ >>> ’Juan␣CANO’.title() ’Juan Cano’ ↱ Algunos m´todos aceptan par´metros. El m´todo replace, por ejemplo, recibe como e a e argumento dos cadenas: un patr´n y un reemplazo. El m´todo busca el patr´n en la o e o cadena sobre la que se invoca el m´todo y sustituye todas sus apariciones por la cadena e de reemplazo. ↱ >>> ’un␣peque˜o␣ejemplo’.replace(’peque˜o’, ’gran’) n n ’un gran ejemplo’ >>> una_cadena = ’abc’.replace(’b’, ’-’) >>> una_cadena ’a-c’ ↱ ↱ Conforme vayamos presentando nuevos tipos de datos y profundizando en nuestro conocimiento de las cadenas, ir´s conociendo nuevos m´todos. a e Cadenas, m´todos y el m´dulo string e o Los m´todos de las cadenas fueron funciones de m´dulos en versiones antiguas de e o Python. Para pasar una cadena a may´sculas, por ejemplo, hab´ que hacer lo siguiente: u ıa ↱ ↱ >>> from string import upper >>> upper(’Otro␣ejemplo’) ’OTRO EJEMPLO’ Y a´n puedes hacerlo as´ aunque resulta m´s c´modo usar m´todos. El m´dulo string u ı, a o e o sigue ofreciendo esas funciones para garantizar la compatibilidad de los programas escritos hace tiempo con las nuevas versiones de Python. Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 57 57 c UJI Introducción a la programación con Python - UJI
    • Cap´ ıtulo 3 Programas ¡Querida, realmente tengo que conseguir un l´piz m´s fino! No puedo en a a absoluto manejar ´ste: escribe todo tipo de cosas, sin que yo se las dicte. e LEWIS CARROLL, Alicia a trav´s del espejo. e Hasta el momento hemos utilizado Python en un entorno interactivo: hemos introducido expresiones (y asignaciones a variables) y Python las ha evaluado y ha proporcionado inmediatamente sus respectivos resultados. Pero utilizar el sistema unicamente de este modo limita bastante nuestra capacidad ´ de trabajo. En este tema aprenderemos a introducir secuencias de expresiones y asignaciones en un fichero de texto y pedir a Python que las ejecute todas, una tras otra. Denominaremos programa al contenido del fichero de texto1 . Puedes generar los ficheros con cualquier editor de texto. Nosotros utilizaremos un entorno de programaci´n: el entorno PythonG. Un entorno de programaci´n es un conjunto o o de herramientas que facilitan el trabajo del programador. 3.1. El entorno PythonG El entorno de programaci´n PythonG es un programa escrito en Python util para eso ´ cribir tus programas Python. Encontrar´s el programa PythonG en la direcci´n web a o http://marmota.act.uji.es/MTP. Una vez lo hayas instalado, ejecuta el programa pythong.py. En pantalla aparecer´ una ventana como la que se muestra en la figura 3.1. a Puedes introducir expresiones en el entorno interactivo de PythonG, del mismo modo que hemos hecho al ejecutar el int´rprete python desde un terminal. e No nos demoremos m´s y escribamos nuestro primer programa. En el men´ Fichero a u hay una opci´n llamada Nuevo. Al seleccionarla, se crea una ventana de edici´n que o o sustituye al entorno interactivo. Entre la ventana y el men´ aparecer´ una pesta˜a con u a n el texto <an´nimo> (figura 3.2). Puedes volver al int´rprete interactivo en cualquier moo e mento haciendo clic en la pesta˜a <python>. Escribe el siguiente texto en la ventana n <an´nimo>2 : o <an´nimo> o 1 2 3 4 from math import pi radio = 1 perimetro = 2 * pi * radio Tambi´n se suele denominar scripts a los programas Python. e No debes teclear los n´meros de l´ u ınea que aparecen en el margen izquierdo de los programas. Los ponemos unicamente para facilitar posteriores referencias a sus l´ ıneas. ´ 1 2 Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 58 58 Introducción a la programación con Python - UJI
    • Figura 3.1: El entorno de programaci´n PythonG. En la zona superior aparece una barra o de men´s. Bajo ella, a mano izquierda, un area de trabajo en la que se muestra un entorno u ´ interactivo Python. En la zona derecha hay dos cuadros: el superior es una zona de dibujo y el inferior una consola de entrada/salida para los programas Python. El bot´n con la o letra G permite ocultar/mostrar el area de salida gr´fica. a ´ perimetro Figura 3.2: Al escoger la opci´n o del men´ u aparece una pesta˜a con el texto n y una ventana de edici´n que oculta al int´rprete de PythonG. o e Guarda el texto que has escrito en un fichero denominado nando la opci´n o del men´ u . from math import pi radio 1 perimetro perimetro 2 pi seleccio- radio La opci´n o del men´ u te permite ejecutar el programa: selecci´nala. ¿Qu´ ocurre? Nada. Aunque el programa se ha ejecutado, no vemos el resultado o e por ninguna parte. Analicemos el programa paso a paso. La primera l´ ınea de no produce salida alguna: se limita a importar la variable pi. La segunda l´ ınea est´ en blanco. Las a l´ ıneas en blanco s´lo sirven para hacer m´s legible el programa separando diferentes o a partes del mismo. La tercera define una variable llamada radio y le asigna el valor 1, y ya vimos que las asignaciones no producen un resultado visible por pantalla. La Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 59 59 Introducción a la programación con Python - cUJI UJI
    • Punto py Hay un convenio por el que los ficheros que contienen programas Python tienen extensi´n py en su nombre. La extensi´n de un nombre de fichero son los caracteres del o o mismo que suceden al (´ltimo) punto. Un fichero llamado ejemplo.py tiene extensi´n u o py. La idea de las extensiones viene de antiguo y es un mero convenio. Puedes prescindir de ´l, pero no es conveniente. En entornos gr´ficos (como KDE, Gnome o Microsoft e a Windows) la extensi´n se utiliza para determinar qu´ icono va asociado al fichero y qu´ o e e aplicaci´n debe arrancarse para abrir el fichero al hacer clic (o doble clic) en el mismo. o cuarta l´ ınea tambi´n es una asignaci´n. La quinta l´ e o ınea est´ en blanco y la ultima es a ´ una expresi´n (aunque muy sencilla). Cuando aparec´ una expresi´n en una l´ o ıa o ınea, el entorno interactivo mostraba el resultado de su evaluaci´n. Sin embargo, no ocurre lo o mismo ahora que trabajamos con un programa. Esta es una diferencia importante entre el uso interactivo de Python y la ejecuci´n de programas: la evaluaci´n de expresiones no o o produce salida por pantalla en un programa. Entonces ¿c´mo veremos los resultados que o producen nuestros programas? Hemos de aprender a utilizar una nueva sentencia: print (en ingl´s, ˂˂imprimir˃˃). En principio, se usa de este modo: e print expresi´n o y escribe en pantalla el resultado de evaluar la expresi´n. o Modificamos el programa para que se lea as´ ı: miprograma.py 1 2 3 4 5 6 miprograma.py from math import pi radio = 1 perimetro = 2 * pi * radio print perimetro Si ejecutas ahora el programa aparecer´ el resultado en el cuadro inferior derecho. a En ese cuadro aparece la salida de toda sentencia print, como se aprecia en la figura 3.3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 31 Dise˜a un programa que, a partir del valor del lado de un cuadrado (3 metros), n muestre el valor de su per´ ımetro (en metros) y el de su area (en metros cuadrados). ´ (El per´ ımetro debe darte 12 metros y el area 9 metros cuadrados.) ´ · 32 Dise˜a un programa que, a partir del valor de la base y de la altura de un tri´ngulo n a (3 y 5 metros, respectivamente), muestre el valor de su area (en metros cuadrados). ´ Recuerda que el area A de un tri´ngulo se puede calcular a partir de la base b y la a ´ altura h como A = 1 bh. 2 (El resultado es 7.5 metros cuadrados.) b h · 33 Dise˜a un programa que, a partir del valor de los dos lados de un rect´ngulo (4 y n a 6 metros, respectivamente), muestre el valor de su per´ ımetro (en metros) y el de su area ´ (en metros cuadrados). (El per´ ımetro debe darte 20 metros y el area 24 metros cuadrados.) ´ .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 60 60 Introducción a la programación con Python - UJIUJI c
    • Teclas El editor de textos que integra el entorno PythonG puede manejarse de forma muy sencilla con el rat´n y los men´s. Muchas de las ´rdenes que puedes dar seleccionando o u o la opci´n de men´ correspondiente tienen un atajo de teclado, es decir, una combinaci´n o u o de teclas que te permite ejecutar la orden sin tener que coger el rat´n, desplazarte a o la barra de men´s, mantener el rat´n pulsado (o hacer clic) en uno de ellos y soltar u o el rat´n (o hacer un nuevo clic) en la opci´n asociada a la orden. Si te acostumbras a o o usar los atajos de teclado, ser´s mucho m´s productivo. Memorizarlos cuesta bastante a a esfuerzo al principio, pero recompensa a medio y largo plazo. Te resumimos aqu´ los atajos de teclado para las diferentes ´rdenes. Algunos atajos ı o requieren la pulsaci´n de cuatro teclas, bueno, de dos grupos de dos teclas que se pulsan o simult´neamente. Por ejemplo, para abrir un fichero has de pulsar C-x y, despu´s, C-f. a e Una secuencia doble como esa se indicar´ as´ C-x C-f. a ı: Nuevo fichero Guardar Cerrar Deshacer Cortar Pegar Reemplazar Aumentar tama˜o letra n Ejecutar programa C-x C-x C-x C-z C-x C-v Esc C-+ C-c C-n C-s k % C-c Abrir fichero Guardar como Salir Rehacer Copiar Buscar Ir a l´ ınea n´mero u Reducir tama˜o letra n Abortar ejecuci´n o C-x C-f C-x C-w C-x C-c C-M-z C-c C-s Esc g C-C-c C-c (Esc representa a la tecla de ˂˂escape˃˃ (la tecla de la esquina superior izquierda en el teclado) y M (en C-M-z) a la tecla Alt, aunque es la inicial del t´rmino ˂˂meta˃˃.) e Hay otras combinaciones de teclas que resultan muy utiles y cuyas ´rdenes no son o ´ accesibles a trav´s de un men´. Aqu´ las tienes: e u ı Ir a principio de l´ ınea Adelantar palabra Seleccionar C-a C-→ S-<tecla de cursor> Ir a final de l´ ınea Volver una palabra atr´s a C-e C-← (S es la tecla de may´sculas, que en ingl´s se llama ˂˂shift˃˃.) u e Edici´n de ficheros en el entorno Unix o Puedes utilizar cualquier editor de texto para escribir programas Python.¡Ojo!, no debes usar un procesador de texto, es decir, el texto no debe tener formato (cambios de tipograf´ de tama˜os de letra, etc.). Aplicaciones como el Microsoft Word s´ dan formato ıa, n ı al texto. El bloc de notas de Microsoft Windows, por ejemplo, es un editor de texto apropiado para la programaci´n (aunque muy pobre). o En Unix existe una gran variedad de editores de texto. Los m´s utilizados son el vi a y el Emacs (o su variante XEmacs). Si has de usar un editor de texto, te recomendamos este ultimo. XEmacs incorpora un modo de trabajo Python (python-mode) que facilita ´ enormemente la escritura de programas Python. Las combinaciones de teclas de PythonG se han definido para hacer f´cil el trabajo a con XEmacs, pues son b´sicamente id´nticas. De ese modo, no te resultar´ dif´ alternar a e a ıcil entre PythonG y XEmacs. 3.2. Ejecuci´n de programas desde la l´ o ınea de ´rdenes Unix o Una vez has escrito un programa es posible ejecutarlo directamente, sin entrar en el entorno PythonG. Si invocas al int´rprete python seguido del nombre de un fichero e desde la l´ ınea de ´rdenes Unix, no se iniciar´ una sesi´n con el int´rprete interactivo, o a o e Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 61 61 Introducción a la programación con Python - c UJI UJI
    • Figura 3.3: Programa de c´lculo del per´ a ımetro. El resultado de la ejecuci´n se muestra en o la consola (cuadro de la esquina inferior derecha). sino que se ejecutar´ el programa contenido en el fichero en cuesti´n. a o Por ejemplo, si ejecutamos la orden python miprograma.py en la l´ ınea de ´rdenes o tenemos el siguiente resultado: ↱ $ python miprograma.py 6.28318530718 A continuaci´n volver´ a aparecer el prompt del int´rprete de ´rdenes Unix pio a e o di´ndonos nuevas ´rdenes. e o 3.3. Entrada/salida Los programas que hemos visto en la secci´n anterior adolecen de un serio inconveniente: o cada vez que quieras obtener resultados para unos datos diferentes deber´s editar el a fichero de texto que contiene el programa. Por ejemplo, el siguiente programa calcula el volumen de una esfera a partir de su radio, que es de un metro: volumen esfera.py volumen esfera 8.py 1 2 3 4 5 6 from math import pi radio = 1 volumen = 4.0 / 3.0 * pi * radio ** 3 print volumen Aqu´ tienes el resultado de ejecutar el programa: ı ↱ $ python volumen_esfera.py 4.18879020479 Si deseas calcular ahora el volumen de una esfera de 3 metros de radio, debes editar el fichero que contiene el programa, yendo a la tercera l´ ınea y cambi´ndola para que el a programa pase a ser ´ste: e Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 62 62 Introducción a la programación con Python - UJI c UJI
    • Ejecuci´n impl´ o ıcita del int´rprete e No es necesario llamar expl´ ıcitamente al int´rprete de Python para ejecutar los proe gramas. En Unix existe un convenio que permite llamar al int´rprete autom´ticamente: e a si la primera l´ ınea del fichero de texto empieza con los caracteres #!, se asume que, a continuaci´n, aparece la ruta en la que encontrar el int´rprete que deseamos utilizar o e para ejecutar el fichero. Si, por ejemplo, nuestro int´rprete Python est´ en /usr/local/bin/python, el e a siguiente fichero: miprograma.py miprograma 5.py 1 2 3 4 5 6 7 8 #! /usr/local/bin/python from math import pi radio = 1 perimetro = 2 * pi * radio print perimetro adem´s de contener el programa, permitir´ invocar autom´ticamente al int´rprete de a ıa a e Python. O casi. Nos faltar´ un ultimo paso: dar permiso de ejecuci´n al fichero. Si ıa o ´ deseas dar permiso de ejecuci´n has de utilizar la orden Unix chmod. Por ejemplo, o ↱ $ chmod u+x miprograma.py da permiso de ejecuci´n al usuario propietario del fichero. A partir de ahora, para ejecutar o el programa s´lo tendremos que escribir el nombre del fichero: o ↱ $ miprograma.py 6.28318530718 Si quieres practicar, genera ficheros ejecutables para los programas de los ultimos ´ tres ejercicios. Ten en cuenta que, a veces, este procedimiento falla. En diferentes sistemas puede que Python est´ instalado en directorios diferentes. Puede resultar m´s pr´ctico sustituir e a a la primera l´ ınea por esta otra: miprograma 6.py 1 2 3 4 5 6 7 8 miprograma.py #! /usr/bin/env python from math import pi radio = 1 perimetro = 2 * pi * radio print perimetro El programa env (que deber´ estar en /usr/bin en cualquier sistema) se encarga de ıa ˂˂buscar˃˃ al programa python. volumen esfera 9.py 1 2 3 4 5 6 volumen esfera.py from math import pi radio = 3 volumen = 4.0 / 3.0 * pi * radio ** 3 print volumen Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 63 63 Introducción a la programación con Python -cUJI UJI
    • Ahora podemos ejecutar el programa: ↱ $ python volumen_esfera.py 113.097335529 Y si ahora quieres calcular el volumen para otro radio, vuelta a empezar: abre el fichero con el editor de texto, ve a la tercera l´ ınea, modifica el valor del radio y guarda el fichero. No es el colmo de la comodidad. 3.3.1. Lectura de datos de teclado Vamos a aprender a hacer que nuestro programa, cuando se ejecute, pida el valor del radio para el que vamos a efectuar los c´lculos sin necesidad de editar el fichero de a programa. Hay una funci´n predefinida, raw_input (en ingl´s significa ˂˂entrada en bruto˃˃), que o e hace lo siguiente: detiene la ejecuci´n del programa y espera a que el usuario escriba un o texto (el valor del radio, por ejemplo) y pulse la tecla de retorno de carro; en ese momento prosigue la ejecuci´n y la funci´n devuelve una cadena con el texto que tecle´ el usuario. o o o Si deseas que el radio sea un valor flotante, debes transformar la cadena devuelta por raw_input en un dato de tipo flotante llamando a la funci´n float. La funci´n float recibir´ o o a como argumento la cadena que devuelve raw_input y proporcionar´ un n´mero en coma a u flotante. (Recuerda, para cuando lo necesites, que existe otra funci´n de conversi´n, int, o o que devuelve un entero en lugar de un flotante.) Por otra parte, raw_input es una funci´n o y, por tanto, el uso de los par´ntesis que siguen a su nombre es obligatorio, incluso e cuando no tenga argumentos. He aqu´ el nuevo programa: ı volumen esfera 10.py 1 2 3 4 5 6 7 from math import pi texto_leido = raw_input() radio = float(texto_leido) volumen = 4.0 / 3.0 * pi * radio ** 3 print volumen Esta otra versi´n es m´s breve: o a volumen esfera 11.py 1 2 3 4 5 6 volumen esfera.py volumen esfera.py from math import pi radio = float(raw_input()) volumen = 4.0 / 3.0 * pi * radio ** 3 print volumen Al ejecutar el programa desde la l´ ınea de ´rdenes Unix, el ordenador parece quedar o bloqueado. No lo est´: en realidad Python est´ solicitando una entrada de teclado y espea a ra que se la proporcione el usuario. Si tecleas, por ejemplo, el n´mero 3 y pulsas la tecla u de retorno de carro, Python responde imprimiendo en pantalla el valor 113.097335529. Puedes volver a ejecutar el programa y, en lugar de teclear el n´mero 3, teclear cualquier u otro valor; Python nos responder´ con el valor del volumen de la esfera para un radio a igual al valor que hayas tecleado. Pero el programa no es muy elegante, pues deja al ordenador bloqueado hasta que el usuario teclee una cantidad y no informa de qu´ es exactamente esa cantidad. Vamos e Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 64 64 Introducción a la programación con Python - UJI c UJI
    • a hacer que el programa indique, mediante un mensaje, qu´ dato desea que se teclee. La e funci´n raw_input acepta un argumento: una cadena con el mensaje que debe mostrar. o Modifica el programa para que quede as´ ı: volumen esfera.py volumen esfera 12.py 1 2 3 4 5 6 from math import pi radio = float(raw_input(’Dame␣el␣radio:␣’)) volumen = 4.0 / 3.0 * pi * radio ** 3 print volumen Ahora, cada vez que lo ejecutes, mostrar´ por pantalla el mensaje ˂˂Dame el radio:˃˃ y a detendr´ su ejecuci´n hasta que introduzcas un n´mero y pulses el retorno de carro. a o u ↱ $ python volumen_esfera.py Dame el radio: 3 113.097335529 La forma de uso del programa desde PythonG es muy similar. Cuando ejecutas el programa, aparece el mensaje ˂˂Dame el radio:˃˃ en la consola de entrada/salida y se detiene la ejecuci´n (figura 3.4 (a)). El usuario debe teclear el valor del radio, que va o apareciendo en la propia consola (figura 3.4 (b)), y pulsar al final la tecla de retorno de carro. El resultado aparece a continuaci´n en la consola (figura 3.4 (c)). o (a) (b) (c) Figura 3.4: Entrada/salida en la consola al ejecutar el programa volumen esfera.py. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 34 Dise˜a un programa que pida el valor del lado de un cuadrado y muestre el valor n de su per´ ımetro y el de su area. ´ (Prueba que tu programa funciona correctamente con este ejemplo: si el lado vale 1.1, el per´ ımetro ser´ 4.4, y el area 1.21.) a ´ · 35 Dise˜a un programa que pida el valor de los dos lados de un rect´ngulo y muestre n a el valor de su per´ ımetro y el de su area. ´ (Prueba que tu programa funciona correctamente con este ejemplo: si un lado mide 1 y el otro 5, el per´ ımetro ser´ 12.0, y el area 5.0.) a ´ · 36 Dise˜a un programa que pida el valor de la base y la altura de un tri´ngulo y n a muestre el valor de su area. ´ (Prueba que tu programa funciona correctamente con este ejemplo: si la base es 10 y la altura 100, el area ser´ 500.0.) a ´ Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 65 65 Introducción a la programación con Python - UJIUJI c
    • · 37 Dise˜a un programa que pida el valor de los tres lados de un tri´ngulo y calcule n a el valor de su area y per´ ımetro. ´ Recuerda que el area A de un tri´ngulo puede calcularse a partir de sus tres lados, a ´ a, b y c, as´ A = s(s − a)(s − b)(s − c), donde s = (a + b + c)/2. ı: (Prueba que tu programa funciona correctamente con este ejemplo: si los lados miden 3, 5 y 7, el per´ ımetro ser´ 15.0 y el area 6.49519052838.) a ´ .................................................................................. 3.3.2. M´s sobre la sentencia print a Las cadenas pueden usarse tambi´n para mostrar textos por pantalla en cualquier moe mento a trav´s de sentencias print. e volumen esfera 13.py 1 2 3 4 5 6 7 8 9 volumen esfera.py from math import pi print ’Programa␣para␣el␣c´lculo␣del␣volumen␣de␣una␣esfera.’ a radio = float(raw_input(’Dame␣el␣radio:␣’)) volumen = 4.0 / 3.0 * pi * radio ** 3 print volumen print ’Gracias␣por␣utilizar␣este␣programa.’ Cuando ejecutes este programa, f´ ıjate en que las cadenas que se muestran con print no aparecen entrecomilladas. El usuario del programa no est´ interesado en saber que le a estamos mostrando datos del tipo cadena: s´lo le interesa el texto de dichas cadenas. o Mucho mejor, pues, no mostrarle las comillas. Una sentencia print puede mostrar m´s de un resultado en una misma l´ a ınea: basta con separar con comas todos los valores que deseamos mostrar. Cada una de las comas se traduce en un espacio de separaci´n. El siguiente programa: o volumen esfera 14.py 1 2 3 4 5 6 7 8 volumen esfera.py from math import pi print ’Programa␣para␣el␣c´lculo␣del␣volumen␣de␣una␣esfera.’ a radio = float(raw_input(’Dame␣el␣radio␣(en␣metros):␣’)) volumen = 4.0/3.0 * pi * radio ** 3 print ’Volumen␣de␣la␣esfera:’, volumen, ’metros␣c´bicos’ u hace que se muestre el texto ˂˂Volumen de la esfera:˃˃, seguido del valor de la variable volumen y acabado con ˂˂metros c´bicos˃˃. Observa que los elementos del ultimo print u ´ se separan entre s´ por espacios en blanco: ı Programa para el c´lculo del volumen de una esfera. a Dame el radio (en metros): 2 El volumen de la esfera es de 33.5103216383 metros c´bicos u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 38 El area A de un tri´ngulo se puede calcular a partir del valor de dos de sus lados, a ´ a y b, y del angulo θ que ´stos forman entre s´ con la f´rmula A = 1 ab sin(θ). Dise˜a un e ı o n ´ 2 programa que pida al usuario el valor de los dos lados (en metros), el angulo que estos ´ forman (en grados), y muestre el valor del area. ´ Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 66 66 Introducción a la programación con Python - UJIUJI c
    • b θ a (Ten en cuenta que la funci´n sin de Python trabaja en radianes, as´ que el angulo o ı ´ que leas en grados deber´s pasarlo a radianes sabiendo que π radianes son 180 grados. a Prueba que has hecho bien el programa introduciendo los siguientes datos: a = 1, b = 2, θ = 30; el resultado es 0.5.) · 39 Haz un programa que pida al usuario una cantidad de euros, una tasa de inter´s y e un n´mero de a˜os. Muestra por pantalla en cu´nto se habr´ convertido el capital inicial u n a a transcurridos esos a˜os si cada a˜o se aplica la tasa de inter´s introducida. n n e Recuerda que un capital de C euros a un inter´s del x por cien durante n a˜os se e n n euros. convierten en C · (1 + x/100) (Prueba tu programa sabiendo que una cantidad de 10 000 ¤ al 4.5% de inter´s anual e se convierte en 24 117.14 ¤ al cabo de 20 a˜os.) n · 40 Haz un programa que pida el nombre de una persona y lo muestre en pantalla repetido 1000 veces, pero dejando un espacio de separaci´n entre aparici´n y aparici´n o o o del nombre. (Utiliza los operadores de concatenaci´n y repetici´n.) o o .................................................................................. Por lo visto hasta el momento, cada print empieza a imprimir en una nueva l´ ınea. Podemos evitarlo si el anterior print finaliza en una coma. F´ ıjate en este programa: volumen esfera.py 1 2 3 4 5 6 7 8 9 volumen esfera.py from math import pi print ’Programa␣para␣el␣c´lculo␣del␣volumen␣de␣una␣esfera.’ a radio = float(raw_input(’Dame␣el␣radio␣(en␣metros):␣’)) volumen = 4.0/3.0 * pi * radio ** 3 print ’Volumen␣de␣la␣esfera:’, print volumen, ’metros␣c´bicos’ u La pen´ltima l´ u ınea es una sentencia print que finaliza en una coma. Si ejecutamos el programa obtendremos un resultado absolutamente equivalente al de la versi´n anterior: o Programa para el c´lculo del volumen de una esfera. a Dame el radio (en metros): 2 El volumen de la esfera es de 33.5103216383 metros c´bicos u Ocurre que cada print imprime, en principio, un car´cter especial denominado ˂˂nueva a l´ ınea˃˃, que hace que el cursor (la posici´n en la que se escribe la salida por pantalla en o cada instante) se desplace a la siguiente l´ ınea. Si print finaliza en una coma, Python no imprime el car´cter ˂˂nueva l´ a ınea˃˃, as´ que el cursor no se desplaza a la siguiente l´ ı ınea. El siguiente print, pues, imprimir´ inmediatamente a continuaci´n, en la misma l´ a o ınea. 3.3.3. Salida con formato Con la sentencia print podemos controlar hasta cierto punto la apariencia de la salida. Pero no tenemos un control total: Cada coma en la sentencia print hace que aparezca un espacio en blanco en la pantalla. ¿Y si no deseamos que aparezca ese espacio en blanco? Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 6767 Introducción a la programación con Python - UJIUJI c
    • Cada n´mero ocupa tantas ˂˂casillas˃˃ de la pantalla como caracteres tiene. Por u ejemplo, el n´mero 2 ocupa una casilla, y el n´mero 2000, cuatro. ¿Y si queremos u u que todos los n´meros ocupen el mismo n´mero de casillas? u u Python nos permite controlar con absoluta precisi´n la salida por pantalla. Para ello o hemos de aprender un nuevo uso del operador %. Estudia detenidamente este programa: potencias.py potencias 1.py 1 2 3 4 5 6 numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u print ’%d␣elevado␣a␣%d␣es␣%d’ print ’%d␣elevado␣a␣%d␣es␣%d’ print ’%d␣elevado␣a␣%d␣es␣%d’ print ’%d␣elevado␣a␣%d␣es␣%d’ % % % % (numero, 2, numero (numero, 3, numero (numero, 4, numero (numero, 5, numero ** ** ** ** 2) 3) 4) 5) Cada una de las cuatro ultimas l´ ıneas presenta este aspecto: ´ print cadena % (valor, valor, valor) La cadena es especial, pues tiene unas marcas de la forma %d. ¿Tienen alg´n signifiu cado? Despu´s de la cadena aparece el operador %, que hemos visto en el tema anterior e como operador de enteros o flotantes, pero que aqu´ combina una cadena (a su izquierda) ı con una serie de valores (a su derecha). ¿Qu´ hace en este caso? e Para entender qu´ hacen las cuatro ultimas l´ e ıneas, ejecutemos el programa: ´ Dame un n´mero: 3 u 3 elevado a 2 es 9 3 elevado a 3 es 27 3 elevado a 4 es 81 3 elevado a 5 es 243 Cada marca de formato %d en la cadena ’%d␣elevado␣a␣%d␣es␣%d’ ha sido sustituida por un n´mero entero. El fragmento %d significa ˂˂aqu´ va un n´mero entero˃˃. u ı u ¿Qu´ n´mero? El que resulta de evaluar cada una de las tres expresiones que aparecen e u separadas por comas y entre par´ntesis a la derecha del operador %. e ’ %d elevado a %d es %d ’ % ( numero , 2 , numero ** 2 ) No s´lo podemos usar el operador % en cadenas que vamos a imprimir con print: el o resultado es una cadena y se puede manipular como cualquier otra: ↱ ↱ ↱ ↱ >>> x = 2 >>> print ’n´mero␣%d␣y␣n´mero␣%d’ % (1, x) u u n´mero 1 y n´mero 2 u u >>> a = ’n´mero␣%d␣y␣n´mero␣%d’ % (1, x) u u >>> a ’n´mero 1 y n´mero 2’ u u >>> print (’n´mero␣%d␣y␣n´mero␣%d’ % (1, x)).upper() u u N´MERO 1 Y N´MERO 2 U U ↱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 41 ¿Qu´ mostrar´ por pantalla este programa? e a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 68 68 Introducción a la programación con Python - UJIUJI c
    • 1 2 3 4 5 6 print ’%d’ % 1 print ’%d␣%d’ % (1, 2) print ’%d%d’ % (1, 2) print ’%d,␣%d’ % (1, 2) print 1, 2 print ’%d␣2’ % 1 · 42 Un alumno inquieto ha experimentado con las marcas de formato y el m´todo e upper y ha obtenido un resultado sorprendente: ↱ >>> print (’n´mero␣%d␣y␣n´mero␣%d’ % (1, 2)).upper() u u N´MERO 1 Y N´MERO 2 U U >>> print ’n´mero␣%d␣y␣n´mero␣%d’.upper() % (1, 2) u u Traceback (most recent call last): File "<stdin>", line 1, in ? ValueError: unsupported format character ’D’ (0x44) at index 8 ↱ ¿Qu´ crees que ha pasado? e (Nota: Aunque experimentar conlleva el riesgo de equivocarse, no podemos enfatizar suficientemente cu´n importante es para que asimiles las explicaciones. Probarlo todo, a cometer errores, reflexionar sobre ellos y corregirlos es uno de los mejores ejercicios imaginables.) .................................................................................. Vamos a modificar ligeramente el programa: potencias.py 1 2 3 4 5 6 potencias.py numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u print ’%d␣elevado␣a␣%d␣es␣%4d’ print ’%d␣elevado␣a␣%d␣es␣%4d’ print ’%d␣elevado␣a␣%d␣es␣%4d’ print ’%d␣elevado␣a␣%d␣es␣%4d’ % % % % (numero, 2, numero (numero, 3, numero (numero, 4, numero (numero, 5, numero ** ** ** ** 2) 3) 4) 5) El tercer %d de cada l´ ınea ha sido sustituido por un %4d. Veamos qu´ ocurre al e ejecutar el nuevo programa: Dame un n´mero: 3 u 3␣elevado␣a␣2␣es␣␣␣␣9 3␣elevado␣a␣3␣es␣␣␣27 3␣elevado␣a␣4␣es␣␣␣81 3␣elevado␣a␣5␣es␣␣243 Los n´meros enteros que ocupan la tercera posici´n aparecen alineados a la derecha. u o El fragmento %4d significa ˂˂aqu´ va un entero que representar´ ocupando 4 casillas˃˃. Si ı e el n´mero entero tiene 4 o menos d´ u ıgitos, Python lo representa dejando delante de ´l los e espacios en blanco que sea menester para que ocupe exactamente 4 espacios. Si tiene m´s de 4 d´ a ıgitos, no podr´ cumplir con la exigencia impuesta, pero seguir´ representando a a el n´mero entero correctamente. u Hagamos la prueba. Ejecutemos de nuevo el mismo programa, pero introduciendo otro n´mero: u Dame un n´mero: 7 u 7␣elevado␣a␣2␣es␣␣␣49 7␣elevado␣a␣3␣es␣␣343 7␣elevado␣a␣4␣es␣2401 7␣elevado␣a␣5␣es␣16807 Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 6969 Introducción a la programación con Python - UJIUJI c
    • ¿Ves? El ultimo n´mero tiene cinco d´ u ıgitos, as´ que ˂˂se sale˃˃ por el margen derecho. ı ´ Las cadenas con marcas de formato como %d se denominan cadenas con formato y el operador % a cuya izquierda hay una cadena con formato es el operador de formato. Las cadenas con formato son especialmente utiles para representar adecuadamente ´ n´meros flotantes. F´ u ıjate en el siguiente programa: area con formato.py 1 2 3 4 5 6 7 area con formato.py from math import pi radio = float(raw_input(’Dame␣el␣radio:␣’)) area = pi*radio**2 print ’El␣´rea␣de␣un␣c´rculo␣de␣radio␣%f␣es␣%f’ % (radio, area) a ı print ’El␣´rea␣de␣un␣c´rculo␣de␣radio␣%6.3f␣es␣%6.3f’ % (radio, area) a ı Ejecutemos el programa: Dame el radio: 2 El ´rea de un c´rculo de radio 2.000000 es 12.566371 a ı El ´rea de un c´rculo de radio 2.000 es 12.566 a ı Observa: la marca %f indica que ah´ aparecer´ un flotante. Podemos meter un n´mero ı a u con decimales entre el % y la f. ¿Qu´ significa? Indica cu´ntas casillas deseamos que e a ocupe el flotante (parte entera del n´mero entre la % y la f) y, de ellas, cu´ntas queremos u a que ocupen los n´meros decimales (parte decimal del mismo n´mero). u u Hemos visto que hay marcas de formato para enteros y flotantes. Tambi´n hay una e marca para cadenas: %s. El siguiente programa lee el nombre de una persona y la saluda: saluda 3.py 1 2 saluda.py nombre = raw_input(’Tu␣nombre:␣’) print ’Hola,␣%s.’ % (nombre) Probemos el programa: Tu nombre: Juan Hola, Juan. ¡Ah! Los par´ntesis en el argumento de la derecha del operador de formato son e opcionales si s´lo se le pasa un valor. Esta nueva versi´n del programa es equivalente: o o saluda 4.py 1 2 saluda.py nombre = raw_input(’Tu␣nombre:␣’) print ’Hola,␣%s.’ % nombre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 43 ¿Qu´ peque˜a diferencia hay entre el programa saluda.py y este otro cuando e n los ejecutamos? saluda2.py 1 2 nombre = raw_input(’Tu␣nombre:␣’) print ’Hola,’, nombre, ’.’ · 44 La marca %s puede representar cadenas con un n´mero fijo de casillas. A la vista u de c´mo se pod´ expresar esta caracter´ o ıa ıstica en la marca de enteros %d, ¿sabr´ como ıas indicar que deseamos representar una cadena que ocupa 10 casillas? .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 70 70 Introducción a la programación con Python - UJIUJI c
    • 3.4. Legibilidad de los programas Los programas que estamos dise˜ando son bastante sencillos. No ocupan m´s all´ de n a a tres o cuatro l´ ıneas y siempre presentan una misma estructura: Piden el valor de una serie de datos (mediante raw_input). Efect´an unos c´lculos con ellos. u a Muestran el resultado de los c´lculos (con print). a Estos programas son f´ciles de leer y, en cierto modo, autoexplicativos. a F´ ıjate en este programa y trata de descifrar qu´ hace: e ilegible.py 1 2 3 4 5 6 ilegible.py h = float(raw_input(’Dame␣h:␣’)) v = float(raw_input(’y␣v:␣’)) z=h*v print ’Resultado␣1␣%6.2f’ % z v=2*h+v+v print ’Resultado␣2␣%6.2f’ % v Mmmm. . . no est´ muy claro, ¿verdad? Podemos entender qu´ hace el programa l´ a e ınea a l´ ınea, pero es dif´ captar su prop´sito. ıcil o Ahora trata de leer este otro. legible.py 1 2 3 4 5 6 7 8 9 10 legible.py print ’Programa␣para␣el␣c´lculo␣del␣per´metro␣y␣el␣´rea␣de␣un␣rect´ngulo.’ a ı a a altura = float(raw_input(’Dame␣la␣altura␣(en␣metros):␣’)) anchura = float(raw_input(’Dame␣la␣anchura␣(en␣metros):␣’)) area = altura * anchura perimetro = 2 * altura + 2 * anchura print ’El␣per´metro␣es␣de␣%6.2f␣metros.’ % perimetro ı print ’El␣´rea␣es␣de␣%6.2f␣metros␣cuadrados.’ % area a Sencillo, ¿verdad? Hemos separado visualmente cuatro zonas con la ayuda de l´ ıneas en blanco. En la primera l´ ınea se anuncia el cometido del programa. En las dos siguientes l´ ıneas no blancas se pide el valor de dos datos y el nombre de las variables en los que los almacenamos ya sugiere qu´ son esos datos. A continuaci´n, se efect´an unos c´lculos. e o u a Tambi´n en este caso el nombre de las variables ayuda a entender qu´ significan los e e resultados obtenidos. Finalmente, en las dos ultimas l´ ıneas del programa se muestran los ´ resultados por pantalla. Evidentemente, el programa pide la altura y la anchura de un rect´ngulo y calcula su per´ a ımetro y area, valores que muestra a continuaci´n. o ´ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 45 Dise˜a un programa que solicite el radio de una circunferencia y muestre su area n ´ y per´ ımetro con s´lo 2 decimales. o .................................................................................. 3.4.1. Algunas claves para aumentar la legibilidad ¿Por qu´ uno de los programas ha resultado m´s sencillo de leer que el otro? e a Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 71 71 Introducción a la programación con Python - UJI c UJI
    • ilegible.py usa nombres arbitrarios y breves para las variables, mientras que legible.py utiliza identificadores representativos y tan largos como sea necesario. El programador de ilegible.py pensaba m´s en teclear poco que en hacer a comprensible el programa. ilegible.py no tiene una estructura clara: mezcla c´lculos con impresi´n de resula o tados. En su lugar, legible.py diferencia claramente zonas distintas del programa (lectura de datos, realizaci´n de c´lculos y visualizaci´n de resultados) y llega a o a o usar marcas visuales como las l´ ıneas en blanco para separarlas. Probablemente el programador de ilegible.py escrib´ el programa conforme se le iban ocurrienıa do cosas. El programador de legible.py ten´ claro qu´ iba a hacer desde el ıa e principio: planific´ la estructura del programa. o ilegible.py utiliza f´rmulas poco frecuentes para realizar algunos de los c´lculos: o a la forma en que calcula el per´ ımetro es v´lida, pero poco ortodoxa. Por contra, a legible.py utiliza formas de expresi´n de los c´lculos que son est´ndar. El proo a a gramador de ilegible.py deber´ haber pensado en los convenios a la hora de ıa utilizar f´rmulas. o Los mensajes de ilegible.py, tanto al pedir datos como al mostrar resultados, son de p´sima calidad. Un usuario que se enfrenta al programa por primera vez tendr´ e a serios problemas para entender qu´ se le pide y qu´ se le muestra como resultado. e e El programa legible.py emplea mensajes de entrada/salida muy informativos. Seguro que el programador de ilegible.py pensaba que ´l ser´ el unico usuario e ıa ´ de su programa. La legibilidad de los programas es clave para hacerlos pr´cticos. ¿Y por qu´ querr´ a e ıa un programador leer programas ya escritos? Por varias razones. He aqu´ algunas: ı Es posible que el programa se escribiera hace unas semanas o meses (o incluso a˜os) y ahora se desee modificar para extender su funcionalidad. Un programa n legible nos permitir´ ponernos mano a la obra r´pidamente. a a Puede que el programa contenga errores de programaci´n y deseemos detectarlos y o corregirlos. Cuanto m´s legible sea el programa, m´s f´cil y r´pido ser´ depurarlo. a a a a a O puede que el programa lo haya escrito un programador de la empresa que ya no est´ trabajando en nuestro equipo. Si nos encargan trabajar sobre ese programa, a nos gustar´ que el mismo estuviera bien organizado y fuera f´cilmente legible.3 ıa a Atenerte a la reglas usadas en legible.py ser´ fundamental para hacer legibles tus a programas. 3.4.2. Comentarios Dentro de poco empezaremos a realizar programas de mayor envergadura y con mucha mayor complicaci´n. Incluso observando las reglas indicadas, va a resultar una tarea o ardua leer un programa completo. Un modo de aumentar la legibilidad de un programa consiste en intercalar comentarios que expliquen su finalidad o que aclaren sus pasajes m´s oscuros. a Como esos comentarios s´lo tienen por objeto facilitar la legibilidad de los programas o para los programadores, pueden escribirse en el idioma que desees. Cuando el int´rprete e Python ve un comentario no hace nada con ´l: lo omite. ¿C´mo le indicamos al int´rprete e o e 3 Si ´ste es tu libro de texto, m´ e ıralo desde un lado ˂˂acad´micamente pragm´tico˃˃: si tus programas han e a de ser evaluados por un profesor, ¿qu´ calificaci´n obtendr´s si le dificultas enormemente la lectura? ;-) e o a Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 72 72 Introducción a la programación con Python - c UJI UJI
    • que cierto texto es un comentario? Necesitamos alguna marca especial. Los comentarios Python se inician con el s´ ımbolo # (que se lee ˂˂almohadilla˃˃): todo texto desde la almohadilla hasta el final de la l´ ınea se considera comentario y, en consecuencia, es omitido por Python. He aqu´ un programa con comentarios: ı rectangulo.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # # # # # rectangulo.py Programa: rectangulo.py Prop´sito: Calcula el per´ o ımetro y el area de un rect´ngulo a partir a ´ de su altura y anchura. Autor: John Cleese Fecha: 1/1/2001 # Petici´n de los datos (en metros) o altura = float(raw_input(’Dame␣la␣altura␣(en␣metros):␣’)) anchura = float(raw_input(’Dame␣la␣anchura␣(en␣metros):␣’)) # C´lculo del area y del per´ a ımetro ´ area = altura * anchura perimetro = 2 * altura + 2 * anchura # Impresi´n de resultados por pantalla o print ’El␣per´metro␣es␣de␣%6.2f␣metros’ % perimetro # s´lo dos decimales. ı o print ’El␣´rea␣es␣de␣%6.2f␣metros␣cuadrados’ % area a Observa que hemos puesto comentarios: en la cabecera del programa, comentando el nombre del programa, su prop´sito, el o autor y la fecha; al principio de cada una de las ˂˂grandes zonas˃˃ del programa, indicando qu´ se e hace en ellas; y al final de una de las l´ ıneas (la pen´ltima), para comentar alguna peculiaridad u de la misma. Es buena pr´ctica que ˂˂comentes˃˃ tus programas. Pero ten presente que no hay a reglas fijas que indiquen cu´ndo, d´nde y c´mo comentar los programas: las que acabes a o o adoptando formar´n parte de tu estilo de programaci´n. a o 3.5. Gr´ficos a Todos los programas que te hemos presentado utilizan el teclado y la pantalla en ˂˂modo texto˃˃ para interactuar con el usuario. Sin embargo, est´s acostumbrado a interactuar con a el ordenador mediante un terminal gr´fico y usando, adem´s del teclado, el rat´n. En este a a o apartado vamos a introducir brevemente las capacidades gr´ficas del entorno PythonG. a En el ap´ndice B se resumen las funciones que presentamos en este y otros apartados. e Inicia el entorno PythonG y ver´s que hay un cuadrado en blanco en la zona superior a derecha. Es la ventana gr´fica o lienzo. Todos los elementos gr´ficos que produzcan tus a a programas se mostrar´n en ella. La esquina inferior izquierda de la ventana gr´fica tiene a a coordenadas (0, 0), y la esquina superior derecha, coordenadas (1000, 1000). Nuestro primer programa gr´fico es muy sencillo: dibuja una l´ a ınea en el lienzo que va del punto (100, 100) al punto (900, 900). La funci´n create_line dibuja una l´ o ınea en pantalla. Debes suministrarle cuatro valores num´ricos: las coordenadas del punto inicial e y las del punto final de la recta: una recta.py 1 create_line(100,100, 900,900) Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o una recta.py 73 73 Introducción a la programación con Python - c UJI UJI
    • Ejecuta el programa. Obtendr´s la salida que se muestra en la figura 3.5. a Figura 3.5: Programa que dibuja una recta en la ventana gr´fica del entorno PythonG. a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 46 Dibuja esta figura. (Te indicamos las coordenadas de las esquinas inferior izquierda y superior derecha.) (900, 900) (100, 100) .................................................................................. Adem´s de l´ a ıneas rectas, puedes dibujar otros elementos gr´ficos. He aqu´ una relaci´n a ı o de las funciones de creaci´n de elementos gr´ficos que te ofrece PythonG: o a create_point(x, y): dibuja un punto en (x, y). (x, y) create_line(x1, y1, x2, y2): dibuja una l´ ınea de (x1, y1) a (x2, y2). (x2 , y2 ) (x1 , y1 ) create_circle(x, y, radio): dibuja una circunferencia con centro en (x, y) y radio radio. radio (x, y) Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 74 74 Introducción a la programación con Python - UJIUJI c
    • create_rectangle(x1, y1, x2, y2): dibuja un rect´ngulo con esquinas opuestas en a (x1, y1) y (x2, y2). (x2 , y2 ) (x1 , y1 ) create_text(x, y, cadena, tama˜o, anclaje): dibuja el texto cadena en el punto n (x, y). El par´metro tama˜o expresa el tama˜o del tipo de letra en puntos. Un valor a n n razonable para las fuentes es 10 o 12 puntos. El ultimo par´metro, anclaje, indica si a ´ el texto se ˂˂ancla˃˃ al punto (x, y) por el centro (’CENTER’), por la esquina superior izquierda (’NW’), inferior izquierda (’SW’), etc. Esta figura muestra los puntos de anclaje y la cadena que hemos de suministrar como par´metro: a ’NW’ ’W’ ’SW’ ’CENTER’ ’NE’ cadena anclada ’E’ ’SE’ ’S’ ’N’ Una Por ejemplo, create_text(100, 100, ’Hola’, 10, ’NE’) dibuja en pantalla el texto ˂˂Hola˃˃ anclando la esquina superior derecha en las coordenadas (100, 100). Hola (100, 100) create_filled_circle(x, y, radio): dibuja un c´ ırculo relleno (de color negro) con centro en (x, y) y radio radio. create_filled_rectangle(x1, y1, x2, y2): dibuja un rect´ngulo relleno (de color a negro) con esquinas opuestas en (x1, y1) y (x2, y2). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 47 Dibuja esta figura. Los tres c´ ırculos conc´ntricos tienen radios 100, 200 y 300, respectivamente. e · 48 Dibuja esta figura. a d b c Los tres c´ ırculos conc´ntricos tienen radios 100, 200 y 300, respectivamente. e Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 75 75 Introducción a la programación con Python - UJIUJI c
    • .................................................................................. Has de saber que todas las funciones de creaci´n de elementos gr´ficos aceptan un o a par´metro opcional: una cadena que puede tomar el valor ’white’ (blanco), ’black’ a (negro), ’red’ (rojo), ’blue’ (azul), ’green’ (verde), ’yellow’ (amarillo), ’cyan’ (ci´n) a o ’magenta’ (magenta). Con ese par´metro se indica el color del elemento. Si se omite, a toma el valor por defecto ’black’. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 49 Dibuja esta figura. a d b c (Hemos usado los colores amarillo y magenta para las l´ ıneas rectas, verde y azul para los c´ ırculos y negro para las letras.) .................................................................................. Vamos a hacer un primer programa con salida gr´fica y que presente cierta utilidad: un a programa que muestra el porcentaje de suspensos, aprobados, notables y sobresalientes de una asignatura mediante un ˂˂gr´fico de pastel˃˃. He aqu´ un ejemplo de gr´fico como a ı a el que deseamos para una tasa de suspensos del 10%, un 20% de aprobados, un 40% de notables y un 30% de sobresalientes: Apr (20 %) Sus (10 %) Not (40 %) Sob (30 %) Empecemos. El c´ ırculo resulta f´cil: tendr´ centro en (500, 500) y su radio ser´ de a a a 500 unidades. As´ conseguimos que ocupe la mayor proporci´n posible de pantalla. ı o pastel 8.py 1 pastel.py create_circle(500,500, 500) Mejor vamos a independizar relativamente el programa del centro y radio de la circunferencia: pastel 9.py 1 2 3 4 pastel.py x = 500 y = 500 radio = 500 create_circle(x, y, radio) De este modo, cambiar la ubicaci´n o el tama˜o del gr´fico de pastel resultar´ sencillo. o n a a Sigamos. Vamos a dibujar el corte de las personas que han suspendido, o sea, nuestro objetivo ahora es conseguir este dibujo: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 76 76 Introducción a la programación con Python - UJIUJI c
    • Hemos de dibujar dos l´ ıneas. La l´ ınea horizontal es muy sencilla: parte de (x, y) y llega a (x + radio, y): pastel.py pastel 10.py 1 2 3 4 5 x = 500 y = 500 radio = 500 create_circle(x, y, radio) create_line(x, y, x+radio, y) La segunda l´ ınea es m´s complicada. ¿Qu´ coordenadas tiene el punto (x1 , y1 ) de a e esta figura: (x, y) α (x1 , y1 ) radio Un poco de trigonometr´ nos vendr´ bien. Si conoci´semos el angulo α, el c´lculo ıa a e a ´ resultar´ sencillo: ıa x1 = x + radio cos(α) y1 = y + radio sin(α) El angulo α representa la porci´n del c´ o ırculo que corresponde a los suspensos. Como una ´ circunferencia completa recorre un angulo de 2π radianes, y los suspensos constituyen el ´ 10% del total, el angulo α es 2π · 10/100 o, para que quede m´s claro, 2π · suspensos/100. a ´ pastel 11.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 pastel.py from math import sin, cos, pi x = 500 y = 500 radio = 500 suspensos = 10 aprobados = 20 notables = 40 sobresalientes = 30 create_circle(x, y, radio) create_line(x, y, x+radio, y) alfa = 2*pi*suspensos/100 create_line(x, y, x+radio*cos(alfa), y+radio*sin(alfa)) Ya est´. De paso, hemos preparado variables para almacenar el porcentaje de suspensos, a aprobados, etc. Vamos a por la siguiente l´ ınea, la que corresponde a los aprobados. ¿Qu´ valor e presenta el angulo β? Si lo conocemos, es inmediato conocer x2 e y2 : ´ (x2 , y2 ) (x, y) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o β radio 77 77 Introducción a la programación con Python - cUJI UJI
    • Podr´ pensar que si α se calcul´ como 2π ·suspensos/100, β ser´ 2π ·aprobados/100. ıas o a Pero te equivocas. El angulo β no representa el 20% de la circunferencia, sino el 30%, ´ que es el resultado de sumar aprobados y suspensos: β = 2π · (suspensos + aprobados)/100 pastel 12.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 pastel.py from math import sin, cos, pi x = 500 y = 500 radio = 500 suspensos = 10 aprobados = 20 notables = 40 sobresalientes = 30 create_circle(x, y, radio) create_line(x, y, x+radio, y) alfa = 2*pi*suspensos/100 create_line(x, y, x+radio*cos(alfa), y+radio*sin(alfa)) beta = 2*pi*(suspensos+aprobados)/100 create_line(x, y, x+radio*cos(beta), y+radio*sin(beta)) Te vamos a dejar que completes t´ mismo el programa incluyendo a los notables y u sobresalientes. Acabaremos presentando, eso s´ el modo en que ponemos las leyendas ı, que indican a qu´ corresponde cada parte del pastel. Queremos etiquetar as´ el primer e ı fragmento: sus (10 %) Usaremos la funci´n create_text. Necesitamos determinar las coordenadas del centro del o texto, que cae en el centro justo de la porci´n de pastel que corresponde a los suspensos. o α/2 El punto tiene por coordenadas (0.5radio cos(α/2), 0.5radio sin(α/2)): pastel 13.py 1 2 3 4 pastel.py from math import sin, cos, pi x = 500 y = 500 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 78 78 Introducción a la programación con Python - cUJI UJI
    • 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 radio = 500 suspensos = 10 aprobados = 20 notables = 40 sobresalientes = 30 create_circle(x, y, radio) create_line(x, y, x+radio, y) alfa = 2*pi*suspensos/100 create_line(x, y, x+radio*cos(alfa), y+radio*sin(alfa)) create_text(x+.5*radio*cos(alfa/2), y+.5*radio*sin(alfa/2),’sus␣(%d%%)’ % suspensos) beta = 2*pi*(suspensos+aprobados)/100 create_line(x, y, x+radio*cos(beta), y+radio*sin(beta)) ¿Y la leyenda de los aprobados? ¿Qu´ coordenadas tiene su centro? F´ e ıjate bien en cu´nto vale el angulo que determina su posici´n: a o ´ α + (β − α)/2 Ya est´: a pastel 14.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 pastel.py from math import sin, cos, pi x = 500 y = 500 radio = 500 suspensos = 10 aprobados = 20 notables = 40 sobresalientes = 30 create_circle(x, y, radio) create_line(x, y, x+radio, y) alfa = 2*pi*suspensos/100 create_line(x, y, x+radio*cos(alfa), y+radio*sin(alfa)) create_text(x+.5*radio*cos(alfa/2), y+.5*radio*sin(alfa/2),’sus␣(%d%%)’ % suspensos) beta = 2*pi*(suspensos+aprobados)/100 create_line(x, y, x+radio*cos(beta), y+radio*sin(beta)) create_text(x+.5*radio*cos(alfa+(beta-alfa)/2), y+.5*radio*sin(alfa+(beta-alfa)/2),’apr␣(%d%%)’ % aprobados Observa la l´ ınea 20. Acaba en una barra invertida y la sentencia contin´a en la u l´ ınea 21. Es una forma de indicar a Python que la sentencia es demasiado larga para que resulte c´modo o legible disponerla en una sola l´ o ınea y que, por tanto, contin´a en u la siguiente l´ ınea. Ponemos ´nfasis en ˂˂acaba˃˃ porque la barra invertida ˂˂˃˃ debe ir e inmediatamente seguida de un salto de l´ ınea. Si pones un espacio en blanco o cualquier otro car´cter detr´s, Python se˜alar´ un error. Lo cierto es que la barra era innecesaria. a a n a Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 79 79 Introducción a la programación con Python - cUJI UJI
    • Si una l´ ınea finaliza sin que se hayan cerrado todos los par´ntesis (o llaves, o corchetes) e abiertos, puede continuar en la siguiente l´ ınea. Completa el programa t´ mismo. u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 50 Modifica el programa para que sea el usuario quien proporcione, mediante el teclado, el valor del porcentaje de suspensos, aprobados, notables y sobresalientes. · 51 Modifica el programa para que sea el usuario quien proporcione, mediante el teclado, el n´mero de suspensos, aprobados, notables y sobresalientes. (Antes de dibujar u el gr´fico de pastel debes convertir esas cantidades en porcentajes.) a · 52 Queremos representar la informaci´n de forma diferente: mediante un gr´fico de o a barras. He aqu´ c´mo: ı o 40 % 30 % 20 % 10 % Sus Apr Not Sob Dise˜a un programa que solicite por teclado el n´mero de personas con cada una de las n u cuatro calificaciones y muestre el resultado con un gr´fico de barras. a .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 80 80 Introducción a la programación con Python - UJIUJI c
    • Cap´ ıtulo 4 Estructuras de control De ah´ que est´n dando vueltas continuamente, supongo dijo Alicia. ı e Si, as´ es dijo el Sombrerero, conforme se van ensuciando las cosas. ı Pero ¿qu´ ocurre cuando vuelven al principio de nuevo? se atrevi´ a e o preguntar Alicia. LEWIS CARROLL, Alicia a trav´s del espejo. e Los programas que hemos aprendido a construir hasta el momento presentan siempre una misma secuencia de acciones: 1. Se piden datos al usuario (asignando a variables valores obtenidos con raw_input). 2. Se efect´an c´lculos con los datos introducidos por el usuario, guardando el resulu a tado en variables (mediante asignaciones). 3. Se muestran por pantalla los resultados almacenados en variables (mediante la sentencia print). Estos programas se forman como una serie de l´ ıneas que se ejecutan una tras otra, desde la primera hasta la ultima y siguiendo el mismo orden con el que aparecen en el ´ fichero: el flujo de ejecuci´n del programa es estrictamente secuencial. o No obstante, es posible alterar el flujo de ejecuci´n de los programas para hacer que: o tomen decisiones a partir de los datos y/o resultados intermedios y, en funci´n de o e ´stas, ejecuten ciertas sentencias y otras no; tomen decisiones a partir de los datos y/o resultados intermedios y, en funci´n de o e a ´stas, ejecuten ciertas sentencias m´s de una vez. El primer tipo de alteraci´n del flujo de control se efect´a con sentencias condicionales o u o de selecci´n y el segundo tipo con sentencias iterativas o de repetici´n. Las sentencias o o que permiten alterar el flujo de ejecuci´n se engloban en las denominadas estructuras de o control de flujo (que abreviamos con el t´rmino ˂˂estructuras de control˃˃). e Estudiaremos una forma adicional de alterar el flujo de control que permite se˜alar, n detectar y tratar los errores que se producen al ejecutar un programa: las sentencias de emisi´n y captura de excepciones. o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 81 81 Introducción a la programación con Python - UJI
    • 4.1. 4.1.1. Sentencias condicionales Un programa de ejemplo: resoluci´n de ecuaciones de primer grado o Veamos un ejemplo. Dise˜emos un programa para resolver cualquier ecuaci´n de primer n o grado de la forma ax + b = 0, donde x es la inc´gnita. o Antes de empezar hemos de responder a dos preguntas: 1. 2. ¿Cu´les son los datos del problema? (Generalmente, los datos del problema se a pedir´n al usuario con raw_input.) a En nuestro problema, los coeficientes a y b son los datos del problema. ¿Qu´ deseamos calcular? (T´ e ıpicamente, lo que calculemos se mostrar´ al usuario a mediante una sentencia print.) Obviamente, el valor de x. Ahora que conocemos los datos de entrada y el resultado que hemos de calcular, es decir, los datos de salida, nos preguntamos: ¿c´mo calculamos la salida a partir de la o entrada? En nuestro ejemplo, despejando x de la ecuaci´n llegamos a la conclusi´n de o o que x se obtiene calculando −b/a. Siguiendo el esquema de los programas que sabemos hacer, procederemos as´ ı: 1. 2. 3. Pediremos el valor de a y el valor de b (que supondremos de tipo flotante). Calcularemos el valor de x como −b/a. Mostraremos por pantalla el valor de x. Escribamos el siguiente programa en un fichero de texto llamado primer grado.py: primer grado 7.py 1 2 3 4 5 6 primer grado.py a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) x = -b / a print ’Soluci´n:␣’, x o Las l´ ıneas se ejecutan en el mismo orden con el que aparecen en el programa. Ve´moslo a funcionar: Valor de a: 10 Valor de b: 2 Soluci´n: -0.2 o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 53 Un programador propone el siguiente programa para resolver la ecuaci´n de primer o grado: 1 2 3 4 5 6 a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) a*x+b=0 print ’Soluci´n:␣’, x o ¿Es correcto este programa? Si no, explica qu´ est´ mal. e a Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 82 82 Introducción a la programación con Python - UJI c UJI
    • · 54 1 2 3 4 5 6 Otro programador propone este programa: x = -b / a a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) print ’Soluci´n:␣’, x o ¿Es correcto? Si no lo es, explica qu´ est´ mal. e a .................................................................................. Nuestro programa presenta un punto d´bil: cuando a vale 0, se produce un error de e divisi´n por cero: o Valor de a: 0 Valor de b: 3 Traceback (innermost last): File ’primer_grado.py’, line 3, in ? x = -b / a ZeroDivisionError: float division En la medida de lo posible hemos de tratar de evitar los errores en tiempo de ejecuci´n: o detienen la ejecuci´n del programa y muestran mensajes de error poco comprensibles para o el usuario del programa. Si al escribir el programa hemos previsto una soluci´n para todo o posible error de ejecuci´n, podemos (y debemos) tomar el control de la situaci´n en todo o o momento. Errores de ejecuci´n o Hemos dicho que conviene evitar los errores de programa que se producen en tiempo de ejecuci´n y, ciertamente, la industria de desarrollo de software realiza un gran esfuerzo o para que sus productos est´n libres de errores de ejecuci´n. No obstante, el gran tama˜o e o n de los programas y su complejidad (unidos a las prisas por sacar los productos al mercado) hacen que muchos de estos errores acaben haciendo acto de presencia. Todos hemos sufrido la experiencia de, ejecutando una aplicaci´n, obtener un mensaje de error o indicando que se ha abortado la ejecuci´n del programa o, peor a´n, el computador o u se ha quedado ˂˂colgado˃˃. Si la aplicaci´n conten´ datos de trabajo importantes y no o ıa los hab´ ıamos guardado en disco, ´stos se habr´n perdido irremisiblemente. Nada hay e a m´s irritante para el usuario que una aplicaci´n poco estable, es decir, propensa a la a o comisi´n de errores en tiempo de ejecuci´n. o o El sistema operativo es, tambi´n, software, y est´ sujeto a los mismos problemas de e a desarrollo de software que las aplicaciones convencionales. Sin embargo, los errores en el sistema operativo son, por regla general, m´s graves, pues suelen ser ´stos los que a e dejan ˂˂colgado˃˃ al ordenador. El famoso ˂˂sal y vuelve a entrar en la aplicaci´n˃˃ o ˂˂reinicia el computador˃˃ que o suele proponerse como soluci´n pr´ctica a muchos problemas de estos es consecuencia o a de los bajos niveles de calidad de buena parte del software que se comercializa. 4.1.2. La sentencia condicional if En nuestro programa de ejemplo nos gustar´ detectar si a vale cero para, en ese caso, ıa no ejecutar el c´lculo de la cuarta l´ a ınea de primer grado.py, que es la que provoca el error. ¿C´mo hacer que cierta parte del programa se ejecute o deje de hacerlo en funci´n o o de una condici´n determinada? o Los lenguajes de programaci´n convencionales presentan una sentencia especial cuyo o significado es: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 83 83 Introducción a la programación con Python - UJIUJI c
    • ˂˂Al llegar a este punto, ejecuta esta(s) acci´n(es) s´lo si esta condici´n es cierta.˃˃ o o o Este tipo de sentencia se denomina condicional o de selecci´n y en Python es de la o siguiente forma: if condici´n: o acci´n o acci´n o ... acci´n o (En ingl´s ˂˂if˃˃ significa ˂˂si˃˃.) e En nuestro caso, deseamos detectar la condici´n ˂˂a no vale 0˃˃ y, s´lo en ese caso, o o ejecutar las ultimas l´ ıneas del programa: ´ primer grado 8.py 1 2 3 4 5 6 primer grado.py a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) if a != 0: x = -b/a print ’Soluci´n:␣’, x o Analicemos detenidamente las l´ ıneas 4, 5 y 6. En la l´ ınea 4 aparece la sentencia condicional if seguida de lo que, seg´n hemos dicho, debe ser una condici´n. La condici´n u o o se lee f´cilmente si sabemos que != significa ˂˂es distinto de˃˃. As´ pues, la l´ a ı ınea 4 se lee ˂˂si a es distinto de 0˃˃. La l´ ınea que empieza con if debe finalizar obligatoriamente con dos puntos (:). F´ ıjate en que las dos siguientes l´ ıneas se escriben m´s a la derecha. Para a destacar esta caracter´ ıstica, hemos dibujados dos l´ ıneas verticales que marcan el nivel al que apareci´ el if. Decimos que esta l´ o ınea presentan mayor indentaci´n o sangrado o que la l´ ınea que empieza con if. Esta mayor indentaci´n indica que la ejecuci´n de estas o o dos l´ ıneas depende de que se satisfaga la condici´n a != 0: s´lo cuando ´sta es cierta o o e se ejecutan las l´ ıneas de mayor sangrado. As´ pues, cuando a valga 0, esas l´ ı ıneas no se ejecutar´n, evitando de este modo el error de divisi´n por cero. a o Veamos qu´ ocurre ahora si volvemos a introducir los datos que antes provocaron el e error: Valor de a: 0 Valor de b: 3 Mmmm. . . no ocurre nada. No se produce un error, es cierto, pero el programa acaba sin proporcionar ninguna informaci´n. Analicemos la causa. Las dos primeras l´ o ıneas del programa se han ejecutado (nos piden los valores de a y b); la tercera est´ en blanco; a la cuarta l´ ınea tambi´n se ha ejecutado, pero dado que la condici´n no se ha cumplido e o (a vale 0), las l´ ıneas 5 y 6 se han ignorado y como no hay m´s l´ a ıneas en el programa, la ejecuci´n ha finalizado sin m´s. No se ha producido un error, ciertamente, pero acabar o a as´ la ejecuci´n del programa puede resultar un tanto confuso para el usuario. ı o Veamos qu´ hace este otro programa: e primer grado 9.py 1 2 3 4 5 6 7 8 primer grado.py a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) if a != 0: x = -b/a print ’Soluci´n:␣’, x o if a == 0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 84 84 Introducción a la programación con Python - UJI c UJI
    • Las l´ ıneas 7 y 8 empiezan, nuevamente, con una sentencia condicional. En lugar de !=, el operador de comparaci´n utilizado es ==. La sentencia se lee ˂˂si a es igual a 0˃˃. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 55 Un estudiante ha tecleado el ultimo programa y, al ejecutarlo, obtiene este mensaje ´ de error. File "primer_grado4.py", line 7 if a = 0: ˆ SyntaxError: invalid syntax Aqu´ tienes el contenido del fichero que ´l ha escrito: ı e primer grado 10.py 1 2 3 4 5 6 7 8 E primer grado.py E a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) if a != 0: x = -b/a print ’Soluci´n:␣’, x o if a = 0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o ´ Por m´s que el estudiante lee el programa, no encuentra fallo alguno. El dice que la a l´ ınea 7, que es la marcada como err´nea, se lee as´ ˂˂si a es igual a cero. . . ˃˃ ¿Est´ en lo o ı: a cierto? ¿Por qu´ se detecta un error? e .................................................................................. Ejecutando el programa con los mismos datos, tenemos ahora: Valor de a: 0 Valor de b: 3 La ecuaci´n no tiene soluci´n. o o Pero, ante datos tales que a es distinto de 0, el programa resuelve la ecuaci´n: o Valor de a: 1 Valor de b: -1 Soluci´n: 1 o Estudiemos con detenimiento qu´ ha pasado en cada uno de los casos: e a=0yb=3 Las l´ ıneas 1 y 2 se ejecutan, con lo que se leen los valores de a y b. ...................................... La l´ ınea 4 se ejecuta y el resultado de la comparaci´n es falso. o ...................................... Las l´ ıneas 5 y 6 se ignoran. ...................................... La l´ ınea 7 se ejecuta y el resultado de la comparaci´n es cierto. o ...................................... La l´ ınea 8 se ejecuta y se muestra por pantalla el mensaje ˂˂La ecuaci´n no o tiene soluci´n.˃˃ o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o a = 1 y b = −1 Las l´ ıneas 1 y 2 se ejecutan, con lo que se leen los valores de a y b. ...................................... La l´ ınea 4 se ejecuta y el resultado de la comparaci´n es cierto. o ...................................... Se ejecutan las l´ ıneas 5 y 6, con lo que se muestra por pantalla el valor de la soluci´n de la ecuaci´n: Soluci´n: 1. o o o ...................................... La l´ ınea 7 se ejecuta y el resultado de la comparaci´n es falso. o ...................................... La l´ ınea 8 se ignora. 85 85 Introducción a la programación con Python - UJIUJI c
    • Este tipo de an´lisis, en el que seguimos el curso del programa l´ a ınea a l´ ınea para una configuraci´n dada de los datos de entrada, recibe el nombre de traza de ejecuci´n. o o Las trazas de ejecuci´n son de gran ayuda para comprender qu´ hace un programa y o e localizar as´ posibles errores. ı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 56 Un programador primerizo cree que la l´ ınea 7 de la ultima versi´n de primer grado.py o ´ es innecesaria, as´ que propone esta otra versi´n como soluci´n v´lida: ı o o a primer grado 11.py 1 2 3 4 5 6 7 8 E primer grado.py E a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) if a != 0: x = -b/a print ’Soluci´n:␣’, x o print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o Haz una traza del programa para a = 2 y b = 2. ¿Son correctos todos los mensajes que muestra por pantalla el programa? .................................................................................. 4.1.3. Trazas con PythonG: el depurador El entorno PythonG te puede ayudar a seguir paso a paso la ejecuci´n de un programa. o Introduce el texto del programa en una ventana de edici´n y selecciona la opci´n ˂˂Activar o o modo depuraci´n˃˃ del men´ Python. El aspecto del entorno ser´ similar al de la figura 4.1. o u a Figura 4.1: Modo de depuraci´n activado. Aparecen dos nuevos marcos: uno bajo la ventana o de edici´n y otro bajo la consola de entrada/salida. El primero incluye una botonera para o controlar la ejecuci´n del programa. En la ventana de edici´n aparece una l´ o o ınea destacada (la primera): es la siguiente l´ ınea a ejecutar. La l´ ınea que se va a ejecutar a continuaci´n aparece con el fondo destacado. Pulsa o en el bot´n etiquetado con ˂˂Sig. (F8)˃˃ (o pulsa la tecla de funci´n ˂˂F8˃˃) y se ejecutar´ o o a la primera l´ ınea. En la consola se solicita el valor de a. Introduce el valor 0 y pulsa el retorno de carro. Se destacar´ ahora la segunda l´ a ınea (ver figura 4.2). Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 86 86 Introducción a la programación con Python - UJIUJI c
    • Figura 4.2: Modo de depuraci´n. Se va a ejecutar la segunda l´ o ınea. Pulsa nuevamente el bot´n o . Se solicitar´ el valor de b. Introduce el valor a 4 y pulsa el retorno de carro. La l´ ınea destacada pasa a ser la cuarta (la tercera est´ a en blanco, as´ que el depurador la ignora), como puedes apreciar en la figura 4.3 (a). La ı expresi´n a o 0 se eval´a a False, as´ que las l´ u ı ıneas 5 y 6 se ignoran y se pasa a la l´ ınea 7 (figura 4.3 (b)) y, al ser a 0 cierto, se sigue con la l´ ınea 8 (figura 4.3 (c)). (a) (b) (c) Figura 4.3: Modo de depuraci´n. Tras leer el valor de a y b, se ejecuta la cuarta l´ o ınea (a). Como la condici´n no se satisface, se pasa entonces a la l´ o ınea 7 (b). La condici´n de esa o l´ ınea s´ cumple, as´ que la siguiente l´ ı ı ınea a ejecutar es la ultima (c). ´ Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 87 87 Introducción a la programación con Python - cUJI UJI
    • Utiliza el depurador cuando dudes acerca del flujo de ejecuci´n de un programa, es o decir, la secuencia de l´ ıneas ejecutadas, o cuando observes un comportamiento extra˜o n en tus programas. 4.1.4. Sentencias condicionales anidadas Vamos a realizar un ultimo refinamiento del programa. De momento, cuando a es 0 ´ el programa muestra un mensaje que indica que la ecuaci´n no tiene soluci´n. Bueno, o o nosotros sabemos que esto no es cierto: si, adem´s, b vale 0, entonces la ecuaci´n tiene a o infinitas soluciones. Para que el programa d´ una informaci´n correcta vamos a modificarlo e o de modo que, cuando a sea 0, muestre un mensaje u otro en funci´n del valor de b: o primer grado 12.py 1 2 3 4 5 6 7 8 9 10 11 primer grado.py a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) if a != 0: x = -b/a print ’Soluci´n:␣’, x o if a == 0: if b != 0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o if b == 0: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o F´ ıjate en la indentaci´n de las l´ o ıneas. Las l´ ıneas 8–11 est´n m´s a la derecha que la a a l´ ınea 7. Ninguna de ellas se ejecutar´ a menos que la condici´n de la l´ a o ınea 7 se satisfaga. M´s a´n, la l´ a u ınea 9 est´ m´s a la derecha que la l´ a a ınea 8, por lo que su ejecuci´n depende o del resultado de la condici´n de dicha l´ o ınea; y la ejecuci´n de la l´ o ınea 11 depende de la satisfacci´n de la condici´n de la l´ o o ınea 10. Recuerda que en los programas Python la indentaci´n determina de qu´ sentencia depende cada bloque de sentencias. o e Pues bien, acabamos de presentar una nueva idea muy potente: las estructuras de control pueden anidarse, es decir, aparecer unas ˂˂dentro˃˃ de otras. Esto no ha hecho m´s a que empezar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 57 Indica qu´ l´ e ıneas del ultimo programa (y en qu´ orden) se ejecutar´n para cada e a ´ uno de los siguientes casos: a) a = 2 y b = 6. b) a = 0 y b = 3. c) a = 0 y b = −3. d) a = 0 y b = 0. · 58 Dise˜a un programa que lea un n´mero flotante por teclado y muestre por pantalla n u el mensaje ˂˂El n´mero es negativo.˃˃ s´lo si el n´mero es menor que cero. u o u · 59 Dise˜a un programa que lea un n´mero flotante por teclado y muestre por pantalla n u el mensaje ˂˂El n´mero es positivo.˃˃ s´lo si el n´mero es mayor o igual que cero. u o u · 60 Dise˜a un programa que lea la edad de dos personas y diga qui´n es m´s joven, n e a la primera o la segunda. Ten en cuenta que ambas pueden tener la misma edad. En tal caso, hazlo saber con un mensaje adecuado. · 61 Dise˜a un programa que lea un car´cter de teclado y muestre por pantalla el n a mensaje ˂˂Es par´ntesis˃˃ s´lo si el car´cter le´ es un par´ntesis abierto o cerrado. e o a ıdo e · 62 Indica en cada uno de los siguientes programas qu´ valores en las respectivas e entradas provocan la aparici´n de los distintos mensajes. Piensa primero la soluci´n y o o comprueba luego que es correcta ayud´ndote con el ordenador. a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 88 88 Introducción a la programación con Python - UJIUJI c
    • a) 2 3 4 5 6 b) misterio.py misterio 3.py 1 letra = raw_input(’Dame␣una␣letra␣min´scula:␣’) u if letra <= ’k’: print ’Es␣de␣las␣primeras␣del␣alfabeto’ if letra >= ’l’: print ’Es␣de␣las␣´ltimas␣del␣alfabeto’ u misterio.py misterio 4.py 1 2 3 4 5 6 7 8 9 10 11 12 13 from math import ceil # ceil redondea al alza. grados = float(raw_input(’Dame␣un␣´ngulo␣(en␣grados):␣’)) a cuadrante = int(ceil(grados) % 360) / 90 if cuadrante == 0: print ’primer␣cuadrante’ if cuadrante == 1: print ’segundo␣cuadrante’ if cuadrante == 2: print ’tercer␣cuadrante’ if cuadrante == 3: print ’cuarto␣cuadrante’ · 63 ¿Qu´ mostrar´ por pantalla el siguiente programa? e a comparaciones.py 1 2 3 4 comparaciones.py if 14 < 120: print ’Primer␣saludo’ if ’14’ < ’120’: print ’Segundo␣saludo’ .................................................................................. Por lo visto hasta el momento podemos comparar valores num´ricos con valores e num´ricos y cadenas con cadenas. Tanto los valores num´ricos como las cadenas pueden e e ser el resultado de una expresi´n que aparezca expl´ o ıcitamente en la propia comparaci´n. o Por ejemplo, para saber si el producto de dos n´meros enteros es igual a 100, podemos u utilizar este programa: compara expresiones.py 1 2 3 4 5 6 7 compara expresiones.py n = int(raw_input(’Dame␣un␣n´mero:␣’)) u m = int(raw_input(’Dame␣otro␣n´mero:␣’)) u if n * m == 100: print ’El␣producto␣%d␣*␣%d␣es␣igual␣a␣100’ % (n, m) if n * m != 100: print ’El␣producto␣%d␣*␣%d␣es␣distinto␣de␣100’ % (n, m) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 64 Dise˜a un programa que, dado un n´mero entero, muestre por pantalla el menn u saje ˂˂El n´mero es par.˃˃ cuando el n´mero sea par y el mensaje ˂˂El n´mero es u u u impar.˃˃ cuando sea impar. (Una pista: un n´mero es par si el resto de dividirlo por 2 es 0, e impar en caso u contrario.) · 65 Dise˜a un programa que, dado un n´mero entero, determine si ´ste es el doble n u e de un n´mero impar. (Ejemplo: 14 es el doble de 7, que es impar.) u Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 89 89 Introducción a la programación con Python - UJIUJI c
    • · 66 Dise˜a un programa que, dados dos n´meros enteros, muestre por pantalla uno de n u estos mensajes: ˂˂El segundo es el cuadrado exacto del primero.˃˃, ˂˂El segundo es menor que el cuadrado del primero.˃˃ o ˂˂El segundo es mayor que el cuadrado del primero.˃˃, dependiendo de la verificaci´n de la condici´n correspondiente al sigo o nificado de cada mensaje. · 67 Un capital de C euros a un inter´s del x por cien anual durante n a˜os se convierte e n n euros. Dise˜a un programa Python que solicite la cantidad C y el en C · (1 + x/100) n inter´s x y calcule el capital final s´lo si x es una cantidad positiva. e o · 68 Realiza un programa que calcule el desglose en billetes y monedas de una cantidad exacta de euros. Hay billetes de 500, 200, 100, 50, 20, 10 y 5 ¤ y monedas de 2 y 1 ¤. Por ejemplo, si deseamos conocer el desglose de 434 ¤, el programa mostrar´ por a pantalla el siguiente resultado: 2 1 1 2 billetes de 200 euros. billete de 20 euros. billete de 10 euros. monedas de 2 euros. (¿Que c´mo se efect´a el desglose? Muy f´cil. Empieza por calcular la divisi´n entera o u a o entre la cantidad y 500 (el valor de la mayor moneda): 434 entre 500 da 0, as´ que no hay ı billetes de 500 ¤ en el desglose; divide a continuaci´n la cantidad 434 entre 200, cabe a o 2 y sobran 34, as´ que en el desglose hay 2 billetes de 200 ¤; dividimos a continuaci´n ı o 34 entre 100 y vemos que no hay ning´n billete de 100 ¤ en el desglose (cabe a 0); u como el resto de la ultima divisi´n es 34, pasamos a dividir 34 entre 20 y vemos que el o ´ desglose incluye un billete de 20 ¤ y a´n nos faltan 14 ¤ por desglosar. . . ) u .................................................................................. 4.1.5. Otro ejemplo: resoluci´n de ecuaciones de segundo grado o Para afianzar los conceptos presentados (y aprender alguno nuevo), vamos a presentar otro ejemplo. En esta ocasi´n vamos a resolver ecuaciones de segundo grado, que son de o la forma ax 2 + bx + c = 0. ¿Cu´les son los datos del problema? Los coeficientes a, b y c. ¿Qu´ deseamos calcular? a e Los valores de x que hacen cierta la ecuaci´n. Dichos valores son: o √ √ −b + b2 − 4ac −b − b2 − 4ac x1 = y x2 = . 2a 2a Un programa directo para este c´lculo es: a segundo grado 11.py 1 2 3 4 5 6 7 8 9 10 segundo grado.py from math import sqrt # sqrt calcula la ra´ cuadrada. ız a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o Ejecutemos el programa: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 90 90 Introducción a la programación con Python - UJIUJI c
    • Valor de a: 2 Valor de b: 7 Valor de c: 2 Soluciones de la ecuaci´n: x1=-0.314 y x2=-3.186 o Un problema evidente de nuestro programa es la divisi´n por cero que tiene lugar o cuando a vale 0 (pues entonces el denominador, 2a, es nulo). Tratemos de evitar el problema de la divisi´n por cero del mismo modo que antes, pero mostrando un mensaje o distinto, pues cuando a vale 0 la ecuaci´n no es de segundo grado, sino de primer grado. o segundo grado 12.py 1 2 3 4 5 6 7 8 9 10 11 12 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o if a == 0: print ’No␣es␣una␣ecuaci´n␣de␣segundo␣grado.’ o 4.1.6. En caso contrario (else) F´ ıjate en que tanto en el ejemplo que estamos desarrollando ahora como en el anterior hemos recurrido a sentencias condicionales que conducen a ejecutar una acci´n si se o cumple una condici´n y a ejecutar otra si esa misma condici´n no se cumple: o o if condici´n: o acciones if condici´n contraria: o otras acciones Este tipo de combinaci´n es muy frecuente, hasta el punto de que se ha incorporado al o lenguaje de programaci´n una forma abreviada que significa lo mismo: o if condici´n: o acciones else: otras acciones La palabra ˂˂else˃˃ significa, en ingl´s, ˂˂si no˃˃ o ˂˂en caso contrario˃˃. Es muy importante e que respetes la indentaci´n: las acciones siempre un poco a la derecha, y el if y el else, o alineados en la misma columna. segundo grado 13.py 1 2 3 4 5 6 7 8 9 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 91 91 c UJI Introducción a la programación con Python - UJI
    • 10 11 12 print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o else: print ’No␣es␣una␣ecuaci´n␣de␣segundo␣grado.’ o El programa no acaba de estar bien. Es verdad que cuando a vale 0, la ecuaci´n es o de primer grado, pero, aunque sabemos resolverla, no lo estamos haciendo. Ser´ mucho ıa mejor si, en ese caso, el programa nos ofreciera la soluci´n: o segundo grado 14.py 1 2 3 4 5 6 7 8 9 10 11 12 13 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o else: x = -c / b print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x o o Mmmm. . . a´n hay un problema: ¿Qu´ pasa si a vale 0 y b tambi´n vale 0? La u e e secuencia de l´ ıneas que se ejecutar´n ser´: 1, 2, 3, 4, 5, 6, 7, 11 y 12. De la l´ a a ınea 12 no pasar´ porque se producir´ una divisi´n por cero. a a o Valor de a: 0 Valor de b: 0 Valor de c: 2 Traceback (innermost last): File ’segundo_grado.py’, line 12, in ? x = -c / b ZeroDivisionError: float division ¿C´mo evitar este nuevo error? Muy sencillo, a˜adiendo nuevos controles con la seno n tencia if, tal y como hicimos para resolver correctamente una ecuaci´n de primer grado: o segundo grado 15.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o else: if b != 0: x = -c / b print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x o o else: if c!= 0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o else: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 92 92 Introducción a la programación con Python - UJI c UJI
    • Es muy importante que te fijes en que las l´ ıneas 12–19 presentan una indentaci´n tal que o todas ellas dependen del else de la l´ ınea 11. Las l´ ıneas 13 y 14 dependen del if de la l´ ınea 12, y las l´ ıneas 16–19 dependen del else de la l´ ınea 15. Estudia bien el programa: aparecen sentencias condicionales anidadas en otras sentencias condicionales que, a su vez, est´n anidadas. ¿Complicado? No tanto. Los principios que aplicamos son siempre los a mismos. Si analizas el programa y lo estudias por partes, ver´s que no es tan dif´ de a ıcil entender. Pero quiz´ lo verdaderamente dif´ no sea entender programas con bastantes a ıcil niveles de anidamiento, sino dise˜arlos. n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 69 ¿Hay alguna diferencia entre el programa anterior y este otro cuando los ejecutamos? segundo grado 16.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a == 0: if b == 0: if c == 0: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o else: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o else: x = -c / b print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x o o else: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o · 70 ¿Hay alguna diferencia entre el programa anterior y este otro cuando los ejecutamos? segundo grado 17.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a == 0 and b == 0 and c == 0: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o else: if a == 0 and b == 0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o else: if a == 0: x = -c / b print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x o o else: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o · 71 Ejecuta paso a paso, con ayuda del entorno de depuraci´n de PythonG, el o programa del ejercicio anterior. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 93 93 Introducción a la programación con Python - UJIUJI c
    • · 72 Dise˜a un programa Python que lea un car´cter cualquiera desde el teclado, y n a muestre el mensaje ˂˂Es una MAY´SCULA˃˃ cuando el car´cter sea una letra may´scula y U a u ´SCULA˃˃ cuando sea una min´scula. En cualquier otro caso, no el mensaje ˂˂Es una MINU u mostrar´ mensaje alguno. (Considera unicamente letras del alfabeto ingl´s.) Pista: aunque a e ´ parezca una obviedad, recuerda que una letra es min´scula si est´ entre la ’a’ y la ’z’, u a y may´scula si est´ entre la ’A’ y la ’Z’. u a · 73 Ampl´ la soluci´n al ejercicio anterior para que cuando el car´cter introducido ıa o a no sea una letra muestre el mensaje ˂˂No es una letra˃˃. (Nota: no te preocupes por las letras e˜e, ce cedilla, vocales acentuadas, etc.) n · 74 Ampl´ el programa del ejercicio anterior para que pueda identificar las letras e˜e ıa n min´scula y may´scula. u u · 75 Modifica el programa que propusiste como soluci´n al ejercicio 66 sustituyendo o todas las condiciones que sea posible por cl´usulas else de condiciones anteriores. a .................................................................................. 4.1.7. Una estrategia de dise˜o: refinamientos sucesivos n Es l´gico que cuando est´s aprendiendo a programar te cueste gran esfuerzo construir o e mentalmente un programa tan complicado, pero posiblemente sea porque sigues una aproximaci´n equivocada: no debes intentar construir mentalmente todo el programa de o una vez. Es recomendable que sigas una estrategia similar a la que hemos usado al desarrollar los programas de ejemplo: 1. Primero haz una versi´n sobre papel que resuelva el problema de forma directa o y, posiblemente, un tanto tosca. Una buena estrategia es plantearse uno mismo el problema con unos datos concretos, resolverlo a mano con l´piz y papel y hacer a un esquema con el orden de las operaciones realizadas y las decisiones tomadas. Tu primer programa puede pedir los datos de entrada (con raw_input), hacer los c´lculos del mismo modo que t´ los hiciste sobre el papel (utilizando variables para a u los resultados intermedios, si fuera menester) y mostrar finalmente el resultado del c´lculo (con print). a 2. 3. 4. Analiza tu programa y considera si realmente resuelve el problema planteado: ¿es posible que se cometan errores en tiempo de ejecuci´n?, ¿hay configuraciones de o los datos que son especiales y, para ellas, el c´lculo debe ser diferente? a Cada vez que te plantees una de estas preguntas y tengas una respuesta, modifica el programa en consecuencia. No hagas m´s de un cambio cada vez. a Si el programa ya funciona correctamente para todas las entradas posibles y eres capaz de anticiparte a los posibles errores de ejecuci´n, ¡enhorabuena!, ya casi has o terminado. En caso contrario, vuelve al paso 2. 5. Ahora que ya est´s ˂˂seguro˃˃ de que todo funciona correctamente, teclea el programa a en el ordenador y efect´a el mayor n´mero de pruebas posibles, comprobando u u cuidadosamente que el resultado calculado es correcto. Presta especial atenci´n o a configuraciones extremas o singulares de los datos (los que pueden provocar divisiones por cero o valores muy grandes, o muy peque˜os, o negativos, etc.). Si n el programa calcula algo diferente de lo esperado o si se aborta la ejecuci´n del o programa por los errores detectados, vuelve al paso 2. Nadie es capaz de hacer un programa suficientemente largo de una sentada, empezando a escribir por la primera l´ ınea y acabando por la ultima, una tras otra, del mismo ´ Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 94 94 Introducción a la programación con Python - UJIUJI c
    • modo que nadie escribe una novela o una sinfon´ de una sentada1 . Lo normal es empezar ıa con un borrador e ir refin´ndolo, mejor´ndolo poco a poco. a a Un error frecuente es tratar de dise˜ar el programa directamente sobre el ordenador, n escribi´ndolo a bote pronto. Es m´s, hay estudiantes que se atreven a empezar con la e a escritura de un programa sin haber entendido bien el enunciado del problema que se pretende resolver. Es f´cil pillarlos en falta: no saben resolver a mano un caso particular a del problema. Una buena pr´ctica, pues, es solucionar manualmente unos pocos ejemplos a concretos para estar seguros de que conocemos bien lo que se nos pide y c´mo calcularlo. o Una vez superada esta fase, estar´s en condiciones de elaborar un borrador con los pasos a que has de seguir. Cr´enos: es mejor que pienses un rato y dise˜es un borrador del e n algoritmo sobre papel. Cuando est´s muy seguro de la validez del algoritmo, implem´ntalo e e en Python y pru´balo sobre el ordenador. Las pruebas con el ordenador te ayudar´n a e a encontrar errores. Ciertamente es posible utilizar el ordenador directamente, como si fuera el papel. Nada impide que el primer borrador lo hagas ya en pantalla, pero, si lo haces, ver´s que: a Los detalles del lenguaje de programaci´n interferir´n en el dise˜o del algoritmo o a n (˂˂¿he de poner dos puntos al final de la l´ ınea?˃˃, ˂˂¿uso marcas de formato para imprimir los resultados?˃˃, etc.): cuando piensas en el m´todo de resoluci´n del e o problema es mejor hacerlo con cierto grado de abstracci´n, sin tener en cuenta o todas las particularidades de la notaci´n. o 4.1.8. Si ya has tecleado un programa y sigue una aproximaci´n incorrecta, te resultar´ o a m´s molesto prescindir de ´l que si no lo has tecleado a´n. Esta molestia conduce a e u a la tentaci´n de ir poniendo parches a tu deficiente programa para ver si se o puede arreglar algo. El resultado ser´, muy probablemente, un programa ilegible, a p´simamente organizado. . . y err´neo. Te costar´ la mitad de tiempo empezar de e o a cero, pero esta vez haciendo bien las cosas: pensando antes de escribir nada. Un nuevo refinamiento del programa de ejemplo Parece que nuestro programa ya funciona correctamente. Probemos a resolver esta ecuaci´n: o x 2 + 2x + 3 = 0 Valor de a: 1 Valor de b: 2 Valor de c: 3 Traceback (innermost last): File ’segundo_grado.py’, line 8, in ? x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) ValueError: math domain error ¡Nuevamente un error! El mensaje de error es diferente de los anteriores y es un ˂˂error de dominio matem´tico˃˃. a El problema es que estamos intentando calcular la ra´ cuadrada de un n´mero neız u gativo en la l´ ınea 8. El resultado es un n´mero complejo, pero el m´dulo math no ˂˂sabe˃˃ u o de n´meros complejos, as´ que sqrt falla y se produce un error. Tambi´n en la l´ u ı e ınea 9 se tiene que calcular la ra´ cuadrada de un n´mero negativo, pero como la l´ ız u ınea 8 se ejecuta en primer lugar, es ah´ donde se produce el error y se aborta la ejecuci´n. La ı o l´ ınea 9 no llega a ejecutarse. 1 Aunque hay excepciones: cuenta la leyenda que Mozart escrib´ sus obras de principio a fin, sin volver ıa atr´s para efectuar correcciones. a Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 95 95 Introducción a la programación con Python - UJI c UJI
    • El s´ ındrome ˂˂a m´ nunca se me hubiera ocurrido esto˃˃ ı Programar es una actividad que requiere un gran esfuerzo intelectual, no cabe duda, pero sobre todo, ahora que empiezas, es una actividad radicalmente diferente de cualquier otra para la que te vienes preparando desde la ense˜anza primaria. Llevas muchos a˜os n n aprendiendo lengua, matem´ticas, f´ a ısica, etc., pero nunca antes hab´ programado. Los ıas programas que hemos visto en este cap´ ıtulo te deben parecer muy complicados, cuando no lo son tanto. La reacci´n de muchos estudiantes al ver la soluci´n que da el profesor o el libro o o de texto a un problema de programaci´n es decirse ˂˂a m´ nunca se me hubiera ocurrido o ı esto˃˃. Debes tener en cuenta dos factores: La soluci´n final muchas veces esconde la l´ o ınea de razonamiento que permiti´ o llegar a ese programa concreto. Nadie construye los programas de golpe: por regla general se hacen siguiendo refinamientos sucesivos a partir de una primera versi´n bastante tosca. o La soluci´n que se te presenta sigue la l´ o ınea de razonamiento de una persona concreta: el profesor. Puede que tu l´ ınea de razonamiento sea diferente y, sin embargo, igualmente v´lida (¡o incluso mejor!), as´ que tu programa puede no a ı parecerse en nada al suyo y, a la vez, ser correcto. No obstante, te conviene estudiar la soluci´n que te propone el profesor: la lectura de programas escritos o por otras personas es un buen m´todo de aprendizaje y, probablemente, la soluci´n e o que te ofrece resuelva cuestiones en las que no hab´ reparado (aunque s´lo sea ıas o porque el profesor lleva m´s a˜os que t´ en esto de programar). a n u Podemos controlar este error asegur´ndonos de que el t´rmino b2 −4ac (que recibe el a e nombre de ˂˂discriminante˃˃) sea mayor o igual que cero antes de calcular la ra´ cuadrada: ız segundo grado 18.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: if b**2 - 4*a*c >= 0: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o else: print ’No␣hay␣soluciones␣reales.’ else: if b != 0: x = -c / b print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x o o else: if c !=0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o else: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 76 Un programador ha intentado solucionar el problema del discriminante negativo con un programa que empieza as´ ı: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 96 96 Introducción a la programación con Python - UJIUJI c
    • 1 2 3 4 5 6 7 8 9 10 11 from math import sqrt E segundo grado.py E a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: if sqrt(b**2 - 4*a*c) >= 0: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) ... Evidentemente, el programa es incorrecto y te sorprender´ saber que algunos estudiantes a proponen soluciones similares a ´sta. El problema estriba en el posible valor negativo e del argumento de sqrt, as´ que la comparaci´n es incorrecta, pues pregunta por el signo ı o de la ra´ de dicho argumento. Pero el programa no llega siquiera a dar soluci´n alguna ız o (bien o mal calculada) cuando lo ejecutamos con, por ejemplo, a = 4, b = 2 y c = 4. ¿Qu´ sale por pantalla en ese caso? ¿Por qu´? e e .................................................................................. Dado que s´lo hemos usado sentencias condicionales para controlar los errores, es o posible que te hayas llevado la impresi´n de que ´sta es su unica utilidad. En absoluto. o e ´ Vamos a utilizar una sentencia condicional con otro prop´sito. Mira qu´ ocurre cuando o e tratamos de resolver la ecuaci´n x 2 − 2x + 1 = 0: o Valor de a: 1 Valor de b: -2 Valor de c: 1 Soluciones de la ecuaci´n: x1=1.000 y x2=1.000 o Las dos soluciones son iguales, y queda un tanto extra˜o que el programa muestre n el mismo valor dos veces. Hagamos que, cuando las dos soluciones sean iguales, s´lo se o muestre una de ellas: segundo grado 19.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: if b**2 - 4*a*c >= 0: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) if x1 == x2: print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x1 o o else: print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o else: print ’No␣hay␣soluciones␣reales.’ else: if b != 0: x = -c / b print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x o o else: if c !=0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 97 97 Introducción a la programación con Python - UJI c UJI
    • else: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o 24 25 Optimizaci´n o Podemos plantear un nuevo refinamiento que tiene por objeto hacer un programa m´s a r´pido, m´s eficiente. F´ a a ıjate que en las l´ ıneas 8, 9 y 10 del ultimo programa se calcula ´ cada vez la expresi´n b**2 - 4*a*c. ¿Para qu´ hacer tres veces un mismo c´lculo? Si o e a las tres veces el resultado va a ser el mismo, ¿no es una p´rdida de tiempo repetir el e c´lculo? Podemos efectuar una sola vez el c´lculo y guardar el resultado en una variable. a a segundo grado 20.py 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 segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) if a != 0: discriminante = b**2 - 4*a*c if discriminante >= 0: x1 = (-b + sqrt( discriminante )) / (2 * a) x2 = (-b - sqrt( discriminante )) / (2 * a) if x1 == x2: print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x1 o o else: print ’Soluciones␣de␣la␣ecuaci´n:’, o print ’x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) else: print ’No␣hay␣soluciones␣reales.’ else: if b != 0: x = -c / b print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x o o else: if c !=0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o else: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o Modificar un programa que funciona correctamente para hacer que funcione m´s efia cientemente es optimizar el programa. No te obsesiones con la optimizaci´n de tus o programas. Ahora est´s aprendiendo a programar. Aseg´rate de que tus programas funa u cionan correctamente. Ya habr´ tiempo para optimizar m´s adelante. a a 4.1.9. Otro ejemplo: m´ximo de una serie de n´meros a u Ahora que sabemos utilizar sentencias condicionales, vamos con un problema sencillo, pero que es todo un cl´sico en el aprendizaje de la programaci´n: el c´lculo del m´ximo a o a a de una serie de n´meros. u Empezaremos por pedirle al usuario dos n´meros enteros y le mostraremos por panu talla cu´l es el mayor de los dos. a Estudia esta soluci´n, a ver qu´ te parece: o e maximo 5.py Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: maximo.py 98 98 Introducción a la programación con Python - c UJI UJI
    • 1 2 3 4 5 6 7 8 9 a = int(raw_input(’Dame␣el␣primer␣n´mero:␣’)) u b = int(raw_input(’Dame␣el␣segundo␣n´mero:␣’)) u if a > b: maximo = a else: maximo = b print ’El␣m´ximo␣es’, maximo a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 77 ¿Qu´ l´ e ıneas del ultimo programa se ejecutan y qu´ resultado aparece por pantalla e ´ en cada uno de estos casos? a) a = 2 y b = 3. b) a = 3 y b = 2. c) a = −2 y b = 0. d) a = 1 y b = 1. Analiza con cuidado el ultimo caso. Observa que los dos n´meros son iguales. ¿Cu´l u a ´ es, pues, el m´ximo? ¿Es correcto el resultado del programa? a · 78 Un aprendiz de programador ha dise˜ado este otro programa para calcular el n m´ximo de dos n´meros: a u maximo.py maximo 6.py 1 2 3 4 5 6 7 8 9 a = int(raw_input(’Dame␣el␣primer␣n´mero:␣’)) u b = int(raw_input(’Dame␣el␣segundo␣n´mero:␣’)) u if a > b: maximo = a if b > a: maximo = b print ’El␣m´ximo␣es’, maximo a ¿Es correcto? ¿Qu´ pasa si introducimos dos n´meros iguales? e u .................................................................................. Vamos con un problema m´s complicado: el c´lculo del m´ximo de tres n´meros a a a u enteros (que llamaremos a, b y c). He aqu´ una estrategia posible: ı 1. Me pregunto si a es mayor que b y, si es as´ de momento a es candidato a ser el ı, mayor, pero no s´ si lo ser´ definitivamente hasta compararlo con c. Me pregunto, e a pues, si a es mayor que c. a) Si a tambi´n es mayor que c, est´ claro que a es el mayor de los tres. e a b) Y si no, c es el mayor de los tres. 2. Pero si no es as´ es decir, si a es menor o igual que b, el n´mero b es, de momento, ı, u mi candidato a n´mero mayor. Falta compararlo con c. u a) Si tambi´n es mayor que c, entonces b es el mayor. e b) Y si no, entonces c es el mayor. Ahora que hemos dise˜ado el procedimiento, construyamos un programa Python que n implemente ese algoritmo: maximo de tres 3.py 1 2 3 maximo de tres.py a = int(raw_input(’Dame␣el␣primer␣n´mero:␣’)) u b = int(raw_input(’Dame␣el␣segundo␣n´mero:␣’)) u c = int(raw_input(’Dame␣el␣tercer␣n´mero:␣’)) u Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 9999 Introducción a la programación con Python - UJIUJI c
    • 4 5 6 7 8 9 10 11 12 13 14 15 16 if a > b: if a > c: maximo else: maximo else: if b > c: maximo else: maximo =a =c =b =c print ’El␣m´ximo␣es’, maximo a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 79 ¿Qu´ secuencia de l´ e ıneas de este ultimo programa se ejecutar´ en cada uno de a ´ estos casos? a) a = 2, b = 3 y c = 4. b) a = 3, b = 2 y c = 4. c) a = 1, b = 1 y c = 1. Ay´date con el modo de depuraci´n de PythonG. u o .................................................................................. Puede que la soluci´n que hemos propuesto te parezca extra˜a y que t´ hayas dio n u se˜ado un programa muy diferente. Es normal. No existe un unico programa para solucion ´ nar un problema determinado y cada persona desarrolla un estilo propio en el dise˜o de n los programas. Si el que se propone como soluci´n no es igual al tuyo, el tuyo no tiene o por qu´ ser err´neo; quiz´ s´lo sea distinto. Por ejemplo, este otro programa tambi´n e o a o e calcula el m´ximo de tres n´meros, y es muy diferente del que hemos propuesto antes: a u maximo de tres 4.py 1 2 3 4 5 6 7 8 9 10 11 12 maximo de tres.py a = int(raw_input(’Dame␣el␣primer␣n´mero:␣’)) u b = int(raw_input(’Dame␣el␣segundo␣n´mero:␣’)) u c = int(raw_input(’Dame␣el␣tercer␣n´mero:␣’)) u candidato = a if b > candidato: candidato = b if c > candidato: candidato = c maximo = candidato print ’El␣m´ximo␣es’, maximo a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 80 Dise˜a un programa que calcule el m´ximo de 5 n´meros enteros. Si sigues una n a u estrategia similar a la de la primera soluci´n propuesta para el problema del m´ximo de o a 3 n´meros, tendr´s problemas. Intenta resolverlo como en el ultimo programa de ejemplo, u a ´ es decir con un ˂˂candidato a valor m´ximo˃˃ que se va actualizando al compararse con a cada n´mero. u · 81 Dise˜a un programa que calcule la menor de cinco palabras dadas; es decir, la n primera palabra de las cinco en orden alfab´tico. Aceptaremos que las may´sculas son e u ˂˂alfab´ticamente˃˃ menores que las min´sculas, de acuerdo con la tabla ASCII. e u · 82 Dise˜a un programa que calcule la menor de cinco palabras dadas; es decir, la n primera palabra de las cinco en orden alfab´tico. No aceptaremos que las may´sculas e u sean ˂˂alfab´ticamente˃˃ menores que las min´sculas. O sea, ’pepita’ es menor que e u ’Pepito’. Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 100 100 c Introducción a la programación con Python - UJIUJI
    • · 83 Dise˜a un programa que, dados cinco n´meros enteros, determine cu´l de los n u a cuatro ultimos n´meros es m´s cercano al primero. (Por ejemplo, si el usuario introduce u a ´ los n´meros 2, 6, 4, 1 y 10, el programa responder´ que el n´mero m´s cercano al 2 es u a u a el 1.) · 84 Dise˜a un programa que, dados cinco puntos en el plano, determine cu´l de n a los cuatro ultimos puntos es m´s cercano al primero. Un punto se representar´ con dos a a ´ variables: una para la abcisa y otra para la ordenada. La distancia entre dos puntos (x1 , y1 ) y (x2 , y2) es (x1 − x2 )2 + (y1 − y2 )2 . .................................................................................. Las comparaciones pueden incluir cualquier expresi´n cuyo resultado sea interpreo table en t´rminos de cierto o falso. Podemos incluir, pues, expresiones l´gicas tan come o plicadas como deseemos. F´ ıjate en el siguiente programa, que sigue una aproximaci´n o diferente para resolver el problema del c´lculo del m´ximo de tres n´meros: a a u maximo de tres.py 1 2 3 4 5 6 7 8 9 10 11 maximo de tres.py a = int(raw_input(’Dame␣el␣primer␣n´mero:␣’)) u b = int(raw_input(’Dame␣el␣segundo␣n´mero:␣’)) u c = int(raw_input(’Dame␣el␣tercer␣n´mero:␣’)) u if a >= b and a >= c: maximo = a if b >= a and b >= c: maximo = b if c >= a and c >= b: maximo = c print ’El␣m´ximo␣es’, maximo a La expresi´n a >= b and a >= c por ejemplo, se lee ˂˂a es mayor o igual que b y a es o mayor o igual que c˃˃. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 85 Indica en cada uno de los siguientes programas qu´ valores o rangos de valores e provocan la aparici´n de los distintos mensajes: o a) aparcar.py 1 2 3 4 5 6 7 8 9 b) if 0 < dia <= 15: print ’Puedes␣aparcar␣en␣el␣lado␣izquierdo␣de␣la␣calle’ else: if 15 < dia < 32: print ’Puedes␣aparcar␣en␣el␣lado␣derecho␣de␣la␣calle’ else: print ’Ning´n␣mes␣tiene␣%d␣d´as.’ % dia u ı estaciones.py 1 2 3 4 5 6 7 8 9 10 11 12 aparcar.py dia = int(raw_input(’Dime␣qu´␣d´a␣es␣hoy:␣’)) e ı estaciones.py mes = int(raw_input(’Dame␣un␣mes:␣’)) if 1 <= mes <= 3: print ’Invierno.’ else: if mes == 4 or mes == 5 or mes == 6: print ’Primavera.’ else: if not (mes < 7 or 9 < mes): print ’Verano.’ else: if not (mes != 10 and mes != 11 and mes != 12): Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 101 101 Introducción a la programación con Python - UJIUJI c
    • print ’Oto˜o.’ n else: print ’Ning´n␣a˜o␣tiene␣%d␣meses.’ % mes u n 13 14 15 c) identificador.py 1 2 3 4 5 6 7 8 9 10 d) identificador.py car = raw_input(’Dame␣un␣car´cter:␣’) a if ’a’ <= car.lower() <= ’z’ or car == ’ ’: print ’Este␣car´cter␣es␣v´lido␣en␣un␣identificador␣en␣Python.’ a a else: if not (car < ’0’ or ’9’ < car): print ’Un␣d´gito␣es␣v´lido␣en␣un␣identificador␣en␣Python,’, ı a print ’siempre␣que␣no␣sea␣el␣primer␣car´cter.’ a else: print ’Car´cter␣no␣v´lido␣para␣formar␣un␣identificador␣en␣Python.’ a a bisiesto.py bisiesto.py 1 2 3 4 5 6 anyo = int(raw_input(’Dame␣un␣a˜o:␣’)) n if anyo % 4 == 0 and (anyo % 100 != 0 or anyo % 400 == 0): print ’El␣a˜o␣%d␣es␣bisiesto.’ % anyo n else: print ’El␣a˜o␣%d␣no␣es␣bisiesto.’ % anyo n · 86 La f´rmula C = C ·(1+x/100)n nos permite obtener el capital final que lograremos o a partir de un capital inicial (C ), una tasa de inter´s anual (x) en tanto por cien y un e n´mero de a˜os (n). Si lo que nos interesa conocer es el n´mero de a˜os n que tardaremos u n u n en lograr un capital final C partiendo de un capital inicial C a una tasa de inter´s anual e x, podemos despejar n en la f´rmula del ejercicio 67 de la siguiente manera: o n= log(C ) − log(C ) log(1 + x/100) Dise˜a un programa Python que obtenga el n´mero de a˜os que se tarda en conseguir n u n un capital final dado a partir de un capital inicial y una tasa de inter´s anual tambi´n e e dados. El programa debe tener en cuenta cu´ndo se puede realizar el c´lculo y cu´ndo a a a no en funci´n del valor de la tasa de inter´s (para evitar una divisi´n por cero, el c´lculo o e o a de logaritmos de valores negativos, etc). . . con una excepci´n: si C y C son iguales, o el n´mero de a˜os es 0 independientemente de la tasa de inter´s (incluso de la que u n e provocar´ un error de divisi´n por cero). ıa o (Ejemplos: Para obtener 11 000 ¤ por una inversi´n de 10 000 ¤ al 5% anual es o necesario esperar 1.9535 a˜os. Obtener 11 000 ¤ por una inversi´n de 10 000 ¤ al 0% n o anual es imposible. Para obtener 10 000 ¤ con una inversi´n de 10 000 ¤ no hay que o esperar nada, sea cual sea el inter´s.) e · 87 Dise˜a un programa que, dado un n´mero real que debe representar la calificaci´n n u o num´rica de un examen, proporcione la calificaci´n cualitativa correspondiente al n´mero e o u dado. La calificaci´n cualitativa ser´ una de las siguientes: ˂˂Suspenso˃˃ (nota menor que o a 5), ˂˂Aprobado˃˃ (nota mayor o igual que 5, pero menor que 7), ˂˂Notable˃˃ (nota mayor o igual que 7, pero menor que 8.5), ˂˂Sobresaliente˃˃ (nota mayor o igual que 8.5, pero menor que 10), ˂˂Matr´ ıcula de Honor˃˃ (nota 10). · 88 Dise˜a un programa que, dado un car´cter cualquiera, lo identifique como vocal n a min´scula, vocal may´scula, consonante min´scula, consonante may´scula u otro tipo de u u u u car´cter. a .................................................................................. Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 102 102 Introducción a la programación con Python - UJIUJI c
    • De Morgan Las expresiones l´gicas pueden resultar complicadas, pero es que los programas hacen, o en ocasiones, comprobaciones complicadas. Tal vez las m´s dif´ a ıciles de entender son las que comportan alg´n tipo de negaci´n, pues generalmente nos resulta m´s dif´ u o a ıcil razonar en sentido negativo que afirmativo. A los que empiezan a programar les l´ ıan muy frecuentemente las negaciones combinadas con or o and. Veamos alg´n ejemplo u ˂˂de juguete˃˃. Sup´n que para aprobar una asignatura hay que obtener m´s de un 5 o a en dos ex´menes parciales, y que la nota de cada uno de ellos est´ disponible en las a a variables parcial1 y parcial2, respectivamente. Estas l´ ıneas de programa muestran el mensaje ˂˂Has suspendido.˃˃ cuando no has obtenido al menos un 5 en los dos ex´menes: a if not (parcial1 >= 5.0 and parcial2 >= 5.0): print ’Has␣suspendido.’ Lee bien la condici´n: ˂˂si no es cierto que has sacado al menos un 5 en ambos (por eso o el and) parciales. . . ˃˃. Ahora f´ ıjate en este otro fragmento: if not parcial1 >= 5.0 or not parcial2 >= 5.0: print ’Has␣suspendido.’ Le´moslo: ˂˂si no has sacado al menos un cinco en uno u otro (por eso el or) parcial. . . ˃˃. a O sea, los dos fragmentos son equivalentes: uno usa un not que se aplica al resultado de una operaci´n and; el otro usa dos operadores not cuyos resultados se combinan con o un operador or. Y sin embargo, dicen la misma cosa. Los l´gicos utilizan una notaci´n o o especial para representar esta equivalencia: ¬(p ∧ q) ¬(p ∨ q) ←→ ←→ ¬p ∨ ¬q, ¬p ∧ ¬q. (Los l´gicos usan ‘¬’ para not, ‘∧’ para and y ‘∨’ para or.) Estas relaciones se deben al o matem´tico De Morgan, y por ese nombre se las conoce. Si es la primera vez que las a ves, te resultar´n chocantes, pero si piensas un poco, ver´s que son de sentido com´n. a a u Hemos observado que los estudiantes comet´is errores cuando hay que expresar la e condici´n contraria a una como ˂˂a and b˃˃. Muchos escrib´ ˂˂not a and not b˃˃ y est´ o ıs a mal. La negaci´n correcta ser´ ˂˂not (a and b)˃˃ o, por De Morgan, ˂˂not a or not b˃˃. o ıa ¿Cu´l ser´ por cierto, la negaci´n de ˂˂a or not b˃˃? a ıa, o 4.1.10. Evaluaci´n con cortocircuitos o La evaluaci´n de expresiones l´gicas es algo especial. Observa la condici´n de este if: o o o if a == 0 or 1/a > 1: ... ¿Puede provocar una divisi´n por cero? No, nunca. Observa que si a vale cero, el primer o t´rmino del or es True. Como la evaluaci´n de una o l´gica de True con cualquier otro e o o valor, True o False, es necesariamente True, Python no eval´a el segundo t´rmino y se u e ahorra as´ un esfuerzo innecesario. ı Algo similar ocurre en este otro caso: if a != 0 and 1/a > 1: ... Si a es nulo, el valor de a != 0 es falso, as´ que ya no se procede a evaluar la segunda ı parte de la expresi´n. o Al calcular el resultado de una expresi´n l´gica, Python eval´a (siguiendo las reglas o o u de asociatividad y precedencia oportunas) lo justo hasta conocer el resultado: cuando el Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 103 103 Introducción a la programación con Python - c UJI UJI
    • primer t´rmino de un or es cierto, Python acaba y devuelve directamente cierto y cuando e el primer t´rmino de un and es falso, Python acaba y devuelve directamente falso. Este e modo de evaluaci´n se conoce como evaluaci´n con cortocircuitos. o o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 89 ¿Por qu´ obtenemos un error en esta sesi´n de trabajo con el int´rprete interactivo? e o e ↱ >>> a = 0 >>> if 1/a > 1 and a != 0: ... print a ... Traceback (most recent call last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo by zero ↱ ↱ ↱ .................................................................................. 4.1.11. Un ´ltimo problema: men´s de usuario u u Ya casi acabamos esta (largu´ ısima) secci´n. Introduciremos una nueva estructura sint´ctica o a planteando un nuevo problema. El problema es el siguiente: imagina que tenemos un programa que a partir del radio de una circunferencia calcula su di´metro, per´ a ımetro o area. S´lo queremos mostrar al usuario una de las tres cosas, el di´metro, el per´ o a ımetro o ´ el area; la que ´l desee, pero s´lo una. e o ´ Nuestro programa podr´ empezar pidiendo el radio del c´ ıa ırculo. A continuaci´n, podr´ o ıa mostrar un men´ con tres opciones: ˂˂calcular el di´metro˃˃, ˂˂calcular el per´ u a ımetro˃˃ y ˂˂calcular el area˃˃. Podr´ ıamos etiquetar cada opci´n con una letra y hacer que el usuario o ´ tecleara una de ellas. En funci´n de la letra tecleada, calcular´ o ıamos una cosa u otra. Analiza este programa: circulo 5.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 circulo.py from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı # Men´ u print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == ’a’: # C´lculo del di´metro. a a diametro = 2 * radio print ’El␣di´metro␣es’, diametro a else: if opcion == ’b’: # C´lculo del per´ a ımetro. perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı else: if opcion == ’c’: # C´lculo del area. a ´ area = pi * radio ** 2 print ’El␣´rea␣es’, area a Ejecutemos el programa y seleccionemos la segunda opci´n: o Dame el radio de un c´rculo: 3 ı Escoge una opci´n: o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 104 104 Introducción a la programación con Python - UJIUJI c
    • a) Calcular el di´metro. a b) Calcular el per´metro. ı c) Calcular el ´rea. a Teclea a, b o c y pulsa el retorno de carro: b El per´metro es 18.8495559215 ı Ejecut´moslo de nuevo, pero seleccionando esta vez la tercera opci´n: e o Dame el radio de un c´rculo: 3 ı Escoge una opci´n: o a) Calcular el di´metro. a b) Calcular el per´metro. ı c) Calcular el ´rea. a Teclea a, b o c y pulsa el retorno de carro: c El ´rea es 28.2743338823 a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 90 Nuestro aprendiz de programador ha tecleado en su ordenador el ultimo programa, ´ pero se ha despistado y ha escrito esto: circulo 6.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 circulo.py from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == a: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a else: if opcion == b: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı else: if opcion == c: area = pi * radio ** 2 print ’El␣´rea␣es’, area a Las l´ ıneas sombreadas son diferentes de sus equivalentes del programa original. ¿Funcionar´ el programa del aprendiz? Si no es as´ ¿por qu´ motivo?. a ı, e .................................................................................. Acabemos de pulir nuestro programa. Cuando el usuario no escribe ni la a, ni la b, ni la c al tratar de seleccionar una de las opciones, deber´ ıamos decirle que se ha equivocado: circulo 7.py 1 2 3 4 5 6 circulo.py from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 105 105 Introducción a la programación con Python - UJIUJI c
    • 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == ’a’: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a else: if opcion == ’b’: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı else: if opcion == ’c’: area = pi * radio ** 2 print ’El␣´rea␣es’, area a else: print ’S´lo␣hay␣tres␣opciones:␣a,␣b␣o␣c.’ o print ’T´␣has␣tecleado’, opcion u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 91 Haz una traza del programa suponiendo que el usuario teclea la letra d cuando se le solicita una opci´n. ¿Qu´ l´ o e ıneas del programa se ejecutan? · 92 El programa presenta un punto d´bil: si el usuario escribe una letra may´scula e u en lugar de min´scula, no se selecciona ninguna opci´n. Modifica el programa para que u o tambi´n acepte letras may´sculas. e u .................................................................................. 4.1.12. Una forma compacta para estructuras condicionales m´ltiples (elif) u El ultimo programa presenta un problema est´tico: la serie de l´ e ıneas que permiten se´ leccionar el c´lculo que hay que efectuar en funci´n de la opci´n de men´ seleccionada a o o u (l´ ıneas 11–24) parece m´s complicada de lo que realmente es. Cada opci´n aparece ina o dentada m´s a la derecha que la anterior, as´ que el c´lculo del area acaba con tres a ı a ´ niveles de indentaci´n. Imagina qu´ pasar´ si el men´ tuviera 8 o 9 opciones: ¡el proo e ıa u grama acabar´ tan a la derecha que pr´cticamente se saldr´ del papel! Python permite ıa a ıa una forma compacta de expresar fragmentos de c´digo de la siguiente forma: o if condici´n: o ... else: if otra condici´n: o ... Un else inmediatamente seguido por un if puede escribirse as´ ı: if condici´n: o ... elif otra condici´n: o ... con lo que nos ahorramos una indentaci´n. El ultimo programa se convertir´ pues, en o ıa, ´ este otro: circulo 8.py 1 2 3 4 circulo.py from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 106 106 Introducción a la programación con Python - UJIUJI c
    • 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == ’a’: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a elif opcion == ’b’: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı elif opcion == ’c’: area = pi * radio ** 2 print ’El␣´rea␣es’, area a else: print ’S´lo␣hay␣tres␣opciones:␣a,␣b␣o␣c.␣T´␣has␣tecleado’, opcion o u El programa es absolutamente equivalente, ocupa menos l´ ıneas y gana mucho en legibilidad: no s´lo evitamos mayores niveles de indentaci´n, tambi´n expresamos de o o e forma clara que, en el fondo, todas esas condiciones est´n relacionadas. a Formas compactas: ¿complicando las cosas? Puede que comprender la estructura condicional if te haya supuesto un esfuerzo considerable. A eso has tenido que a˜adir la forma if-else. ¡Y ahora el if-elif! Parece que no n hacemos m´s que complicar las cosas. M´s bien todo lo contrario: las formas if-else e a a if-elif (que tambi´n acepta un if-elif-else) debes considerarlas una ayuda. En realidad, e ninguna de estas formas permite hacer cosas que no pudi´ramos hacer con s´lo el if, e o aunque, eso s´ necesitando un esfuerzo mayor. ı, Mientras est´s dando tus primeros pasos en la programaci´n, si dudas sobre qu´ e o e forma utilizar, trata de expresar tu idea con s´lo el if. Una vez tengas una soluci´n, o o plant´ate si tu programa se beneficiar´ del uso de una forma compacta. Si es as´ e ıa ı, usala. M´s adelante seleccionar´s instintivamente la forma m´s apropiada para cada a a a ´ caso. Bueno, eso cuando hayas adquirido bastante experiencia, y s´lo la adquirir´s o a practicando. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 93 Modifica la soluci´n del ejercicio 87 usando ahora la estructura elif. ¿No te parece o m´s legible la nueva soluci´n? a o .................................................................................. 4.2. Sentencias iterativas A´n vamos a presentar una ultima reflexi´n sobre el programa de los men´s. Cuando el u o u ´ usuario no escoge correctamente una opci´n del men´ el programa le avisa, pero finaliza o u inmediatamente. Lo ideal ser´ que cuando el usuario se equivocara, el programa le pidiera ıa de nuevo una opci´n. Para eso ser´ necesario repetir la ejecuci´n de las l´ o ıa o ıneas 11–21. Una aproximaci´n na¨ consistir´ b´sicamente, en a˜adir al final una copia de esas l´ o ıf ıa, a n ıneas precedidas de un if que comprobara que el usuario se equivoc´. Pero esa aproximaci´n o o es muy mala: ¿qu´ pasar´ si el usuario se equivocara una segunda vez? Cuando decimos e ıa que queremos repetir un fragmento del programa no nos referimos a copiarlo de nuevo, sino a ejecutarlo otra vez. Pero, ¿es posible expresar en este lenguaje que queremos que se repita la ejecuci´n de un trozo del programa? o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 107 107 Introducción a la programación con Python - UJIUJI c
    • Python permite indicar que deseamos que se repita un trozo de programa de dos formas distintas: mediante la sentencia while y mediante la sentencia for. La primera de ellas es m´s general, por lo que la estudiaremos en primer lugar. a 4.2.1. La sentencia while En ingl´s, ˂˂while˃˃ significa ˂˂mientras˃˃. La sentencia while se usa as´ e ı: while condici´n: o acci´n o acci´n o ... acci´n o y permite expresar en Python acciones cuyo significado es: ˂˂Mientras se cumpla esta condici´n, repite estas acciones.˃˃ o Las sentencias que denotan repetici´n se denominan bucles. o Vamos a empezar estudiando un ejemplo y viendo qu´ ocurre paso a paso. Estudia e detenidamente este programa: contador 3.py 1 2 3 4 5 contador.py i=0 while i < 3: print i i += 1 print ’Hecho’ Observa que la l´ ınea 2 finaliza con dos puntos (:) y que la indentaci´n indica que las o l´ ıneas 3 y 4 dependen de la l´ ınea 2, pero no la l´ ınea 5. Podemos leer el programa as´ ı: primero, asigna a i el valor 0; a continuaci´n, mientras i sea menor que 3, repite estas o acciones: muestra por pantalla el valor de i e incrementa i en una unidad; finalmente, muestra por pantalla la palabra ˂˂Hecho˃˃. Si ejecutamos el programa, por pantalla aparecer´ el siguiente texto: a 0 1 2 Hecho Veamos qu´ ha ocurrido paso a paso con una traza. e Se ha ejecutado la l´ ınea 1, con lo que i vale 0. Despu´s, se ha ejecutado la l´ e ınea 2, que dice ˂˂mientras i sea menor que 3, hacer. . . ˃˃. Primero se ha evaluado la condici´n i < 3, que ha resultado ser cierta. Como la o condici´n se satisface, deben ejecutarse las acciones supeditadas a esta l´ o ınea (las l´ ıneas 3 y 4). Se ejecuta en primer lugar la l´ ınea 3, que muestra el valor de i por pantalla. Aparece, pues, un cero. Se ejecuta a continuaci´n la l´ o ınea 4, que incrementa el valor de i. Ahora i vale 1. ¡Ojo!, ahora no pasamos a la l´ ınea 5, sino que volvemos a la l´ ınea 2. Cada vez que finalizamos la ejecuci´n de las acciones que dependen de un while, volvemos a la o l´ ınea del while. Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 108 108 Introducción a la programación con Python - UJI c UJI
    • i = 0 while i <3: print i i += 1 ⇐ la condici´n se satisface o print ’Hecho’ Estamos nuevamente en la l´ ınea 2, as´ que comprobamos si i es menor que 3. Es ı as´ por lo que toca ejecutar de nuevo las l´ ı, ıneas 3 y 4. Volvemos a ejecutar la l´ ınea 3, as´ que aparece un 1 por pantalla. ı Volvemos a ejecutar la l´ ınea 4, con lo que i vuelve a incrementarse y pasa de valer 1 a valer 2. Nuevamente pasamos a la l´ ınea 2. Siempre que acaba de ejecutarse la ultima acci´n o ´ de un bucle while, volvemos a la l´ ınea que contiene la palabra ·while·. Como i sigue siendo menor que 3, deberemos repetir las acciones expresadas en las l´ ıneas 3 y 4. As´ que ejecutamos otra vez la l´ ı ınea 3 y en pantalla aparece el n´mero 2. u Incrementamos de nuevo el valor de i, como indica la l´ ınea 4, as´ que i pasa de ı valer 2 a valer 3. Y de nuevo pasamos a la l´ ınea 2. Pero ahora ocurre algo especial: la condici´n no o se satisface, pues i ya no es menor que 3. Como la condici´n ya no se satisface, no o hay que ejecutar otra vez las l´ ıneas 3 y 4. Ahora hemos de ir a la l´ ınea 5, que es la primera l´ ınea que no est´ ˂˂dentro˃˃ del bucle. a i = 0 while i <3: print i i += 1 ⇐ la condici´n no se satisface o print ’Hecho’ Se ejecuta la l´ ınea 5, que muestra por pantalla la palabra ˂˂Hecho˃˃ y finaliza el programa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 94 Ejecuta el ultimo programa paso a paso con el entorno de depuraci´n de PythonG. o ´ .................................................................................. Pero, ¿por qu´ tanta complicaci´n? Este otro programa muestra por pantalla lo mismo, e o se entiende m´s f´cilmente y es m´s corto. a a a contador simple.py 1 2 3 4 print 0 print 1 print 2 print ’Hecho’ Bueno, contador.py es un programa que s´lo pretende ilustrar el concepto de bucle, o as´ que ciertamente no hace nada demasiado util, pero aun as´ nos permite vislumbrar la ı ı ´ potencia del concepto de iteraci´n o repetici´n. Piensa en qu´ ocurre si modificamos un o o e s´lo n´mero del programa: o u Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 109 109 Introducción a la programación con Python - UJI c UJI
    • contador.py contador 4.py 1 2 3 4 5 i=0 while i < 1000: print i i += 1 print ’Hecho’ ¿Puedes escribir f´cilmente un programa que haga lo mismo y que no utilice bucles? a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 95 Haz una traza de este programa: ejercicio bucle 9.py 1 2 3 4 5 ejercicio bucle.py i=0 while i <= 3: print i i += 1 print ’Hecho’ · 96 Haz una traza de este programa: ejercicio bucle 10.py 1 2 3 4 5 ejercicio bucle.py i=0 while i < 10: print i i += 2 print ’Hecho’ · 97 Haz una traza de este programa: ejercicio bucle 11.py 1 2 3 4 5 ejercicio bucle.py i=3 while i < 10: i += 2 print i print ’Hecho’ · 98 Haz una traza de este programa: ejercicio bucle 12.py 1 2 3 4 ejercicio bucle.py i=1 while i < 100: i *= 2 print i · 99 Haz una traza de este programa: ejercicio bucle 13.py 1 2 3 4 ejercicio bucle.py i = 10 while i < 2: i *= 2 print i · 100 Haz unas cuantas trazas de este programa para diferentes valores de i. ejercicio bucle 14.py 1 2 3 4 ejercicio bucle.py i = int(raw_input(’Valor␣inicial:␣’)) while i < 10: print i i += 1 ¿Qu´ ocurre si el valor de i es mayor o igual que 10? ¿Y si es negativo? e Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 110 110 Introducción a la programación con Python - UJIUJI c
    • · 101 Haz unas cuantas trazas de este programa para diferentes valores de i y de limite. ejercicio bucle 15.py 1 2 3 4 5 ejercicio bucle.py i = int(raw_input(’Valor␣inicial:␣’)) limite = int(raw_input(’L´mite:␣’)) ı while i < limite: print i i += 1 · 102 Haz unas cuantas trazas de este programa para diferentes valores de i, de limite y de incremento. ejercicio bucle 16.py 1 2 3 4 5 6 ejercicio bucle.py i = int(raw_input(’Valor␣inicial:␣’)) limite = int(raw_input(’L´mite:␣’)) ı incremento = int(raw_input(’Incremento:␣’)) while i < limite: print i i += incremento · 103 Implementa un programa que muestre todos los m´ltiplos de 6 entre 6 y 150, u ambos inclusive. · 104 Implementa un programa que muestre todos los m´ltiplos de n entre n y m · n, u ambos inclusive, donde n y m son n´meros introducidos por el usuario. u · 105 Implementa un programa que muestre todos los n´meros potencia de 2 entre 20 u y 230 , ambos inclusive. .................................................................................. Bucles sin fin Los bucles son muy utiles a la hora de confeccionar programas, pero tambi´n son pelie ´ grosos si no andas con cuidado: es posible que no finalicen nunca. Estudia este programa y ver´s qu´ queremos decir: a e 1 2 3 i=0 while i < 10: print i E bucle infinito.py E La condici´n del bucle siempre se satisface: dentro del bucle nunca se modifica el valor o de i, y si i no se modifica, jam´s llegar´ a valer 10 o m´s. El ordenador empieza a a a a mostrar el n´mero 0 una y otra vez, sin finalizar nunca. Es lo que denominamos un bucle u sin fin o bucle infinito. Cuando se ejecuta un bucle sin fin, el ordenador se queda como ˂˂colgado˃˃ y nunca nos devuelve el control. Si est´s ejecutando un programa desde la l´ a ınea de ´rdenes Unix, o puedes abortarlo pulsando C-c. Si la ejecuci´n tiene lugar en el entorno PythonG (o o en el editor XEmacs) puedes abortar la ejecuci´n del programa con C-c C-c. o 4.2.2. Un problema de ejemplo: c´lculo de sumatorios a Ahora que ya hemos presentado lo fundamental de los bucles, vamos a resolver algunos problemas concretos. Empezaremos por un programa que calcula la suma de los 1000 primeros n´meros, es decir, un programa que calcula el sumatorio u 1000 Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o i=1 i, 111 111 Introducción a la programación con Python - UJIUJI c
    • o, lo que es lo mismo, el resultado de 1 + 2 + 3 + · · · + 999 + 1000. Vamos paso a paso. La primera idea que suele venir a quienes aprenden a programar es reproducir la f´rmula con una sola expresi´n Python, es decir: o o E sumatorio.py E 1 2 sumatorio = 1 + 2 + 3 + . . + 999 + 1000 . print sumatorio Pero, obviamente, no funciona: los puntos suspensivos no significan nada para Python. Aunque una persona puede aplicar su intuici´n para deducir qu´ significan los puntos o e suspensivos en ese contexto, Python carece de intuici´n alguna: exige que todo se describa o de forma precisa y rigurosa. Esa es la mayor dificultad de la programaci´n: el nivel de o detalle y precisi´n con el que hay que describir qu´ se quiere hacer. o e Bien. Abord´moslo de otro modo. Vamos a intentar calcular el valor del sumatorio e ˂˂acumulando˃˃ el valor de cada n´mero en una variable. Analiza este otro programa u (incompleto): 1 2 3 4 sumatorio sumatorio sumatorio sumatorio . . . 1000 1001 1002 =0 += 1 += 2 += 3 sumatorio += 999 sumatorio += 1000 print sumatorio Como programa no es el colmo de la elegancia. F´ ıjate en que, adem´s, presenta una a estructura casi repetitiva: las l´ ıneas de la 2 a la 1001 son todas de la forma sumatorio += n´mero u donde n´mero va tomando todos los valores entre 1 y 1000. Ya que esa sentencia, con u ligeras variaciones, se repite una y otra vez, vamos a tratar de utilizar un bucle. Empecemos construyendo un borrador incompleto que iremos refinando progresivamente: sumatorio.py 1 2 3 4 sumatorio = 0 while condici´n : o sumatorio += n´mero u print sumatorio Hemos dicho que n´mero ha de tomar todos los valores crecientes desde 1 hasta 1000. u Podemos usar una variable que, una vez inicializada, vaya tomando valores sucesivos con cada iteraci´n del bucle: o sumatorio.py 1 2 3 4 5 6 sumatorio = 0 i=1 while condici´n : o sumatorio += i i += 1 print sumatorio S´lo resta indicar la condici´n con la que se decide si hemos de iterar de nuevo o, o o por el contrario, hemos de finalizar el bucle: Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 112 112 Introducción a la programación con Python - UJI c UJI
    • sumatorio.py sumatorio 4.py 1 2 3 4 5 6 sumatorio = 0 i=1 while i <= 1000 : sumatorio += i i += 1 print sumatorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 106 Estudia las diferencias entre el siguiente programa y el ultimo que hemos estu´ diado. ¿Producen ambos el mismo resultado? sumatorio.py sumatorio 5.py 1 2 3 4 5 6 sumatorio = 0 i=0 while i < 1000: i += 1 sumatorio += i print sumatorio · 107 Dise˜a un programa que calcule n m i=n i, donde n y m son n´meros enteros que deber´ introducir el usuario por teclado. u a · 108 Modifica el programa anterior para que si n > m, el programa no efect´e ning´n u u c´lculo y muestre por pantalla un mensaje que diga que n debe ser menor o igual que a m. · 109 Queremos hacer un programa que calcule el factorial de un n´mero entero pou sitivo. El factorial de n se denota con n!, pero no existe ning´n operador Python que u permita efectuar este c´lculo directamente. Sabiendo que a n! = 1 · 2 · 3 · . . . · (n − 1) · n y que 0! = 1, haz un programa que pida el valor de n y muestre por pantalla el resultado de calcular n!. · 110 El n´mero de combinaciones que podemos formar tomando m elementos de un u conjunto con n elementos es: m Cn = n m = n! . (n − m)! m! m Dise˜a un programa que pida el valor de n y m y calcule Cn . (Ten en cuenta que n ha n de ser mayor o igual que m.) (Puedes comprobar la validez de tu programa introduciendo los valores n = 15 y m = 10: el resultado es 3003.) .................................................................................. 4.2.3. Otro programa de ejemplo: requisitos en la entrada Vamos con otro programa sencillo pero ilustrativo. Estudia este programa: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 113 113 Introducción a la programación con Python - UJIUJI c
    • raiz 4.py 1 2 3 4 5 raiz.py from math import sqrt x = float(raw_input(’Introduce␣un␣n´mero␣positivo:␣’)) u print ’La␣ra´z␣cuadrada␣de␣%f␣es␣%f’ % (x, sqrt(x)) ı Como puedes ver, es muy sencillo: pide un n´mero (flotante) y muestra por pantalla su u ra´ cuadrada. Como sqrt no puede trabajar con n´meros negativos, pedimos al usuario ız u que introduzca un n´mero positivo. Pero nada obliga al usuario a introducir un n´mero u u positivo. En lugar de adoptar una soluci´n como las estudiadas anteriormente, esto es, evitando o ejecutar el c´lculo de la ra´ cuadrada cuando el n´mero es negativo con la ayuda de una a ız u sentencia condicional, vamos a obligar a que el usuario introduzca un n´mero positivo u repitiendo la sentencia de la l´ ınea 3 cuantas veces sea preciso. Dado que vamos a repetir un fragmento de programa, utilizaremos una sentencia while. En principio, nuestro programa presentar´ este aspecto: a raiz.py 1 2 3 4 5 6 from math import sqrt while condici´n: o x = float(raw_input(’Introduce␣un␣n´mero␣positivo:␣’)) u print ’La␣ra´z␣cuadrada␣de␣%f␣es␣%f’ % (x, sqrt(x)) ı ¿Qu´ condici´n poner? Est´ claro: el bucle deber´ leerse as´ ˂˂mientras x sea un valor e o a ıa ı inv´lido, hacer. . . ˃˃, es decir, ˂˂mientras x sea menor que cero, hacer. . . ˃˃; y esa ultima frase a ´ se traduce a Python as´ ı: raiz 5.py 1 2 3 4 5 6 from math import sqrt E raiz.py E while x < 0 : x = float(raw_input(’Introduce␣un␣n´mero␣positivo:␣’)) u print ’La␣ra´z␣cuadrada␣de␣%f␣es␣%f’ % (x, sqrt(x)) ı Pero el programa no funciona correctamente. Mira qu´ obtenemos al ejecutarlo: e Traceback (innermost last): File ’raiz.py’, line 3, in ? while x < 0: NameError: x Python nos indica que la variable x no est´ definida (no existe) en la l´ a ınea 3. ¿Qu´ e ocurre? Vayamos paso a paso: Python empieza ejecutando la l´ ınea 1, con lo que importa la funci´n sqrt del m´dulo math; la l´ o o ınea 2 est´ en blanco, as´ que, a continuaci´n, Python a ı o ejecuta la l´ ınea 3, lo cual pasa por saber si la condici´n del while es cierta o falsa. Y ah´ o ı se produce el error, pues se intenta conocer el valor de x cuando x no est´ inicializada. a Es necesario, pues, inicializar antes la variable; pero, ¿con qu´ valor? Desde luego, no e con un valor positivo. Si x empieza tomando un valor positivo, la l´ ınea 4 no se ejecutar´. a Probemos, por ejemplo, con el valor −1. raiz.py 1 2 3 4 from math import sqrt x = -1 while x < 0: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 114 114 Introducción a la programación con Python - UJI c UJI
    • x = float(raw_input(’Introduce␣un␣n´mero␣positivo:␣’)) u 5 6 7 print ’La␣ra´z␣cuadrada␣de␣%f␣es␣%f’ % (x, sqrt(x)) ı 1. 2. 3. Ahora s´ Hagamos una traza. ı. Empezamos ejecutando la l´ ınea 1, con lo que importa la funci´n sqrt. o La l´ ınea 2 se ignora. Ahora ejecutamos la l´ ınea 3, con lo que x vale −1. 4. En la l´ ınea 4 nos preguntamos: ¿es x menor que cero? La respuesta es s´ de modo ı, que debemos ejecutar la l´ ınea 5. 5. La l´ ınea 5 hace que se solicite al usuario un valor para x. Supongamos que el usuario introduce un n´mero negativo, por ejemplo, −3. u 6. Como hemos llegado al final de un bucle while, volvemos a la l´ ınea 4 y nos volvemos a preguntar ¿es x menor que cero? De nuevo, la respuesta es s´ as´ que pasamos ı, ı a la l´ ınea 4. 7. 8. Supongamos que ahora el usuario introduce un n´mero positivo, pongamos que el u 16. Por llegar al final de un bucle, toca volver a la l´ ınea 4 y plantearse la condici´n: o ¿es x menor que cero? En este caso la respuesta es no, as´ que salimos del bucle ı y pasamos a ejecutar la l´ ınea 7, pues la l´ ınea 6 est´ vac´ a ıa. 9. La l´ ınea 7 muestra por pantalla ˂˂La ra´z cuadrada de 16.000000 es 4.000000˃˃. ı Y ya hemos acabado. F´ ıjate en que las l´ ıneas 4–5 se pueden repetir cuantas veces haga falta: s´lo es posible o salir del bucle introduciendo un valor positivo en x. Ciertamente hemos conseguido obligar al usuario a que los datos que introduce satisfagan una cierta restricci´n. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 111 ¿Qu´ te parece esta otra versi´n del mismo programa? e o raiz 6.py 1 2 3 4 5 6 7 raiz.py from math import sqrt x = float(raw_input(’Introduce␣un␣n´mero␣positivo:␣’)) u while x < 0: x = float(raw_input(’Introduce␣un␣n´mero␣positivo:␣’)) u print ’La␣ra´z␣cuadrada␣de␣%f␣es␣%f’ % (x, sqrt(x)) ı · 112 Dise˜a un programa que solicite la lectura de un n´mero entre 0 y 10 (ambos n u inclusive). Si el usuario teclea un n´mero fuera del rango v´lido, el programa solicitar´ u a a nuevamente la introducci´n del valor cuantas veces sea menester. o · 113 Dise˜a un programa que solicite la lectura de un texto que no contenga letras n may´sculas. Si el usuario teclea una letra may´scula, el programa solicitar´ nuevamente u u a la introducci´n del texto cuantas veces sea preciso. o .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 115 115 Introducción a la programación con Python - UJIUJI c
    • 4.2.4. Mejorando el programa de los men´s u Al acabar la secci´n dedicada a sentencias condicionales presentamos este programa: o circulo.py circulo 4.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == ’a’: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a elif opcion == ’b’: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı elif opcion == ’c’: area = pi * radio ** 2 print ’El␣´rea␣es’, area a else: print ’S´lo␣hay␣tres␣opciones:␣a,␣b␣o␣c.␣T´␣has␣tecleado’, opcion o u Y al empezar esta secci´n, dijimos que cuando el usuario no introduce correctamente una o de las tres opciones del men´ nos gustar´ volver a mostrar el men´ hasta que escoja u ıa u una opci´n v´lida. o a En principio, si queremos que el men´ vuelva a aparecer por pantalla cuando el usuario u se equivoca, deberemos repetir desde la l´ ınea 5 hasta la ultima, as´ que la sentencia while ı ´ deber´ aparecer inmediatamente despu´s de la segunda l´ a e ınea. El borrador del programa puede quedar as´ ı: circulo 13.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from math import pi E circulo.py E radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı while opcion < ’a’ or opcion > ’c’: print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == ’a’: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a elif opcion == ’b’: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı elif opcion == ’c’: area = pi * radio ** 2 print ’El␣´rea␣es’, area a else: print ’S´lo␣hay␣tres␣opciones:␣a,␣b␣o␣c.␣T´␣has␣tecleado’, opcion o u Parece correcto, pero no lo es. ¿Por qu´? El error estriba en que opcion no existe e la primera vez que ejecutamos la l´ ınea 5. ¡Nos hemos olvidado de inicializar la variable Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 116 116 Introducción a la programación con Python - c UJI UJI
    • opcion! Desde luego, el valor inicial de opcion no deber´ ser ’a’, ’b’ o ’c’, pues ıa entonces el bucle no se ejecutar´ (piensa por qu´). Cualquier otro valor har´ que el ıa e a programa funcione. Nosotros utilizaremos la cadena vac´ para inicializar opcion: ıa circulo 14.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 circulo.py from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı opcion = ’’ while opcion < ’a’ or opcion > ’c’: print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == ’a’: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a elif opcion == ’b’: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı elif opcion == ’c’: area = pi * radio ** 2 print ’El␣´rea␣es’, area a else: print ’S´lo␣hay␣tres␣opciones:␣a,␣b␣o␣c.␣T´␣has␣tecleado’, opcion o u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 114 ¿Es correcto este otro programa? ¿En qu´ se diferencia del anterior? ¿Cu´l te e a parece mejor (si es que alguno de ellos te parece mejor)? circulo 15.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 circulo.py from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı opcion = ’’ while opcion < ’a’ or opcion > ’c’: print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion < ’a’ or opcion > ’c’: print ’S´lo␣hay␣tres␣opciones:␣a,␣b␣o␣c.␣T´␣has␣tecleado’, opcion o u if opcion == ’a’: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a elif opcion == ’b’: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı elif opcion == ’c’: area = pi * radio ** 2 print ’El␣´rea␣es’, area a .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 117 117 Introducción a la programación con Python - UJIUJI c
    • Es habitual que los programas con men´ repitan una y otra vez las acciones de preu sentaci´n del listado de opciones, lectura de selecci´n y ejecuci´n del c´lculo. Una opci´n o o o a o del men´ permite finalizar el programa. Aqu´ tienes una nueva versi´n de circulo.py u ı o que finaliza cuando el usuario desea: circulo 16.py 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 circulo.py from math import pi radio = float(raw_input(’Dame␣el␣radio␣de␣un␣c´rculo:␣’)) ı opcion = ’’ while opcion != ’d’: print ’Escoge␣una␣opci´n:␣’ o print ’a)␣Calcular␣el␣di´metro.’ a print ’b)␣Calcular␣el␣per´metro.’ ı print ’c)␣Calcular␣el␣´rea.’ a print ’d)␣Finalizar.’ opcion = raw_input(’Teclea␣a,␣b␣o␣c␣y␣pulsa␣el␣retorno␣de␣carro:␣’) if opcion == ’a’: diametro = 2 * radio print ’El␣di´metro␣es’, diametro a elif opcion == ’b’: perimetro = 2 * pi * radio print ’El␣per´metro␣es’, perimetro ı elif opcion == ’c’: area = pi * radio ** 2 print ’El␣´rea␣es’, area a elif opcion != ’d’: print ’S´lo␣hay␣cuatro␣opciones:␣a,␣b,␣c␣o␣d.␣T´␣has␣tecleado’, opcion o u print ’Gracias␣por␣usar␣el␣programa’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 115 El programa anterior pide el valor del radio al principio y, despu´s, permite e seleccionar uno o m´s c´lculos con ese valor del radio. Modifica el programa para que a a pida el valor del radio cada vez que se solicita efectuar un nuevo c´lculo. a · 116 Un vector en un espacio tridimensional es una tripleta de valores reales (x, y, z). Deseamos confeccionar un programa que permita operar con dos vectores. El usuario ver´ a en pantalla un men´ con las siguientes opciones: u 1) 2) 3) 4) 5) 6) 7) 8) 9) Introducir el primer vector Introducir el segundo vector Calcular la suma Calcular la diferencia Calcular el producto escalar Calcular el producto vectorial Calcular el ´ngulo (en grados) entre ellos a Calcular la longitud Finalizar Puede que necesites que te refresquemos la memoria sobre los c´lculos a realizar. Si a es as´ la tabla 4.1 te ser´ de ayuda: ı, a Tras la ejecuci´n de cada una de las acciones del men´ ´ste reaparecer´ en pantalla, a o ue a menos que la opci´n escogida sea la n´mero 9. Si el usuario escoge una opci´n diferente, o u o el programa advertir´ al usuario de su error y el men´ reaparecer´. a u a Las opciones 4 y 6 del men´ pueden proporcionar resultados distintos en funci´n del u o orden de los operandos, as´ que, si se escoge cualquiera de ellas, deber´ mostrarse un ı a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 118 118 Introducción a la programación con Python - UJIUJI c
    • Operaci´n o C´lculo a Producto escalar: (x1 , y1 , z1 ) · (x2 , y2 , z2 ) x1 x2 + y1 y2 + z1 z2 Suma: (x1 , y1 , z1 ) + (x2 , y2 , z2 ) Diferencia: (x1 , y1 , z1 ) − (x2 , y2 , z2 ) Producto vectorial: (x1 , y1 , z1 ) × (x2 , y2 , z2 ) ´ Angulo entre (x1 , y1 , z1 ) y (x2 , y2 , z2 ) Longitud de (x, y, z) (x1 + x2 , y1 + y2 , z1 + z2 ) (x1 − x2 , y1 − y2 , z1 − z2 ) (y1 z2 − z1 y2 , z1 x2 − x1 z2 , x1 y2 − y1 x2 )   180 x1 x2 + y1 y2 + z1 z2  · arccos  π 2 + y2 + z 2 x 2 + y2 + z 2 x x 2 + y2 + z 2 1 1 1 2 2 2 Tabla 4.1: Recordatorio de operaciones b´sicas sobre vectores. a nuevo men´ que permita seleccionar el orden de los operandos. Por ejemplo, la opci´n 4 u o mostrar´ el siguiente men´: a u 1) Primer vector menos segundo vector 2) Segundo vector menos primer vector Nuevamente, si el usuario se equivoca, se le advertir´ del error y se le permitir´ a a corregirlo. La opci´n 8 del men´ principal conducir´ tambi´n a un submen´ para que el usuario o u a e u decida sobre cu´l de los dos vectores se aplica el c´lculo de longitud. a a Ten en cuenta que tu programa debe contemplar y controlar toda posible situaci´n o excepcional: divisiones por cero, ra´ con argumento negativo, etc´tera. (Nota: La funci´n ıces e o arcocoseno se encuentra disponible en el m´dulo math y su identificador es acos.) o .................................................................................. 4.2.5. El bucle for-in Hay otro tipo de bucle en Python: el bucle for-in, que se puede leer como ˂˂para todo elemento de una serie, hacer. . . ˃˃. Un bucle for-in presenta el siguiente aspecto: for variable in serie de valores: acci´n o acci´n o ... acci´n o Veamos c´mo funciona con un sencillo ejemplo: o saludos.py 1 2 saludos.py for nombre in [’Pepe’, ’Ana’, ’Juan’]: print ’Hola,␣%s.’ % nombre F´ ıjate en que la relaci´n de nombres va encerrada entre corchetes y que cada nombre o se separa del siguiente con una coma. Se trata de una lista de nombres. M´s adelante a estudiaremos con detalle las listas. Ejecutemos ahora el programa. Por pantalla aparecer´ a el siguiente texto: Hola, Pepe. Hola, Ana. Hola, Juan. Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 119 119 Introducción a la programación con Python - UJI c UJI
    • Se ha ejecutado la sentencia m´s indentada una vez por cada valor de la serie de a nombres y, con cada iteraci´n, la variable nombre ha tomado el valor de uno de ellos o (ordenadamente, de izquierda a derecha). En el cap´ ıtulo anterior estudiamos el siguiente programa: potencias 2.py 1 2 3 4 5 6 potencias.py numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u print ’%d␣elevado␣a␣%d␣es␣%d’ print ’%d␣elevado␣a␣%d␣es␣%d’ print ’%d␣elevado␣a␣%d␣es␣%d’ print ’%d␣elevado␣a␣%d␣es␣%d’ % % % % (numero, 2, numero (numero, 3, numero (numero, 4, numero (numero, 5, numero Ahora podemos ofrecer una versi´n m´s simple: o a potencias.py 1 2 3 4 ** ** ** ** 2) 3) 4) 5) potencias.py numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u for potencia in [2, 3, 4, 5]: print ’%d␣elevado␣a␣%d␣es␣%d’ % (numero, potencia, numero ** potencia) El bucle se lee de forma natural como ˂˂para toda potencia en la serie de valores 2, 3, 4 y 5, haz. . . ˃˃. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 117 Haz un programa que muestre la tabla de multiplicar de un n´mero introducido u por teclado por el usuario. Aqu´ tienes un ejemplo de c´mo se debe comportar el programa: ı o Dame un n´mero: 5 u 5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25 5 x 6 = 30 5 x 7 = 35 5 x 8 = 40 5 x 9 = 45 5 x 10 = 50 · 118 Realiza un programa que proporcione el desglose en billetes y monedas de una cantidad entera de euros. Recuerda que hay billetes de 500, 200, 100, 50, 20, 10 y 5 ¤ y monedas de 2 y 1 ¤. Debes ˂˂recorrer˃˃ los valores de billete y moneda disponibles con uno o m´s bucles for-in. a · 119 Haz un programa que muestre la ra´ n-´sima de un n´mero le´ por teclado, ız e u ıdo para n tomando valores entre 2 y 100. .................................................................................. El ultimo ejercicio propuesto es todo un desaf´ a nuestra paciencia: teclear 99 ıo ´ n´meros separados por comas supone un esfuerzo b´rbaro y conduce a un programa u a poco elegante. Es hora de aprender una nueva funci´n predefinida de Python que nos ayudar´ a o a evitar ese tipo de problemas: la funci´n range (que en ingl´s significa ˂˂rango˃˃). En o e principio, range se usa con dos argumentos: un valor inicial y un valor final (con matices). Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 120 120 Introducción a la programación con Python - UJIUJI c
    • ↱ >>> range(2, 10) [2, 3, 4, 5, 6, 7, 8, 9] >>> range(0, 3) [0, 1, 2] >>> range(-3, 3) [-3, -2, -1, 0, 1, 2] ↱ ↱ Observa que la lista devuelta contiene todos los enteros comprendidos entre los argumentos de la funci´n, incluyendo al primero pero no al ultimo. o ´ La funci´n range devuelve una lista de n´meros enteros. Estudia este ejemplo: o u contador con for.py contador con for.py 1 2 for i in range(1, 6): print i Al ejecutar el programa, veremos lo siguiente por pantalla: 1 2 3 4 5 La lista que devuelve range es usada por el bucle for-in como serie de valores a recorrer. El ultimo ejercicio propuesto era pesad´ ısimo: ¡nos obligaba a escribir una serie de 99 ´ n´meros! Con range resulta much´ u ısimo m´s sencillo. He aqu´ la soluci´n: a ı o raices.py raices 2.py 1 2 3 4 numero = float(raw_input(’Dame␣un␣n´mero:␣’)) u for n in range(2, 101): print ’la␣ra´z␣%d-´sima␣de␣%f␣es␣%f’ % (numero, n, numero**(1.0/n)) ı e (F´ ıjate en que range tiene por segundo argumento el valor 101 y no 100: recuerda que el ultimo valor de la lista es el segundo argumento menos uno.) ´ Podemos utilizar la funci´n range con uno, dos o tres argumentos. Si usamos range o con un argumento estaremos especificando unicamente el ultimo valor (m´s uno) de la a ´ ´ serie, pues el primero vale 0 por defecto: ↱ >>> range(5) [0, 1, 2, 3, 4] Si usamos tres argumentos, el tercero permite especificar un incremento para la serie de valores. Observa en estos ejemplos qu´ listas de enteros devuelve range: e ↱ range(2, 10, 2) 4, 6, 8] range(2, 10, 3) 5, 8] ↱ >>> [2, >>> [2, F´ ıjate en que si pones un incremento negativo (un decremento), la lista va de los valores altos a los bajos. Recuerda que con range el ultimo elemento de la lista no llega ´ a ser el valor final ↱ ↱ >>> range(10, 5, -1) [10, 9, 8, 7, 6] >>> range(3, -1, -1) [3, 2, 1, 0] Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 121 121 c UJI Introducción a la programación con Python - UJI
    • As´ pues, si el tercer argumento es negativo, la lista finaliza en el valor final m´s uno ı a (y no menos uno). Finalmente, observa que es equivalente utilizar range con dos argumentos a utilizarla con un valor del incremento igual a 1. range(2, 5, 1) 3, 4] range(2, 5) 3, 4] ↱ ↱ >>> [2, >>> [2, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 120 Haz un programa que muestre, en l´ ıneas independientes, todos los n´meros pares u comprendidos entre 0 y 200 (ambos inclusive). · 121 Haz un programa que muestre, en l´ ıneas independientes y en orden inverso, todos los n´meros pares comprendidos entre 0 y 200 (ambos inclusive). u · 122 Escribe un programa que muestre los n´meros pares positivos entre 2 y un u n´mero cualquiera que introduzca el usuario por teclado. u .................................................................................. Obi Wan Puede resultar sorprendente que range(a, b) incluya todos los n´meros enteros comu prendidos entre a y b, pero sin incluir b. En realidad la forma ˂˂natural˃˃ o m´s frecuente a de usar range es con un s´lo par´metro: range(n) que devuelve una lista con los n o a primeros n´meros enteros incluyendo al cero (hay razones para que esto sea lo conu veniente, ya llegaremos). Como incluye al cero y hay n n´meros, no puede incluir al u propio n´mero n. Al extenderse el uso de range a dos argumentos, se ha mantenido u la ˂˂compatibilidad˃˃ eliminando el ultimo elemento. Una primera ventaja es que resulta ´ f´cil calcular cu´ntas iteraciones realizar´ un bucle range(a, b): exactamente b - a. a a a (Si el valor b estuviera incluido, el n´mero de elementos ser´ b - a + 1.) u ıa Hay que ir con cuidado, pues es f´cil equivocarse ˂˂por uno˃˃. De hecho, equivocarse a ˂˂por uno˃˃ es tan frecuente al programar (y no s´lo con range) que hay una expresi´n o o para este tipo de error: un error Obi Wan (Kenobi), que es m´s o menos como suena en a ingl´s ˂˂off by one˃˃ (pasarse o quedarse corto por uno). e 4.2.6. for-in como forma compacta de ciertos while Ciertos bucles se ejecutan un n´mero de veces fijo y conocido a priori. Por ejemplo, al u desarrollar el programa que calcula el sumatorio de los 1000 primeros n´meros utilizamos u un bucle que iteraba exactamente 1000 veces: sumatorio 6.py 1 2 3 4 5 6 sumatorio.py sumatorio = 0 i=1 while i <= 1000 : sumatorio += i i += 1 print sumatorio El bucle se ha construido de acuerdo con un patr´n, una especie de ˂˂frase hecha˃˃ o del lenguaje de programaci´n: o i = valor inicial while i <= valor final : acciones i += 1 Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 122 122 Introducción a la programación con Python - UJIUJI c
    • En este patr´n la variable i suele denominarse ´ o ındice del bucle. Podemos expresar de forma compacta este tipo de bucles con un for-in siguiendo este otro patr´n: o for i in range(valor inicial, valor final + 1): acciones F´ ıjate en que las cuatro l´ ıneas del fragmento con while pasan a expresarse con s´lo dos o gracias al for-in con range. El programa de c´lculo del sumatorio de los 1000 primeros n´meros se puede expresar a u ahora de este modo: sumatorio.py sumatorio.py 1 2 3 4 5 sumatorio = 0 for i in range(1, 1001): sumatorio += i print sumatorio ¡Bastante m´s f´cil de leer que usando un while! a a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 123 Haz un programa que pida el valor de dos enteros n y m y que muestre por pantalla el valor de m i=n i. Debes usar un bucle for-in para el c´lculo del sumatorio. a · 124 Haz un programa que pida el valor de dos enteros n y m y que muestre por pantalla el valor de m i=n i2 . · 125 Haz un programa que pida el valor de dos enteros n y m y calcule el sumatorio de todos los n´meros pares comprendidos entre ellos (incluy´ndolos en el caso de que u e sean pares). .................................................................................. 4.2.7. N´meros primos u Vamos ahora con un ejemplo m´s. Nos proponemos construir un programa que nos diga a si un n´mero (entero) es o no es primo. Recuerda: un n´mero primo es aquel que s´lo es u u o divisible por s´ mismo y por 1. ı ¿C´mo empezar? Resolvamos un problema concreto, a ver qu´ estrategia seguir´ o e ıamos normalmente. Supongamos que deseamos saber si 7 es primo. Podemos intentar dividirlo por cada uno de los n´meros entre 2 y 6. Si alguna de las divisiones es exacta, entonces u el n´mero no es primo: u Dividendo 7 7 7 7 7 Divisor 2 3 4 5 6 Cociente 3 2 1 1 1 Resto 1 1 3 2 1 Ahora estamos seguros: ninguno de los restos dio 0, as´ que 7 es primo. Hagamos que el ı ordenador nos muestre esa misma tabla: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 123 123 Introducción a la programación con Python - UJIUJI c
    • es primo.py es primo 10.py 1 2 3 4 5 num = 7 for divisor in range(2, num): print ’%d␣entre␣%d’ % (num, divisor) , print ’es␣%d␣con␣resto␣%d’ % (num / divisor, num % divisor) (Recuerda que range(2,num) comprende todos los n´meros enteros entre 2 y num - 1.) u Aqu´ tienes el resultado de ejecutar el programa: ı 7 7 7 7 7 entre entre entre entre entre 2 3 4 5 6 es es es es es 3 2 1 1 1 con con con con con resto resto resto resto resto 1 1 3 2 1 Est´ claro que probar todas las divisiones es f´cil, pero, ¿c´mo nos aseguramos de a a o que todos los restos son distintos de cero? Una posibilidad es contarlos y comprobar que hay exactamente num - 2 restos no nulos: es primo 11.py 1 2 3 4 5 6 7 8 9 10 11 es primo.py num = 7 restos_no_nulos = 0 for divisor in range(2, num): if num % divisor != 0: restos_no_nulos += 1 if restos_no_nulos == num - 2: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u Pero vamos a proponer un m´todo distinto basado en una ˂˂idea feliz˃˃ y que, m´s e a adelante, nos permitir´ acelerar notabil´ a ısimamente el c´lculo. Vale la pena que la estudies a bien: la utilizar´s siempre que quieras probar que toda una serie de valores cumple una a propiedad. En nuestro caso la propiedad que queremos demostrar que cumplen todos los n´meros entre 2 y num-1 es ˂˂al dividir a num, da resto distinto de cero˃˃. u Empieza siendo optimista: sup´n que la propiedad es cierta y asigna a una variable o el valor ˂˂cierto˃˃. Recorre todos los n´meros y cuando alguno de los elementos de la secuencia no u satisfaga la propiedad, modifica la variable antes mencionada para que contenga el valor ˂˂falso˃˃. Al final del todo, mira qu´ vale la variable: si a´n vale ˂˂cierto˃˃, es que nadie la puso e u a ˂˂falso˃˃, as´ que la propiedad se cumple para todos los elementos y el n´mero es ı u primo; y si vale ˂˂falso˃˃, entonces alguien la puso a ˂˂falso˃˃ y para eso es preciso que alg´n elemento no cumpliera la propiedad en cuesti´n, por lo que el n´mero u o u no puede ser primo. Mira c´mo plasmamos esa idea en un programa: o es primo 12.py 1 2 es primo.py num = 7 Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 124 124 Introducción a la programación con Python - UJI c UJI
    • 3 4 5 6 7 8 9 10 11 creo_que_es_primo = True for divisor in range(2, num): if num % divisor == 0: creo_que_es_primo = False if creo_que_es_primo: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 126 Haz un traza del programa para los siguientes n´meros: u a) 4 b) 13 c) 18 d) 2 (¡ojo con ´ste!) e .................................................................................. True == True F´ ıjate en la l´ ınea 8 de este programa: 1 2 3 4 5 6 7 8 9 10 11 es primo.py num = 7 creo_que_es_primo = True for divisor in range(2, num): if num % divisor == 0: creo_que_es_primo = False if creo_que_es_primo: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u La condici´n del if es muy extra˜a, ¿no? No hay comparaci´n alguna. ¿Qu´ condici´n o n o e o es esa? Muchos estudiantes optan por esta f´rmula alternativa para las l´ o ıneas 8 y sucesivas es primo.py . . . 8 9 10 11 if creo_que_es_primo == True: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u Les parece m´s natural porque de ese modo se compara el valor de creo_que_es_primo a con algo. Pero, si lo piensas bien, esa comparaci´n es superflua: a fin de cuentas, o el resultado de la comparaci´n creo_que_es_primo == True es True y, directamente, o creo_que_es_primo vale True. No es que est´ mal efectuar esa comparaci´n extra, sino que no aporta nada y resta e o legibilidad. Ev´ ıtala si puedes. Despu´s de todo, no es tan dif´ Aunque esta idea feliz la utilizar´s muchas veces, e ıcil. a es probable que cometas un error (al menos, muchos compa˜eros tuyos caen en ´l una y n e otra vez). F´ ıjate en este programa, que est´ mal: a es primo 13.py E es primo.py E Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 125 125 Introducción a la programación con Python - UJIUJI c
    • 1 2 3 4 5 6 7 8 9 10 11 12 13 num = 7 creo_que_es_primo = True for divisor in range(2, num): if num % divisor == 0: creo_que_es_primo = False else: creo_que_es_primo = True if creo_que_es_primo: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u ¡El programa s´lo se acuerda de lo que pas´ con el ultimo valor del bucle! Haz la prueba: o o ´ haz una traza sustituyendo la asignaci´n de la l´ o ınea 1 por la sentencia num = 4. El n´mero u no es primo, pero al no ser exacta la divisi´n entre 4 y 3 (el ultimo valor de divisor en o ´ el bucle), el valor de creo_que_es_primo es True. El programa concluye, pues, que 4 es primo. Vamos a refinar el programa. En primer lugar, haremos que trabaje con cualquier n´mero que el usuario introduzca: u es primo 14.py 1 2 3 4 5 6 7 8 9 10 11 es primo.py num = int(raw_input(’Dame␣un␣n´mero:␣’)) u creo_que_es_primo = True for divisor in range(2, num): if num % divisor == 0: creo_que_es_primo = False if creo_que_es_primo: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u F´cil. Ahora vamos a hacer que vaya m´s r´pido. Observa qu´ ocurre cuando tratamos a a a e de ver si el n´mero 1024 es primo o no. Empezamos dividi´ndolo por 2 y vemos que el u e resto de la divisi´n es cero. Pues ya est´: estamos seguros de que 1024 no es primo. Sin o a embargo, nuestro programa sigue haciendo c´lculos: pasa a probar con el 3, y luego con a el 4, y con el 5, y as´ hasta llegar al 1023. ¿Para qu´, si ya sabemos que no es primo? ı e Nuestro objetivo es que el bucle deje de ejecutarse tan pronto estemos seguros de que el n´mero no es primo. Pero resulta que no podemos hacerlo con un bucle for-in, pues este u tipo de bucles se basa en nuestro conocimiento a priori de cu´ntas iteraciones vamos a a hacer. Como en este caso no lo sabemos, hemos de utilizar un bucle while. Escribamos primero un programa equivalente al anterior, pero usando un while en lugar de un for-in: es primo 15.py 1 2 3 4 5 6 7 8 9 10 es primo.py num = int(raw_input(’Dame␣un␣n´mero:␣’)) u creo_que_es_primo = True divisor = 2 while divisor < num: if num % divisor == 0: creo_que_es_primo = False divisor += 1 if creo_que_es_primo: Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 126 126 Introducción a la programación con Python - cUJI UJI
    • Se cumple para todos/se cumple para alguno Muchos de los programas que dise˜aremos necesitan verificar que cierta condici´n se n o cumple para alg´n elemento de un conjunto o para todos los elementos del conjunto. En u ambos casos tendremos que recorrer todos los elementos, uno a uno, y comprobar si la condici´n es cierta o falsa para cada uno de ellos. o Cuando queramos comprobar que todos cumplen una condici´n, haremos lo siguiente: o 1. 2. 3. Seremos optimistas y empezaremos suponiendo que la condici´n se cumple para o todos. Preguntaremos a cada uno de los elementos si cumple la condici´n. o S´lo cuando detectemos que uno de ellos no la cumple, cambiaremos de opini´n o o y pasaremos a saber que la condici´n no se cumple para todos. Nada nos podr´ o a hacer cambiar de opini´n. o He aqu´ un esquema que usa la notaci´n de Python: ı o 1 2 3 4 5 6 7 creo_que_se_cumple_para_todos = True for elemento in conjunto: if not condici´n: o creo_que_se_cumple_para_todos = False if creo_que_se_cumple_para_todos: print ’Se␣cumple␣para␣todos’ Cuando queramos comprobar que alguno cumple una condici´n, haremos lo siguiente: o 1. 2. 3. Seremos pesimistas y empezaremos suponiendo que la condici´n no se cumple o para ninguno. Preguntaremos a cada uno de los elementos si se cumple la condici´n. o S´lo cuando detectemos que uno de ellos s´ la cumple, cambiaremos de opini´n o ı o y pasaremos a saber que la condici´n se cumple para alguno. Nada nos podr´ o a hacer cambiar de opini´n. o He aqu´ un esquema que usa la notaci´n de Python: ı o 1 2 3 4 5 6 7 11 12 13 creo_que_se_cumple_para_alguno = False for elemento in conjunto: if condici´n: o creo_que_se_cumple_para_alguno = True if creo_que_se_cumple_para_alguno: print ’Se␣cumple␣para␣alguno’ print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 127 Haz una traza del ultimo programa para el n´mero 125. u ´ .................................................................................. Hemos sustituido el for-in por un while, pero no hemos resuelto el problema: con el 1024 seguimos haciendo todas las pruebas de divisibilidad. ¿C´mo hacer que el bucle o acabe tan pronto se est´ seguro de que el n´mero no es primo? Pues complicando un e u poco la condici´n del while: o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 127 127 Introducción a la programación con Python - UJIUJI c
    • Error para alguno/error para todos Ya te hemos dicho que muchos de los programas que dise˜aremos necesitan verificar n que cierta condici´n se cumple para alg´n elemento de un conjunto o para todos los o u elementos del conjunto. Y tambi´n te hemos dicho c´mo abordar ambos problemas. Pero, e o aun as´ es probable que cometas un error (muchos, muchos estudiantes lo hacen). Aqu´ ı, ı tienes un ejemplo de programa err´neo al tratar de comprobar que una condici´n se o o cumple para todos los elementos de un conjunto: 1 2 3 4 5 6 7 8 9 creo_que_se_cumple_para_todos = True for elemento in conjunto: if not condici´n: o creo_que_se_cumple_para_todos = False else: # Esta l´ ınea y la siguiente sobran creo_que_se_cumple_para_todos = True E if creo_que_se_cumple_para_todos: print ’Se␣cumple␣para␣todos’ Y aqu´ tienes una versi´n err´nea para el intento de comprobar que una condici´n se ı o o o cumple para alguno: 1 2 3 4 5 6 7 8 9 creo_que_se_cumple_para_alguno = False for elemento in conjunto: if condici´n: o creo_que_se_cumple_para_alguno = True else: # Esta l´ ınea y la siguiente sobran creo_que_se_cumple_para_alguno = False E if creo_que_se_cumple_para_alguno: print ’Se␣cumple␣para␣alguno’ En ambos casos, s´lo se est´ comprobando si el ultimo elemento del conjunto cumple o o a ´ no la condici´n. o es primo 16.py 1 2 3 4 5 6 7 8 9 10 11 12 13 es primo.py num = int(raw_input(’Dame␣un␣n´mero:␣’)) u creo_que_es_primo = True divisor = 2 while divisor < num and creo_que_es_primo : if num % divisor == 0: creo_que_es_primo = False divisor += 1 if creo_que_es_primo: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u Ahora s´ ı. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 128 Haz una traza del ultimo programa para el n´mero 125. u ´ · 129 Haz un programa que calcule el m´ximo com´n divisor (mcd) de dos enteros a u positivos. El mcd es el n´mero m´s grande que divide exactamente a ambos n´meros. u a u · 130 Haz un programa que calcule el m´ximo com´n divisor (mcd) de tres enteros a u Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 128 128 Introducción a la programación con Python - UJIUJI c
    • positivos. El mcd de tres n´meros es el n´mero m´s grande que divide exactamente a los u u a tres. .................................................................................. 4.2.8. Rotura de bucles: break El ultimo programa dise˜ado aborta su ejecuci´n tan pronto sabemos que el n´mero n o u ´ estudiado no es primo. La variable creo_que_es_primo juega un doble papel: ˂˂recordar˃˃ si el n´mero es primo o no al final del programa y abortar el bucle while tan pronto u sabemos que el n´mero no es primo. La condici´n del while se ha complicado un poco u o para tener en cuenta el valor de creo_que_es_primo y abortar el bucle inmediatamente. Hay una sentencia que permite abortar la ejecuci´n de un bucle desde cualquier o punto del mismo: break (en ingl´s significa ˂˂romper˃˃). Observa esta nueva versi´n del e o mismo programa: es primo 17.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 es primo.py num = int(raw_input(’Dame␣un␣n´mero:␣’)) u creo_que_es_primo = True divisor = 2 while divisor < num : if num % divisor == 0: creo_que_es_primo = False break divisor += 1 if creo_que_es_primo: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u Cuando se ejecuta la l´ ınea 8, el programa sale inmediatamente del bucle, es decir, pasa a la l´ ınea 10 sin pasar por la l´ ınea 9. Nuevamente estamos ante una comodidad ofrecida por el lenguaje: la sentencia break permite expresar de otra forma una idea que ya pod´ expresarse sin ella. S´lo debes ıa o considerar la utilizaci´n de break cuando te resulte c´moda. No abuses del break: a o o veces, una condici´n bien expresada en la primera l´ o ınea del bucle while hace m´s legible a un programa. La sentencia break tambi´n es utilizable con el bucle for-in. Analicemos esta nueva e versi´n de es primo.py: o es primo 18.py 1 2 3 4 5 6 7 8 9 10 11 12 es primo.py num = int(raw_input(’Dame␣un␣n´mero:␣’)) u creo_que_es_primo = True for divisor in range(2, num): if num % divisor == 0: creo_que_es_primo = False break if creo_que_es_primo: print ’El␣n´mero’, num, ’es␣primo’ u else: print ’El␣n´mero’, num, ’no␣es␣primo’ u Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 129 129 Introducción a la programación con Python - c UJI UJI
    • Versiones eficientes de ˂˂se cumple para alguno/se cumple para todos˃˃ Volvemos a visitar los problemas de ˂˂se cumple para alguno˃˃ y ˂˂se cumple para todos˃˃. Esta vez vamos a hablar de c´mo acelerar el c´lculo gracias a la sentencia break. o a Si quieres comprobar si una condici´n se cumple para todos los elementos de un o conjunto y encuentras que uno de ellos no la satisface, ¿para qu´ seguir? ¡Ya sabemos e que no se cumple para todos! 1 2 3 4 5 6 7 8 creo_que_se_cumple_para_todos = True for elemento in conjunto: if not condici´n: o creo_que_se_cumple_para_todos = False break if creo_que_se_cumple_para_todos: print ’Se␣cumple␣para␣todos’ Como ves, esta mejora puede suponer una notable aceleraci´n del c´lculo: cuando el o a primer elemento del conjunto no cumple la condici´n, acabamos inmediatamente. Ese es o el mejor de los casos. El peor de los casos es que todos cumplan la condici´n, pues nos o vemos obligados a recorrer todos los elementos del conjunto. Y eso es lo que hac´ ıamos hasta el momento: recorrer todos los elementos. O sea, en el peor de los casos, hacemos el mismo esfuerzo que ven´ ıamos haciendo para todos los casos. ¡No est´ nada mal! a Si quieres comprobar si una condici´n se cumple para alguno de los elementos de o un conjunto y encuentras que uno de ellos la satisface, ¿para qu´ seguir? ¡Ya sabemos e que la cumple alguno! 1 2 3 4 5 6 7 8 creo_que_se_cumple_para_alguno = False for elemento in conjunto: if condici´n: o creo_que_se_cumple_para_alguno = True break if creo_que_se_cumple_para_alguno: print ’Se␣cumple␣para␣alguno’ Podemos hacer la misma reflexi´n en torno a la eficiencia de esta nueva versi´n que en o o el caso anterior. Esta versi´n es m´s concisa que la anterior (ocupa menos l´ o a ıneas) y, en cierto sentido, m´s elegante: el bucle for-in expresa mejor la idea de que divisor recorre ascendentea mente un rango de valores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 131 Haz una traza del programa para el valor 125. · 132 En realidad no hace falta explorar todo el rango de n´meros entre 2 y n − 1 para u saber si un n´mero n es o no es primo. Basta con explorar el rango de n´meros entre 2 y u u la parte entera de n/2. Piensa por qu´. Modifica el programa para que s´lo exploremos e o ese rango. · 133 Ni siquiera hace falta explorar todo el rango de n´meros entre 2 y n/2 para u saber si un n´mero n es o no es primo. Basta con explorar el rango de n´meros entre 2 u u √ y la parte entera de n. (Cr´etelo.) Modifica el programa para que s´lo exploremos ese e o rango. · 134 Haz un programa que vaya leyendo n´meros y mostr´ndolos por pantalla hasta u a que el usuario introduzca un n´mero negativo. En ese momento, el programa mostrar´ un u a mensaje de despedida y finalizar´ su ejecuci´n. a o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 130 130 Introducción a la programación con Python - UJIUJI c
    • · 135 Haz un programa que vaya leyendo n´meros hasta que el usuario introduzca un u n´mero negativo. En ese momento, el programa mostrar´ por pantalla el n´mero mayor u a u de cuantos ha visto. .................................................................................. 4.2.9. Anidamiento de estructuras Ahora vamos a resolver otro problema. Vamos a hacer que el programa pida un n´mero u y nos muestre por pantalla los n´meros primos entre 1 y el que hemos introducido. Mira u este programa: primos.py primos.py 1 2 3 4 5 6 7 8 9 10 limite = int(raw_input(’Dame␣un␣n´mero:␣’)) u for num in range(1, limite+1): creo_que_es_primo = True for divisor in range(2, num): if num % divisor == 0: creo_que_es_primo = False break if creo_que_es_primo: print num No deber´ resultarte dif´ entender el programa. Tiene bucles anidados (un for-in ıa ıcil dentro de un for-in), pero est´ claro qu´ hace cada uno de ellos: el m´s exterior recorre a e a con num todos los n´meros comprendidos entre 1 y limite (ambos inclusive); el m´s interior u a forma parte del procedimiento que determina si el n´mero que estamos estudiando en u cada instante es o no es primo. Dicho de otro modo: num va tomando valores entre 1 y limite y para cada valor de num se ejecuta el bloque de las l´ ıneas 4–10, as´ que, para cada valor de num, se comprueba ı si ´ste es primo o no. S´lo si el n´mero resulta ser primo se muestra por pantalla. e o u Puede que te intrigue el break de la l´ ınea 8. ¿A qu´ bucle ˂˂rompe˃˃? S´lo al m´s e o a interior: una sentencia break siempre aborta la ejecuci´n de un solo bucle y ´ste es el o e que lo contiene directamente. Antes de acabar: existen procedimientos m´s eficientes para determinar si un n´mero a u es primo o no, as´ como para listar los n´meros primos en un intervalo. Hacer buenos ı u programas no s´lo pasa por conocer bien las reglas de escritura de programas en un o lenguaje de programaci´n: has de saber dise˜ar algoritmos y, muchas veces, buscar los o n mejores algoritmos conocidos en los libros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 136 ¿Qu´ resultar´ de ejecutar estos programas? e a a) ejercicio for 7.py 1 2 3 b) ejercicio for 8.py 1 2 3 c) for i in range(0, 5): for j in range(0, 3): print i, j for i in range(0, 5): for j in range(i, 5): print i, j ejercicio for 9.py 1 2 3 for i in range(0, 5): for j in range(0, i): print i, j ejercicio for.py ejercicio for.py ejercicio for.py Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 131 131 Introducción a la programación con Python - UJIUJI c
    • ´ Indice de bucle for-in: ¡prohibido asignar! Hemos aprendido que el bucle for-in utiliza una variable ´ ındice a la que se van asignando los diferentes valores del rango. En muchos ejemplos se utiliza la variable i, pero s´lo porque tambi´n en matem´ticas los sumatorios y productorios suelen utilizar la o e a letra i para indicar el nombre de su variable ´ ındice. Puedes usar cualquier nombre de variable v´lido. a Pero que el ´ ındice sea una variable cualquiera no te da libertad absoluta para hacer con ella lo que quieras. En un bucle, las variables de ´ ındice s´lo deben usarse para o consultar su valor, nunca para asignarles uno nuevo. Por ejemplo, este fragmento de programa es incorrecto: 1 2 for i in range(0, 5): i += 2 E Y ahora que sabes que los bucles pueden anidarse, tambi´n has de tener mucho e cuidado con sus ´ ındices. Un error frecuente entre primerizos de la programaci´n es o utilizar el mismo ´ ındice para dos bucles anidados. Por ejemplo, estos bucles anidados est´n mal: a 1 2 3 for i in range(0, 5): for i in range(0, 3): print i E En el fondo, este problema es una variante del anterior, pues de alg´n modo se est´ u a asignando nuevos valores a la variable i en el bucle interior, pero i es la variable del bucle exterior y asignarle cualquier valor est´ prohibido. a Recuerda: nunca debes asignar un valor a un ´ ındice de bucle ni usar la misma variable ´ ındice en bucles anidados. d) ejercicio for 10.py 1 2 3 4 e) ejercicio for 11.py 1 2 3 4 f) for i in range(0, 4): for j in range(0, 4): for k in range(0, 2): print i, j, k for i in range(0, 4): for j in range(0, 4): for k in range(i, j): print i, j, k ejercicio for 12.py 1 2 3 ejercicio for.py ejercicio for.py ejercicio for.py for i in range(1, 5): for j in range(0, 10, i): print i, j .................................................................................. 4.3. Captura y tratamiento de excepciones Ya has visto que en nuestros programas pueden aparecer errores en tiempo de ejecuci´n, o es decir, pueden generar excepciones: divisiones por cero, intentos de calcular ra´ ıces de valores negativos, problemas al operar con tipos incompatibles (como al sumar una cadena y un entero), etc. Hemos presentado la estructura de control if como un medio para controlar estos problemas y ofrecer un tratamiento especial cuando convenga (aunque luego hemos considerado muchas otras aplicaciones de esta sentencia). La detecci´n de o Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 132 132 Introducción a la programación con Python - c UJI UJI
    • Una excepci´n a la regla de indentaci´n o o Cada vez que una sentencia acaba con dos puntos (:), Python espera que la sentencia o sentencias que le siguen aparezcan con una mayor indentaci´n. Es la forma de marcar o el inicio y el fin de una serie de sentencias que ˂˂dependen˃˃ de otra. Hay una excepci´n: si s´lo hay una sentencia que ˂˂depende˃˃ de otra, puedes escribir o o ambas en la misma l´ ınea. Este programa: 1 2 3 4 5 6 7 a = int(raw_input(’Dame␣un␣entero␣positivo:␣’)) while a < 0: a = int(raw_input(’Te␣he␣dicho␣positivo:␣’)) if a % 2 == 0: print ’El␣n´mero␣es␣par’ u else: print ’El␣n´mero␣es␣impar’ u y este otro: 1 2 3 4 a = int(raw_input(’Dame␣un␣entero␣positivo:␣’)) while a < 0: a = int(raw_input(’Te␣he␣dicho␣positivo:␣’)) if a % 2 == 0: print ’El␣n´mero␣es␣par’ u else: print ’El␣n´mero␣es␣impar’ u son equivalentes. posibles errores con if resulta un tanto pesada, pues modifica sensiblemente el aspecto del programa al llenarlo de comprobaciones. Hay una estructura de control especial para la detecci´n y tratamiento de excepciones: o try-except. Su forma b´sica de uso es ´sta: a e try: acci´n o acci´n o ... acci´n o except: acci´n o acci´n o ... acci´n o potencialmente err´nea o potencialmente err´nea o potencialmente err´nea o para tratar el error para tratar el error para tratar el error Podemos expresar la idea fundamental as´ ı: ˂˂Intenta ejecutar estas acciones y, si se comete un error, ejecuta inmediatamente estas otras.˃˃ Es f´cil entender qu´ hace b´sicamente si estudiamos un ejemplo sencillo. Volvamos a e a a considerar el problema de la resoluci´n de una ecuaci´n de primer grado: o o primer grado 14.py 1 2 3 4 5 6 7 8 9 primer grado.py a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) try: x = -b/a print ’Soluci´n:␣’, x o except: if b != 0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 133 133 Introducción a la programación con Python - cUJI UJI
    • 10 11 else: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o Las l´ ıneas 5 y 6 est´n en un bloque que depende de la sentencia try. Es admisible a que se lancen excepciones desde ese bloque. Si se lanza una, la ejecuci´n pasar´ inmeo a diatamente al bloque que depende de la sentencia except. Hagamos dos trazas, una para una configuraci´n de valores de a y b que provoque un error de divisi´n por cero y una o o para otra que no genere excepci´n alguna: o a=0yb=3 Las l´ ıneas 1 y 2 se ejecutan, con lo que se leen los valores de a y b. ...................................... La l´ ınea 4 se ejecuta, pero no hay un efecto asociado a su ejecuci´n. o ...................................... Al ejecutarse la l´ ınea 5, se produce una excepci´n (divisi´n por cero). Se salta ino o mediatamente a la l´ ınea 8. ...................................... Se ejecuta la l´ ınea 8 y el resultado de la comparaci´n es cierto. o ...................................... La l´ ınea 9 se ejecuta y se muestra por pantalla el mensaje ˂˂La ecuaci´n no o tiene soluci´n.˃˃ o Atrev´monos ahora con la resoluci´n de una ecuaci´n de segundo grado: a o o segundo grado 23.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 a = 1 y b = −1 Las l´ ıneas 1 y 2 se ejecutan, con lo que se leen los valores de a y b. ...................................... La l´ ınea 4 se ejecuta, pero no hay un efecto asociado a su ejecuci´n. o ...................................... Se ejecutan las l´ ıneas 5 y 6, con lo que se muestra por pantalla el valor de la soluci´n de la ecuaci´n: Soluci´n: 1. La o o o ejecuci´n finaliza. o segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) try: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) if x1 == x2: print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x1 o o else: print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o except: # No sabemos si llegamos aqu´ por una divisi´n por cero o si llegamos ı o # por intentar calcular la ra´ cuadrada de un discriminante negativo. ız print ’O␣no␣hay␣soluciones␣reales␣o␣es␣una␣ecuaci´n␣de␣primer␣grado’ o Como es posible que se cometan dos tipos de error diferentes, al llegar al bloque dependiente del except no sabemos cu´l de los dos tuvo lugar. Evidentemente, podemos a efectuar las comprobaciones pertinentes sobre los valores de a, b y c para deducir el error concreto, pero queremos contarte otra posibilidad de la sentencia try-except. Las excepciones tienen un ˂˂tipo˃˃ asociado y podemos distinguir el tipo de excepci´n para o actuar de diferente forma en funci´n del tipo de error detectado. Una divisi´n por cero o o es un error de tipo ZeroDivisionError y el intento de calcular la ra´ cuadrada de un ız valor negativo es un error de tipo ValueError. Mmmm. Resulta dif´ recordar de qu´ ıcil e tipo es cada error, pero el int´rprete de Python resulta util para recordar si provocamos e ´ deliberadamente un error del tipo que deseamos tratar: Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 134 134 Introducción a la programación con Python - cUJI UJI
    • ↱ >>> 1 / 0 Traceback (most recent call last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo by zero >>> from math import sqrt >>> sqrt(-1) Traceback (most recent call last): File "<stdin>", line 1, in ? ValueError: math domain error ↱ segundo grado 24.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ↱ Es posible usar varias cl´usulas except, una por cada tipo de error a tratar: a segundo grado.py from math import sqrt a = float(raw_input(’Valor␣de␣a:␣’)) b = float(raw_input(’Valor␣de␣b:␣’)) c = float(raw_input(’Valor␣de␣c:␣’)) try: x1 = (-b + sqrt(b**2 - 4*a*c)) / (2 * a) x2 = (-b - sqrt(b**2 - 4*a*c)) / (2 * a) if x1 == x2: print ’Soluci´n␣de␣la␣ecuaci´n:␣x=%4.3f’ % x1 o o else: print ’Soluciones␣de␣la␣ecuaci´n:␣x1=%4.3f␣y␣x2=%4.3f’ % (x1, x2) o except ZeroDivisionError: if b != 0: print ’La␣ecuaci´n␣no␣tiene␣soluci´n.’ o o else: print ’La␣ecuaci´n␣tiene␣infinitas␣soluciones.’ o except ValueError: print ’No␣hay␣soluciones␣reales’ 4.4. 4.4.1. Algunos ejemplos gr´ficos a Un graficador de funciones Nuestro objetivo ahora es utilizar las funciones gr´ficas predefinidas para representar la a funci´n seno entre −2π y 2π. Vamos a empezar definiendo el nuevo sistema de coordenao das con una llamada a window_coordinates(x1, y1, x2, y2). Est´ claro que x1 valdr´ a a −2π y x2 valdr´ 2π. ¿Qu´ valores tomar´n y1 e y2? La funci´n seno toma valores entre a e a o −1 y 1, as´ que esos son los valores que asignaremos a y1 e y2, respectivamente. ı Recuerda que, en el sistema de coordenadas del lienzo, la esquina inferior izquierda es el punto (0, 0) y la esquina superior derecha es el punto (1000, 1000). Si dibujamos directamente valores de la funci´n seno, no apreciaremos el aspecto ondulado que eso peramos: el valor m´ximo del seno es 1, que sobre 1000 es un valor muy peque˜o, y el a n valor m´ ınimo es −1, que ni siquiera se mostrar´ en pantalla. Hay una funci´n predefinida a o que nos permite cambiar el sistema de coordenadas, window_coordinates, y otra que nos permite cambiar el tama˜o del lienzo, window_size. n window_coordinates(x1, y1, x2, y2): Cambia el sistema de coordenadas del lienzo. La esquina inferior izquierda pasa a tener coordenadas (x1, y1) y la esquina superior derecha pasa a tener coordenadas (x2, y2). Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 135 135 c UJI Introducción a la programación con Python - UJI
    • window_size(x, y): Cambia el tama˜o del lienzo, que pasa a tener una anchura n de x p´ ıxels y una altura de y p´ ıxels. Empezaremos ajustando las dimensiones del lienzo, su sistema de coordenadas y dibujando algunos puntos de la funci´n seno: o seno.py seno 6.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 from math import pi, sin window_size (500, 500) window_coordinates(-2*pi, -1.5, 2*pi, 1.5) create_point(-2*pi, sin(-2*pi)) create_point(-1.5*pi, sin(-1.5*pi)) create_point(-pi, sin(-pi)) create_point(-0.5*pi, sin(-0.5*pi)) create_point(0, sin(0)) create_point(0.5*pi, sin(0.5*pi)) create_point(pi, sin(pi)) create_point(1.5*pi, sin(1.5*pi)) create_point(2*pi, sin(2*pi)) Figura 4.4: Primeras pruebas de dibujo con la funci´n seno. o La figura 4.4 muestra el resultado que aparece en pantalla. Vamos bien. Aparecen pocos puntos, pero podemos apreciar que est´n dispuestos como corresponde a la funci´n a o seno. La cosa mejorar´ a˜adiendo m´s puntos, pero desde luego que no lo haremos ıa n a repitiendo l´ ıneas en el programa como en el ejemplo: usaremos un bucle while. La idea es hacer que una variable x vaya recorriendo, paso a paso, el intervalo [−2π, 2π], y para cada valor, llamar a create_point(x, sin(x)). ¿Qu´ queremos decir con e ˂˂paso a paso˃˃? Pues que de una iteraci´n a la siguiente, aumentaremos x en una cantidad o fija. Pongamos, inicialmente, que esta cantidad es 0.05. Nuestro programa presentar´ este a aspecto Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 136 136 Introducción a la programación con Python - cUJI UJI
    • seno.py 1 2 3 4 5 6 7 8 9 from math import pi, sin window_size (500, 500) window_coordinates(-2*pi, -1.5, 2*pi, 1.5) x = valor inicial while condici´n : o create_point(x, sin(x)) x += 0.05 ¿Qu´ valor inicial asignamos a x? Podemos probar con −2π, que es la coordenada X del e primer punto que nos interesa mostrar. ¿Y qu´ condici´n ponemos en el while? A ver, nos e o interesa repetir mientras x sea menor que 2π. Pues ya est´: a seno.py seno 7.py 1 2 3 4 5 6 7 8 9 from math import pi, sin window_size (500, 500) window_coordinates(-2*pi, -1.5, 2*pi, 1.5) x = -2*pi while x <= 2*pi : create_point(x, sin(x)) x += 0.05 Figura 4.5: La funci´n seno trazada con varios puntos. o La figura 4.5 muestra el resultado de ejecutar el programa. Esto ya es otra cosa. A´n as´ u ı, nos gustar´ mostrar m´s puntos. Ahora el cambio que debemos efectuar es muy sencillo: ıa a en lugar de poner un incremento de 0.05, podemos poner un incremento m´s peque˜o. a n Cuanto menor sea el incremento, m´s puntos dibujaremos. ¿Y si deseamos que aparezcan a exactamente 1000 puntos? Muy sencillo: podemos calcular el incremento dividiendo entre 1000 el dominio de la funci´n: o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 137 137 Introducción a la programación con Python - cUJI UJI
    • seno.py seno 8.py 1 2 3 4 5 6 7 8 9 10 11 from math import pi, sin window_size (500, 500) window_coordinates(-2*pi, -1.5, 2*pi, 1.5) incremento = (2*pi - -2*pi) / 1000 x = -2*pi while x <= 2*pi : create_point(x, sin(x)) x += incremento Figura 4.6: La funci´n seno trazada con 1000 puntos. o Hagamos que el usuario pueda introducir el intervalo de valores de x que desea examinar, as´ como el n´mero de puntos que desee representar: ı u seno 9.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 seno.py from math import pi, sin x1 = float(raw_input(’Dime␣el␣l´mite␣inferior␣del␣intervalo:␣’)) ı x2 = float(raw_input(’Dime␣el␣l´mite␣superior␣del␣intervalo:␣’)) ı puntos = int(raw_input(’Dime␣cu´ntos␣puntos␣he␣de␣mostrar:␣’)) a window_size(500, 500) window_coordinates(x1, -1.5, x2, 1.5) incremento = (x2 - x1) / puntos x = x1 while x <= x2: create_point(x, sin(x)) Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 138 138 Introducción a la programación con Python - cUJI UJI
    • 15 x += incremento Haz varias pruebas con el programa. Los dibujos punto a punto no parecen formar una gr´fica cont´ a ınua a menos que usemos un n´mero muy elevado de puntos. ¿Y si en u lugar de puntos aislados mostramos las l´ ıneas que los unen? Estudia este otro programa, a ver si averiguas qu´ hace y c´mo: e o seno 10.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 seno.py from math import pi, sin x1 = float(raw_input(’Dime␣el␣l´mite␣inferior␣del␣intervalo:␣’)) ı x2 = float(raw_input(’Dime␣el␣l´mite␣superior␣del␣intervalo:␣’)) ı puntos = int(raw_input(’Dime␣cu´ntos␣puntos␣he␣de␣mostrar:␣’)) a window_size(500, 500) window_coordinates(x1, -1.5, x2, 1.5) incremento = (x2 - x1) / puntos x = x1 while x <= x2 - incremento: create_line(x, sin(x), x+incremento, sin(x+incremento)) x += incremento Prueba el programa con diferentes valores. F´ ıjate en qu´ programa tan util hemos e ´ construido con muy pocos elementos: variables, bucles, el m´dulo math y unas pocas o funciones predefinidas para trabajar con gr´ficos. a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 137 Haz un programa que muestre la funci´n coseno en el intervalo que te indique o el usuario. · 138 Modifica el programa anterior para que se muestren dos funciones a la vez: la funci´n seno y la funci´n coseno, pero cada una en un color distinto. o o · 139 Haz un programa que muestre la funci´n 1/(x + 1) en el intervalo [−2, 2] con 100 o puntos azules. Ten en cuenta que la funci´n es ˂˂problem´tica˃˃ en x = −1, por lo que o a dibujaremos un punto rojo en las coordenadas (−1, 0). · 140 Haz un programa que, dados tres valores a, b y c, muestre la funci´n f (x) = o 2 + bx + c en el intervalo [z , z ], donde z y z son valores proporcionados por el ax 1 2 1 2 usuario. El programa de dibujo debe calcular el valor m´ximo y m´ a ınimo de f (x) en el intervalo indicado para ajustar el valor de window_coordinates de modo que la funci´n o se muestre sin recorte alguno. · 141 A˜ade a la gr´fica del ejercicio anterior una representaci´n de los ejes coorden a o nados en color azul. Dibuja con c´ ırculos rojos los puntos en los que la par´bola f (x) corta a el eje horizontal. Recuerda que la par´bola corta al eje horizontal en los puntos x1 y x2 a que son soluci´n de la ecuaci´n de segundo grado ax 2 + bx + c = 0. o o .................................................................................. 4.4.2. Una animaci´n: simulaci´n gravitacional o o Vamos a construir ahora un peque˜o programa de simulaci´n gravitacional. Representaren o mos en pantalla dos cuerpos y veremos qu´ movimiento presentan bajo la influencia mutua e de la gravedad en un universo bidimensional. Nos har´ falta repasar algunas nociones a b´sicas de f´ a ısica. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 139 139 Introducción a la programación con Python - UJIUJI c
    • La ley de gravitaci´n general de Newton nos dice que dos cuerpos de masas m1 y o m2 se atraen con una fuerza m1 m2 F =G 2 , r donde G es la constante de gravitaci´n universal y r es la distancia que separa a los o cuerpos. Sometido a esa fuerza, cada cuerpo experimenta una aceleraci´n. Recuerda que o la aceleraci´n a experimentada por un cuerpo de masa m sometido a una fuerza F es o a = F /m. Cada cuerpo experimentar´ una aceleraci´n distinta: a o m2 , r2 m1 = G 2. r a1 = G a2 Como los cuerpos ocupan las posiciones (x1 , y1 ) y (x2 , y2 ) en el plano, podemos dar una formulaci´n vectorial de las f´rmulas anteriores: o o m2 r12 , r3 m1 r21 = G 3 , r a1 = G a2 donde los s´ ımbolos en negrita son vectores. y2 r12 y 1 m1 x1 m2 r21 x2 En particular, r12 es el vector (x2 − x1 , y2 − y1 ) y r21 es el vector (x1 − x2 , y1 − y2 ). El valor de r, su m´dulo, es o (x2 − x1 )2 + (y2 − y1 )2 . La aceleraci´n afecta en cada instante de tiempo a la velocidad de cada cuerpo. Si un o cuerpo se desplaza en un instante dado a una velocidad (vx , vy ), una unidad de tiempo m´s a tarde se desplazar´ a velocidad (vx +ax , vy +ay ), siendo (ax , ay ) su vector de aceleraci´n. a o El vector de aceleraci´n del primer cuerpo es proporcional a r12 , y el del segundo cuerpo o es proporcional a r21 . Ya basta de f´ ısica. Volvamos al mundo de PythonG. Para abordar nuestra tarea hemos de aprender un par de nuevas funciones y alguna t´cnica que a´n no hemos estudiado. e u Representaremos cada cuerpo con un c´ ırculo cuyo radio es proporcional a su masa. La funci´n create_circle acepta como par´metros las coordenadas del centro de una o a circunferencia, su radio y, opcionalmente, el color. ¿Con qu´ datos modelamos cada cuerpo? Una variable almacenar´ la masa de cada e a cuerpo, eso est´ claro. Llamemos a esas variables m1 y m2. En cada instante, cada cuerpo a ocupa una posici´n en el plano. Cada posici´n se representa con dos valores: la posici´n o o o en el eje X y la posici´n en el eje Y . Las variables x1 e y1 almacenar´n la posici´n del o a o primer cuerpo y las variables x2 e y2 las del segundo. Otro dato importante es la velocidad que cada cuerpo lleva en un instante dado. La velocidad es un vector, as´ que necesitamos ı dos variables para representarla. Las variables velocidad_x1 y velocidad_y1 almacenar´n a el vector de velocidad del primer cuerpo y las variables velocidad_x2 y velocidad_y2 el del segundo. Tambi´n la aceleraci´n de cada cuerpo requiere dos variables y para e o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 140 140 Introducción a la programación con Python - cUJI UJI
    • representarla seguiremos el mismo patr´n, s´lo que las variables empezar´n con el prefijo o o a aceleracion. Inicialmente cada cuerpo ocupa una posici´n y lleva una velocidad determinada. Nueso tro programa puede empezar, de momento, as´ ı: gravedad.py 1 2 3 4 5 6 7 8 9 10 11 x1 = -200 y1 = -200 velocidad_x1 = 0.1 velocidad_y1 = 0 m1 = 20 x2 = 200 y2 = 200 velocidad_x2 = -0.1 velocidad_y2 = 0 m2 = 20 Los c´lculos que nos permiten actualizar los valores de posici´n y velocidad de cada a o cuerpo son, de acuerdo con las nociones de f´ ısica que hemos repasado, estos: gravedad.py 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 r = sqrt( (x2-x1)**2 + (y2-y1)**2 ) aceleracion_x1 = m2 * (x2 - x1) / r**3 aceleracion_y1 = m2 * (y2 - y1) / r**3 aceleracion_x2 = m1 * (x1 - x2) / r**3 aceleracion_y2 = m1 * (y1 - y2) / r**3 velocidad_x1 += aceleracion_x1 velocidad_y1 += aceleracion_y1 velocidad_x2 += aceleracion_x2 velocidad_y2 += aceleracion_y2 x1 += velocidad_x1 y1 += velocidad_y1 x2 += velocidad_x2 y2 += velocidad_y2 Advertir´s que no hemos usado la constante de gravitaci´n G. Como afecta linealmente a a o la f´rmula, su unico efecto pr´ctico es ˂˂acelerar˃˃ la simulaci´n, as´ que hemos decidido o a o ı ´ prescindir de ella. Mostraremos los cuerpos con sendas llamadas a create_circle: gravedad.py 30 31 create_circle(x1, y1, m1, ’red’) create_circle(x2, y2, m2, ’blue’) Si queremos ver c´mo evolucionan los cuerpos a lo largo del tiempo, deberemos repetir o este c´lculo numerosas veces, as´ que formar´ parte de un bucle. Para ver qu´ ocurre a a ı a e lo largo de 10000 unidades de tiempo, por ejemplo, insertaremos esa serie de acciones en un bucle al final del cual se redibujan los dos cuerpos: gravedad 6.py 1 2 3 4 5 gravedad.py from math import sqrt window_coordinates(-500,-500, 500,500) # Puedes cambiar estos valores para hacer zoom x1 = -200 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 141 141 Introducción a la programación con Python - cUJI UJI
    • 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 y1 = -200 velocidad_x1 = 0.1 velocidad_y1 = 0 m1 = 20 x2 = 200 y2 = 200 velocidad_x2 = -0.1 velocidad_y2 = 0 m2 = 20 for t in range(10000): r = sqrt( (x2-x1)**2 + (y2-y1)**2 ) aceleracion_x1 = m2 * (x2 - x1) / r**3 aceleracion_y1 = m2 * (y2 - y1) / r**3 aceleracion_x2 = m1 * (x1 - x2) / r**3 aceleracion_y2 = m1 * (y1 - y2) / r**3 velocidad_x1 += aceleracion_x1 velocidad_y1 += aceleracion_y1 velocidad_x2 += aceleracion_x2 velocidad_y2 += aceleracion_y2 x1 += velocidad_x1 y1 += velocidad_y1 x2 += velocidad_x2 y2 += velocidad_y2 create_circle(x1, y1, m1, ’red’) create_circle(x2, y2, m2, ’blue’) Y ya est´: ejecutemos el programa en el entorno PythonG. He aqu´ el resultado final a ı (en pantalla aparecer´ como una animaci´n): a o Como puedes observar, no apreciamos ya la posici´n de los cuerpos: se han dibujado o tantos c´ ırculos que unos tapan a otros. Deber´ ıamos haber desplazado cada c´ ırculo en lugar de ir a˜adiendo un c´ n ırculo tras otro. Lamentablemente, no sabemos (a´n) de ninguna u funci´n que permita desplazar un c´ o ırculo. S´ disponemos, no obstante, de la posibilidad ı de borrar un c´ ırculo existente. Si borramos cada c´ ırculo antes de dibujar el siguiente, conseguiremos el mismo efecto que si desplaz´semos un solo c´ a ırculo. Esa es la primera t´cnica que usaremos para efectuar la animaci´n. e o ¿C´mo borramos un c´ o ırculo? Mediante la funci´n predefinida erase. Esa funci´n no o o s´lo borra c´ o ırculos: borra cualquier objeto creado con una funci´n predefinida que empieza o por create_ . Para ello, hemos de asociar una variable al objeto creado cuando invocamos a una funci´n create_ . He aqu´ un ejemplo de uso: o ı 1 2 c = create_circle(0, 0, 100, ’yellow’) erase(c) Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 142 142 Introducción a la programación con Python - cUJI UJI
    • Ya est´ claro c´mo actuar: a o gravedad 7.py 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 29 30 31 32 33 34 35 36 37 38 39 40 gravedad.py from math import sqrt window_coordinates(-500, -500, 500, 500) x1 = -200 y1 = -200 velocidad_x1 = 0.1 velocidad_y1 = 0 m1 = 20 x2 = 200 y2 = 200 velocidad_x2 = -0.1 velocidad_y2 = 0 m2 = 20 circulo_ 1 = create_circle(x1, y1, m1, ’red’) circulo_ 2 = create_circle(x2, y2, m2, ’blue’) for t in range(10000): r = sqrt( (x2-x1)**2 + (y2-y1)**2 ) aceleracion_x1 = m2 * (x2 - x1) / r**3 aceleracion_y1 = m2 * (y2 - y1) / r**3 aceleracion_x2 = m1 * (x1 - x2) / r**3 aceleracion_y2 = m1 * (y1 - y2) / r**3 velocidad_x1 += aceleracion_x1 velocidad_y1 += aceleracion_y1 velocidad_x2 += aceleracion_x2 velocidad_y2 += aceleracion_y2 x1 += velocidad_x1 y1 += velocidad_y1 x2 += velocidad_x2 y2 += velocidad_y2 erase(circulo_ 1) circulo_ 1 = create_circle(x1, y1, m1, ’red’) erase(circulo_ 2) circulo_ 2 = create_circle(x2, y2, m2, ’blue’) Si ejecutas ahora el programa ver´s c´mo la r´pida creaci´n y destrucci´n del c´ a o a o o ırculo provocan la ilusi´n de un desplazamiento. Pero hay un problema: aparece un molesto o parpadeo. Al destruir y crear r´pidamente los objetos, hay breves instantes en los que, a sencillamente, no est´n en pantalla. Esta desaparici´n y aparici´n continuadas se traa o o ducen en un p´simo efecto. Una soluci´n posible consiste en invertir el orden: en lugar e o de destruir y crear, crear y destruir. Ello supone que, en algunos instantes, haya dos copias del mismo objeto en pantalla (ligeramente desplazadas). El efecto conseguido no obstante, es agradable. Hay una funci´n adicional especialmente pensada para animaciones: move. La funci´n o o move recibe tres par´metros: un objeto creado con una funci´n create_ y dos valores dx a o e dy . Si el objeto se encuentra en el punto (x, y), el efecto de move es desplazar el objeto al punto (x + dx , y + dy ). gravedad 8.py Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o gravedad.py 143 143 Introducción a la programación con Python - cUJI UJI
    • 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 29 30 31 32 33 34 35 36 37 38 39 40 from math import sqrt window_coordinates(-500, -500, 500, 500) x1 = -200 y1 = -200 velocidad_x1 = 0.1 velocidad_y1 = 0 m1 = 20 x2 = 200 y2 = 200 velocidad_x2 = -0.1 velocidad_y2 = 0 m2 = 20 circulo_ 1 = create_circle(x1, y1, m1, ’red’) circulo_ 2 = create_circle(x2, y2, m2, ’blue’) for t in range(10000): r3 = sqrt( (x2-x1)**2 + (y2-y1)**2 ) ** 3 aceleracion_x1 = m2 * (x2 - x1) / r3 aceleracion_y1 = m2 * (y2 - y1) / r3 aceleracion_x2 = m1 * (x1 - x2) / r3 aceleracion_y2 = m1 * (y1 - y2) / r3 velocidad_x1 += aceleracion_x1 velocidad_y1 += aceleracion_y1 velocidad_x2 += aceleracion_x2 velocidad_y2 += aceleracion_y2 x1 += velocidad_x1 y1 += velocidad_y1 x2 += velocidad_x2 y2 += velocidad_y2 move(circulo_ 1, velocidad_x1, velocidad_y1) move(circulo_ 2, velocidad_x2, velocidad_y2) F´ ıjate en que hemos hecho otro cambio: en lugar de calcular el valor de r y elevarlo al cubo en cuatro ocasiones (una operaci´n costosa), hemos calculado directamente el valor o del cubo de r. Nos gustar´ ahora que los cuerpos dejasen una ˂˂traza˃˃ de los lugares por los que ıa han pasado, pues as´ resultar´ m´s f´cil apreciar las ´rbitas que describen. Estudia este ı a a a o otro programa y averigua c´mo hemos hecho para dejar esa traza: o gravedad 9.py 1 2 3 4 5 6 7 8 9 10 gravedad.py from math import sqrt window_coordinates(-500, -500, 500, 500) x1 = -200 y1 = -200 velocidad_x1 = 0.1 velocidad_y1 = 0 m1 = 20 Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 144 144 Introducción a la programación con Python - cUJI UJI
    • 11 12 13 14 15 16 17 18 19 20 21 22 x2 = 200 y2 = 200 velocidad_x2 = -0.1 velocidad_y2 = 0 m2 = 20 circulo_ 1 = create_circle(x1, y1, m1, ’red’) circulo_ 2 = create_circle(x2, y2, m2, ’blue’) for t in range(10000): r3 = sqrt( (x2-x1)**2 + (y2-y1)**2 ) ** 3 23 aceleracion_x1 = m2 * (x2 - x1) / r3 aceleracion_y1 = m2 * (y2 - y1) / r3 aceleracion_x2 = m1 * (x1 - x2) / r3 aceleracion_y2 = m1 * (y1 - y2) / r3 24 25 26 27 28 velocidad_x1 += aceleracion_x1 velocidad_y1 += aceleracion_y1 velocidad_x2 += aceleracion_x2 velocidad_y2 += aceleracion_y2 29 30 31 32 33 viejo_x1 = x1 viejo_y1 = y1 viejo_x2 = x2 viejo_y2 = y2 34 35 36 37 38 x1 += velocidad_x1 y1 += velocidad_y1 x2 += velocidad_x2 y2 += velocidad_y2 39 40 41 42 43 move(circulo_ 1, velocidad_x1, velocidad_y1) create_line(viejo_x1, viejo_y1, x1, y1, ’red’) move(circulo_ 2, velocidad_x2, velocidad_y2) create_line(viejo_x2, viejo_y2, x2, y2, ’blue’) 44 45 46 47 Esta imagen se ha obtenido cuando el programa iba por la iteraci´n 5000: o a) Divi´rtete con el programa. He aqu´ algunas configuraciones iniciales interesantes: e ı 1 2 3 4 5 6 7 8 x1 = -200 y1 = -200 velocidad_x1 = 0.1 velocidad_y1 = 0 m1 = 0.001 x2 = 200 y2 = 200 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 145 145 Introducción a la programación con Python - cUJI UJI
    • 9 10 11 b) 1 2 3 4 5 6 7 8 9 10 11 velocidad_x2 = 0 velocidad_y2 = 0 m2 = 20 x1 = -200 y1 = -200 velocidad_x1 = -0.1 velocidad_y1 = 0 m1 = 20 x2 = 200 y2 = 200 velocidad_x2 = -0.1 velocidad_y2 = 0 m2 = 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 142 ¿Qu´ pasar´ si los dos cuerpos ocuparan exactamente la misma posici´n en el e ıa o plano? Modifica el programa para que, si se da el caso, no se produzca error alguno y finalice inmediatamente la ejecuci´n del bucle. o · 143 Modifica el programa para que la simulaci´n no finalice nunca (bueno, s´lo o o cuando el usuario interrumpa la ejecuci´n del programa). o · 144 ¿Ser´ capaz de extender el programa para que muestre la interacci´n entre ıas o tres cuerpos? Repasa la formulaci´n f´ o ısica del problema antes de empezar a programar. .................................................................................. 4.4.3. Un programa interactivo: un videojuego Ya sabemos dibujar gr´ficas y mostrar sencillas animaciones. Demos el siguiente paso: a hagamos un programa gr´fico interactivo. En este apartado dise˜aremos un videojuego a n muy simple que nos ponga a los mandos de una nave espacial que debe aterrizar en una plataforma m´vil. o La nave aparecer´ en pantalla a cierta altura y, desde el primer instante, empezar´ a a a caer atra´ por la gravedad del planeta. Disponemos de un control muy rudimentario: ıda podemos activar los propulsores de la nave con las teclas de cursor para contrarrestar el efecto de la gravedad, as´ como desplazarnos lateralmente. El desplazamiento lateral ı ser´ necesario para conseguir que la nave aterrice sobre la plataforma, pues ´sta se ir´ a e a trasladando por la superficie del planeta durante el juego. Con cada activaci´n de los propulsores se consumir´ una determinada cantidad de o a fuel. Cuando nos quedemos sin combustible, la nave entrar´ en ca´ libre. Perderemos a ıda la partida si no acertamos a aterrizar en la plataforma o si, al aterrizar, la velocidad de ca´ es excesiva. ıda Planifiquemos el trabajo: 1. Empezaremos por mostrar la nave espacial en pantalla y ˂˂dejarla caer˃˃. As´ aprenı deremos a simular el efecto de la gravedad. 2. A continuaci´n nos encargaremos de controlar el propulsor inferior de la nave, el o que contrarresta el efecto de la gravedad. 3. El siguiente objetivo ser´ permitir el movimiento lateral de la nave. a 4. Iremos entonces a por el dibujo de la plataforma de aterrizaje y su desplazamiento. Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 146 146 Introducción a la programación con Python - UJIUJI c
    • 5. En seguida pasaremos a considerar el consumo de fuel y a mostrar en pantalla algunos datos informativos, como la velocidad de ca´ y el fuel disponible. ıda 6. Para acabar, detectaremos los aterrizajes y valoraremos la actuaci´n del jugador o (si gan´ o perdi´ y, en este ultimo caso, por qu´ motivo). o o e ´ Vamos all´. El mundo en el que trascurre la acci´n ser´ un simple plano con el a o a sistema de coordenadas que decidamos. Como la ventana gr´fica de PythonG tiene una a resoluci´n por defecto de 400 × 400, asumiremos ese sistema de coordenadas. o aterrizaje.py 1 2 3 4 # Paisaje altura_paisaje = 400 anchura_paisaje = 400 window_coordinates(0, 0, anchura_paisaje, altura_paisaje) No estamos para alardes gr´ficos: nuestra nave ser´ un sencillo cuadrado de color a a azul de 10 × 10 p´ ıxels en cierta posici´n (x, y). o aterrizaje.py 1 2 3 4 5 6 ... # Nave tamanyo_nave = 10 x = anchura_paisaje / 2 y = altura_paisaje - 100 create_filled_rectangle(x, y, x+tamanyo_nave, y+tamanyo_nave, ’blue’) Que empiece la acci´n. ¿C´mo efectuamos la simulaci´n de la atracci´n gravitatoria? o o o o No hace falta complicarse tanto la vida como en la secci´n anterior: aqu´ la gravedad o ı siempre tira de la nave hacia abajo. El simulador actuar´ as´ la nave tiene una velocidad a ı: de ca´ y, con cada iteraci´n de la simulaci´n, esta aumenta en cierta cantidad (digamos ıda o o g). La nave ir´ actualizando su posici´n a partir de la posici´n y velocidad de ca´ en a o o ıda cada instante. aterrizaje.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... # Gravedad g=1 # Nave tamanyo_nave = 10 x = anchura_paisaje / 2 y = altura_paisaje - 100 vy = 0 nave = create_filled_rectangle(x, y, x+tamanyo_nave, y+tamanyo_nave, ’blue’) # Simulaci´n o while condici´n : o vy -= g y += vy move(nave, 0, vy) Varias cosas. Por un lado, ¿no hemos dicho que la velocidad de ca´ aumentar´ ıda ıa en cada paso? Pues no estamos sumando el valor de g a la velocidad vertical vy, sino rest´ndolo. No te preocupes: es lo correcto. La velocidad aumenta en valor absoluto, pero a su direcci´n es de ca´ de ah´ que el signo del incremento sea negativo. Por otra parte, o ıda, ı ¿qu´ condici´n determina el final de la simulaci´n? Est´ claro: que la nave toque tierra, e o o a Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 147 147 Introducción a la programación con Python - cUJI UJI
    • es decir, que su altura sea igual o menor que cero. ¿Por qu´ menor que cero? Es posible e que la nave lleve tal velocidad de ca´ que ˂˂aterrice˃˃ formando un hermoso cr´ter. Mejor ıda a estar preparados para esa eventualidad. Aqu´ tienes el programa completo en su estado ı actual. aterrizaje 14.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 aterrizaje.py # Paisaje altura_paisaje = 400 anchura_paisaje = 400 window_coordinates(0, 0, anchura_paisaje, altura_paisaje) # Gravedad g=1 # Nave tamanyo_nave = 10 x = anchura_paisaje / 2 y = altura_paisaje - 100 vy = 0 nave = create_filled_rectangle(x, y, x+tamanyo_nave, y+tamanyo_nave, ’blue’) # Simulaci´n o while y > 0: vy -= g y += vy move(nave, 0, vy) Ejecuta el programa. ¿Qu´ ocurre? La nave aparece directamente en el suelo. En e realidad, ha pasado por varios sitios en su ca´ hasta el suelo, s´lo que lo ha hecho ıda o tan r´pidamente que no hemos podido percibir el desplazamiento. Hemos de modificar a el valor de g para obtener una simulaci´n m´s lenta. Un valor de g razonable en el o a ordenador en el que estamos desarrollando el programa es 0.0001. Encuentra t´ el m´s u a adecuado para tu ordenador. aterrizaje 15.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 aterrizaje.py # Paisaje altura_paisaje = 400 anchura_paisaje = 400 window_coordinates(0, 0, anchura_paisaje, altura_paisaje) # Gravedad g = 0.00001 # Nave tamanyo_nave = 10 x = anchura_paisaje / 2 y = altura_paisaje - 100 vy = 0 nave = create_filled_rectangle(x, y, x+tamanyo_nave, y+tamanyo_nave, ’blue’) # Simulaci´n o while y > 0: vy -= g y += vy move(nave, 0, vy) Es hora de habilitar el control del propulsor vertical. PythonG ofrece una funci´n o predefinida para acceder al teclado: keypressed (en ingl´s significa ˂˂tecla pulsada˃˃). La e puedes llamar de estas dos formas diferentes (entre otras): Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 148 148 Introducción a la programación con Python - cUJI UJI
    • keypressed(1): devuelve None si no hay ninguna tecla pulsada y una cadena que describe la tecla pulsada en caso contrario. None significa ˂˂ausencia de valor˃˃ y es equivalente al valor l´gico falso. o keypressed(2): espera a que el usuario pulse una tecla y devuelve entonces una cadena que la describe. Nos interesa detectar la pulsaci´n de la tecla de cursor hacia arriba. La cadena que o la describe es ’Up’. Su efecto es sumar cierta cantidad, a la que llamaremos impulso_y, a la velocidad de ca´ ıda. ¿Qu´ cantidad sumar? Si es g, mal: como mucho podremos e contrarrestar el efecto gravitatorio, pero no podremos moderar la velocidad de ca´ ıda. Pongamos que impulso_y es dos veces g. aterrizaje 16.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 aterrizaje.py # Paisaje altura_paisaje = 400 anchura_paisaje = 400 window_coordinates(0, 0, anchura_paisaje, altura_paisaje) # Gravedad g = 0.00001 # Nave tamanyo_nave = 10 x = anchura_paisaje / 2 y = altura_paisaje - 100 vy = 0 impulso_y = 2*g nave = create_filled_rectangle(x, y, x+tamanyo_nave, y+tamanyo_nave, ’blue’) # Simulaci´n o while y > 0: vy -= g if keypressed(1) == ’Up’: vy += impulso_y y += vy move(nave, 0, vy) Prueba ahora el juego. Frena la nave manteniendo pulsada la tecla ’Up’. No te pases: ¡puede que la nave desaparezca por el extremo superior de la imagen! Mmmm. Eso no parece bueno. ¿Qu´ hacer si la nave se sale por encima? No hab´ e ıamos contemplado esa eventualidad en la especificaci´n del juego. Improvisemos una soluci´n: haremos que el o o juego termine tambi´n en ese caso y, adem´s, lo consideraremos un fracaso del jugador. e a aterrizaje 17.py 1 aterrizaje.py # Paisaje . . . 17 18 19 20 21 22 23 24 # Simulaci´n o while y > 0 and y < altura_paisaje : vy -= g if keypressed(1) == ’Up’: vy += impulso_y y += vy move(nave, 0, vy) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 149 149 Introducción a la programación con Python - cUJI UJI
    • Siguiendo nuestro plan de trabajo hemos de ocuparnos ahora del desplazamiento lateral de la nave. Para conseguir un efecto ˂˂realista˃˃ dotaremos a dicho movimiento de inercia. Es decir, la nave llevar´ una velocidad horizontal que s´lo se modificar´ cuando a o a actuemos sobre los propulsores laterales. El propulsor izquierdo se activar´ con la tecla a de cursor a izquierdas (’Left’) y el propulsor derecho con la tecla de cursor a derechas (’Right’). Y ahora que dotamos de desplazamiento lateral a la nave, el jugador puede chocar con las ˂˂paredes˃˃. Consideraremos tambi´n que chocar contra las ˂˂paredes˃˃ es e un fracaso del jugador. aterrizaje 18.py 1 aterrizaje.py # Paisaje . . . 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 impulso_x = 0.00001 vx = 0 nave = create_filled_rectangle(x, y, x+tamanyo_nave, y+tamanyo_nave, ’blue’) # Simulaci´n o while y > 0 and y < altura_paisaje and x > 0 and x < anchura_paisaje - tamanyo_nave : vy -= g if keypressed(1) == ’Up’: vy += impulso_y elif keypressed(1) == ’Left’: vx -= impulso_x elif keypressed(1) == ’Right’: vx += impulso_x y += vy x += vx move(nave, vx, vy) El valor de impulso_x se ha escogido para obtener un buen comportamiento de la nave en nuestro ordenador. Tendr´s que encontrar un valor adecuado para tu m´quina. a a A por la plataforma de aterrizaje. La plataforma se representar´ con un rect´ngulo de a a color diferente, pongamos rojo. ¿D´nde dibujarla? Empezaremos ubic´ndola en la zona o a central: aterrizaje 19.py 1 aterrizaje.py # Paisaje . . . 18 19 20 21 22 23 24 25 26 27 28 29 # Plataforma px = anchura_paisaje / 2 py = 0 anchura_plataforma = 40 altura_plataforma = 3 plataforma = create_rectangle(px, py, px+anchura_plataforma, py+altura_plataforma, ’red’) # Simulaci´n o while y > 0 and y < altura_paisaje and x > 0 and x < anchura_paisaje - tamanyo_nave: . . . Perfecto. Dijimos que la plataforma se desplazar´ lateralmente. El juego a˜adir´ una ıa n a cantidad vpx (por ˂˂velocidad de plataforma en el eje X ˃˃) al valor de px con cada paso y Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 150 150 Introducción a la programación con Python - cUJI UJI
    • actualizar´ su imagen en pantalla. Cuando llegue a un extremo de la imagen, cambiar´ a a de direcci´n. o aterrizaje 20.py 1 aterrizaje.py # Paisaje . . . 18 19 20 21 22 23 24 25 26 27 28 29 30 # Plataforma px = anchura_paisaje / 2 py = 0 vpx = .05 anchura_plataforma = 40 altura_plataforma = 3 plataforma = create_rectangle(px, py, px+anchura_plataforma, py+altura_plataforma, ’red’) # Simulaci´n o while y > 0 and y < altura_paisaje and x > 0 and x < anchura_paisaje - tamanyo_nave: . . . 40 41 42 43 44 px += vpx if px <= 0 or px >= anchura_paisaje - anchura_plataforma: vpx = -vpx move(nave, vx, vy) move(plataforma, vpx, 0) (Puede que necesites ajustar el valor de vpx para que la plataforma se desplace a una velocidad razonable en tu ordenador.) ¿Qu´ implementamos ahora? ¡Ah, s´ El consumo e ı! de fuel. Empezaremos con el dep´sito lleno: 1000 litros de fuel. Cada vez que se active o un propulsor consumiremos una cierta cantidad de fuel, digamos 1 litro. aterrizaje 21.py 1 aterrizaje.py # Paisaje . . . 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 # Tanque de combustible fuel = 1000 consumo = 1 # Simulaci´n o while y > 0 and y < altura_paisaje and x > 0 and x < anchura_paisaje - tamanyo_nave: vy -= g if keypressed(1) == ’Up’: vy += impulso_y fuel -= consumo elif keypressed(1) == ’Left’: vx -= impulso_x fuel -= consumo elif keypressed(1) == ’Right’: vx += impulso_x fuel -= consumo . . . 47 48 49 50 51 px += vpx if px <= 0 or px >= anchura_paisaje - anchura_plataforma: vpx = -vpx move(nave, vx, vy) move(plataforma, vpx, 0) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 151 151 Introducción a la programación con Python - cUJI UJI
    • Recuerda que no podemos usar los propulsores cuando no hay fuel: aterrizaje 22.py 1 aterrizaje.py # Paisaje . . . 34 35 36 37 38 39 40 41 42 43 44 while y > 0 and y < altura_paisaje and x > 0 and x < anchura_paisaje - tamanyo_nave: vy -= g if keypressed(1) == ’Up’ and fuel > 0: vy += impulso_y fuel -= consumo elif keypressed(1) == ’Left’ and fuel > 0 : vx -= impulso_x fuel -= consumo elif keypressed(1) == ’Right’ and fuel > 0: vx += impulso_x fuel -= consumo . . . El simulador debe mostrar en pantalla la cantidad de fuel disponible. Vamos a mostrarlo con una representaci´n del tanque de combustible y la proporci´n de fuel con o o respecto a su capacidad. aterrizaje 23.py 1 aterrizaje.py # Paisaje . . . 30 31 32 33 34 35 36 fuel = 1000 consumo = 1 create_rectangle(0,altura_paisaje, 10, altura_paisaje-100, ’black’) lleno = create_filled_rectangle(1,altura_paisaje, 9, altura_paisaje-fuel/10, ’green’) # Simulaci´n o while y > 0 and y < altura_paisaje and x > 0 and x < anchura_paisaje - tamanyo_nave: . . . 53 54 55 56 move(plataforma, vpx, 0) viejo_lleno = lleno lleno = create_filled_rectangle(1,altura_paisaje, 9, altura_paisaje-fuel/10, ’green’) erase(viejo_lleno) Mmmm. Parece que nuestra nave consume demasiado: el dep´sito se vac´ con apenas o ıa activar un propulsor. Hemos de ajustar, pues, el consumo. En nuestro programa lo hemos ajustado a un valor de 0.1. Tambi´n interesa mostrar la velocidad de ca´ Dibujaremos un dial con la velocidad e ıda. y una aguja que nos indique la velocidad actual. Estudia el fragmento de programa que te presentamos a continuaci´n: o aterrizaje 24.py 1 2 aterrizaje.py from math import sin, cos, pi # Paisaje . . . 35 36 37 38 39 # Dial de velocidad create_circle(anchura_paisaje-50, altura_paisaje-50, 50, ’black’) for i in range(0, 360, 10): create_line(anchura_paisaje-50 + 40 * sin(i*pi/180), Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 152 152 Introducción a la programación con Python - cUJI UJI
    • altura_paisaje-50 + 40 * cos(i*pi/180), anchura_paisaje-50 + 50 * sin(i*pi/180), altura_paisaje-50 + 50 * cos(i*pi/180)) 40 41 42 43 44 45 46 aguja = create_line(anchura_paisaje-50, altura_paisaje-50, anchura_paisaje-50 + 50 * sin(0*pi/180), altura_paisaje-50 + 50 * cos(0*pi/180), ’blue’) . . . 70 71 72 73 74 vieja_aguja = aguja aguja = create_line(anchura_paisaje-50, altura_paisaje-50, anchura_paisaje-50 + 50 * sin(1000*vy*pi/180), altura_paisaje-50 + 50 * cos(1000*vy*pi/180), ’blue’) erase(vieja_aguja) Una cuesti´n est´tica. Nos vendr´ bien poner alg´n texto en pantalla para rotular o e ıa u el dep´sito o el veloc´ o ımetro. Recuerda que PythonG te ofrece la funci´n predefinida o create_text para dibujar texto. aterrizaje.py aterrizaje 25.py 1 2 from math import sin, cos, pi # Paisaje . . . 35 36 37 38 39 40 41 42 43 44 45 46 create_text(25, altura_paisaje-8, ’0%’, 10, ’W’) create_text(30, altura_paisaje-95, ’100%’, 10, ’W’) # Dial de velocidad create_circle(anchura_paisaje-50, altura_paisaje-50, 50, ’black’) for i in range(0, 360, 10): create_line(anchura_paisaje-50 + 40 * sin(i*pi/180), altura_paisaje-50 + 40 * cos(i*pi/180), anchura_paisaje-50 + 50 * sin(i*pi/180), altura_paisaje-50 + 50 * cos(i*pi/180)) if i % 30 == 0: create_text(anchura_paisaje-50 + 30 * sin(i*pi/180), altura_paisaje-50 + 30 * cos(i*pi/180), str(i), 5, ’CENTER’) 47 48 49 50 51 52 aguja = create_line(anchura_paisaje-50, altura_paisaje-50, anchura_paisaje-50 + 50 * sin(0*pi/180), altura_paisaje-50 + 50 * cos(0*pi/180), ’blue’) . . . 76 77 78 79 80 vieja_aguja = aguja aguja = create_line(anchura_paisaje-50, altura_paisaje-50, anchura_paisaje-50 + 50 * sin(1000*vy*pi/180), altura_paisaje-50 + 50 * cos(1000*vy*pi/180), ’blue’) erase(vieja_aguja) Y aqu´ tienes una imagen del aspecto actual de nuestro simulador: ı Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 153 153 Introducción a la programación con Python - cUJI UJI
    • Ya estamos cerca del final. Nos queda determinar si el jugador gan´ o perdi´ la o o partida e informarle del resultado. Las ultimas l´ ıneas del programa, que te mostramos ´ ahora completo, se encargan de ello: aterrizaje 26.py 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 29 30 31 32 33 34 35 36 37 aterrizaje.py from math import sin, cos, pi # Paisaje altura_paisaje = 400 anchura_paisaje = 400 window_coordinates(0, 0, anchura_paisaje, altura_paisaje) # Gravedad g = 0.00001 # Nave tamanyo_nave = 10 x = anchura_paisaje / 2 y = altura_paisaje - 100 vy = 0 impulso_y = 2*g impulso_x = 0.00001 vx = 0 nave = create_filled_rectangle(x, y, x+tamanyo_nave, y+tamanyo_nave, ’blue’) # Plataforma px = anchura_paisaje / 2 py = 0 vpx = .05 anchura_plataforma = 40 altura_plataforma = 3 plataforma = create_rectangle(px, py, px+anchura_plataforma, py+altura_plataforma, ’red’) # Tanque de combustible fuel = 1000 consumo = 0.1 create_rectangle(0,altura_paisaje, 10, altura_paisaje-100, ’black’) lleno = create_filled_rectangle(1,altura_paisaje, 9, altura_paisaje-fuel/10, ’green’) create_text(25, altura_paisaje-8, ’0%’, 10, ’W’) create_text(30, altura_paisaje-95, ’100%’, 10, ’W’) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 154 154 Introducción a la programación con Python - cUJI UJI
    • 40 41 42 43 44 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 # Dial de velocidad create_circle(anchura_paisaje-50, altura_paisaje-50, 50, ’black’) for i in range(0, 360, 10): create_line(anchura_paisaje-50 + 40 * sin(i*pi/180), altura_paisaje-50 + 40 * cos(i*pi/180), anchura_paisaje-50 + 50 * sin(i*pi/180), altura_paisaje-50 + 50 * cos(i*pi/180)) if i % 30 == 0: create_text(anchura_paisaje-50 + 30 * sin(i*pi/180), altura_paisaje-50 + 30 * cos(i*pi/180), str(i), 5, ’CENTER’) aguja = create_line(anchura_paisaje-50, altura_paisaje-50, anchura_paisaje-50 + 50 * sin(0*pi/180), altura_paisaje-50 + 50 * cos(0*pi/180), ’blue’) # Simulaci´n o while y > 0 and y < altura_paisaje and x > 0 and x < anchura_paisaje - tamanyo_nave: vy -= g if keypressed(1) == ’Up’ and fuel > 0: vy += impulso_y fuel -= consumo elif keypressed(1) == ’Left’ and fuel > 0: vx -= impulso_x fuel -= consumo elif keypressed(1) == ’Right’ and fuel > 0: vx += impulso_x fuel -= consumo y += vy x += vx px += vpx if px <= 0 or px >= anchura_paisaje - anchura_plataforma: vpx = -vpx move(nave, vx, vy) move(plataforma, vpx, 0) viejo_lleno = lleno lleno = create_filled_rectangle(1,altura_paisaje, 9, altura_paisaje-fuel/10, ’green’) erase(viejo_lleno) vieja_aguja = aguja aguja = create_line(anchura_paisaje-50, altura_paisaje-50, anchura_paisaje-50 + 50 * sin(1000*vy*pi/180), altura_paisaje-50 + 50 * cos(1000*vy*pi/180), ’blue’) erase(vieja_aguja) msg_x = anchura_paisaje/2 msg_y1 = altura_paisaje/2 msg_y2 = altura_paisaje/3 if y >= altura_paisaje: create_text(msg_x, msg_y1, ’Perdiste’, 24, ’CENTER’) create_text(msg_x, msg_y2, ’ Rumbo␣a␣las␣estrellas?’, 12, ’CENTER’) elif y <= 0 and vy < -0.1: create_text(msg_x, msg_y1, ’Perdiste’, 24, ’CENTER’) create_text(msg_x, msg_y2, ’Te␣has␣estrellado.’, 12, ’CENTER’) elif y <= 0 and abs((px+anchura_plataforma/2)-(x+tamanyo_nave/2)) >= anchura_plataforma/2: create_text(msg_x, msg_y1, ’Perdiste’, 24, ’CENTER’) create_text(msg_x, msg_y2, ’ Qu´␣mala␣punter´a!’, 12, ’CENTER’) e ı elif x <= 0 or x >= anchura_paisaje - tamanyo_nave: create_text(msg_x, msg_y1, ’Perdiste’, 24, ’CENTER’) ! 39 ? 38 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 155 155 Introducción a la programación con Python -cUJI UJI
    • 98 99 100 create_text(msg_x, msg_y2, ’Chocaste␣con␣la␣pared.’, 12, ’CENTER’) else: create_text(msg_x, msg_y1, ’Ganaste’, 24, ’CENTER’) create_text(msg_x, msg_y2, ’ Enhorabuena,␣piloto!’, 12, ’CENTER’) ! 97 A disfrutar del juego. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 145 Modifica el juego para que la barra que indica el combustible disponible se ponga de color rojo cuando quede menos del 25%. · 146 Modifica el juego para que el usuario pueda escoger, con un men´, un nivel u de dificultad. Ofrece al menos tres niveles: f´cil, normal y dif´ Puedes modificar la a ıcil. dificultad del juego a voluntad alterando par´metros como el fuel disponible, el consumo, a la fuerza de la gravedad, la velocidad de desplazamiento de la plataforma, etc. · 147 Modifica el juego para que la plataforma no est´ en el suelo, sino flotando. e El usuario debe aterrizar en la plataforma desde arriba, claro est´. Si se golpea a la a plataforma desde abajo, la nave se destruir´ y el jugador habr´ fracasado. a a · 148 A˜ade efectos especiales al juego. Por ejemplo, cambia el color del fondo para que n sea negro y a˜ade unas estrellas. Tambi´n puedes mostrar una l´ n e ıneas amarillas saliendo de la nave cuando se activa alg´n propulsor. Si se acciona el propulsor inferior, la l´ u ıneas saldr´n de debajo de la nave, y si se activa un propulsor lateral, las l´ a ıneas saldr´n del a lado correspondiente. · 149 Modifica el juego para que aparezca un n´mero determinado de meteoritos en u pantalla (tres, por ejemplo). Cada meteorito se representar´ con un c´ a ırculo de color rojo y se ir´ desplazando por la pantalla. Si la nave toca un meteorito, ´sta se destruir´. a e a · 150 Programa un juego de front´n electr´nico. El usuario controlar´ una raqueta en o o a el lado inferior de la pantalla. Con la raqueta podr´ golpear una pelota que rebotar´ en a a las paredes. Si la pelota se sale por el borde inferior de la pantalla, el juego finaliza. · 151 Modifica el juego del front´n para convertirlo en un teletenis. El ordenador o controlar´ una raqueta en el lado superior de la imagen. No permitas que el ordenador a haga trampas, es decir, la velocidad de desplazamiento de la raqueta ha de ser (como mucho) la misma que la del usuario. .................................................................................. 4.5. Una reflexi´n final o En este tema te hemos presentado varias estructuras de control de flujo que, esencialmente, se reducen a dos conceptos: la selecci´n condicional de sentencias y la repetici´n o o condicional de sentencias. En los primeros tiempos de la programaci´n no siempre se utio lizaban estas estructuras: exist´ una sentencia comod´ que permit´ ˂˂saltar˃˃ a cualquier ıa ın ıa punto de un programa: la que se conoce como sentencia goto (en ingl´s, ˂˂ir-a˃˃). e o Observa c´mo se podr´ haber escrito el programa es primo.py (secci´n 4.2.7) en o ıa el lenguaje de programaci´n BASIC, que originariamente carec´ de estructuras como el o ıa bucle while: Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 156 156 Introducción a la programación con Python - UJIUJI c
    • 10 INPUT "DAME UN N´MERO:"; NUM U 20 DIVISOR = 2 30 40 50 60 70 80 90 100 IF INT(NUM / DIVISOR) = NUM / DIVISOR THEN GOTO 90 DIVISOR = DIVISOR + 1 IF DIVISOR = NUM THEN GOTO 70 GOTO 30 PRINT .El n´mero", NUM, .es primo" u GOTO 100 PRINT .El n´mero", NUM, "no es primo" u END Cada l´ ınea del programa est´ numerada y la sentencia GOTO indica en qu´ l´ a e ınea debe continuar la ejecuci´n del programa. Como es posible saltar a cualquier l´ o ınea en funci´n o de la satisfacci´n de una condici´n, es posible ˂˂montar a mano˃˃ cualquier estructura de o o control. Ahora bien, una cosa es que sea posible y otra que el resultado presente un m´ ınimo de elegancia. El programa BASIC del ejemplo es endiabladamente complejo: resulta dif´ ıcil apreciar que las l´ ıneas 30–60 forman un bucle while. Los programas construidos abusando del GOTO recib´ el nombre de ˂˂c´digo spaghetti˃˃, pues al representar con flechas los ıan o posibles saltos del programa se formaba una mara˜a que recuerda a un plato de spaghetti. n En los a˜os 70 hubo una corriente en el campo de la inform´tica que propugnaba la n a supresi´n de la sentencia goto. Edsger W. Dijkstra public´ un influyente art´ o o ıculo titulado ˂˂Goto considered harmful˃˃ (˂˂La sentencia “Goto” considerada da˜ina˃˃) en el que se hac´ n ıa una severa cr´ ıtica al uso de esta sentencia en los programas. Se demostr´ que era posible o construir cualquier programa con s´lo selecciones y repeticiones condicionales y que estos o programas resultaban mucho m´s legibles. La denominada programaci´n estructurada es a o la corriente que propugna (entre otros principios) la programaci´n usando unicamente o ´ estructuras de control (if, while, for-in, . . . ) para alterar el flujo del programa. Al poco tiempo de su aparici´n, la programaci´n estructurada se convirti´ en la metoo o o dolog´ de programaci´n. (Los puristas de la programaci´n estructurada no s´lo censuran ıa o o o el uso de sentencias goto: tambi´n otras como break est´n proscritas.) e a Hay que decir, no obstante, que programar es una forma de describir ideas algor´ ıtmicas siguiendo unas reglas sint´cticas determinadas y que, en ocasiones, romper una regla pera mite una mejor expresi´n. Pero, ¡ojo!, s´lo estar´s capacitado para romper reglas cuando o o a las conozcas perfectamente. Por una cuesti´n de disciplina es preferible que, al principio, o procures no utilizar en absoluto alteraciones del flujo de control arbitrarias. . . aunque de todos modos no podr´s hacerlo de momento: ¡Python no tiene sentencia goto! a Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 157 157 Introducción a la programación con Python - UJI c UJI
    • Cap´ ıtulo 5 Tipos estructurados: secuencias Primero llegaron diez soldados portando bastos: ten´ la misma forma que ıan los tres jardineros, plana y rectangular, con las manos y los pies en las esquinas; luego ven´ los diez cortesanos, todos adornados de diamantes, y ıan caminaban de dos en dos, como los soldados. Segu´ los Infantes: eran diez ıan en total y era encantador verlos venir cogidos de la mano, en parejas, dando alegres saltos: estaban adornados con corazones. LEWIS CARROLL, Alicia en el pa´ de las maravillas. ıs Hasta el momento hemos tratado con datos de tres tipos distintos: enteros, flotantes y cadenas. Los dos primeros son tipos de datos escalares. Las cadenas, por contra, son tipos de datos secuenciales. Un dato de tipo escalar es un elemento unico, at´mico. Por contra, o ´ un dato de tipo secuencial se compone de una sucesi´n de elementos y una cadena es o una sucesi´n de caracteres. Los datos de tipo secuencial son datos estructurados. En o Python es posible manipular los datos secuenciales de diferentes modos, facilitando as´ ı la escritura de programas que manejan conjuntos o series de valores. En algunos puntos de la exposici´n nos desviaremos hacia cuestiones relativas al o modelo de memoria de Python. Aunque se trata de un material que debes comprender y dominar, no pierdas de vista que lo realmente importante es que aprendas a dise˜ar e n implementar algoritmos que trabajan con secuencias. En este tema empezaremos aprendiendo m´s de lo que ya sabemos sobre cadenas. a Despu´s, te presentaremos las listas. Una lista es una sucesi´n de elementos de cualquier e o tipo. Finalmente, aprender´s a definir y manejar matrices: disposiciones bidimensionales a de elementos. Python no incorpora un tipo de datos nativo para matrices, as´ que las ı construiremos como listas de listas. 5.1. 5.1.1. Cadenas Lo que ya sabemos Ya vimos en temas anteriores que una cadena es una sucesi´n de caracteres encerrada o entre comillas (simples o dobles). Python ofrece una serie de operadores y funciones predefinidos que manipulan cadenas o devuelven cadenas como resultado. Repasemos brevemente las que ya conocemos de temas anteriores: Operador + (concatenaci´n de cadenas): acepta dos cadenas como operandos y o devuelve la cadena que resulta de unir la segunda a la primera. Operador * (repetici´n de cadena): acepta una cadena y un entero y devuelve la o concatenaci´n de la cadena consigo misma tantas veces como indica el entero. o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 158 158 Introducción a la programación con Python - UJI
    • Operador % (sustituci´n de marcas de formato): acepta una cadena y una o m´s o a expresiones (entre par´ntesis y separadas por comas) y devuelve una cadena en e la que las marcas de formato (secuencias como %d, %f, etc.) se sustituyen por el resultado de evaluar las expresiones. int: recibe una cadena cuyo contenido es una secuencia de d´ ıgitos y devuelve el n´mero entero que describe. u float: acepta una cadena cuyo contenido describe un flotante y devuelve el flotante en cuesti´n. o str: se le pasa un entero o flotante y devuelve una cadena con una representaci´n o del valor como secuencia de caracteres. ord: acepta una cadena compuesta por un unico car´cter y devuelve su c´digo ASCII a o ´ (un entero). chr: recibe un entero (entre 0 y 255) y devuelve una cadena con el car´cter que a tiene a dicho entero como c´digo ASCII. o Podemos manipular cadenas, adem´s, mediante m´todos que les son propios: a e a.lower() (paso a min´sculas): devuelve una cadena con los caracteres de a conu vertidos en min´sculas. u a.upper() (paso a may´sculas): devuelve una cadena con los caracteres de a u convertidos en may´sculas. u a.capwords() (paso a palabras con inicial may´scula): devuelve una cadena en la u que toda palabra de a empieza por may´scula. u Aprenderemos ahora a utilizar nuevas herramientas. Pero antes, estudiemos algunas peculiaridades de la codificaci´n de los caracteres en las cadenas. o 5.1.2. Escapes Las cadenas que hemos estudiado hasta el momento consist´ en sucesiones de caracıan teres ˂˂normales˃˃: letras, d´ ıgitos, signos de puntuaci´n, espacios en blanco. . . Es posible, o no obstante, incluir ciertos caracteres especiales que no tienen una representaci´n trivial. o Por ejemplo, los saltos de l´ ınea se muestran en pantalla como eso, saltos de l´ ınea, no como un car´cter convencional. Si intentamos incluir un salto de l´ a ınea en una cadena pulsando la tecla de retorno de carro, Python se queja: ↱ >>> a = ’una File "<string>", line 1 ’una ˆ SyntaxError: invalid token ¿Ves? Al pulsar la tecla de retorno de carro, el int´rprete de Python intenta ejecutar e la sentencia inmediatamente y considera que la cadena est´ inacabada, as´ que notifica a ı que ha detectado un error. Observa esta otra asignaci´n de una cadena a la variable a y mira qu´ ocurre cuando o e mostramos el contenido de a: ↱ >>> a = ’unancadena’ >>> print a una cadena ↱ Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 159 159 Introducción a la programación con Python - UJI c UJI
    • Al mostrar la cadena se ha producido un salto de l´ ınea detr´s de la palabra una. El a salto de l´ ınea se ha codificado en la cadena con dos caracteres: la barra invertida y la letra n. La barra invertida se denomina car´cter de escape y es un car´cter especial: indica a a que el siguiente car´cter tiene un significado diferente del usual. Si el car´cter que le a a sigue es la letra n, por ejemplo, se interpreta como un salto de l´ ınea (la n viene del t´rmino ˂˂new line˃˃, es decir, ˂˂nueva l´ e ınea˃˃). Ese par de caracteres forma una secuencia de escape y denota un unico car´cter. ¿Y un salto de l´ a ınea es un unico car´cter? S´ a ı. ´ ´ Ocupa el mismo espacio en memoria que cualquier otro car´cter (un byte) y se codifica a internamente con un valor num´rico (c´digo ASCII): el valor 10. e o ↱ >>> ord(’n’) 10 Cuando una impresora o un terminal de pantalla tratan de representar el car´cter de a valor ASCII 10, saltan de l´ ınea. El car´cter n es un car´cter de control, pues su funci´n a a o es permitirnos ejecutar una acci´n de control sobre ciertos dispositivos (como la impresora o o el terminal). Secuencia de escape para car´cter de control a a b f n r t v ooo xhh Resultado Car´cter de ˂˂campana˃˃ (BEL) a ˂˂Espacio atr´s˃˃ (BS) a Alimentaci´n de formulario (FF) o Salto de l´ ınea (LF) Retorno de carro (CR) Tabulador horizontal (TAB) Tabulador vertical (VT) Car´cter cuyo c´digo ASCII en octal es ooo a o Car´cter cuyo c´digo ASCII en hexadecimal es hh a o Tabla 5.1: Secuencias de escape para caracteres de control en cadenas Python. Hay muchos caracteres de control (ver tabla 5.1), pero no te preocupes: nosotros utilizaremos fundamentalmente dos: n y t. Este ultimo representa el car´cter de tabulaci´n a o ´ horizontal o, simplemente, tabulador. El tabulador puede resultar util para alinear en ´ columnas datos mostrados por pantalla. Mira este ejemplo, en el que destacamos los espacios en blanco de la salida por pantalla para que puedas contarlos: ↱ >>> print ’unotdosttres’ uno␣␣␣␣␣dos␣␣␣␣␣tres >>> print ’1t2t3’ 1␣␣␣␣␣␣␣2␣␣␣␣␣␣␣3 >>> print ’1t12t13n21t2t33’ 1␣␣␣␣␣␣␣12␣␣␣␣␣␣13 21␣␣␣␣␣␣2␣␣␣␣␣␣␣33 ↱ ↱ Es como si hubiera unas marcas de alineaci´n (los tabuladores) cada 8 columnas. o Alternativamente, puedes usar el c´digo ASCII (en octal o hexadecimal) de un car´cter o a de control para codificarlo en una cadena, como se muestra en las dos ultimas filas de la ´ tabla 5.1. El salto de l´ ınea tiene valor ASCII 10, que en octal se codifica con 012 y en hexadecimal con x0a. Aqu´ te mostramos una cadena con tres saltos de l´ ı ınea codificados de diferente forma: Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 160 160 Introducción a la programación con Python - UJI c UJI
    • ↱ >>> print ’AnB012Cx0aD’ A B C D Ciertos caracteres no se pueden representar directamente en una cadena. La barra invertida es uno de ellos. Para expresarla, debes usar dos barras invertidas seguidas. ↱ >>> print ’ab’ ab En una cadena delimitada con comillas simples no puedes usar una comilla simple: si Python trata de analizar una cadena mal formada como ’Munich’72’, encuentra un error, pues cree que la cadena es ’Munich’ y no sabe c´mo interpretar los caracteres 72’. o Una comilla simple en una cadena delimitada con comillas simples ha de ir precedida de la barra invertida. Lo mismo ocurre con la comilla doble en una cadena delimitada con comillas dobles (v´ase la tabla 5.2): e ↱ Otras secuencias de escape ’ " y salto de l´ ınea ↱ >>> print ’Munich’72’ Munich’72 >>> print "Una␣"cosa"␣rara." Una "cosa" rara. Resultado Car´cter barra invertida () a Comilla simple (’) Comilla doble (") Se ignora (para expresar una cadena en varias l´ ıneas). Tabla 5.2: Secuencias de escape para algunos caracteres especiales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 152 ¿Qu´ se mostrar´ en pantalla al ejecutar estas sentencias? e a ↱ ↱ >>> print ’n’ >>> print ’157143164141154’ >>> print ’ttunabo’ ↱ (Te recomendamos que resuelvas este ejercicio a mano y compruebes la validez de tus respuestas con ayuda del ordenador.) · 153 ¿C´mo crees que se pueden representar dos barras invertidas seguidas en una o cadena? · 154 La secuencia de escape a emite un aviso sonoro (la ˂˂campana˃˃). ¿Qu´ hace e exactamente cuando se imprime en pantalla? Ejecuta print ’a’ y lo averiguar´s. a · 155 Averigua el c´digo ASCII de los 10 primeros caracteres de la tabla 5.1. o .................................................................................. Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 161 161 c UJI Introducción a la programación con Python - UJI
    • Unix, Microsoft y Apple: condenados a no entenderse Te hemos dicho que n codifica el car´cter de control ˂˂salto de l´ a ınea˃˃. Es cierto, pero no es toda la verdad. En los antiqu´ ısimos sistemas de teletipo (b´sicamente, m´quinas de a a escribir controladas por ordenador que se usaban antes de que existieran los monitores) se necesitaban dos caracteres para empezar a escribir al principio de la siguiente l´ ınea: un salto de l´ ınea (n) y un retorno de carro (r). Si s´lo se enviaba el car´cter n o a el ˂˂carro˃˃ saltaba a la siguiente l´ ınea, s´ pero se quedaba en la misma columna. El ı, car´cter r hac´ que el carro retornase a la primera columna. a ıa Con objeto de ahorrar memoria, los dise˜adores de Unix decidieron que el final de n l´ ınea en un fichero deber´ marcarse unicamente con n. Al dise˜ar MS-DOS, Microsoft ıa n ´ opt´ por utilizar dos caracteres: nr. As´ pues, los ficheros de texto de Unix no son o ı directamente compatibles con los de Microsoft. Si llevas un fichero de texto de un sistema Microsoft a Unix ver´s que cada l´ a ınea acaba con un s´ ımbolo extra˜o (¡el retorno n de carro!), y si llevas el fichero de Unix a un sistema Microsoft, parecer´ que las l´ a ıneas est´n mal alineadas. a Para poner peor las cosas, nos falta hablar de la decisi´n que adopt´ Apple en los o o ordenadores Macintosh: usar s´lo el retorno de carro (r). ¡Tres sistemas operativos y o tres formas distintas de decir lo mismo! De todos modos, no te preocupes en exceso, editores de texto como XEmacs y PythonG son bastante ˂˂listos˃˃: suelen detectar estas situaciones y las corrigen autom´ticamente. a M´s sobre la codificaci´n de las cadenas a o Hemos visto que podemos codificar cadenas encerrando un texto entre comillas simples o entre comillas dobles. En tal caso, necesitamos usar secuencias de escape para acceder a ciertos caracteres. Python ofrece a´n m´s posibilidades para codificar cadenas. Una u a de ellas hace que no se interpreten las secuencias de escape, es decir, que todos sus caracteres se interpreten literalmente. Estas cadenas ˂˂directas˃˃ (en ingl´s, ˂˂raw strings˃˃) e preceden con la letra ˂˂r˃˃ a las comillas (simples o dobles) que la inician: ↱ ↱ >>> print r’un’ un >>> print r"un" un Cuando una cadena ocupa varias l´ ıneas, podemos usar la secuencia de escape n para marcar cada salto de l´ ınea. O podemos usar una ˂˂cadena multil´ ınea˃˃. Las cadenas multil´ ınea empiezan con tres comillas simples (o dobles) y finalizan con tres comillas simples (o dobles): ↱ ↱ ↱ 5.1.3. ↱ >>> print ’’’Una ... cadena ... que ocupa ... varias l´neas’’’ ı Una cadena que ocupa varias l´neas ı Longitud de una cadena La primera nueva funci´n que estudiaremos es len (abreviatura del ingl´s ˂˂length˃˃, en o e espa˜ol, ˂˂longitud˃˃) que devuelve la longitud de una cadena, es decir, el n´mero de n u Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 162 162 Introducción a la programación con Python - c UJI UJI
    • caracteres que la forman. Se trata de una funci´n predefinida, as´ que podemos usarla o ı directamente: len(’abc’) ↱ len(’abcd’ * 4) ↱ len(’anb’) ↱ len(’a’) ↱ >>> 3 >>> 1 >>> 16 >>> 3 Hay una cadena que merece especial atenci´n, la cadena que denotamos abriendo y o cerrando inmediatamente las comillas simples, ’’, o dobles, "", sin ning´n car´cter entre u a ellas. ¿Qu´ valor devuelve len(’’)? e ↱ >>> len(’’) 0 La cadena ’’ se denomina cadena vac´ y tiene longitud cero. No confundas la cadena ıa vac´ ’’, con la cadena que contiene un espacio en blanco, ’␣’, pues, aunque parecidas, ıa, no son iguales. F´ ıjate bien en que la segunda cadena contiene un car´cter (el espacio en a blanco) y, por tanto, es de longitud 1. Podemos comprobarlo f´cilmente: a ↱ 5.1.4. ↱ >>> len(’’) 0 >>> len(’␣’) 1 Indexaci´n o Podemos acceder a cada uno de los caracteres de una cadena utilizando un operador de indexaci´n. El ´ o ındice del elemento al que queremos acceder debe encerrarse entre corchetes. Si a es una cadena, a[i] es el car´cter que ocupa la posici´n i+1. Debes a o tener en cuenta que el primer elemento tiene ´ ındice cero. Los ´ ındices de la cadena ’Hola,␣mundo.’ se muestran en esta figura: 0 1 2 3 4 H o l a , ’Hola,␣mundo.’[0] ’Hola,␣mundo.’[1] 7 8 9 10 11 m u n d o . ↱ a = ’Hola,␣mundo.’ a[2] 6 ↱ ↱ ↱ a[len(a)-1] ↱ i=3 a[i] ↱ ↱ a[1] ↱ >>> ’H’ >>> ’o’ >>> >>> ’l’ >>> ’o’ >>> >>> ’a’ >>> ’.’ 5 Observa que el ultimo car´cter de la cadena almacenada en la variable a no es a ´ a[len(a)], sino a[len(a)-1]. ¿Por qu´? Evidentemente, si el primer car´cter tiene ´ e a ındice Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 163 163 Introducción a la programación con Python - UJI c UJI
    • 0 y hay len(a) caracteres, el ultimo ha de tener ´ ındice len(a)-1. Si intentamos acceder ´ al elemento a[len(a)], Python protesta: ↱ >>> a[len(a)] Traceback (innermost last): File "<stdin>", line 1, in ? IndexError: string index out of range El error cometido es del tipo IndexError (error de indexaci´n) y, en el texto explicativo o que lo detalla, Python nos informa de que el ´ ındice de la cadena est´ fuera del rango de a valores v´lidos. a Recuerda que las secuencias de escape codifican caracteres simples, aunque se expresen con dos caracteres. La cadena ’Hola,nmundo.’, por ejemplo, no ocupa 13 casillas, sino 12: 0 1 2 3 4 5 6 7 8 9 10 11 H o l a , n m u n d o . Tambi´n puedes utilizar ´ e ındices negativos con un significado especial: los valores negativos acceden a los caracteres de derecha a izquierda. El ultimo car´cter de una a ´ cadena tiene ´ ındice −1, el pen´ltimo, −2, y as´ sucesivamente. Analiza este ejemplo: u ı a = ’Ejemplo’ a[-1] ↱ ↱ a[-len(a)] ↱ a[-3] ↱ a[len(a)-1] ↱ >>> >>> ’o’ >>> ’o’ >>> ’p’ >>> ’E’ De este modo se simplifica notablemente el acceso a los caracteres del final de la cadena. Es como si dispusieras de un doble juego de ´ ındices: 0 1 2 3 4 5 6 -7 -6 H o l a , -12 -11 -10 -9 -8 7 8 9 10 11 m u n d o . -5 -4 -3 -2 -1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 156 La ultima letra del DNI puede calcularse a partir de sus n´meros. Para ello u ´ s´lo tienes que dividir el n´mero por 23 y quedarte con el resto. El resto es un n´mero o u u entre 0 y 22. La letra que corresponde a cada n´mero la tienes en esta tabla: u 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 T R W A G M Y F P D X B N J Z S Q V H L C K E Dise˜a un programa que lea de teclado un n´mero de DNI y muestre en pantalla la letra n u que le corresponde. (Nota: una implementaci´n basada en tomar una decisi´n con if-elif conduce a un o o programa muy largo. Si usas el operador de indexaci´n de cadenas de forma inteligente, o el programa apenas ocupa tres l´ ıneas. Piensa c´mo.) o .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 164 164 Introducción a la programación con Python - UJIUJI c
    • 5.1.5. Recorrido de cadenas Una propiedad interesante de los datos secuenciales es que pueden recorrerse de izquierda a derecha con un bucle for-in. Por ejemplo, el siguiente bucle recorre los caracteres de una cadena de uno en uno, de izquierda a derecha: ↱ >>> for caracter in "mi␣cadena": ... print caracter ... m i ↱ ↱ c a d e n a En cada paso, la variable del bucle (en el ejemplo, caracter) toma el valor de uno de los caracteres de la cadena. Es lo que cab´ esperar: recuerda que el bucle for-in ıa recorre uno a uno los elementos de una serie de valores, y una cadena es una secuencia de caracteres. Tienes una forma alternativa de recorrer los elementos de una cadena: recorriendo el rango de valores que toma su ´ ındice e indexando cada uno de ellos. Estudia este ejemplo: ↱ ↱ >>> a = "mi␣cadena" >>> for i in range(len(a)): ... print a[i] ... m i ↱ ↱ c a d e n a La variable i toma los valores de range(len(a)), en este caso los valores comprendidos entre 0 y 8, ambos inclusive. Con a[i] hemos accedido, pues, a cada uno de ellos. Si mostramos tanto i como a[i], quiz´s entiendas mejor qu´ ocurre exactamente: a e ↱ ↱ >>> a = "mi␣cadena" >>> for i in range(len(a)): ... print i, a[i] ... 0 m 1 i 2 3 c 4 a 5 d 6 e 7 n 8 a ↱ ↱ Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 165 165 Introducción a la programación con Python - UJI c UJI
    • Tambi´n puedes mostrar los caracteres de la cadena en orden inverso, aunque en tal e caso has de hacerlo necesariamente con un bucle for-in y un range: ↱ >>> a = "mi␣cadena" >>> for i in range(len(a)): ... print a[len(a)-i-1] ... a n e d a c ↱ ↱ ↱ i m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 157 Intentamos mostrar los caracteres de la cadena en orden inverso as´ ı: ↱ ↱ ↱ ¿Funciona? ↱ >>> a = "mi␣cadena" >>> for i in range(len(a), -1): ... print a[i] ... · 158 Intentamos mostrar los caracteres de la cadena en orden inverso as´ ı: ↱ ↱ >>> a = "mi␣cadena" >>> for i in range(len(a)-1, -1, -1): ... print a[i] ... ↱ ↱ ¿Funciona? · 159 Dise˜a un programa que lea una cadena y muestre el n´mero de espacios en n u blanco que contiene. · 160 Dise˜a un programa que lea una cadena y muestre el n´mero de letras may´sculas n u u que contiene. · 161 Dise˜a una programa que lea una cadena y muestra en pantalla el mensaje n ˂˂Contiene d´gito˃˃ si contiene alg´n d´ ı u ıgito y ˂˂No contiene d´gito˃˃ en caso conı trario. .................................................................................. 5.1.6. Un ejemplo: un contador de palabras Ahora que tenemos nuevas herramientas para la manipulaci´n de cadenas, vamos a desao rrollar un programa interesante: leer´ cadenas de teclado y mostrar´ en pantalla el a a n´mero de palabras que contienen. u Empecemos estudiando el problema con un ejemplo concreto. ¿Cu´ntas palabras hay a en la cadena ’una␣dos␣tres’? Tres palabras. ¿C´mo lo sabemos? Muy f´cil: contando el o a n´mero de espacios en blanco. Si hay dos espacios en blanco, entonces hay tres palabras, u ya que cada espacio en blanco separa dos palabras. Hagamos, pues, que el programa cuente el n´mero de espacios en blanco y muestre ese n´mero m´s uno: u u a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 166 166 Introducción a la programación con Python - UJIUJI c
    • E palabras.py E palabras 5.py 1 2 3 4 5 6 7 8 9 10 cadena = raw_input(’Escribe␣una␣frase:␣’) while cadena != ’’: blancos = 0 for caracter in cadena: if caracter == ’␣’: blancos += 1 palabras = blancos + 1 # Hay una palabra m´s que blancos a print ’Palabras:’, palabras cadena = raw_input(’Escribe␣una␣frase:␣’) El programa finaliza la ejecuci´n cuando teclamos una cadena vac´ es decir, si pulsamos o ıa, retorno de carro directamente. Ejecutemos el programa: Escribe una Palabras: 3 Escribe una Palabras: 2 Escribe una Palabras: 1 Escribe una Palabras: 3 frase: una dos tres frase: mi␣ejemplo frase: ejemplo frase: otro␣␣ejemplo ¡Eh! ¿Qu´ ha pasado con el ultimo ejemplo? Hay dos palabras y el programa dice que e ´ hay tres. Est´ claro: entre las palabras ˂˂otro˃˃ y ˂˂ejemplo˃˃ de la cadena ’otro␣␣ejemplo’ a hay dos espacios en blanco, y no uno solo. Corrijamos el programa para que trate correctamente casos como ´ste. Desde luego, contar espacios en blanco, sin m´s, no es la clave e a para decidir cu´ntas palabras hay. Se nos ocurre una idea mejor: mientras recorremos la a cadena, veamos cu´ntas veces pasamos de un car´cter que no sea el espacio en blanco a a a un espacio en blanco. En la cadena ’una dos tres’ pasamos dos veces de letra a espacio en blanco (una vez pasamos de la ˂˂a˃˃ al blanco y otra de la ˂˂s˃˃ al blanco), y hay tres palabras; en la cadena problem´tica ’otro␣␣ejemplo’ s´lo pasamos una vez de la letra a o ˂˂o˃˃ a un espacio en blanco y, por tanto, hay dos palabras. Si contamos el n´mero de u transiciones, el n´mero de palabras ser´ ese mismo n´mero m´s uno. ¿Y c´mo hacemos u a u a o para comparar un car´cter y su vecino? El truco est´ en recordar siempre cu´l era el a a a car´cter anterior usando una variable auxiliar: a palabras 6.py 1 2 3 4 5 6 7 8 9 10 11 12 E palabras.py E cadena = raw_input(’Escribe␣una␣frase:␣’) while cadena != ’’: cambios = 0 anterior = ’’ for caracter in cadena: if caracter == ’␣’ and anterior != ’␣’: cambios += 1 anterior = caracter palabras = cambios + 1 # Hay una palabra m´s que cambios de no blanco a blanco a print ’Palabras:’, palabras cadena = raw_input(’Escribe␣una␣frase:␣’) ¿Por qu´ hemos dado un valor a anterior en la l´ e ınea 4? Para inicializar la variable. De no hacerlo, tendr´ ıamos problemas al ejecutar la l´ ınea 6 por primera vez, ya que en ella se consulta el valor de anterior. Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 167 167 Introducción a la programación con Python - UJI c UJI
    • . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 162 Haz una traza del programa para la cadena ’a␣b’. ¿Qu´ l´ e ıneas se ejecutan y qu´ valores toman las variables cambios, anterior y caracter tras la ejecuci´n de cada e o una de ellas? · 163 ´ Idem para la cadena ’a␣␣b’. .................................................................................. Probemos nuestra nueva versi´n: o Escribe una Palabras: 3 Escribe una Palabras: 2 Escribe una Palabras: 1 Escribe una Palabras: 2 Escribe una Palabras: 2 frase: una␣dos␣tres frase: mi␣ejemplo frase: ejemplo frase: otro␣␣ejemplo frase: ejemplo␣ ¡No! ¡Otra vez mal! ¿Qu´ ha ocurrido ahora? Si nos fijamos bien veremos que la e cadena del ultimo ejemplo acaba en un espacio en blanco, as´ que hay una transici´n ı o ´ de ˂˂no blanco˃˃ a espacio en blanco y eso, para nuestro programa, significa que hay una nueva palabra. ¿C´mo podemos corregir ese problema? Analic´moslo: parece que s´lo o e o nos molestan los blancos al final de la cadena. ¿Y si descontamos una palabra cuando la cadena acaba en un espacio en blanco? E palabras.py E palabras 7.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cadena = raw_input(’Escribe␣una␣frase:␣’) while cadena != ’’: cambios = 0 anterior = ’’ for caracter in cadena: if caracter == ’␣’ and anterior != ’␣’: cambios += 1 anterior = caracter if cadena[-1] == ’␣’: cambios -= 1 palabras = cambios + 1 print ’Palabras:’, palabras cadena = raw_input(’Escribe␣una␣frase:␣’) Probemos ahora esta nueva versi´n: o Escribe una Palabras: 3 Escribe una Palabras: 2 Escribe una Palabras: 1 Escribe una Palabras: 2 Escribe una Palabras: 1 frase: una␣dos␣tres frase: mi␣ejemplo frase: ejemplo frase: otro␣␣ejemplo frase: ejemplo␣ Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 168 168 Introducción a la programación con Python - UJIUJI c
    • ¡Perfecto! Ya est´. ¿Seguro? Mmmm. Los espacios en blanco dieron problemas al final a de la cadena. ¿Ser´n problem´ticos tambi´n al principio de la cadena? Probemos: a a e Escribe una frase: ␣ejemplo␣ Palabras: 2 S´ ¡qu´ horror! ¿Por qu´ falla ahora? El problema radica en la inicializaci´n de ı, e e o anterior (l´ ınea 4). Hemos dado una cadena vac´ como valor inicial y eso hace que, si la ıa cadena empieza por un blanco, la condici´n de la l´ o ınea 6 se eval´e a cierto para el primer u car´cter, incrementando as´ la variable cambios (l´ a ı ınea 7) la primera vez que iteramos el bucle. Podr´ ıamos evitarlo modificando la inicializaci´n de la l´ o ınea 4: un espacio en blanco nos vendr´ mejor como valor inicial de anterior. ıa palabras.py palabras 8.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cadena = raw_input(’Escribe␣una␣frase:␣’) while cadena != ’’: cambios = 0 anterior = ’␣’ for caracter in cadena: if caracter == ’␣’ and anterior != ’␣’: cambios += 1 anterior = caracter if cadena[-1] == ’␣’: cambios = cambios - 1 palabras = cambios + 1 print ’Palabras:’, palabras cadena = raw_input(’Escribe␣una␣frase:␣’) Ahora s´ ı: Escribe una Palabras: 3 Escribe una Palabras: 2 Escribe una Palabras: 1 Escribe una Palabras: 2 Escribe una Palabras: 1 Escribe una Palabras: 1 frase: una␣dos␣tres frase: mi␣ejemplo frase: ejemplo frase: otro␣␣ejemplo frase: ejemplo␣ frase: ␣ejemplo␣ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 164 ¿Funciona el programa cuando introducimos una cadena formada s´lo por espao cios en blanco? ¿Por qu´? Si su comportamiento no te parece normal, corr´ e ıgelo. .................................................................................. El ejemplo que hemos desarrollado tiene un doble objetivo did´ctico. Por una parte, a familiarizarte con las cadenas; por otra, que veas c´mo se resuelve un problema poco a o poco. Primero hemos analizado el problema en busca de una soluci´n sencilla (contar o espacios en blanco). Despu´s hemos implementado nuestra primera soluci´n y la hemos e o probado con varios ejemplos. Los ejemplos que nos hemos puesto no son s´lo los m´s o a sencillos, sino aquellos que pueden hacer ˂˂cascar˃˃ el programa (en nuestro caso, poner dos o m´s espacios en blanco seguidos). Detectar ese error nos ha conducido a una a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 169 169 Introducción a la programación con Python - UJIUJI c
    • ˂˂mejora˃˃ del programa (en realidad, una correcci´n): no deb´ o ıamos contar espacios en blanco, sino transiciones de ˂˂no blanco˃˃ a espacio en blanco. Nuevamente hemos puesto a prueba el programa y hemos encontrado casos para los que falla (espacios al final de la cadena). Un nuevo refinamiento ha permitido tratar el fallo y, otra vez, hemos encontrado un caso no contemplado (espacios al principio de la cadena) que nos ha llevado a un ultimo cambio del programa. F´ ıjate en que cada vez que hemos hecho un ´ cambio al programa hemos vuelto a introducir todos los casos que ya hab´ ıamos probado (al modificar un programa es posible que deje de funcionar para casos en los que ya iba bien) y hemos a˜adido uno nuevo que hemos sospechado que pod´ ser problem´tico. As´ n ıa a ı es como se llega a la soluci´n final: siguiendo un proceso reiterado de an´lisis, prueba o a y error. Durante ese proceso el programador debe ˂˂jugar˃˃ en dos ˂˂equipos˃˃ distintos: a ratos juega en el equipo de los programadores y trata de encontrar la mejor soluci´n al problema propuesto; o y a ratos juega en el equipo de los usuarios y pone todo su empe˜o en buscar n configuraciones especiales de los datos de entrada que provoquen fallos en el programa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 165 Modifica el programa para que base el c´mputo de palabras en el n´mero de o u transiciones de blanco a no blanco en lugar de en el n´mero de transiciones de no blanco u a blanco. Comprueba si tu programa funciona en toda circunstancia. · 166 Nuestro aprendiz aventajado propone esta otra soluci´n al problema de contar o palabras: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 cadena = raw_input(’Escribe␣una␣frase:␣’) while cadena != ’’: cambios = 0 for i in range(1, len(cadena)): if cadena[i] == ’␣’ and cadena[i-1] != ’␣’: cambios = cambios + 1 if cadena[-1] == ’␣’: cambios = cambios - 1 palabras = cambios + 1 print ’Palabras:’, palabras cadena = raw_input(’Escribe␣una␣frase:␣’) ¿Es correcta? · 167 Dise˜a un programa que lea una cadena y un n´mero entero k y nos diga cu´ntas n u a palabras tienen una longitud de k caracteres. · 168 Dise˜a un programa que lea una cadena y un n´mero entero k y nos diga si n u alguna de sus palabras tiene una longitud de k caracteres. · 169 Dise˜a un programa que lea una cadena y un n´mero entero k y nos diga si n u todas sus palabras tienen una longitud de k caracteres. · 170 Escribe un programa que lea una cadena y un n´mero entero k y muestre el u mensaje ˂˂Hay palabras largas˃˃ si alguna de las palabras de la cadena es de longitud mayor o igual que k, y ˂˂No hay palabras largas˃˃ en caso contrario. · 171 Escribe un programa que lea una cadena y un n´mero entero k y muestre u el mensaje ˂˂Todas son cortas˃˃ si todas las palabras de la cadena son de longitud estrictamente menor que k, y ˂˂Hay alguna palabra larga˃˃ en caso contrario. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 170 170 Introducción a la programación con Python - UJIUJI c
    • · 172 Escribe un programa que lea una cadena y un n´mero entero k y muestre el u mensaje ˂˂Todas las palabras son largas˃˃ si todas las palabras de la cadena son de longitud mayor o igual que k, y ˂˂Hay alguna palabra corta˃˃ en caso contrario. · 173 Dise˜a un programa que muestre la cantidad de d´ n ıgitos que aparecen en una cadena introducida por teclado. La cadena ’un␣1␣y␣un␣20’, por ejemplo, tiene 3 d´ ıgitos: un 1, un 2 y un 0. · 174 Dise˜a un programa que muestre la cantidad de n´meros que aparecen en una n u cadena le´ de teclado. ¡Ojo! Con n´mero no queremos decir d´ ıda u ıgito, sino n´mero prou piamente dicho, es decir, secuencia de d´ ıgitos. La cadena ’un␣1,␣un␣201␣y␣2␣unos’, por ejemplo, tiene 3 n´meros: el 1, el 201 y el 2. u · 175 Dise˜a un programa que indique si una cadena le´ de teclado est´ bien formada n ıda a como n´mero entero. El programa escribir´ ˂˂Es entero˃˃ en caso afirmativo y ˂˂No es u a entero˃˃ en caso contrario. Por ejemplo, para ’12’ mostrar´ ˂˂Es entero˃˃, pero para ’1␣2’ o ’a’ mostrar´ ˂˂No a a es entero˃˃. · 176 Dise˜a un programa que indique si una cadena introducida por el usuario est´ n a bien formada como identificador de variable. Si lo est´, mostrar´ el texto ˂˂Identificador a a v´lido˃˃ y si no, ˂˂Identificador inv´lido˃˃. a a · 177 Dise˜a un programa que indique si una cadena le´ por teclado est´ bien n ıda a formada como n´mero flotante. u Prueba el programa con estas cadenas: ’3.1’, ’3.’, ’.1’, ’1e+5’, ’-10.2E3’, ’3.1e-2’, ’.1e01’. En todos los casos deber´ indicar que se trata de n´meros flotantes a u correctamente formados. · 178 Un texto est´ bien parentizado si por cada par´ntesis abierto hay otro m´s a e a adelante que lo cierra. Por ejemplo, la cadena ’Esto␣(es␣(un)␣(ejemplo␣(de)␣((cadena)␣bien))␣parentizada).’ est´ bien parentizada, pero no lo est´n estas otras: a a ’una␣cadena)’ ’(una␣cadena’ ’(una␣(cadena)’ ’)una(␣cadena’ Dise˜a un programa que lea una cadena y nos diga si la cadena est´ bien o mal parenn a tizada. · 179 Implementa un programa que lea de teclado una cadena que representa un n´mero binario. Si alg´n car´cter de la cadena es distinto de ’0’ o ’1’, el programa u u a advertir´ al usuario de que la cadena introducida no representa un n´mero binario y a u pedir´ de nuevo la lectura de la cadena. a .................................................................................. 5.1.7. Otro ejemplo: un programa de conversi´n de binario a decimal o Nos proponemos dise˜ar un programa que reciba una cadena compuesta por ceros y unos n y muestre un n´mero: el que corresponde al valor decimal de la cadena si interpretamos u e u a ´sta como un n´mero codificado en binario. Por ejemplo, nuestro programa mostrar´ el valor 13 para la cadena ’1101’. Empezaremos por plantearnos c´mo har´ o ıamos manualmente el c´lculo. Podemos recoa rrer la cadena de izquierda a derecha e ir considerando el aporte de cada bit al n´mero u global. El n-´simo bit contribuye al resultado con el valor 2n−1 si vale ’1’, y con el e valor 0 si vale ’0’. Pero, ¡ojo!, cuando decimos n-´simo bit, no nos referimos al n-´simo e e Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 171 171 Introducción a la programación con Python - UJIUJI c
    • car´cter de la cadena. Por ejemplo, la cadena ’100’ tiene su tercer bit a 1, pero ´se a e es el car´cter que ocupa la primera posici´n de la cadena (la que tiene ´ a o ındice 0), no la tercera. Podemos recorrer la cadena de izquierda a derecha e ir llevando la cuenta del n´mero de bit actual en una variable: u decimal.py 1 2 3 4 5 6 7 8 9 10 decimal.py bits = raw_input(’Dame␣un␣n´mero␣binario:␣’) u n = len(bits) valor = 0 for bit in bits: if bit == ’1’: valor = valor + 2 ** (n-1) n -= 1 print ’Su␣valor␣decimal␣es’, valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 180 Haz una traza para las cadenas ’1101’ y ’010’. · 181 Una vez m´s, nuestro aprendiz ha dise˜ado un programa diferente: a n decimal 4.py 1 2 3 4 5 6 7 8 9 10 decimal.py bits = raw_input(’Dame␣un␣n´mero␣binario:␣’) u valor = 0 for bit in bits: if bit == ’1’: valor = 2 * valor + 1 else: valor = 2 * valor print ’Su␣valor␣decimal␣es’, valor ¿Es correcto? Haz trazas para las cadenas ’1101’ y ’010’. · 182 ¿Y esta otra versi´n? ¿Es correcta? o decimal 5.py 1 2 3 4 5 6 7 8 9 10 decimal.py bits = raw_input(’Dame␣un␣n´mero␣binario:␣’) u valor = 0 for bit in bits: if bit == ’1’: valor += valor + 1 else: valor += valor print ’Su␣valor␣decimal␣es’, valor Haz trazas para las cadenas ’1101’ y ’010’. · 183 ¿Y esta otra? ¿Es correcta? decimal 6.py 1 2 3 4 5 6 7 decimal.py bits = raw_input(’Dame␣un␣n´mero␣binario:␣’) u valor = 0 for bit in bits: valor += valor + int(bit) print ’Su␣valor␣decimal␣es’, valor Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 172 172 Introducción a la programación con Python - UJIUJI c
    • Haz trazas para las cadenas ’1101’ y ’010’. · 184 ¿Qu´ pasa si introducimos una cadena con caracteres que no pertenecen al e conjunto de d´ ıgitos binarios como, por ejemplo, ’101a2’? Modifica el programa para que, en tal caso, muestre en pantalla el mensaje ˂˂N´mero binario mal formado˃˃ y solicite u nuevamente la introducci´n de la cadena. o · 185 Dise˜a un programa que convierta una cadena de d´ n ıgitos entre el ˂˂0˃˃ y el ˂˂7˃˃ al valor correspondiente a una interpretaci´n de dicha cadena como n´mero en base octal. o u · 186 Dise˜a un programa que convierta una cadena de d´ n ıgitos o letras entre la ˂˂a˃˃ y la ˂˂f˃˃ al valor correspondiente a una interpretaci´n de dicha cadena como n´mero en o u base hexadecimal. · 187 Dise˜a un programa que reciba una cadena que codifica un n´mero en octal, n u decimal o hexadecimal y muestre el valor de dicho n´mero. Si la cadena empieza por u ˂˂0x˃˃ o ˂˂0X˃˃ se interpretar´ como un n´mero hexadecimal (ejemplo: ’0xff’ es 255); si a u no, si el primer car´cter es ˂˂0˃˃, la cadena se interpretar´ como un n´mero octal (ejemplo: a a u ’017’ es 15); y si no, se interpretar´ como un n´mero decimal (ejemplo: ’99’ es 99). a u · 188 Dise˜a un programa que lea un n´mero entero y muestre una cadena con su n u representaci´n octal. o · 189 Dise˜a un programa que lea una cadena que representa un n´mero codificado n u en base 8 y muestre por pantalla su representaci´n en base 2. o .................................................................................. 5.1.8. A vueltas con las cadenas: inversi´n de una cadena o Recuerda del tema 2 que el operador + puede trabajar con cadenas y denota la operaci´n o de concatenaci´n, que permite obtener la cadena que resulta de unir otras dos: o ↱ >>> ’abc’ + ’def’ ’abcdef’ Vamos a utilizar este operador en el siguiente ejemplo: un programa que lee una cadena y muestra su inversi´n en pantalla. El programa se ayudar´ de una cadena o a auxiliar, inicialmente vac´ en la que iremos introduciendo los caracteres de la cadena ıa, original, pero de atr´s hacia adelante. a inversion.py 1 2 3 4 5 6 7 inversion.py cadena = raw_input(’Introduce␣una␣cadena:␣’) inversion = ’’ for caracter in cadena: inversion = caracter + inversion print ’Su␣inversi´n␣es:’, inversion o Probemos el programa: Introduce una cadena: uno Su inversi´n es: onu o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 190 Una palabra es ˂˂alfab´tica˃˃ si todas sus letras est´n ordenadas alfab´ticamente. e a e Por ejemplo, ˂˂amor˃˃, ˂˂chino˃˃ e ˂˂himno˃˃ son palabras ˂˂alfab´ticas˃˃. Dise˜a un programa e n que lea una palabra y nos diga si es alfab´tica o no. e Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 173 173 Introducción a la programación con Python - UJIUJI c
    • · 191 Dise˜a un programa que nos diga si una cadena es pal´ n ındromo o no. Una cadena es pal´ ındromo si se lee igual de izquierda a derecha que de derecha a izquierda. Por ejemplo, ’ana’ es un pal´ ındromo. · 192 Una frase es pal´ ındromo si se lee igual de derecha a izquierda que de izquierda a derecha, pero obviando los espacios en blanco y los signos de puntuaci´n. Por o ejemplo, las cadenas ’s´␣verla␣al␣rev´s’, ’anita␣lava␣la␣tina’, ’luz␣azul’ y e e ’la␣ruta␣natural’ contienen frases pal´ ındromas. Dise˜a un programa que diga si una n frase es o no es pal´ ındroma. · 193 Probablemente el programa que has dise˜ado para el ejercicio anterior falle ante n frases pal´ ındromas como ´stas: ˂˂D´bale arroz a la zorra el abad˃˃, ˂˂Salta Len´ el atlas˃˃, e a ın ´ ˂˂Amigo, no gima˃˃, ˂˂Atale, demon´ ıaco Ca´ o me delata˃˃, ˂˂An´s us´ tu auto, Susana˃˃, ın, a o ˂˂A Mercedes, ´se de crema˃˃, ˂˂A mam´ Roma le aviva el amor a pap´, y a pap´ Roma e a a a le aviva el amor a mam´˃˃ y ˂˂¡arriba la birra!˃˃, pues hemos de comparar ciertas letras a con sus versiones acentuadas, o may´sculas o la apertura de exclamaci´n con su cierre. u o Modifica tu programa para que identifique correctamente frases pal´ ındromas en las que pueden aparecer letras may´sculas, vocales acentuadas y la vocal ˂˂u˃˃ con di´resis. u e · 194 Hay un tipo de pasatiempos que propone descifrar un texto del que se han suprimido las vocales. Por ejemplo, el texto ˂˂.n .j.mpl. d. p.s.t..mp.s˃˃, se descifra sustituyendo cada punto con una vocal del texto. La soluci´n es ˂˂un ejemplo de o pasatiempos˃˃. Dise˜a un programa que ayude al creador de pasatiempos. El programa n recibir´ una cadena y mostrar´ otra en la que cada vocal ha sido reemplazada por un a a punto. · 195 El nombre de un fichero es una cadena que puede tener lo que denominamos una extensi´n. La extensi´n de un nombre de fichero es la serie de caracteres que suceden al o o ultimo punto presente en la cadena. Si el nombre no tiene ning´n punto, asumiremos que u ´ su extensi´n es la cadena vac´ Haz un programa que solicite el nombre de un fichero o ıa. y muestre por pantalla los caracteres que forman su extensi´n. Prueba la validez de tu o programa pidiendo que muestre la extensi´n de los nombres de fichero documento.doc o y tema.1.tex, que son doc y tex, respectivamente. · 196 Haz un programa que lea dos cadenas que representen sendos n´meros binarios. u A continuaci´n, el programa mostrar´ el n´mero binario que resulta de sumar ambos (y o a u que ser´ otra cadena). Si, por ejemplo, el usuario introduce las cadenas ’100’ y ’111’, a el programa mostrar´ como resultado la cadena ’1011’. a (Nota: El procedimiento de suma con acarreo que implementes deber´ trabajar direca tamente con la representaci´n binaria le´ o ıda.) · 197 Una de las t´cnicas de criptograf´ m´s rudimentarias consiste en sustituir cada e ıa a uno de los caracteres por otro situado n posiciones m´s a la derecha. Si n = 2, por ejemplo, a sustituiremos la ˂˂a˃˃ por la ˂˂c˃˃, la ˂˂b˃˃ por la ˂˂e˃˃, y as´ sucesivamente. El problema que ı aparece en las ultimas n letras del alfabeto tiene f´cil soluci´n: en el ejemplo, la letra a o ´ ˂˂y˃˃ se sustituir´ por la ˂˂a˃˃ y la letra ˂˂z˃˃ por la ˂˂b˃˃. La sustituci´n debe aplicarse a las a o letras min´sculas y may´sculas y a los d´ u u ıgitos (el ˂˂0˃˃ se sustituye por el ˂˂2˃˃, el ˂˂1˃˃ por el ˂˂3˃˃ y as´ hasta llegar al ˂˂9˃˃, que se sustituye por el ˂˂1˃˃). ı Dise˜a un programa que lea un texto y el valor de n y muestre su versi´n criptogran o fiada. · 198 Dise˜a un programa que lea un texto criptografiado siguiendo la t´cnica descrita n e en el apartado anterior y el valor de n utilizado al encriptar para mostrar ahora el texto decodificado. .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 174 174 Introducción a la programación con Python - UJIUJI c
    • 5.1.9. Subcadenas: el operador de corte Desarrollemos un ultimo ejemplo: un programa que, dados una cadena y dos ´ ındices i y ´ j, muestra la (sub)cadena formada por todos los caracteres entre el que tiene ´ ındice i y el que tiene ´ ındice j, incluyendo al primero pero no al segundo. La idea b´sica consiste en construir una nueva cadena que, inicialmente, est´ vac´ a a ıa. Con un recorrido por los caracteres comprendidos entre los de ´ ındices i y j − 1 iremos a˜adiendo caracteres a la cadena. Vamos con una primera versi´n: n o subcadena 3.py 1 2 3 4 5 6 7 8 9 E subcadena.py E cadena = raw_input(’Dame␣una␣cadena:␣’) i = int(raw_input(’Dame␣un␣n´mero:␣’)) u j = int(raw_input(’Dame␣otro␣n´mero:␣’)) u subcadena = ’’ for k in range(i, j): subcadena += cadena[k] print ’La␣subcadena␣entre␣%d␣y␣%d␣es␣%s.’ % (i, j, subcadena) Us´mosla: e Dame una cadena: Ejemplo Dame un n´mero: 2 u Dame otro n´mero: 5 u La subcadena entre 2 y 5 es emp. ¿Falla algo en nuestro programa? S´ es f´cil cometer un error de indexaci´n. Por ı: a o ejemplo, al ejecutar el programa con la cadena y los ´ ındices 3 y 20 se cometer´ un error, a pues 20 es mayor que la longitud de la cadena. Corrijamos ese problema: subcadena 4.py 1 2 3 4 5 6 7 8 9 10 11 12 13 subcadena.py cadena = raw_input(’Dame␣una␣cadena:␣’) i = int(raw_input(’Dame␣un␣n´mero:␣’)) u j = int(raw_input(’Dame␣otro␣n´mero:␣’)) u if j > len(cadena): final = len(cadena) else: final = j subcadena = ’’ for k in range(i, final ): subcadena += cadena[k] print ’La␣subcadena␣entre␣%d␣y␣%d␣es␣%s.’ % (i, j, subcadena) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 199 ¿Y si se introduce un valor de i negativo? Corrige el programa para que detecte esa posibilidad e interprete un ´ ındice inicial negativo como el ´ ındice 0. · 200 ¿No ser´ tambi´n problem´tico que introduzcamos un valor del ´ a e a ındice i mayor o igual que el de j? ¿Se producir´ entonces un error de ejecuci´n? ¿Por qu´? a o e · 201 Dise˜a un programa que, dados una cadena c, un ´ n ındice i y un n´mero n, muestre u la subcadena de c formada por los n caracteres que empiezan en la posici´n de ´ o ındice i. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 175 175 Introducción a la programación con Python - UJIUJI c
    • .................................................................................. Hemos visto c´mo construir una subcadena car´cter a car´cter. Esta es una operaci´n o a a o frecuente en los programas que manejan informaci´n textual, as´ que Python ofrece un o ı operador predefinido que facilita esa labor: el operador de corte (en ingl´s, ˂˂slicing e operator˃˃). La notaci´n es un tanto peculiar, pero c´moda una vez te acostumbras a ella. o o F´ ıjate en este ejemplo: ↱ >>> a = ’Ejemplo’ >>> a[2:5] ’emp’ ↱ El operador de corte se denota con dos puntos (:) que separan dos ´ ındices dentro de los corchetes del operador de indexaci´n. La expresi´n a[i:j] significa que se desea o o obtener la subcadena formada por los caracteres a[i], a[i+1],. . . , a[j-1], (observa que, como en range, el valor del ultimo ´ ındice se omite). ´ Ya que se omite el ultimo ´ ındice del corte, puede que te resulte de ayuda imaginar que ´ los ´ ındices de los elementos se disponen en las fronteras entre elementos consecutivos, como se puede ver en esta figura: 0 1 2 3 4 5 6 7 E j e m p l o -7 -6 -5 -4 -3 -2 -1 Ah´ queda claro que a[2:5], a[-5:5], a[2,:-2] y a[-5:-2], siendo a la cadena de la ı figura, es la cadena ’emp’. Cada ´ ındice de corte tiene un valor por defecto, as´ que puedes omitirlo si te conviene. ı El corte a[:j] es equivalente a a[0:j] y el corte a[i:] equivale a a[i:len(a)]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 202 Si a vale ’Ejemplo’, ¿qu´ es el corte a[:]? e · 203 ¿Qu´ corte utilizar´ para obtener los n caracteres de una cadena a partir de e ıas la posici´n de ´ o ındice i? · 204 Dise˜a un programa que, dada una cadena, muestre por pantalla todos sus n prefijos. Por ejemplo, dada la cadena ’UJI’, por pantalla debe aparecer: U UJ UJI · 205 Dise˜a un programa que lea una cadena y muestre por pantalla todas sus subn cadenas de longitud 3. · 206 Dise˜a un programa que lea una cadena y un entero k y muestre por pantalla n todas sus subcadenas de longitud k. · 207 Dise˜a un programa que lea dos cadenas a y b y nos diga si b es un prefijo de n a o no. (Ejemplo: ’sub’ es un prefijo de ’subcadena’.) · 208 Dise˜a un programa que lea dos cadenas a y b y nos diga si b es una subcadena n de a o no. (Ejemplo: ’de’ es una subcadena de ’subcadena’.) · 209 Dise˜a un programa que lea dos cadenas y devuelva el prefijo com´n m´s largo n u a de ambas. (Ejemplo: las cadenas ’polit´cnico’ y ’polinizaci´n’ tienen como prefijo com´n e o u m´s largo a la cadena ’poli’.) a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 176 176 Introducción a la programación con Python - UJIUJI c
    • · 210 Dise˜a un programa que lea tres cadenas y muestre el prefijo com´n m´s largo n u a de todas ellas. (Ejemplo: las cadenas ’polit´cnico’, ’polinizaci´n’ y ’poros’ tienen como e o prefijo com´n m´s largo a la cadena ’po’.) u a .................................................................................. Cortes avanzados Desde la versi´n 2.3, Python entiende una forma extendida de los cortes. Esta forma o acepta tres valores separados por el car´cter ˂˂:˃˃. El tercer valor equivale al tercer a par´metro de la funci´n range: indica el incremento del ´ a o ındice en cada iteraci´n. Por o ejemplo, si c contiene la cadena ’Ejemplo’, el corte c[0:len(c):2] selecciona los caracteres de ´ ındice par, o sea, devuelve la cadena ’Eepo’. El tercer valor puede ser negativo. Ello permite invertir una cadena con una expresi´n muy sencilla: c[::-1]. o Haz la prueba. 5.1.10. Una aplicaci´n: correo electr´nico personalizado o o Vamos a desarrollar un programa ˂˂´til˃˃: uno que env´ textos personalizados por correo u ıa electr´nico. Deseamos enviar una carta tipo a varios clientes, pero adaptando algunos o datos de la misma a los propios de cada cliente. Aqu´ tienes un ejemplo de carta tipo: ı Estimado =S =A: Por la presente le informamos de que nos debe usted la cantidad de =E euros. Si no abona dicha cantidad antes de 3 d´as, su nombre ı pasar´ a nuestra lista de morosos. a Deseamos sustituir las marcas ˂˂=S˃˃, ˂˂=A˃˃ y ˂˂=E˃˃ por el tratamiento (se˜or o se˜ora), n n el apellido y la deuda, respectivamente, de cada cliente y enviarle el mensaje resultante por correo electr´nico. Nuestro programa pedir´ los datos de un cliente, personalizar´ el o a a escrito, se lo enviar´ por correo electr´nico y a continuaci´n, si lo deseamos, repetir´ el a o o a proceso para un nuevo cliente. Antes de empezar a desarrollar el programa nos detendremos para aprender lo b´sico a del m´dulo smtplib, que proporciona funciones para usar el protocolo de env´ de correo o ıo electr´nico SMTP (siglas de ˂˂Simple Mail Transfer Protocol˃˃, o sea, ˂˂Protocolo Sencillo o de Transferencia de Correo˃˃)1 . Lo mejor ser´ que estudiemos un ejemplo de uso de la a librer´ y que analicemos lo que hace paso a paso. ıa ejemplo smtp.py 1 2 3 4 5 6 7 8 9 10 ejemplo smtp.py from smtplib import SMTP servidor = SMTP(’alu-mail.uji.es’) # Cambia la cadena por el nombre de tu servidor. remitente = ’al00000@alumail.uji.es’ destinatario = ’al99999@alumail.uji.es’ mensaje = ’From:␣%snTo:␣%snn’ % (remitente, destinatario) mensaje += ’Hola.n’ mensaje += ’Hasta␣luego.n’ servidor.sendmail(remitente, destinatario, mensaje) Vamos por partes. La primera l´ ınea importa la funci´n SMTP del m´dulo smtplib. o o La l´ ınea 3 crea una conexi´n con la m´quina servidora (v´ la llamada a SMTP), que o a ıa 1 No pierdas de vista que el objetivo de esta secci´n es aprender el manejo de cadenas. No te despistes o tratando de profundizar ahora en los conceptos del SMTP y las peculiaridades del correspondiente m´dulo. o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 177 177 Introducción a la programación con Python - UJIUJI c
    • en nuestro ejemplo es alu-mail@uji.es, y devuelve un objeto que guardamos en la variable servidor. Las l´ ıneas 4 y 5 guardan las direcciones de correo del remitente y del destinatario en sendas variables, mientras que las tres l´ ıneas siguientes definen el mensaje que vamos a enviar. As´ la l´ ı, ınea 6 define las denominadas ˂˂cabeceras˃˃ (˂˂headers˃˃) del correo y son obligatorias en el protocolo SMTP (respetando, adem´s, los saltos de l´ a ınea que puedes apreciar al final de las cadenas). Las dos l´ ıneas siguientes constituyen el mensaje en s´ mismo. Finalmente, la ultima l´ ı ınea se encarga de efectuar el env´ del ıo ´ correo a trav´s de la conexi´n almacenada en servidor y el m´todo sendmail. Eso es todo. e o e Si ejecutamos el programa y tenemos permiso del servidor, al99999@alumail.uji.es recibir´ un correo de al00000@alumail.uji.es con el texto que hemos almacenado en a mensaje. Nuestro programa presentar´ el siguiente aspecto: a spam.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from smtplib import SMTP servidor = SMTP(’alu-mail.uji.es’) remitente = ’al00000@alumail.uji.es’ texto = ’Estimado␣=S␣=A:nn’ texto += ’Por␣la␣presente␣le␣informamos␣de␣que␣nos␣debe␣usted␣la␣’ texto += ’cantidad␣de␣=E␣euros.␣Si␣no␣abona␣dicha␣cantidad␣antes␣’ texto += ’de␣3␣d´as,␣su␣nombre␣pasar´␣a␣nuestra␣lista␣de␣morosos.’ ı a seguir = ’s’ while seguir == ’s’: destinatario = raw_input(’Direcci´n␣del␣destinatario:␣’) o tratamiento = raw_input(’Tratamiento:␣’) apellido = raw_input(’Apellido:␣’) euros = raw_input(’Deuda␣(en␣euros):␣’) mensaje = ’From:␣%snTo:␣%snn’ % (remitente, destinatario) mensaje += texto personalizado servidor.sendmail(remitente, destinatario, mensaje) seguir = raw_input(’Si␣desea␣enviar␣otro␣correo,␣pulse␣’s’:␣’) En la l´ ınea 18 hemos dejado un fragmento de programa por escribir: el que se encarga de personalizar el contenido de texto con los datos que ha introducido el usuario. ¿C´mo o personalizamos el texto? Deber´ ıamos ir copiando los caracteres de texto uno a uno en una variable auxiliar (inicialmente vac´ hasta ver el car´cter ˂˂=˃˃, momento en el que ıa) a deberemos estudiar el siguiente car´cter y, en funci´n de cu´l sea, a˜adir el contenido a o a n de tratamiento, apellido o euros. spam 2.py 1 2 3 4 5 6 7 8 9 10 11 12 13 spam.py from smtplib import SMTP servidor = SMTP(’alu-mail.uji.es’) remitente = ’al00000@alumail.uji.es’ texto = ’Estimado␣=S␣=A:nn’ texto += ’Por␣la␣presente␣le␣informamos␣de␣que␣nos␣debe␣usted␣la␣’ texto += ’cantidad␣de␣=E␣euros.␣Si␣no␣abona␣dicha␣cantidad␣antes␣’ texto += ’de␣3␣d´as,␣su␣nombre␣pasar´␣a␣nuestra␣lista␣de␣morosos.’ ı a seguir = ’s’ while seguir == ’s’: destinatario = raw_input(’Direcci´n␣del␣destinatario:␣’) o tratamiento = raw_input(’Tratamiento:␣’) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 178 178 Introducción a la programación con Python - cUJI UJI
    • 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 apellido euros = raw_input(’Apellido:␣’) = raw_input(’Deuda␣(en␣euros):␣’) mensaje = ’From:␣%snTo:␣%snn’ % (remitente, destinatario) personalizado = ’’ i=0 while i < len(texto): if texto[i] != ’=’: personalizado += texto[i] else: if texto[i+1] == ’A’: personalizado += apellido i=i+1 elif texto[i+1] == ’E’: personalizado += euros i=i+1 elif texto[i+1] == ’S’: personalizado += tratamiento i=i+1 else: personalizado += ’=’ i=i+1 mensaje += personalizado servidor.sendmail(remitente, destinatario, mensaje) seguir = raw_input(’Si␣desea␣enviar␣otro␣correo,␣pulse␣’s’:␣’) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 211 El programa no funcionar´ bien con cualquier carta. Por ejemplo, si la variable a texto vale ’Hola␣=A.␣=’ el programa falla. ¿Por qu´? ¿Sabr´ corregir el programa? e ıas .................................................................................. Buscando texto en cadenas Estudiamos los aspectos fundamentales de las cadenas y montamos ˂˂a mano˃˃ las operaciones m´s sofisticadas. Por ejemplo, hemos estudiado la indexaci´n y la utilizamos, a o en combinaci´n con un bucle, para buscar un car´cter determinado en una cadena. Pero o a esa es una operaci´n muy frecuente, as´ que Python la trae ˂˂de serie˃˃. o ı El m´todo find recibe una cadena y nos dice si ´sta aparece o no en la cadena sobre e e la que se invoca. Si est´, nos devuelve el ´ a ındice de su primera aparici´n. Si no est´, o a devuelve el valor −1. Atenci´n a estos ejemplos: o c = ’Un␣ejemplo␣=A.’ c.find(’=’) ↱ ↱ c.find(’z’) ↱ c.find(’ejem’) ↱ >>> >>> 11 >>> 3 >>> -1 ´ Util, ¿no? Pues hay muchos m´s m´todos que permiten realizar operaciones complejas a e con enorme facilidad. Encontrar´s, entre otros, m´todos para sustituir un fragmento de a e texto por otro, para saber si todos los caracteres son min´sculas (o may´sculas), para u u saber si empieza o acaba con un texto determinado, etc. Cuantos m´s m´todos avanzados a e conozcas, m´s productivo ser´s. ¿Que d´nde encontrar´s la relaci´n de m´todos? En la a a o a o e documentaci´n de Python. Acost´mbrate a manejarla. o u Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 179 179 Introducción a la programación con Python - UJIUJI c
    • 5.1.11. Referencias a cadenas En el apartado 2.4 hemos representado las variables y su contenido con diagramas de cajas. Por ejemplo, las siguientes asignaciones: ↱ ↱ >>> a = 2 >>> b = 3.25 conducen a una disposici´n de la informaci´n en la memoria que mostramos gr´ficamente o o a as´ ı: a 2 b 3.25 Decimos que a apunta al valor 2 y que b apunta al valor 3.25. La flecha recibe el nombre de puntero o referencia. Con las cadenas representaremos los valores desglosando cada uno de sus caracteres en una caja individual con un ´ ındice asociado. El resultado de una asignaci´n como ´sta: o e ↱ >>> c = ’Una␣cadena’ se representar´ del siguiente modo: a 0 c 1 2 3 U n a 4 5 6 7 8 9 c a d e n a Decimos que la variable c apunta a la cadena ’Una␣cadena’, que es una secuencia de caracteres. La cadena vac´ no ocupa ninguna celda de memoria y la representamos gr´ficamente ıa a de un modo especial. Una asignaci´n como ´sta: o e ↱ >>> c = ’’ se representa as´ ı: c Que las variables contengan referencias a los datos y no los propios datos es muy util para aprovechar la memoria del ordenador. El siguiente ejemplo te ilustrar´ el ahorro a ´ que se consigue. ↱ >>> a = ’Una␣cadena’ >>> b = a ↱ Tras ejecutar la primera acci´n tenemos: o 0 a Y despu´s de ejecutar la segunda: e a 1 2 3 U n a 0 1 2 U n a 4 5 6 7 8 9 c a d e n a 3 4 5 6 7 8 9 c a d e n a b Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 180 180 Introducción a la programación con Python - UJI c UJI
    • Las referencias son direcciones de memoria (I) Vamos a darte una interpretaci´n de las referencias que, aunque constituye una simo plificaci´n de la realidad, te permitir´ entender qu´ son. Ya dijimos en el tema 1 que o a e la memoria del computador se compone de una serie de celdas numeradas con sus direcciones. En cada celda cabe un escalar. La cadena ’Hola’ ocupa cuatro celdas, una por cada car´cter. Por otra parte, una variable s´lo puede contener un escalar. Como a o la direcci´n de memoria es un n´mero y, por tanto, un escalar, el ˂˂truco˃˃ consiste en o u almacenar en la variable la direcci´n de memoria en la que empieza la cadena. F´ o ıjate en este ejemplo en el que una variable ocupa la direcci´n de memoria 1001 y ˂˂contiene˃˃ o la cadena ’Hola’: . . . 1000: 1001: 1002: 1003: . . . 2099: 2100: 2101: 2102: 2103: 2104: . . . . a 2100 . . . . . H o l a . . . . . . . . . Como puedes ver, en realidad la cadena ocupa posiciones consecutivas a partir de una direcci´n determinada (en el ejemplo, la 2100) y la variable contiene el valor de o dicha referencia. La flecha de los diagramas hace m´s ˂˂legibles˃˃ las referencias: a 1000: 1001: 1002: 1003: . . . 2099: 2100: 2101: 2102: 2103: 2104: . . . a 2100 . . . H o l a . . . ¡Tanto a como b apuntan a la misma cadena! Al asignar a una variable la cadena contenida en otra unicamente se copia su referencia y no cada uno de los caracteres que la ´ componen. Si se hiciera del segundo modo, la memoria ocupada y el tiempo necesarios para la asignaci´n ser´ tanto mayores cuanto m´s larga fuera la cadena. El m´todo eso ıan a e cogido unicamente copia el valor de la referencia, as´ que es independiente de la longitud ı ´ de la cadena (y pr´cticamente instant´neo). a a Has de tener en cuenta, pues, que una asignaci´n unicamente altera el valor de un o ´ puntero. Pero otras operaciones con cadenas comportan la reserva de nueva memoria. Tomemos por caso el operador de concatenaci´n. La concatenaci´n toma dos cadenas y o o forma una cadena nueva que resulta de unir ambas, es decir, reserva memoria para una nueva cadena. Veamos paso a paso c´mo funciona el proceso con un par de ejemplos. o F´ ıjate en estas sentencias: ↱ ↱ >>> a = ’otra␣’ >>> b = ’cadena’ >>> c = a + b ↱ Podemos representar gr´ficamente el resultado de la ejecuci´n de las dos primeras a o sentencias as´ ı: Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 181 181 Introducción a la programación con Python - UJI c UJI
    • Las referencias son direcciones de memoria (y II) Veamos qu´ ocurre cuando dos variables comparten referencia. El ejemplo que hemos e desarrollado en el texto estudia el efecto de estas dos asignaciones: ↱ >>> a = ’Una␣cadena’ >>> b = a ↱ Como vimos antes, la primera asignaci´n conduce a esta situaci´n: o o . . . . . . 1000: 1001: 1002: 1003: 1004: a 2100 . . . . . . 2099: 2100: 2101: 2102: 2103: 2104: . . . H o l a . . . . . . . . . Pues bien, la segunda asignaci´n copia en la direcci´n de b (que suponemos es la 1002) o o el valor que hay almacenado en la direcci´n de a, es decir, el valor 2100: o 1000: 1001: 1002: 1003: 1004: a b 2100 2100 . . . . . . 2099: 2100: 2101: 2102: 2103: 2104: . H o l a . . . . . Copiar un valor escalar de una posici´n de memoria a otra es una acci´n muy r´pida. o o a 0 a 2 3 4 o t r a 0 b 1 1 2 3 4 5 c a d e n a Analicemos ahora la tercera sentencia. En primer lugar, Python eval´a la expresi´n a + b, u o as´ que reserva un bloque de memoria con espacio para 11 caracteres y copia en ellos ı los caracteres de a seguidos de los caracteres de b: 0 a 2 3 4 o t r a 0 b 1 1 2 3 4 5 c a d e n a 0 1 2 3 4 o t r a 5 6 7 8 9 10 c a d e n a Y ahora que ha creado la nueva cadena, se ejecuta la asignaci´n en s´ es decir, se hace o ı, que c apunte a la nueva cadena: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 182 182 Introducción a la programación con Python - cUJI UJI
    • 0 a 1 2 3 4 o t r a 0 b 1 2 3 4 5 c a d e n a 0 c 1 2 3 4 5 o t r a 6 7 8 9 10 c a d e n a El orden en el que ocurren las cosas tiene importancia para entender c´mo puede o verse afectada la velocidad de ejecuci´n de un programa por ciertas operaciones. Tomemos o por caso estas dos ´rdenes: o ↱ >>> a = ’una␣cadena␣muy␣muy␣muy␣larga’ >>> a = a + ’.’ ↱ A simple vista parece que la primera sentencia ser´ m´s lenta en ejecuci´n que a a o la segunda, pues comporta la reserva de una zona de memoria que puede ser grande (imagina si la cadena tuviera mil o incluso cien mil caracteres), mientras que la segunda sentencia se limita a a˜adir un solo car´cter. Pero no es as´ ambas tardan casi lo mismo. n a ı: Veamos cu´l es la raz´n. La primera sentencia reserva memoria para 28 caracteres, los a o guarda en ella y hace que a apunte a dicha zona: 0 a 1 2 3 4 u n a 5 6 7 8 9 10 11 c a d e n a 12 13 14 15 m u y 16 17 18 19 m u y 20 21 22 23 m u y 24 25 26 27 l a r g a Y ahora veamos paso a paso qu´ ocurre al ejecutar la segunda sentencia. En primer lugar e se eval´a la parte derecha, es decir, se reserva espacio para 29 caracteres y se copian u en ´l los 28 caracteres de a y el car´cter punto: e a 0 a 1 2 3 u n a 0 1 2 4 5 6 7 8 9 10 11 10 11 c a d e n a 3 u n a 4 5 6 7 8 9 12 13 14 15 14 15 m u y c a d e n a 12 13 16 17 18 19 18 19 m u y m u y 16 17 20 21 22 23 22 23 m u y m u y 20 21 24 25 26 27 l a r g a m u y 24 25 26 27 28 l a r g a . Y ahora, al ejecutar la asignaci´n, la variable a pasa de apuntar a la zona de memoria o original para apuntar a la nueva zona de memoria: 0 a 1 2 3 u n a 0 1 2 4 5 6 7 8 9 10 11 10 11 c a d e n a 3 u n a 4 5 6 7 8 9 12 13 14 15 14 15 m u y c a d e n a 12 13 16 17 18 19 18 19 m u y m u y 16 17 20 21 22 23 22 23 m u y m u y 20 21 24 25 26 27 l a r g a m u y 24 25 26 27 28 l a r g a . Como la zona inicial de memoria ya no se usa para nada, Python la ˂˂libera˃˃, es decir, considera que est´ disponible para futuras operaciones, con lo que, a efectos pr´cticos, a a desaparece: a 0 1 2 u n a 3 4 5 6 7 8 9 c a d e n a 10 11 12 13 m u y 14 15 16 17 m u y 18 19 20 21 m u y 22 23 24 25 26 27 28 l a r g a . Como puedes ver, la sentencia que consiste en a˜adir un simple punto a una cadena es n m´s costosa en tiempo que la que comporta una asignaci´n a una variable de esa misma a o cadena. El operador con asignaci´n += act´a exactamente igual con cadenas, as´ que sustituir o u ı la ultima sentencia por a += ’.’ presenta el mismo problema. ´ El operador de corte tambi´n reserva una nueva zona de memoria: e Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 183 183 Introducción a la programación con Python - UJI c UJI
    • ↱ >>> a = ’cadena’ >>> b = a[1:-1] 0 a 2 3 4 5 c a d e n a ↱ 0 b 1 1 2 3 a d e n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 212 Dibuja un diagrama con el estado de la memoria tras ejecutar estas sentencias: ↱ >>> a = ’cadena’ >>> b = a[2:3] >>> c = b + ’’ ↱ ↱ · 213 Dibuja diagramas que muestren el estado de la memoria paso a paso para esta secuencia de asignaciones. ↱ ↱ a = ’ab’ a *= 3 b=a c = a[:] c=c+b ↱ ↱ ↱ >>> >>> >>> >>> >>> ¿Qu´ se mostrar´ por pantalla si imprimimos a, b y c al final? e a .................................................................................. 5.2. Listas El concepto de secuencia es muy potente y no se limita a las cadenas. Python nos permite definir secuencias de valores de cualquier tipo. Por ejemplo, podemos definir secuencias de n´meros enteros o flotantes, o incluso de cadenas. Hablamos entonces de listas. En u una lista podemos, por ejemplo, registrar las notas de los estudiantes de una clase, la evoluci´n de la temperatura hora a hora, los coeficientes de un polinomio, la relaci´n de o o nombres de personas asistentes a una reuni´n, etc. o Python sigue una notaci´n especial para representar las listas. Los valores de una o lista deben estar encerrados entre corchetes y separados por comas. He aqu´ una lista ı con los n´meros del 1 al 3: u ↱ >>> [1, 2, 3] [1, 2, 3] Podemos asignar listas a variables: ↱ >>> a = [1, 2, 3] >>> a [1, 2, 3] ↱ Los elementos que forman una lista tambi´n pueden ser cadenas. e ↱ >>> nombres = [’Juan’, ’Antonia’, ’Luis’, ’Mar´a’] ı Y tambi´n podemos usar expresiones para calcular el valor de cada elemento de una e lista: Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 184 184 c UJI Introducción a la programación con Python - UJI
    • ↱ >>> a = [1, 1+1, 6/2] >>> a [1, 2, 3] ↱ Python almacena las listas del mismo modo que las cadenas: mediante referencias (punteros) a la secuencia de elementos. As´ el ultimo ejemplo hace que la memoria ı, ´ presente un aspecto como el que muestra el siguiente diagrama: 0 a 1 2 1 2 3 La asignaci´n a una variable del contenido de otra variable que almacena una (refeo rencia a una) lista supone la copia de, unicamente, su referencia, as´ que ambas acaban ı ´ apuntando a la misma zona de memoria: ↱ >>> a = [1, 2, 3] >>> b = a 0 ↱ a 1 2 1 2 3 b La lista que contiene un s´lo elemento presenta un aspecto curioso: o ↱ >>> a = [10] >>> b = 10 0 ↱ a 10 b 10 Observa que no es lo mismo [10] que 10. [10] es la lista cuyo unico elemento es el ´ entero 10, y 10 es el entero 10. Gr´ficamente lo hemos destacado enmarcando la lista a y disponiendo encima de la celda su ´ ındice. Si pedimos a Python que nos muestre el contenido de las variables a y b, veremos que la representaci´n de la lista que contiene o un escalar y la del escalar son diferentes: ↱ ↱ >>> print a [10] >>> print b 10 La lista siempre se muestra encerrada entre corchetes. Del mismo modo que hay una cadena vac´ existe tambi´n una lista vac´ La lista ıa, e ıa. vac´ se denota as´ [] y la representamos gr´ficamente como la cadena vac´ ıa ı: a ıa: >>> a = [] ↱ >>> print a [] ↱ a Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 185 185 c UJI Introducción a la programación con Python - UJI
    • 5.2.1. Cosas que, sin darnos cuenta, ya sabemos sobre las listas Una ventaja de Python es que proporciona operadores y funciones similares para trabajar con tipos de datos similares. Las cadenas y las listas tienen algo en com´n: ambas son u secuencias de datos, as´ pues, muchos de los operadores y funciones que trabajan sobre ı cadenas tambi´n lo hacen sobre listas. Por ejemplo, la funci´n len, aplicada sobre una e o lista, nos dice cu´ntos elementos la integran: a ↱ len([0, 1, 10, 5]) ↱ len([10]) ↱ a = [1, 2, 3] len(a) ↱ >>> >>> 3 >>> 4 >>> 1 La longitud de la lista vac´ es 0: ıa ↱ >>> len([]) 0 El operador + concatena listas: ↱ >>> [1, 2] + [3, 4] [1, 2, 3, 4] >>> a = [1, 2, 3] >>> [10, 20] + a [10, 20, 1, 2, 3] ↱ ↱ y el operador * repite un n´mero dado de veces una lista: u ↱ >>> [1, 2] * 3 [1, 2, 1, 2, 1, 2] >>> a = [1, 2, 3] >>> b = [10, 20] + a * 2 >>> b [10, 20, 1, 2, 3, 1, 2, 3] ↱ ↱ ↱ Has de tener en cuenta que tanto + como * generan nuevas listas, sin modificar las originales. Observa este ejemplo: ↱ >>> a = [1, 2, 3] >>> b = a + [4] >>> c = b ↱ ↱ La memoria queda as´ ı: 0 a 2 1 2 3 0 b 1 1 2 3 1 2 3 4 c ¿Ves? La asignaci´n a b deja intacta la lista a porque apunta al resultado de concatenar o algo a a. La operaci´n de concatenaci´n no modifica la lista original: reserva memoria o o para una nueva lista con tantos elementos como resultan de sumar la longitud de las listas concatenadas y, a continuaci´n, copia los elementos de la primera lista seguidos por los o Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 186 186 Introducción a la programación con Python - UJI c UJI
    • de la segunda lista en la nueva zona de memoria. Como asignamos a b el resultado de la concatenaci´n, tenemos que b apunta a la lista reci´n creada. La tercera sentencia es o e una simple asignaci´n a c, as´ que Python se limita a copiar la referencia. o ı El operador de indexaci´n tambi´n es aplicable a las listas: o e a = [1, 2, 3] a[1] ↱ ↱ a[-1] ↱ a[len(a)-1] ↱ >>> >>> 2 >>> 3 >>> 3 A veces, el operador de indexaci´n puede dar lugar a expresiones algo confusas a o primera vista: ↱ >>> [1, 2, 3][0] 1 En este ejemplo, el primer par de corchetes indica el principio y final de la lista (formada por el 1, el 2 y el 3) y el segundo par indica el ´ ındice del elemento al que deseamos acceder (el primero, es decir, el de ´ ındice 0). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 214 ¿Qu´ aparecer´ por pantalla al evaluar la expresi´n [1][0]? ¿Y al evaluar la e a o expresi´n [][0]? o .................................................................................. De todos modos, no te preocupes por esa notaci´n un tanto confusa: lo normal es que o accedas a los elementos de listas que est´n almacenadas en variables, con lo que rara a vez tendr´s dudas. a >>> a = [1, 2, 3] >>> a[0] 1 ↱ a = [1, 2, 3] a[1:-1] ↱ ↱ Tambi´n el operador de corte es aplicable a las listas: e ↱ a[1:] 3] ↱ >>> >>> [2] >>> [2, Has de tener en cuenta que un corte siempre se extrae copiando un fragmento de la lista, por lo que comporta la reserva de memoria para crear una nueva lista. Analiza la siguiente secuencia de acciones y sus efectos sobre la memoria: 0 a 1 2 3 4 1 2 3 4 5 ↱ >>> b = a[1:3] ↱ >>> a = [1, 2, 3, 4, 5] 0 a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 2 3 4 1 2 3 4 5 0 b 1 1 2 3 187 187 Introducción a la programación con Python - UJIUJI c
    • ↱ >>> c = a 0 a 2 3 4 1 2 3 4 5 0 b 1 1 2 3 c ↱ >>> d = a[:] 0 a 2 3 4 1 2 3 4 5 0 b 1 1 2 3 c 0 d 1 2 3 4 1 2 3 4 5 Si deseas asegurarte de que trabajas con una copia de una lista y no con la misma lista (a trav´s de una referencia) utiliza el operador de corte en la asignaci´n. e o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 215 Hemos asignado a x la lista [1, 2, 3] y ahora queremos asignar a y una copia. Podr´ ıamos hacer y = x[:], pero parece que y = x + [] tambi´n funciona. ¿Es as´ ¿Por e ı? qu´? e .................................................................................. El iterador for-in tambi´n recorre los elementos de una lista: e ↱ >>> for i in [1, 2, 3]: ... print i ... 1 2 3 ↱ ↱ De hecho, ya hemos utilizado bucles que iteran sobre listas. Cuando utilizamos un bucle for-in del modo convencional, es decir, haciendo uso de range, estamos recorriendo una lista: ↱ >>> for i in range(1, 4): ... print i ... 1 2 3 ↱ ↱ Y es que range(1, 4) construye y devuelve la lista [1, 2, 3]: ↱ >>> a = range(1, 4) >>> print a [1, 2, 3] ↱ Una forma corriente de construir listas que contienen r´plicas de un mismo valor se e ayuda del operador *. Supongamos que necesitamos una lista de 10 elementos, todos los cuales valen 0. Podemos hacerlo as´ ı: Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 188 188 c UJI Introducción a la programación con Python - UJI
    • ↱ >>> [0] * 10 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 216 ¿Qu´ aparecer´ por pantalla al ejecutar este programa? e a 1 2 3 4 print ’Principio’ for i in []: print ’paso’, i print ’y␣fin’ · 217 ¿Qu´ aparecer´ por pantalla al ejecutar este programa? e a 1 2 for i in [1] * 10: print i .................................................................................. 5.2.2. Comparaci´n de listas o Los operadores de comparaci´n tambi´n trabajan con listas. Parece claro c´mo se como e o portar´n operadores como el de igualdad (==) o el de desigualdad (!=): a si las listas son de talla diferente, resolviendo que las listas son diferentes; y si miden lo mismo, comparando elemento a elemento de izquierda a derecha y resolviendo que las dos listas son iguales si todos sus elementos son iguales, y diferentes si hay alg´n elemento distinto. u Hagamos un par de pruebas con el int´rprete de Python: e ↱ ↱ ↱ >>> [1, 2, 3] == [1, 2] False >>> [1, 2, 3] == [1, 2, 3] True >>> [1, 2, 3] == [1, 2, 4] False Los operadores <, >, <= y >= tambi´n funcionan con listas. ¿C´mo? Del mismo modo e o que con las cadenas, pues al fin y al cabo, tanto cadenas como listas son secuencias. Tomemos, por ejempo, el operador < al comparar las listas [1, 2, 3] y [1, 3, 2], es decir, al evaluar la expresi´n [1, 2, 3] < [1, 3, 2]. Se empieza por comparar los primeros o elementos de ambas listas. Como no es cierto que 1 < 1, pasamos a comparar los respectivos segundos elementos. Como 2 < 3, el resultado es True, sin necesidad de efectuar ninguna comparaci´n adicional. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 218 ¿Sabr´ decir que resultados se mostrar´n al ejecutar estas sentencias? ıas a ↱ [1, 2] < [1, 2] [1, 2, 3] < [1, 2] [1, 1] < [1, 2] [1, 3] < [1, 2] [10, 20, 30] > [1, 2, 3] [10, 20, 3] > [1, 2, 3] [10, 2, 3] > [1, 2, 3] [1, 20, 30] > [1, 2, 3] [0, 2, 3] <= [1, 2, 3] [1] < [2, 3] [1] < [1, 2] [1, 2] < [0] ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ Introducci´n a la programaci´n con Python o o ↱ >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 189 189 c UJI Introducción a la programación con Python - UJI
    • · 219 Dise˜a un programa que tras asignar dos listas a sendas variables nos diga si n la primera es menor que la segunda. No puedes utilizar operadores de comparaci´n entre o listas para implementar el programa. .................................................................................. 5.2.3. El operador is Hemos visto que las listas conllevan una forma de reservar memoria curiosa: en ocasiones, dos variables apuntan a una misma zona de memoria y en ocasiones no, incluso cuando los datos de ambas variables son id´nticos. F´ e ıjate en este ejemplo: ↱ ↱ >>> a = [1, 2, 3] >>> b = [1, 2, 3] >>> c = a ↱ Ya hemos visto que, tras efectuar las asignaciones, la memoria quedar´ as´ a ı: 0 a 2 1 2 3 0 b 1 1 2 1 2 3 c ¿Qu´ ocurre si comparamos entre s´ los diferentes elementos? e ı ↱ ↱ >>> a == b True >>> a == c True Efectivamente: siempre dice que se trata de listas iguales, y es cierto. S´ pero, ¿no ı, son ˂˂m´s iguales˃˃ las listas a y c que las listas a y b? A fin de cuentas, tanto a como a c apuntan exactamente a la misma zona de memoria, mientras que b apunta a una zona distinta. Python dispone de un operador de comparaci´n especial que a´n no te hemos o u presentado: is (en espa˜ol, ˂˂es˃˃). El operador is devuelve True si dos objetos son en n realidad el mismo objeto, es decir, si residen ambos en la misma zona de memoria, y False en caso contrario. ↱ ↱ >>> a is b False >>> a is c True Python reserva nuevos bloques de memoria conforme eval´a expresiones. Observa u este ejemplo: ↱ ↱ ↱ >>> a = [1, 2] >>> a is [1, 2] False >>> a == [1, 2] True La segunda orden compara la lista almacenada en a, que se cre´ al evaluar una o expresi´n en la orden anterior, con la lista [1, 2] que se crea en ese mismo instante, o as´ que is nos dice que ocupan posiciones de memoria diferentes. El operador == sigue ı Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 190 190 Introducción a la programación con Python - UJIUJI c
    • devolviendo el valor True, pues aunque sean objetos diferentes son equivalentes elemento a elemento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 220 ¿Qu´ ocurrir´ al ejecutar estas ´rdenes Python? e a o = [1, 2, 3] is a + [] is a + [] == a ↱ ↱ ↱ a a a a ↱ >>> >>> >>> >>> · 221 Explica, con la ayuda de un gr´fico que represente la memoria, los resultados a de evaluar estas expresiones: ↱ ↱ ↱ >>> a = [1, 2, 1] >>> b = [1, 2, 1] >>> (a[0] is b[0]) and (a[1] is b[1]) and (a[2] is b[2]) True >>> a == b True >>> a is b False ↱ ↱ · 222 ¿Qu´ ocurrir´ al ejecutar estas ´rdenes Python? e a o ↱ ↱ ↱ [1, 2] == [1, 2] [1, 2] is [1, 2] a = [1, 2, 3] b = [a[0], a[1], a[2]] a == b a is b a[0] == b[1] b is [b[0], b[1], b[2]] ↱ ↱ ↱ ↱ ↱ >>> >>> >>> >>> >>> >>> >>> >>> · 223 Que se muestra por pantalla como respuesta a cada una de estas sentencias Python: a = [1, 2, 3, 4, 5] b = a[1:3] c=a d = a[:] a == c a == d c == d a == b a is c a is d c is d a is b ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> .................................................................................. 5.2.4. Modificaci´n de elementos de listas o Hasta el momento hemos aprendido a crear listas y a consultar su contenido, bien accediendo a uno cualquiera de sus elementos (mediante indexaci´n), bien recorriendo todos o sus elementos (con un bucle for-in). En este apartado veremos c´mo modificar el contenido o de las listas. Podemos asignar valores a elementos particulares de una lista gracias al operador de indexaci´n: o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 191 191 Introducción a la programación con Python - UJIUJI c
    • ↱ >>> a = [1, 2, 3] 0 a 2 1 2 3 ↱ >>> a[1] = 10 1 0 a 1 2 1 10 3 ↱ >>> a [1, 10, 3] Cada celda de una lista es, en cierto modo, una variable aut´noma: podemos almacenar o en ella un valor y modificarlo a voluntad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 224 Haz un programa que almacene en una variable a la lista obtenida con range(1,4) y, a continuaci´n, la modifique para que cada componente sea igual al cuadrado o del componente original. El programa mostrar´ la lista resultante por pantalla. a · 225 Haz un programa que almacene en a una lista obtenida con range(1,n), donde n es un entero que se pide al usuario y modifique dicha lista para que cada componente sea igual al cuadrado del componente original. El programa mostrar´ la lista resultante a por pantalla. · 226 Haz un programa que, dada una lista a cualquiera, sustituya cualquier elemento negativo por cero. · 227 ¿Qu´ mostrar´ por pantalla el siguiente programa? e a copias 2.py 1 2 3 4 5 6 7 8 9 10 11 copias.py a = range(0, 5) b = range(0, 5) c=a d = b[:] e=a+b f = b[:1] g = b[0] c[0] = 100 d[0] = 200 e[0] = 300 print a, b, c, d, e, f , g Comprueba con el ordenador la validez de tu respuesta. .................................................................................. 5.2.5. Mutabilidad, inmutabilidad y representaci´n de la informaci´n en meo o moria Python procura no consumir m´s memoria que la necesaria. Ciertos objetos son inmutables, a es decir, no pueden modificar su valor. El n´mero 2 es siempre el n´mero 2. Es un objeto u u inmutable. Python procura almacenar en memoria una sola vez cada valor inmutable. Si dos o m´s variables contienen ese valor, sus referencias apuntan a la misma zona de a memoria. Considera este ejemplo: Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 192 192 c UJI Introducción a la programación con Python - UJI
    • ↱ ↱ >>> a = 1 + 1 >>> b = 2 * 1 La memoria presenta, tras esas asignaciones, este aspecto: a 2 b ¿Y qu´ ocurre cuando modificamos el valor de una variable inmutable? No se modifica el e contenido de la caja que contiene el valor, sino que el correspondiente puntero pasa a apuntar a una caja con el nuevo valor; y si ´sta no existe, se crea. e Si a las asignaciones anteriores le siguen ´stas: e ↱ >>> b = b + 1 la memoria pasa a tener este aspecto: a 2 b 3 Tambi´n las cadenas Python son objetos inmutables2 . Que lo sean tiene efectos sobre e las operaciones que podemos efectuar con ellas. La asignaci´n a un elemento de una o cadena, por ejemplo est´ prohibida, as´ que Python la se˜ala con un ˂˂error de tipo˃˃ a ı n (TypeError): ↱ ↱ >>> a = ’Hola’ >>> a[0] = ’h’ Traceback (innermost last): File "<stdin>", line 1, in ? TypeError: object doesn’t support item assignment Las listas se comportan de forma diferente: a diferencia de las cadenas, son mutables. De momento te hemos proporcionado una representaci´n de las listas excesivamente o simplificada. Hemos representando el resultado de la asignaci´n a = [1, 2, 1] como se o muestra a la izquierda, cuando lo correcto ser´ hacerlo como se muestra a la derecha: ıa a 1 0 2 1 2 1 1 1 0 2 2 a La realidad, como ves, es algo complicada: la lista almacena referencias a los valores, y no los propios valores. Pero a´n no lo has visto todo. ¿Qu´ ocurre tras ejecutar estas u e sentencias? ↱ a = [1, 2, 1] b=1 c = [1, 2, 1] d=c ↱ ↱ ↱ >>> >>> >>> >>> Nada menos que esto: Aunque los ejemplos que hemos presentado con enteros no son directamente trasladables al caso de las cadenas. Aunque parezca parad´jico, Python puede decidir por razones de eficiencia que dos cadenas con o id´ntico contenido se almacenen por duplicado. e 2 Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 193 193 c UJI Introducción a la programación con Python - UJI
    • 0 1 1 2 0 1 2 a b 2 c d Como habr´s observado, para cada aparici´n de un literal de lista, es decir, de una lista a o expresada expl´ ıcitamente, (como [1, 2, 1]), Python ha reservado nueva memoria, aunque exista otra lista de id´ntico valor. As´ pues, a = [1, 2, 1] y c = [1, 2, 1] han generado e ı sendas reservas de memoria y cada variable apunta a una zona de memoria diferente. Como el contenido de cada celda ha resultado ser un valor inmutable (un entero), se han compartido las referencias a los mismos. El operador is nos ayuda a confirmar nuestra hip´tesis: o ↱ ↱ >>> a[0] is b True >>> c[-1] is a[0] True Modifiquemos ahora el contenido de una celda de una de las listas: ↱ >>> d[2] = 3 El resultado es ´ste: e 0 1 2 1 2 3 0 1 2 a b c d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 228 Representa el estado de la memoria tras efectuar cada una de las siguientes asignaciones: ↱ a = [1, 2, 1] b=1 c = [2, 1, 2] d=c d[2] = 3 e = d[:1] f = d[:] f [0] = a[1] f [1] = 1 ↱ ↱ ↱ ↱ ↱ ↱ ↱ ↱ >>> >>> >>> >>> >>> >>> >>> >>> >>> .................................................................................. Aunque los diagramas que hemos mostrado responden a la realidad, usaremos normalmente su versi´n simplificada (y, en cierto modo, ˂˂falsa˃˃), pues es suficiente para el dise˜o o n de la mayor parte de programas que vamos a presentar. Con esta visi´n simplificada, la o ultima figura se representar´ as´ ıa ı: ´ Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 194 194 Introducción a la programación con Python - UJIUJI c
    • 0 1 2 a 1 2 1 b 1 0 1 2 1 2 3 c d 5.2.6. Adici´n de elementos a una lista o Podemos a˜adir elementos a una lista, esto es, hacerla crecer. ¿C´mo? Una idea que n o parece natural, pero que no funciona, es asignar un valor a a[len(a)] (siendo a una variable que contiene una lista), pues de alg´n modo estamos se˜alando una posici´n u n o m´s a la derecha del ultimo elemento. Python nos indicar´ que estamos cometiendo un a a ´ error: ↱ ↱ >>> a = [1, 2, 3] >>> a[len(a)] = 4 Traceback (innermost last): File "<stdin>", line 1, in ? IndexError: list assignment index out of range Una idea mejor consiste en utilizar el operador +: ↱ >>> a = [1, 2, 3] >>> a = a + 4 Traceback (innermost last): File "<stdin>", line 1, in ? TypeError: illegal argument type for built-in operation ↱ Algo ha ido mal. ¡Claro!, el operador de concatenaci´n trabaja con dos listas, no con o una lista y un entero, as´ que el elemento a a˜adir debe formar parte de una lista. . . ı n aunque ´sta s´lo tenga un elemento: e o ↱ >>> a = a + [4] >>> a [1, 2, 3, 4] ↱ Existe otro modo efectivo de a˜adir elementos a una lista: mediante el m´todo append n e (que en ingl´s significa ˂˂a˜adir˃˃). Observa c´mo usamos append: e n o ↱ ↱ a = [1, 2, 3] a.append(4) a 2, 3, 4] ↱ >>> >>> >>> [1, Hay una diferencia fundamental entre usar el operador de concatenaci´n + y usar o append: la concatenaci´n crea una nueva lista copiando los elementos de las listas que o participan como operandos y append modifica la lista original. Observa qu´ ocurre paso e a paso en el siguiente ejemplo: ↱ >>> a = [1, 2, 3] 0 a Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 1 2 1 2 3 195 195 Introducción a la programación con Python - UJI c UJI
    • ↱ >>> b = a + [4] 0 a 1 1 2 3 0 b 1 2 3 1 2 3 4 ↱ >>> c = b 2 0 a 1 2 1 2 3 0 b 1 2 3 1 2 3 4 c ↱ >>> c.append(5) 0 a 2 1 2 3 0 b 1 1 2 3 4 1 2 3 4 5 c ↱ print a 2, 3] print b 2, 3, 4, 5] print c 2, 3, 4, 5] ↱ ↱ >>> [1, >>> [1, >>> [1, ¿Por qu´ complicarse la vida con append, cuando la concatenaci´n hace lo mismo y e o nos asegura trabajar con una copia de la memoria? Por eficiencia: es m´s eficiente hacer a append que concatenar. Concatenar supone crear una lista nueva en la que se copian todos y cada uno de los elementos de las listas concatenadas. Es decir, la concatenaci´n o del siguiente ejemplo supone la copia de 1001 elementos (los 1000 de la lista original y el que a˜adimos): n >>> a = range(1000) >>> a = a + [0] ↱ >>> a = range(1000) >>> a.append(0) ↱ ↱ Sin embargo, el append de este otro ejemplo equivalente trabaja sobre la lista original y le a˜ade una celda cuyo contenido es 0:3 n ↱ En este ejemplo, pues, el append ha resultado unas 1000 veces m´s eficiente que la a concatenaci´n. o Desarrollemos un ejemplo pr´ctico. Vamos a escribir un programa que construya una a lista con todos los n´meros primos entre 1 y n. Como no sabemos a priori cu´ntos hay, u a No siempre es m´s eficiente a˜adir que concatenar. Python puede necesitar memoria para almacenar la a n lista resultante de a˜adir un elemento y, entonces, ha de efectuar una copia del contenido de la lista. Pero n esto supone entrar en demasiado detalle para el nivel de este texto. 3 Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 196 196 c UJI Introducción a la programación con Python - UJI
    • construiremos una lista vac´ e iremos a˜adiendo n´meros primos conforme los vayamos ıa n u encontrando. En el tema anterior ya estudiamos un m´todo para determinar si un n´mero es primo e u o no, as´ que no nos detendremos en volver a explicarlo. ı obten primos.py obten primos.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 n = raw_input(’Introduce␣el␣valor␣m´ximo:␣’) a primos = [] for i in range(1, n+1): # Determinamos si i es primo. creo_que_es_primo = True for divisor in range(2, n): if num % divisor == 0: creo_que_es_primo = False break # Y si es primo, lo a˜adimos a la lista. n if creo_que_es_primo: primos.append(i) print primos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 229 Dise˜a un programa que construya una lista con los n primeros n´meros primos n u (ojo: no los primos entre 1 y n, sino los n primeros n´meros primos). ¿Necesitas usar u append? ¿Puedes reservar en primer lugar un vector con n celdas nulas y asignarle a cada una de ellas uno de los n´meros primos? u .................................................................................. 5.2.7. Lectura de listas por teclado Hasta el momento hemos aprendido a construir listas de diferentes modos, pero nada hemos dicho acerca de c´mo leer listas desde el teclado. La funci´n que lee de teclado o o es raw_input, ¿funcionar´ tambi´n con listas? a e ↱ >>> lista = raw_input(’Dame␣una␣lista:␣’) Dame una lista: [1, 2, 3] >>> lista ’[1, 2, 3]’ ↱ ¿Ha funcionado? No. Lo que se ha le´ es una cadena, no una lista. Se puede advertir ıdo en las comillas que rodean el texto de la respuesta. Podemos cerciorarnos accediendo a su primer elemento: si fuera una lista, valdr´ 1 y si fuera una cadena, ’[’. ıa ↱ >>> lista[0] ’[’ De todos modos, era previsible, pues ya dijimos en su momento que raw_input devolv´ una cadena. Cuando quer´ ıa ıamos obtener, por ejemplo, un entero, ˂˂encerr´bamos˃˃ la a llamada a raw_input con una llamada a la funci´n int y cuando quer´ o ıamos un flotante, con float. ¿Habr´ alguna funci´n similar para obtener listas? Si queremos una lista, lo a o l´gico ser´ utilizar una llamada a list, que en ingl´s significa lista: o ıa e ↱ >>> lista = list(raw_input(’Dame␣una␣lista:␣’)) Dame una lista: [1, 2, 3] >>> lista [’[’, ’1’, ’,’, ’ ’, ’2’, ’,’, ’ ’, ’3’, ’]’] ↱ Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 197 197 Introducción a la programación con Python - UJIUJI c
    • ¡Oh, oh! Tenemos una lista, s´ pero no la que esper´bamos: ı, a 0 lista 1 2 3 4 5 6 7 8 ’[’ ’1’ ’,’ ’ ’ ’2’ ’,’ ’ ’ ’3’ ’]’ La funci´n list devuelve una lista a partir de una cadena, pero cada elemento de la lista o es un car´cter de la cadena (por ejemplo, el 2 que ocupa la posici´n de ´ a o ındice 5 no es el entero 2, sino el car´cter 2). No se interpreta, pues, como hubi´ramos deseado, es decir, a e como esta lista de n´meros enteros: u 0 lista 1 2 1 2 3 Para leer listas deberemos utilizar un m´todo distinto. Lo que haremos es ir leyendo e la lista elemento a elemento y construir la lista paso a paso. Este programa, por ejemplo, lee una lista de 5 enteros: 1 2 3 4 lista = [] for i in range(5): elemento = int(raw_input(’Dame␣un␣elemento:’)) lista = lista + [elemento] Mejor a´n: si usamos append, evitaremos que cada concatenaci´n genere una lista nueva u o copiando los valores de la antigua y a˜adiendo el elemento reci´n le´ n e ıdo. 1 2 3 4 lista = [] for i in range(5): elemento = int(raw_input(’Dame␣un␣elemento:’)) lista.append(elemento) Existe un m´todo alternativo que consiste en crear una lista con 5 celdas y leer e despu´s el valor de cada una: e 1 2 3 lista = [0] * 5 for i in range(5): elemento[i] = int(raw_input(’Dame␣un␣elemento:’)) Supongamos que deseamos leer una lista de enteros positivos cuya longitud es desconocida. ¿C´mo hacerlo? Podemos ir leyendo n´meros y a˜adi´ndolos a la lista hasta que o u n e nos introduzcan un n´mero negativo. El n´mero negativo indicar´ que hemos finalizado, u u a pero no se a˜adir´ a la lista: n a 1 2 3 4 5 lista = [] numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u while numero >= 0: lista.append(numero) numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 230 Dise˜a un programa que lea una lista de 10 enteros, pero asegur´ndose de n a que todos los n´meros introducidos por el usuario son positivos. Cuando un n´mero sea u u negativo, lo indicaremos con un mensaje y permitiremos al usuario repetir el intento cuantas veces sea preciso. · 231 Dise˜a un programa que lea una cadena y muestre por pantalla una lista con n todas sus palabras en min´sculas. La lista devuelta no debe contener palabras repetidas. u Por ejemplo: ante la cadena ’Una␣frase␣formada␣con␣palabras.␣␣Otra␣frase␣con␣otras␣palabras.’, el programa mostrar´ la lista a [’una’, ’frase’, ’formada’, ’con’, ’palabras’, ’otra’, ’otras’]. Observa que en la lista no aparece dos veces la palabra ˂˂frase˃˃, aunque s´ aparec´ dos ı ıa veces en la cadena le´ ıda. .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 198 198 Introducción a la programación con Python - UJIUJI c
    • Lectura de expresiones Python Hemos aprendido a leer enteros, flotantes y cadenas con raw_input, pero esa funci´n o no resulta util para leer listas. Python pone a nuestro alcance otra funci´n de lectura o ´ (input) de datos por teclado capaz de leer expresiones Python, y un literal de lista es una expresi´n. o Estudia estos ejemplos: ↱ ↱ >>> a = input(’Dame␣un␣n´mero:␣’) u Dame un n´mero: 2+2 u >>> a 4 >>> b = input(’Dame␣una␣cadena:␣’) Dame una cadena: ’a’ >>> b ’a’ >>> c = input(’Dame␣una␣lista:␣’) Dame una lista: [1, 1+1, 3] >>> c [1, 2, 3] ↱ ↱ ↱ ↱ ↱ ↱ ↱ A primera vista input parece mucho m´s flexible y util que raw_input, pero presenta a ´ un gran inconveniente: el usuario de tus programas ha de saber programar en Python, ya que las expresiones deben seguir las reglas sint´cticas propias del lenguaje de a programaci´n, y eso no es razonable. De todos modos, input puede resultarte de utilidad o mientras desarrolles borradores de los programas que dise˜es y manejen listas. n 5.2.8. Borrado de elementos de una lista Tambi´n podemos eliminar elementos de una lista. Para ello utilizamos la sentencia del e (abreviatura de ˂˂delete˃˃, que en ingl´s significa borrar). Debes indicar qu´ elemento e e deseas eliminar inmediatamente despu´s de la palabra del: e 0 a 1 2 1 2 3 ↱ >>> del a[1] ↱ >>> a = [1, 2, 3] 0 a 1 1 3 ↱ >>> a [1, 3] La sentencia del no produce una copia de la lista sin la celda borrada, sino que modifica directamente la lista sobre la que opera. F´ ıjate en qu´ efecto produce si dos e variables apuntan a la misma lista: a = [1, 2, 3] b=a del a[1] a 3] b 3] ↱ ↱ ↱ ↱ ↱ >>> >>> >>> >>> [1, >>> [1, Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 199 199 Introducción a la programación con Python - UJI c UJI
    • Las cadenas son inmutables (y III) Recuerda que las cadenas son inmutables. Esta propiedad tambi´n afecta a la posibilidad e de borrar elementos de una cadena: ↱ >>> a = ’Hola’ >>> del a[1] Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: object doesn’t support item deletion ↱ El borrado de elementos de una lista es peligroso cuando se mezcla con el recorrido de las mismas. Ve´moslo con un ejemplo. Hagamos un programa que elimina los elementos a negativos de una lista. solo positivos 5.py 1 2 3 4 5 6 7 a = [1, 2, -1, -4, 5, -2] E solo positivos.py E for i in a: if i < 0: del i print a ¡Mal! Estamos usando del sobre un escalar (i), no sobre un elemento indexado de la lista (que, en todo caso, ser´ a[i]). Este es un error t´ ıa ıpico de principiante. La sentencia del no se usa as´ Vamos con otra versi´n: ı. o solo positivos 6.py 1 2 3 4 5 6 7 a = [1, 2, -1, -4, 5, -2] E solo positivos.py E for i in range(0, len(a)): if a[i] < 0: del a[i] print a Ahora s´ usamos correctamente la sentencia del, pero hay otro problema. Ejecutemos el ı programa: Traceback (most recent call last): File "solo_positivos.py", line 4, in ? if a[i] < 0: IndexError: list index out of range El mensaje de error nos dice que tratamos de acceder a un elemento con ´ ındice fuera del rango de ´ ındices v´lidos. ¿C´mo es posible, si la lista tiene 6 elementos y el ´ a o ındice i toma valores desde 0 hasta 5? Al eliminar el tercer elemento (que es negativo), la lista ha pasado a tener 5 elementos, es decir, el ´ ındice de su ultimo elemento es 4. Pero el bucle ´ ˂˂decidi´˃˃ el rango de ´ o ındices a recorrer antes de borrarse ese elemento, es decir, cuando la lista ten´ el valor 5 como ´ ıa ındice del ultimo elemento. Cuando tratamos de acceder ´ a a[5], Python detecta que estamos fuera del rango v´lido. Es necesario que el bucle a ˂˂actualice˃˃ el valor del ultimo ´ ındice v´lido con cada iteraci´n: a o ´ Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 200 200 Introducción a la programación con Python - UJI c UJI
    • solo positivos 7.py 1 2 3 4 5 6 7 8 9 a = [1, 2, -1, -4, 5, -2] E solo positivos.py E i=0 while i < len(a): if a[i] < 0: del a[i] i += 1 print a Ejecutemos el programa: [1, 2, -4, 5] ¡No ha funcionado! El -4 no ha sido eliminado. ¿Por qu´? Inicialmente la lista era: e 0 1 a 1 2 2 3 4 5 −1 −4 5 −2 Al eliminar el elemento a[2] de la lista original, i val´ 2. ıa 0 1 2 3 4 1 a 2 −4 5 −2 Despu´s del borrado, incrementamos i y eso hizo que la siguiente iteraci´n considerara e o el posible borrado de a[3], pero en ese instante -4 estaba en a[2] (f´ ıjate en la ultima ´ figura), as´ que nos lo ˂˂saltamos˃˃. La soluci´n es sencilla: s´lo hemos de incrementar i ı o o en las iteraciones que no producen borrado alguno: solo positivos 8.py 1 2 3 4 5 6 7 8 9 10 solo positivos.py a = [1, 2, -1, -4, 5, -2] i=0 while i < len(a): if a[i] < 0: del a[i] else: i += 1 print a Ejecutemos el programa: [1, 2, 5] ¡Ahora s´ ı! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 232 ¿Qu´ sale por pantalla al ejecutar este programa?: e 1 2 3 4 a = range(0, 5) del a[1] del a[1] print a · 233 Dise˜a un programa que elimine de una lista todos los elementos de ´ n ındice par y muestre por pantalla el resultado. (Ejemplo: si trabaja con la lista [1, 2, 1, 5, 0, 3], ´sta pasar´ a ser [2, 5, 3].) e a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 201 201 Introducción a la programación con Python - UJIUJI c
    • · 234 Dise˜a un programa que elimine de una lista todos los elementos de valor par n y muestre por pantalla el resultado. (Ejemplo: si trabaja con la lista [1, -2, 1, -5, 0, 3], ´sta pasar´ a ser [1, 1, -5, 3].) e a · 235 A nuestro programador novato se le ha ocurrido esta otra forma de eliminar el elemento de ´ ındice i de una lista a: 1 a = a[:i] + a[i+1:] ¿Funciona? Si no es as´ ¿por qu´? Y si funciona correctamente, ¿qu´ diferencia hay con ı, e e respecto a usar del a[i]? .................................................................................. La sentencia del tambi´n funciona sobre cortes: e a = [1, 2, 3, 4, 5, 6] del a[2:4] a 2, 5, 6] ↱ ↱ 5.2.9. ↱ >>> >>> >>> [1, Pertenencia de un elemento a una lista Dise˜emos un programa que, dados un elemento y una lista, nos diga si el elemento pern tenece o no a la lista mostrando en pantalla el mensaje ˂˂Pertenece˃˃ o ˂˂No pertenece˃˃ en funci´n del resultado. o pertenencia 5.py 1 2 3 4 5 6 7 8 9 10 11 12 13 pertenencia.py elemento = 5 lista = [1, 4, 5, 1, 3, 8] pertenece = False for i in lista: if elemento == i: pertenece = True break if pertenece: print ’Pertenece’ else: print ’No␣pertenece’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 236 ¿Por qu´ este otro programa es err´neo? e o pertenencia 6.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 elemento = 5 lista = [1, 4, 5, 1, 3, 8] E pertenencia.py E for i in lista: if elemento == i: pertenece = True else: pertenece = False break if pertenece: print ’Pertenece’ else: print ’No␣pertenece’ Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 202 202 Introducción a la programación con Python - UJIUJI c
    • .................................................................................. La pregunta de si un elemento pertenece o no a una lista es tan frecuente que Python nos proporciona un operador predefinido que hace eso mismo. El operador es binario y se denota con la palabra in (que en ingl´s significa ˂˂en˃˃ o ˂˂pertenece a˃˃). El operador e in recibe un elemento por su parte izquierda y una lista por su parte derecha y devuelve cierto o falso. No necesitamos, pues, definir la funci´n pertenece. Un programa que o necesita determinar si un elemento pertenece o no a una lista y actuar en consecuencia puede hacerlo as´ ı: pertenencia.py pertenencia 7.py 1 2 3 4 conjunto = [1, 2, 3] elemento = int(raw_input(’Dame␣un␣n´mero:␣’)) u if not elemento in conjunto : conjunto.append(elemento) O, equivalentemente: pertenencia 8.py 1 2 3 4 pertenencia.py conjunto = [1, 2, 3] elemento = int(raw_input(’Dame␣un␣n´mero:␣’)) u if elemento not in conjunto: conjunto.append(elemento) El operador ˂˂not in˃˃ es el operador in negado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 237 ¿Qu´ hace este programa? e 1 2 3 letra = raw_input(’Dame␣una␣letra:␣’) if (len(letra) == 1 and ’a’<=letra <=’z’) or letra in [’´’,’´’,’´’,’´’,’´’,’¨’,’˜’]: a e ı o u u n print letra, ’es␣una␣letra␣min´scula’ u · 238 ¿Qu´ hace este programa? e 1 2 3 letra = raw_input(’Dame␣una␣letra:␣’) if len(letra) == 1 and (’a’<= letra <=’z’ or letra in ’´´´´´¨˜’): aeıouun print letra, ’es␣una␣letra␣min´scula’ u .................................................................................. Ya te hemos dicho que Python ofrece funcionalidades similares entre tipos de datos similares. Si el operador in funciona con listas, ¿funcionar´ con cadenas, que tambi´n son a e 4: secuencias? S´ El operador in comprueba si una cadena forma parte o no de otra ı. ↱ ↱ 5.2.10. ↱ >>> ’a’ in ’cadena’ True >>> ’ade’ in ’cadena’ True >>> ’ada’ in ’cadena’ False Ordenaci´n de una lista o En este apartado nos ocuparemos de un problema cl´sico: ordenar (de menor a mayor) los a elementos de una lista de valores. La ordenaci´n es muy util en infinidad de aplicaciones, o ´ as´ que se ha puesto mucho empe˜o en estudiar algoritmos de ordenaci´n eficientes. De ı n o momento estudiaremos unicamente un m´todo muy sencillo (e ineficiente): el m´todo de la e e ´ burbuja. Trataremos de entender bien en qu´ consiste mediante un ejemplo. Supongamos e que deseamos ordenar (de menor a mayor) la lista [2, 26, 4, 3, 1], es decir, hacer que pase a ser [1, 2, 3, 4, 26]. Se procede del siguiente modo: 4 Este comportamiento s´lo se da desde la versi´n 2.3 de Python. Versiones anteriores s´lo aceptaban o o o que, si ambos operandos eran cadenas, el operador izquierdo fuera de longitud 1. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 203 203 Introducción a la programación con Python - UJIUJI c
    • 0 1 2 3 4 2 26 4 3 1 Z Z Empezamos por comparar los dos primeros elementos (a[0] y a[1]). Si est´n a ordenados, los dejamos tal cual; si no, los intercambiamos. En nuestro caso ya est´n ordenados. a 0 1 2 3 4 2 26 4 3 1 Z Z Ahora comparamos los dos siguientes (a[1] y a[2]) y hacemos lo mismo. 0 1 2 3 4 2 4 26 3 1 Z Z En este caso no est´n ordenados, as´ que los intercambiamos y la lista queda as´ a ı ı: 0 1 2 3 4 2 4 26 3 1 Z Z Ahora comparamos los dos siguientes (a[2] y a[3]) y hacemos lo mismo. 0 1 2 3 4 2 4 3 26 1 Z Z En este caso tampoco est´n ordenados, as´ que los intercambiamos y la lista queda a ı as´ ı: 0 1 2 3 4 2 4 3 26 1 Z Z Ahora comparamos los dos siguientes (a[3] y a[4]), que son los ultimos. ´ En este caso tampoco est´n ordenados, as´ que los intercambiamos y la lista queda a ı as´ ı: 1 2 3 4 2 4 3 1 26 Z Z 0 La lista a´n no est´ ordenada, pero f´ u a ıjate en qu´ ha ocurrido con el elemento m´s e a grande del conjunto: ya est´ a la derecha del todo, que es el lugar que le corresponde a definitivamente. 0 1 2 3 4 2 4 3 1 26 © Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 204 204 Introducción a la programación con Python - cUJI UJI
    • La importancia de ordenar r´pidamente a Ordenar el contenido de una lista es un problema importante porque se plantea en numerosos campos de aplicaci´n de la programaci´n: la propia palabra ˂˂ordenador˃˃ lo o o pone de manifiesto. Ordenar es, quiz´, el problema m´s estudiado y para el que existe a a mayor n´mero de soluciones diferentes, cada una con sus ventajas e inconvenientes o u especialmente adaptada para tratar casos particulares. Podemos citar aqu´ a Donald E. Knuth en el tercer volumen (˂˂Sorting and searı ching˃˃) de ˂˂The art of computer programming˃˃, un texto cl´sico de programaci´n: ˂˂Los a o fabricantes de ordenadores de los a˜os 60 estimaron que m´s del 25 por ciento del n a tiempo de ejecuci´n en sus ordenadores se dedicaba a ordenar cuando consideraban o al conjunto de sus clientes. De hecho, hab´ muchas instalaciones en las que la tarea ıa de ordenar era responsable de m´s de la mitad del tiempo de computaci´n. De estas a o estad´ ısticas podemos concluir que (i) la ordenaci´n cuenta con muchas aplicaciones o importantes, (ii) mucha gente ordena cuando no debiera, o (iii) se usan com´nmente u algoritmos de ordenaci´n ineficientes.˃˃ o Desde que hemos examinado ese valor, cada paso del procedimiento lo ha movido una posici´n a la derecha. De hecho, el nombre de este procedimiento de ordenaci´n (m´todo o o e de la burbuja) toma el nombre del comportamiento que hemos observado. Es como si las burbujas en un medio l´ ıquido subieran hacia la superficie del mismo: las m´s grandes a alcanzar´n el nivel m´s pr´ximo a la superficie y lo har´n r´pidamente. a a o a a Ahora s´lo es preciso ordenar los 4 primeros elementos de la lista, as´ que aplicamos o ı el mismo procedimiento a esa ˂˂sublista˃˃: 0 1 2 3 4 2 4 3 1 Z Z Empezamos por comparar los dos primeros elementos (a[0] y a[1]). Si est´n a ordenados, los dejamos tal cual; si no, los intercambiamos. 26 © En nuestro caso ya est´n ordenados. a 0 1 2 3 4 2 4 3 1 Z Z Ahora comparamos los dos siguientes (a[1] y a[2]) y hacemos lo mismo. 26 © 0 1 2 3 4 2 3 4 1 Z Z En este caso no est´n ordenados, as´ que los intercambiamos y la lista queda as´ a ı ı: 26 © 0 1 2 3 4 2 3 4 1 Z Z Ahora comparamos los dos siguientes (a[2] y a[3]) y hacemos lo mismo. 26 © En este caso tampoco est´n ordenados, as´ que los intercambiamos y la lista queda a ı as´ ı: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 205 205 Introducción a la programación con Python - cUJI UJI
    • 0 1 2 3 4 2 3 1 4 Z Z 26 © Ahora resulta que el segundo mayor elemento ya est´ en su posici´n definitiva. Parece a o que cada vez que recorremos la lista, al menos un elemento se ubica en su posici´n o definitiva: el mayor de los que a´n estaban por ordenar. u A ver qu´ ocurre en el siguiente recorrido (que se limitar´ a la ˂˂sublista˃˃ de los tres e a primeros elementos, pues los otros dos ya est´n bien puestos): a 0 1 2 3 4 2 3 1 Z Z Empezamos por comparar los dos primeros elementos (a[0] y a[1]). Si est´n a ordenados, los dejamos tal cual; si no, los intercambiamos. 4 © 26 © En nuestro caso ya est´n ordenados. a 0 1 2 3 4 2 3 1 Z Z Ahora comparamos los dos siguientes (a[1] y a[2]) y hacemos lo mismo. 4 © 26 © 0 1 2 3 4 2 1 3 Z Z En este caso no est´n ordenados, as´ que los intercambiamos y la lista queda as´ a ı ı: 4 © 26 © Parece que nuestra hip´tesis es cierta. A´n nos falta un poco para acabar: o u 0 1 2 3 4 2 1 Z Z Comparamos los dos primeros elementos (a[0] y a[1]). Si est´n ordenados, los a dejamos tal cual; si no, los intercambiamos. 3 © 4 © 26 © No est´n ordenados, as´ que los intercambiamos. La lista queda, finalmente, as´ a ı ı: 2 3 4 1 2 3 © 4 © 26 © Z 1 Z 0 Perfecto: la lista ha quedado completamente ordenada. 0 1 2 3 4 1 © 2 © 3 © 4 © 26 © Recapitulemos: para ordenar una lista de n elementos hemos de hacer n − 1 pasadas. En cada pasada conseguimos poner al menos un elemento en su posici´n: el mayor. o (Hacen falta n − 1 y no n porque la ultima pasada nos pone dos elementos en su sitio: ´ el mayor va a la segunda posici´n y el menor se queda en el unico sitio que queda: la o ´ primera celda de la lista.) Intentemos codificar esa idea en Python: Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 206 206 Introducción a la programación con Python - cUJI UJI
    • burbuja.py 1 2 3 4 5 6 lista = [2, 26, 4, 3, 1] for i in range(1, len(lista)): # Bucle que hace len(lista)-1 pasadas. hacer una pasada print lista ¿En qu´ consiste la i-´sima pasada? En explorar todos los pares de celdas contiguas, e e desde el primero hasta el ultimo. En cada paso comparamos un par de elementos: ´ burbuja.py 1 2 3 4 5 6 7 lista = [2, 26, 4, 3, 1] for i in range(1, len(lista)): for j in range(0, len(lista)-i): comparar lista[j] y lista[j+1] y, si procede, intercambiarlos print lista Lo que queda deber´ ser f´cil: ıa a burbuja.py 1 2 3 4 5 6 7 8 9 10 burbuja.py lista = [2, 26, 4, 3, 1] for i in range(1, len(lista)): for j in range(0, len(lista)-i): if lista[j] > lista[j+1]: elemento = lista[j] lista[j] = lista[j+1] lista[j+1] = elemento print lista ¡Buf! ¿Estar´ bien? He aqu´ el resultado de ejecutar el programa: a ı [1, 2, 3, 4, 26] ¡S´ Pero, ¿estar´ bien con seguridad? Para tener una certeza mayor, vamos a modificar ı! a el programa para que nos diga por pantalla qu´ hace en cada instante: e burbuja 2.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 burbuja.py lista = [2, 26, 4, 3, 1] for i in range(1, len(lista)): print ’Pasada’, i for j in range(0, len(lista)-i): print ’␣␣Comparaci´n␣de␣los␣elementos␣en␣posici´n␣%d␣y␣%d’ % (j, j+1) o o if lista[j] > lista[j+1]: elemento = lista[j] lista[j] = lista[j+1] lista[j+1] = elemento print ’␣␣Se␣intercambian’ print ’␣␣Estado␣actual␣de␣la␣lista’, lista print lista Probemos de nuevo: Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 207 207 Introducción a la programación con Python - UJI c UJI
    • Pasada 1 Comparaci´n de los elementos en posici´n 0 o o Estado actual de la lista [2, 26, 4, 3, 1] Comparaci´n de los elementos en posici´n 1 o o Se intercambian Estado actual de la lista [2, 4, 26, 3, 1] Comparaci´n de los elementos en posici´n 2 o o Se intercambian Estado actual de la lista [2, 4, 3, 26, 1] Comparaci´n de los elementos en posici´n 3 o o Se intercambian Estado actual de la lista [2, 4, 3, 1, 26] Pasada 2 Comparaci´n de los elementos en posici´n 0 o o Estado actual de la lista [2, 4, 3, 1, 26] Comparaci´n de los elementos en posici´n 1 o o Se intercambian Estado actual de la lista [2, 3, 4, 1, 26] Comparaci´n de los elementos en posici´n 2 o o Se intercambian Estado actual de la lista [2, 3, 1, 4, 26] Pasada 3 Comparaci´n de los elementos en posici´n 0 o o Estado actual de la lista [2, 3, 1, 4, 26] Comparaci´n de los elementos en posici´n 1 o o Se intercambian Estado actual de la lista [2, 1, 3, 4, 26] Pasada 4 Comparaci´n de los elementos en posici´n 0 o o Se intercambian Estado actual de la lista [1, 2, 3, 4, 26] [1, 2, 3, 4, 26] y 1 y 2 y 3 y 4 y 1 y 2 y 3 y 1 y 2 y 1 Bueno, seguros de que est´ bien no estamos, pero al menos s´ parece hacer lo que e ı toca. Ya podemos eliminar las sentencias print que hemos introducido en el programa para hacer esta traza autom´tica. Mostrar los mensajes que informan de por d´nde pasa a o el flujo de ejecuci´n de un programa y del contenido de algunas de sus variables es o un truco frecuentemente utilizado por los programadores para ver si un programa hace lo que debe y, cuando el programa tiene errores, detectarlos y corregirlos. Por supuesto, una vez nos hemos asegurado de que el programa funciona, hemos de eliminar las sentencias adicionales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 239 ¿Qu´ ocurrir´ si sustituimos la primera l´ e a ınea de burbuja.py por esta otra?: 1 lista = [’Pepe’, ’Juan’, ’Mar´a’, ’Ana’, ’Luis’, ’Pedro’] ı .................................................................................. 5.3. De cadenas a listas y viceversa En muchas ocasiones nos encontraremos convirtiendo cadenas en listas y viceversa. Python nos ofrece una serie de utilidades que conviene conocer si queremos ahorrarnos muchas horas de programaci´n. o Una acci´n frecuente consiste en obtener una lista con todas las palabras de una o cadena. He aqu´ c´mo puedes hacerlo: ı o Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 208 208 c UJI Introducción a la programación con Python - UJI
    • Depuraci´n y correcci´n de programas o o Es muy frecuente que un programa no se escriba bien a la primera. Por regla general, gran parte del tiempo de programaci´n se dedica a buscar y corregir errores. Esta activio dad se denomina depurar el c´digo (en ingl´s, ˂˂debugging˃˃, que significa ˂˂desinsectar˃˃). o e Existen herramientas de ayuda a la depuraci´n: los depuradores (en ingl´s, debuggers). o e Un depurador permite ejecutar paso a paso un programa bajo el control del programador, y consultar en cualquier instante el valor de las variables. Pero con la ayuda de un buen depurador nunca podemos estar seguros de que un programa est´ bien. Cuando un programa aborta su ejecuci´n o deja colgado al e o ordenador es evidente que hay un error, pero, ¿c´mo podemos estar seguros de que un o programa que, de momento, parece funcionar bien, lo har´ siempre? ¿Y si tiene un error a tan sutil que s´lo se manifiesta ante una entrada muy particular? Por extra˜a que sea esa o n entrada, cabe la posibilidad de que el programa se enfrente a ella durante su utilizaci´n o por parte de los usuarios. Y cuando eso ocurra, el programa abortar´ su ejecuci´n o, a o peor a´n, ofrecer´ resultados mal calculados como si fueran buenos. Asusta pensar que u a de ese programa puedan depender vidas humanas, cosa que ocurre en no pocos casos (programas para el c´lculo de estructuras en edificaciones, para el lanzamiento y guiado a de naves espaciales, para el control de centrales nucleares, etc.) Existe una serie de t´cnicas matem´ticas para demostrar que un programa hace lo e a que se le pide. Bajo ese enfoque, demostrar que un programa es correcto equivale a demostrar un teorema. ↱ >>> ’uno␣dos␣tres’.split() [’uno’, ’dos’, ’tres’] En ingl´s ˂˂split˃˃ significa ˂˂partir˃˃. ¿Funcionar´ con textos ˂˂maliciosos˃˃, es decir, con e a espacios en blanco al inicio, al final o repetidos? ↱ >>> ’␣␣␣uno␣␣dos␣tres␣␣’.split() [’uno’, ’dos’, ’tres’] S´ Fant´stico. ¿Recuerdas los quebraderos de cabeza que supuso contar el n´mero ı. a u de palabras de una frase? Mira c´mo se puede calcular con la ayuda de split: o ↱ >>> len(’␣␣␣uno␣␣dos␣tres␣␣’.split()) 3 El m´todo split acepta un argumento opcional: el car´cter ˂˂divisor˃˃, que por defecto e a es el espacio en blanco: ↱ >>> ’uno:dos␣tres:cuatro’.split(’:’) [’uno’, ’dos tres’, ’cuatro’] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 240 En una cadena llamada texto disponemos de un texto formado por varias frases. ¿Con qu´ orden simple puedes contar el n´mero de frases? e u · 241 En una cadena llamada texto disponemos de un texto formado por varias frases. Escribe un programa que determine y muestre el n´mero de palabras de cada frase. u .................................................................................. Hay un m´todo que hace lo contrario: une las cadenas de una lista en una sola e cadena. Su nombre es join (que en ingl´s significa ˂˂unir˃˃) y se usa as´ e ı: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 209 209 Introducción a la programación con Python - UJIUJI c
    • Pickle Con lo aprendido hasta el momento ya puedes hacer algunos programas interesantes. Puedes ir anotando en una lista ciertos datos de inter´s, como los apuntes de una e cuenta bancaria (serie de flotantes positivos o negativos para ingresos y reintegros, respectivamente). El problema estriba en que tu programa deber´ leer la lista ¡cada vez a que se ejecute! No es una forma natural de funcionar. Te vamos a ense˜ar una t´cnica que te permite guardar una lista en el disco duro y n e recuperarla cuando quieras. Tu programa podr´ empezar a ejecutarse leyendo la lista ıa del disco duro y, justo antes de acabar la ejecuci´n, guardar nuevamente la lista en el o disco duro. El m´dulo pickle permite guardar/cargar estructuras de datos Python. Vemos un o ejemplo: guardar.py 1 2 3 4 5 6 guardar.py import pickle # Creamos una lista ... lista = [1, 2, 3, 4] # y ahora la guardamos en un fichero llamado mifichero.mio. pickle.dump(lista, open(’mifichero.mio’, ’w’)) Al ejecutar ese programa, se crea un fichero cuyo contenido es la lista. Este otro programa leer´ la misma lista: ıa cargar.py 1 2 3 4 5 6 cargar.py import pickle # Leemos la lista carg´ndola del fichero mifichero.mio... a lista = pickle.load(open(’mifichero.mio’)) # y la mostramos por pantalla. print lista Nos hemos anticipado un poco al tema dedicado a la gesti´n de ficheros, pero de o este modo te estamos capacitando para que hagas programas que pueden ˂˂recordar˃˃ informaci´n entre diferentes ejecuciones. Si quieres saber m´s, lee la documentaci´n del o a o m´dulo pickle. ¡Que lo disfrutes! o ↱ >>> ’␣’.join([’uno’, ’dos’, ’tres’]) ’uno dos tres’ >>> ’:’.join([’uno’, ’dos’, ’tres’]) ’uno:dos:tres’ >>> ’---’.join([’uno’, ’dos’, ’tres’]) ’uno---dos---tres’ ↱ ↱ ¿Ves? Se usa una cadena a mano izquierda del punto y se suministra una lista como argumento. El resultado es una cadena formada por los elementos de la lista separados entre s´ por la cadena a mano izquierda. ı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 242 ¿Qu´ resulta de ejecutar esta orden? e ↱ >>> print ’’.join([’uno’, ’dos’, ’tres’]) · 243 Disponemos de una cadena que contiene una frase cuyas palabras est´n separaa das por un n´mero arbitrario de espacios en blanco. ¿Podr´ ˂˂estandarizar˃˃ la separaci´n u ıas o de palabras en una sola l´ ınea Python? Por estandarizar queremos decir que la cadena no Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 210 210 Introducción a la programación con Python - UJIUJI c
    • empiece ni acabe con espacios en blanco y que cada palabra se separe de la siguiente por un unico espacio en blanco. ´ .................................................................................. Hay, adem´s, una funci´n predefinida que permite convertir una cadena en una lista: a o list. La funci´n list devuelve una lista formada por los caracteres individuales de la cadena: o ↱ >>> list(’cadena’) [’c’, ’a’, ’d’, ’e’, ’n’, ’a’] Los m´todos join y split son insustituibles en la caja de herramientas de un prograe mador Python. Acost´mbrate a utilizarlos. u 5.4. Matrices Las matrices son disposiciones bidimensionales de valores. En notaci´n matem´tica, una o a matriz se denota encerrando entre par´ntesis los valores, que se disponen en filas y e columnas. He aqu´ una matriz M: ı   1 2 3  2 12 6   M=  1 0 −3  0 −1 0 Esta matriz tiene 4 filas y 3 columnas, lo cual abreviamos diciendo que es una matriz de dimensi´n 4 × 3. o Las listas permiten representar series de datos en una sola dimensi´n. Con una lista o de n´meros no se puede representar directamente una matriz, pero s´ con una lista de u ı listas. ↱ >>> M = [ [1, 2, 3], [2, 12, 6], [1, 0, -3], [0, -1, 0] ] 2 3 0 1 2 12 6 0 1 2 0 0 1 −3 0 3 2 1 2 1 2 1 0 1 0 M −1 2 0 En la notaci´n matem´tica el elemento que ocupa la fila i-´sima y la columna j-´sima o a e e de una matriz M se representa con Mi,j . Por ejemplo, el elemento de una matriz que ocupa la celda de la fila 1 y la columna 2 se denota con M1,2 . Pero si deseamos acceder a ese elemento en la matriz Python M, hemos de tener en cuenta que Python siempre cuenta desde cero, as´ que la fila tendr´ ´ ı a ındice 0 y la columna tendr´ ´ a ındice 1: ↱ >>> M[0][1] 2 Observa que utilizamos una doble indexaci´n para acceder a elementos de la matriz. o ¿Por qu´? El primer ´ e ındice aplicado sobre M devuelve un componente de M, que es una lista: ↱ >>> M[0] [1, 2, 3] Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 211 211 Introducción a la programación con Python - UJI c UJI
    • Y el segundo ´ ındice accede a un elemento de esa lista, que es un entero: ↱ >>> M[0][0] 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 244 Una matriz nula es aquella que s´lo contiene ceros. Construye una matriz nula o de 5 filas y 5 columnas. · 245 Una matriz identidad es aquella cuyos elementos en la diagonal principal, es decir, accesibles con una expresi´n de la forma M[i][i], valen uno y el resto valen cero. o Construye una matriz identidad de 4 filas y 4 columnas. · 246 ¿Qu´ resulta de ejecutar este programa? e 1 2 3 4 5 6 7 8 9 10 M = [ [1, 0, 0], [0, 1, 0], [0, 0, 1] ] print M[-1][0] print M[-1][-1] print ’--’ for i in range(0, 3): print M[i] print ’--’ for i in range(0, 3): for j in range(0, 3): print M[i][j] · 247 ¿Qu´ resulta de ejecutar este programa? e 1 2 3 4 5 6 M = [ [1, 0, 0], [0, 1, 0], [0, 0, 1] ] s = 0.0 for i in range(0, 3): for j in range(0, 3): s += M[i][j] print s / 9.0 .................................................................................. 5.4.1. Sobre la creaci´n de matrices o Crear una matriz consiste, pues, en crear una lista de listas. Si deseamos crear una matriz nula (una matriz cuyos componentes sean todos igual a 0) de tama˜o 2 × 2, bastar´ con n a escribir: ↱ >>> m = [ [0, 0], [0, 0] ] Parece sencillo, pero ¿y si nos piden una matriz nula de 6 × 6? Tiene 36 componentes y escribirlos expl´ ıcitamente resulta muy tedioso. ¡Y pensemos en lo inviable de definir as´ ı una matriz de dimensi´n 10 × 10 o 100 × 100! o Recuerda que hay una forma de crear listas (vectores) de cualquier tama˜o, siempre n que tengan el mismo valor, utilizando el operador *: ↱ >>> a = [0] * 6 >>> a [0, 0, 0, 0, 0, 0] ↱ Si una matriz es una lista de listas, ¿qu´ ocurrir´ si creamos una lista con 3 duplicados e a de la lista a? ↱ >>> [a] * 3 [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 212 212 Introducción a la programación con Python - UJIUJI c
    • ¡Estupendo! Ya tenemos una matriz nula de 3 × 6. Trabajemos con ella: ↱ ↱ ↱ >>> a = [0] * 6 >>> M = [a] * 3 >>> M[0][0] = 1 >>> print M [[1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0]] ↱ ¿Qu´ ha ocurrido? ¡No se ha modificado unicamente el componente 0 de la primera e ´ lista, sino todos los componentes 0 de todas las listas de la matriz! Vamos paso a paso. Primero hemos creado a: ↱ >>> a = [0] * 6 0 1 2 3 4 5 0 a 0 0 0 0 0 A continuaci´n hemos definido la lista M como la copia por triplicado de la lista a: o ↱ >>> M = [a] * 3 Python nos ha obedecido copiando tres veces. . . ¡la referencia a dicha lista!: 0 2 3 4 5 0 a 1 0 0 0 0 0 0 M 1 2 Y hemos modificado el elemento M[0][0] asign´ndole el valor 1: a ↱ >>> M[0][0] = 1 as´ que hemos modificado tambi´n M[1][0] y M[2][0], pues son el mismo elemento: ı e 0 1 2 3 4 5 1 a 0 0 0 0 0 0 M 1 2 Por la misma raz´n, tampoco funcionar´ este modo m´s directo de crear una matriz: o a a ↱ >>> M = [ [0] * 6 ] * 3 M 0 1 2 3 4 5 0 0 0 0 0 0 0 1 2 Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 213 213 Introducción a la programación con Python - UJI c UJI
    • Hay que construir matrices con m´s cuidado, asegur´ndonos de que cada fila es una a a lista diferente de las anteriores. Intent´moslo de nuevo: e ↱ >>> M = [] >>> for i in range(3): ... a = [0] * 6 ... M.append( a ) ... >>> print M [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] ↱ ↱ ↱ ↱ ↱ La lista creada en la asignaci´n a = [0] * 6 es diferente con cada iteraci´n, as´ que o o ı estamos a˜adiendo a M una lista nueva cada vez. La memoria queda as´ n ı: 2 2 3 4 5 0 0 0 0 0 0 1 2 3 4 5 0 0 0 0 0 0 1 2 3 4 5 0 1 1 0 M 0 0 0 0 0 0 0 0 Lo cierto es que no es necesario utilizar la variable auxiliar a: ↱ >>> M = [] >>> for i in range(3): ... M.append( [0] * 6 ) ... >>> print M [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] >>> M[0][0] = 1 >>> print M [[1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] ↱ ↱ ↱ ↱ ↱ ↱ 2 2 3 4 5 0 0 0 0 0 0 1 2 3 4 5 0 0 0 0 0 0 1 2 3 4 5 0 1 1 0 M 0 1 0 0 0 0 0 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 248 Crea la siguiente matriz utilizando la t´cnica del bucle descrita anteriormente. e   1 0 0 0  0 1 0 0     0 0 1 0  0 0 0 1 · 249 Haz un programa que pida un entero positivo n y almacene en una variable M la matriz identidad de n × n (la que tiene unos en la diagonal principal y ceros en el resto de celdas). .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 214 214 Introducción a la programación con Python - UJIUJI c
    • 5.4.2. Lectura de matrices Si deseamos leer una matriz de tama˜o determinado, podemos crear una matriz nula n como hemos visto en el apartado anterior y, a continuaci´n, rellenar cada uno de sus o componentes: matrices.py matrices.py 1 2 3 4 5 6 7 8 9 10 11 12 13 # Pedimos la dimensi´n de la matriz, o m = int(raw_input(’Dime␣el␣n´mero␣de␣filas:␣’)) u n = int(raw_input(’Dime␣el␣n´mero␣de␣columnas:␣’)) u # Creamos una matriz nula... M = [] for i in range(m): M.append( [0] * n ) # ... y leemos su contenido de teclado for i in range(m): for j in range(n): M[i][j] = float(raw_input(’Dame␣el␣componente␣(%d,%d):␣’ % (i, j))) 5.4.3. ¿Qu´ dimensi´n tiene una matriz? e o Cuando dese´bamos saber cu´l era la longitud de una lista utiliz´bamos la funci´n len. a a a o ¿Funcionar´ tambi´n sobre matrices? Hagamos la prueba: a e >>> a = [[1, 0], [0, 1], [0, 0]] >>> len(a) 3 ↱ >>> a = [[1, 0], [0, 1], [0, 0]] >>> len(a[0]) 2 ↱ ↱ No funciona correctamente: s´lo nos devuelve el n´mero de filas (que es el n´mero o u u de componentes de la lista de listas que es la matriz). ¿C´mo averiguar el n´mero de o u columnas? F´cil: a ↱ 5.4.4. Operaciones con matrices Desarrollemos ahora algunos programas que nos ayuden a efectuar operaciones con matrices como la suma o el producto. Empecemos por dise˜ar un programa que sume dos matrices. Recuerda que s´lo es n o posible sumar matrices con la misma dimensi´n, as´ que solicitaremos una sola vez el o ı n´mero de filas y columnas: u suma matrices 3.py 1 2 3 4 5 6 7 8 9 10 suma matrices.py # Pedimos la dimensi´n de las matrices, o m = int(raw_input(’Dime␣el␣n´mero␣de␣filas:␣’)) u n = int(raw_input(’Dime␣el␣n´mero␣de␣columnas:␣’)) u # Creamos dos matrices nulas... A = [] for i in range(m): A.append( [0] * n ) B = [] Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 215 215 Introducción a la programación con Python - UJI c UJI
    • 11 12 13 14 15 16 17 18 19 20 21 22 23 for i in range(m): B.append( [0] * n ) # ... y leemos sus contenidos de teclado. print ’Lectura␣de␣la␣matriz␣A’ for i in range(m): for j in range(n): A[i][j] = float(raw_input(’Dame␣el␣componente␣(%d,%d):␣’ % (i, j))) print ’Lectura␣de␣la␣matriz␣B’ for i in range(m): for j in range(n): B[i][j] = float(raw_input(’Dame␣el␣componente␣(%d,%d):␣’ % (i, j))) Hemos de tener claro c´mo se calcula C = A + B. Si la dimensi´n de A y de B es o o m × n, la matriz resultante ser´ de esa misma dimensi´n, y su elemento de coordenadas a o (i, j), es decir, Ci,j , se calcula as´ ı: Ci,j = Ai,j + Bi,j , para 1 ≤ i ≤ m y 1 ≤ j ≤ n. Recuerda que la convenci´n adoptada en la notaci´n o o matem´tica hace que los ´ a ındices de las matrices empiecen en 1, pero que en Python todo empieza en 0. Codifiquemos ese c´lculo en Python. a suma matrices 4.py suma matrices.py . . . 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 # Constru´ ımos otra matriz nula para albergar el resultado. C = [] for i in range(m): C.append( [0] * n ) # Empieza el c´lculo de la suma. a for i in range(m): for j in range(n): C [i][j] = A[i][j] + B[i][j] # Y mostramos el resultado por pantalla print "Suma:" for i in range(m): for j in range(n): print C [i][j], print . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 250 Dise˜a un programa que lea dos matrices y calcule la diferencia entre la primera n y la segunda. · 251 Dise˜a un programa que lea una matriz y un n´mero y devuelva una nueva n u matriz: la que resulta de multiplicar la matriz por el n´mero. (El producto de un n´mero u u por una matriz es la matriz que resulta de multiplicar cada elemento por dicho n´mero.) u .................................................................................. Multiplicar matrices es un poco m´s dif´ que sumarlas (y, por descontado, el opea ıcil rador * no calcula el producto de matrices). Una matriz A de dimensi´n p × q se puede o multiplicar por otra matriz B si ´sta es de dimensi´n q × r, es decir, si el n´mero de e o u columnas de la primera es igual al n´mero de filas de la segunda. Hemos de pedir, pues, u el n´mero de filas y columnas de la primera matriz y s´lo el n´mero de columnas de la u o u segunda. Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 216 216 Introducción a la programación con Python - UJIUJI c
    • multiplica matrices 3.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 multiplica matrices.py # Pedimos la dimensi´n de la primera matriz y el n´mero de columnas de la segunda. o u p = int(raw_input(’Dime␣el␣n´mero␣de␣filas␣de␣A:␣’)) u q = int(raw_input(’Dime␣el␣n´mero␣de␣columnas␣de␣A␣(y␣filas␣de␣B):␣’)) u r = int(raw_input(’Dime␣el␣n´mero␣de␣columnas␣de␣B:␣’)) u # Creamos dos matrices nulas... A = [] for i in range(p): A.append( [0] * q ) B = [] for i in range(q): B.append( [0] * r ) # ... y leemos sus contenidos de teclado. print ’Lectura␣de␣la␣matriz␣A’ for i in range(p): for j in range(q): A[i][j] = float(raw_input(’Dame␣el␣componente␣(%d,%d):␣’ % (i, j))) print ’Lectura␣de␣la␣matriz␣B’ for i in range(q): for j in range(r): B[i][j] = float(raw_input(’Dame␣el␣componente␣(%d,%d):␣’ % (i, j))) Sigamos. La matriz resultante del producto es de dimensi´n p × r: o multiplica matrices.py 26 27 28 29 # Creamos una matriz nula m´s para el resultado... a C = [] for i in range(p): C.append( [0] * r ) El elemento de coordenadas Ci,j se calcula as´ ı: para 1 ≤ i ≤ p y 1 ≤ j ≤ r. multiplica matrices 4.py Ci,j = q k=1 Ai,k · Bk,j , multiplica matrices.py . . . 30 31 32 33 34 35 # Y efectuamos el c´lculo del producto. a for i in range(p): for j in range(r): for k in range(q): C [i][j] += A[i][k] * B[k][j] ¿Complicado? No tanto: a fin de cuentas las l´ ıneas 34–35 corresponden al c´lculo de un a sumatorio, algo que hemos codificado en Python una y otra vez. S´lo falta mostrar el resultado por pantalla, pero ya hemos visto c´mo se hace. Como o pleta t´ el programa. u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 252 La traspuesta de una matriz A de dimensi´n m×n es una matriz AT de dimensi´n o o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 217 217 Introducción a la programación con Python - UJIUJI c
    • Otros usos de las matrices De momento s´lo hemos discutido aplicaciones num´ricas de las matrices, pero son o e utiles en muchos otros campos. Por ejemplo, muchos juegos de ordenador representan ´ informaciones mediante matrices: El tablero de tres en raya es una matriz de 3 × 3 en el que cada casilla est´ a vac´ o contiene la ficha de un jugador, as´ que podr´ ıa ı ıamos codificar con el valor 0 el que est´ vac´ con el valor 1 el que tenga una ficha de un jugador y con un e ıa, 2 el que tenga una ficha del otro jugador. Un tablero de ajedrez es una matriz de 8 × 8 en el que cada casilla est´ vac´ o a ıa contiene una pieza. ¿C´mo las codificar´ o ıas? El tablero del juego del buscaminas es una matriz. En cada celda se codifica si hay bomba o no y si el usuario la ha descubierto ya o no. ... Las c´maras de video digitales permiten recoger im´genes, cada una de las cuales a a no es m´s que una matriz de valores. Si la imagen es en blanco y negro, cada valor a es un n´mero que representa la intensidad de brillo en ese punto; si la imagen es u en color, cada casilla contiene tres valores: la intensidad de la componente roja, la de la componente verde y la de la componente azul. Los sistemas de visi´n artificial o aplican transformaciones a esas matrices y las analizan para tratar de identificar en ellas determinados objetos. n × m tal que AT = Aj,i . Por ejemplo, si i,j  entonces:  1 2 3  2 12 6   A=  1 0 −3  10 −1 0   1 2 1 10 0 −1  AT =  2 12 3 6 −3 0 Dise˜a un programa que lea una matriz y muestre su traspuesta. n · 253 Dise˜a un programa tal que lea una matriz A de dimensi´n m × n y muestre un n o vector v de talla n tal que para i entre 1 y n. vi = m Ai,j , j=1 · 254 Dise˜a un programa que lea una matriz A de dimensi´n m × n y muestre un n o vector v de talla min(n, m) tal que para i entre 1 y min(n, m). vi = i i j=1 k=1 Aj,k , · 255 Dise˜a un programa que determine si una matriz es prima o no. Una matriz A n es prima si la suma de los elementos de cualquiera de sus filas es igual a la suma de los elementos de cualquiera de sus columnas. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 218 218 Introducción a la programación con Python - UJIUJI c
    • · 256 Una matriz es diagonal superior si todos los elementos por debajo de la diagonal principal son nulos. Por ejemplo, esta matriz es diagonal superior:   1 2 3  0 12 6   A=  0 0 −3  0 0 0 Dise˜a un programa que diga si una matriz es o no es diagonal superior. n .................................................................................. 5.4.5. El juego de la vida El juego de la vida es un juego sin jugadores. Se trata de colocar una serie de fichas en un tablero y dejar que evolucionen siguiendo unas reglas extremadamente simples. Lo curioso es que esas reglas dan origen a una gran complejidad que hace apasionante la mera observaci´n de la evoluci´n de las fichas en el tablero (hay gustos para todo). o o En el juego original se utiliza un tablero (una matriz) con infinitas filas y columnas. Como disponer de una matriz de dimensi´n infinita en un programa es imposible, suprono dremos que presenta dimensi´n m × n, donde m y n son valores escogidos por nosotros. o Cada celda del tablero contiene una c´lula que puede estar viva o muerta. Representaree mos las c´lulas vivas con su casilla de color negro y las c´lulas muertas con la celda en e e blanco. Cada casilla del tablero cuenta con ocho celdas vecinas. El mundo del juego de la vida est´ gobernado por un reloj que marca una serie de pulsos con los que mueren y a nacen c´lulas. Cu´ndo nace y cu´ndo muere una c´lula s´lo depende de cu´ntas c´lulas e a a e o a e vecinas est´n vivas. He aqu´ las reglas: a ı 1. Regla del nacimiento. Una c´lula muerta resucita si tiene exactamente tres vecinos e vivos. En estas figuras te se˜alamos celdas muertas que pasan a estar vivas con el n siguiente pulso: 2. Regla de la supervivencia. Una celda viva permanece viva si tiene dos o tres vecinos. Aqu´ te se˜alamos c´lulas que ahora est´n vivas y permanecer´n as´ tras el ı n e a a ı siguiente pulso: 3. Regla de la superpoblaci´n. Una c´lula muere o permanece muerta si tiene cuatro o e o m´s vecinos. Estas figuras muestran c´lulas que ahora est´n vivas o muertas y a e a estar´n muertas tras el siguiente pulso: a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 219 219 Introducción a la programación con Python - UJIUJI c
    • 4. Regla del aislamiento. Una c´lula muere o permanece muerta si tiene menos de e dos vecinos. En estas figuras te se˜alamos c´lulas que ahora est´n vivas o muertas n e a y estar´n muerta tras el siguiente pulso: a Vamos a hacer un programa que muestre la evoluci´n del juego de la vida durante o una serie de pulsos de reloj. Empezaremos con un prototipo que nos muestra la evoluci´n o del tablero en el terminal y lo modificaremos despu´s para hacer uso del area gr´fica de e a ´ PythonG. Necesitamos representar de alg´n modo nuestro ˂˂universo˃˃: el tablero de celdas. Eviu dentemente, se trata de una matriz. ¿De qu´ dimensi´n? La que queramos. Usaremos dos e o variables: filas y columnas para la dimensi´n y una matriz de valores l´gicos para repreo o sentar el tablero. Inicializaremos el tablero con ceros y, para hacer pruebas, supondremos que la matriz es de 10 × 10: vida.py 1 2 3 4 5 6 filas = 10 columnas = 10 tablero = [] for i in range(filas): tablero.append([False]*columnas) Ahora deber´ ıamos inicializar el universo ubicando algunas c´lulas vivas. De lo cone trario, nunca aparecer´ ˂˂vida˃˃ en el juego. Un patr´n sencillo y a la vez interesante es a o e ´ste: F´ ıjate en qu´ ocurre tras unos pocos pulsos de actividad: e Es lo que denominamos un oscilador: alterna entre dos o m´s configuraciones. a vida.py 8 9 10 tablero[4][5] = True tablero[5][5] = True tablero[6][5] = True Ahora deber´ ıamos representar el tablero de juego en pantalla. Usaremos de momento el terminal de texto: un punto representar´ una c´lula muerta y un asterisco representar´ a e a una c´lula viva. e vida 6.py vida.py . . . 11 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 220 220 Introducción a la programación con Python - cUJI UJI
    • 12 13 14 15 16 17 18 . . . . . . . . . . for y in range(filas): for x in range(columnas): if tablero[y][x]: print ’*’, else: print ’.’, print Aqu´ tienes lo que muestra por pantalla, de momento, el programa: ı . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * * * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sigamos. El mundo del juego est´ gobernado por un reloj. Nosotros seguiremos la a evoluci´n del juego durante un n´mero determinado de pulsos. Fijemos, de momento, el o u n´mero de pulsos a 10: u vida.py 20 21 22 pulsos = 10 for t in range(pulsos): Acciones asociadas a cada pulso de reloj ¿Qu´ acciones asociamos a cada pulso? Primero, actualizar el tablero, y segundo, e mostrarlo: vida.py 21 22 23 24 25 26 27 28 29 30 31 32 for t in range(pulsos): Actualizar el tablero # Representar el tablero. print "Pulso", t+1 for y in range(filas): for x in range(columnas): if tablero[y][x]: print ’*’, else: print ’.’, print Vamos a actualizar el tablero. Detallemos un poco m´s esa tarea: a vida.py 21 22 23 24 25 26 27 28 29 for t in range(pulsos): # Actualizar el tablero. for y in range(filas): for x in range(columnas): # Calcular el n´mero de vecinos de la celda que estamos visitando. u n = calcular el n´mero de vecinos u # Aplicar las reglas. if tablero[y][x] and (n == 2 or n == 3): # Supervivencia tablero[y][x] = True Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 221 221 Introducción a la programación con Python - UJI c UJI
    • elif not tablero[y][x] and n == 3: tablero[y][x] = True else: tablero[y][x] = False 30 31 32 33 34 # Representar el tablero. ... 35 36 # Nacimiento # Superpoblaci´n y aislamiento o S´lo nos falta determinar el n´mero de vecinos. ¿C´mo lo hacemos? F´cil: consultando o u o a cada una de las casillas vecinas e incrementando un contador (inicializado a cero) cada vez que encontremos una c´lula viva: e vida 7.py vida.py . . . 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 for t in range(pulsos): # Actualizar el tablero. for y in range(filas): for x in range(columnas): # Calcular el n´mero de vecinos de la celda que estamos visitando. u n=0 if tablero[y-1][x-1]: n += 1 if tablero[ y ][x-1]: n += 1 if tablero[y+1][x-1]: n += 1 if tablero[y-1][ x ]: n += 1 if tablero[y+1][ x ]: n += 1 if tablero[y-1][x+1]: n += 1 if tablero[ y ][x+1]: n += 1 if tablero[y+1][x+1]: n += 1 # Aplicar las reglas. . . . 50 . . . # Representar el tablero. Ya est´. Ejecutemos el programa: a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * . . . . . . . . . * . . . . . . . . . * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Traceback (most recent call last): File "vida.py", line 37, in ? if tablero[y-1][x+1]: IndexError: list index out of range Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 222 222 Introducción a la programación con Python - UJI c UJI
    • ¿Qu´ ha ido mal? Python nos dice que nos hemos salido de rango al acceder a un e elemento de la matriz. Ya est´ claro: cuando x vale columnas-1, x+1 vale columnas y nos a salimos del rango v´lido de ´ a ındices. (Hay un problema similar cuando x vale 0 y tratamos de consultar la columna x-1, s´lo que no se produce un error de ejecuci´n porque la o o columna de ´ ındice -1 existe: ¡es la columna columnas-1!) El juego de la vida original asume que el tablero es infinito. Nosotros hemos de jugar con un tablero que tiene l´ ımites, as´ que tendremos que tratar de modo especial las casillas fronterizas, pues no tienen 8 ı casillas colindantes. Esta nueva versi´n tiene esa precauci´n: o o vida.py vida 8.py . . . 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 for t in range(pulsos): # Actualizar el tablero. for y in range(filas): for x in range(columnas): # Calcular el n´mero de vecinos de la celda que estamos visitando. u n=0 if y > 0 and x > 0 and tablero[y-1][x-1]: n += 1 if x > 0 and tablero[ y ][x-1]: n += 1 if y < filas-1 and x > 0 and tablero[y+1][x-1]: n += 1 if y > 0 and tablero[y-1][ x ]: n += 1 if y < filas-1 and tablero[y+1][ x ]: n += 1 if y > 0 and x < columnas-1 and tablero[y-1][x+1]: n += 1 if x < columnas-1 and tablero[ y ][x+1]: n += 1 if y < filas-1 and x < columnas-1 and tablero[y+1][x+1]: n += 1 # Aplicar las reglas. if tablero[y][x] and (n == 2 or n == 3): # Supervivencia tablero[y][x] = True elif not tablero[y][x] and n == 3: # Nacimiento tablero[y][x] = True else: # Superpoblaci´n y aislamiento o tablero[y][x] = False 45 46 47 48 49 50 51 52 . . . # Representar el tablero. Ejecutemos ahora el programa: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pulso . . . . . . . . . . 1 . . . . . . . . . . . . . . * * * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 223 223 Introducción a la programación con Python - UJI c UJI
    • . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ¡Alto! ¿Qu´ ha pasado? ¡No aparece el patr´n de oscilaci´n que esper´bamos! Haz e o o a una traza para ver si averiguas qu´ ha pasado. Date un poco de tiempo antes de seguir e leyendo. De acuerdo. Confiamos en que has reflexionado un poco y ya has encontrado una explicaci´n de lo ocurrido antes de leer esto. Confirma que est´s en lo cierto: ha ocurrido o a que estamos aplicando las reglas sobre un tablero que se modifica durante la propia aplicaci´n de las reglas, y eso no es v´lido. Numeremos algunas celdas afectadas por el o a oscilador para explicar lo ocurrido: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 . . . . . . . . 1 3 5 . . . . . . . . 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Cuando hemos procesado la celda 1, su n´mero de vecinos era 0 as´ que ha muerto u ı (regla de aislamiento). La celda 2 pasa entonces a tener 2 vecinos, as´ que muere. Si ı la celda 1 no hubiera muerto a´n, hubi´semos contado 3 vecinos, y la celda 2 hubiese u e pasado a estar viva (regla de nacimiento). La celda 3 tiene ahora 1 vecino, luego muere (lo correcto hubiera sido contar 2 vecinos y aplicar la regla de supervivencia). La celda 4 cuenta con un solo vecino (deber´ haber sido 3), luego muere. Y la celda 5 no tiene ıan vecinos, luego tambi´n muere. Resultado: todas las c´lulas mueren. e e ¿C´mo podemos ingeniar un m´todo que no mate/resucite c´lulas durante el propio o e e pulso? Una t´cnica sencilla consiste en usar dos tableros. Uno de ellos no se modifica e durante la aplicaci´n de las reglas y los vecinos se cuentan sobre su configuraci´n. La o o nueva configuraci´n se va calculando y escribiendo en el segundo tablero. Cuando finaliza o el proceso, el tablero actual copia su contenido del tablero nuevo. Te ofrecemos ya una versi´n completa del juego: o vida 9.py 1 2 3 4 5 6 7 8 9 10 11 vida.py filas = 10 columnas = 10 tablero = [] for i in range(filas): tablero.append([False]*columnas) tablero[4][5] = True tablero[5][5] = True tablero[6][5] = True Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 224 224 Introducción a la programación con Python - UJI c UJI
    • 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 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 # Representar el tablero for y in range(filas): for x in range(columnas): if tablero[y][x]: print ’*’, else: print ’.’, print pulsos = 10 for t in range(pulsos): # Preparar un nuevo tablero. nuevo = [] for i in range(filas): nuevo.append([0]*columnas) # Actualizar el tablero. for y in range(filas): for x in range(columnas): # Calcular el n´mero de vecinos de la celda que estamos visitando. u n=0 if y > 0 and x > 0 and tablero[y-1][x-1]: n += 1 if x > 0 and tablero[ y ][x-1]: n += 1 if y < filas-1 and tablero[y+1][x-1]: n += 1 if y > 0 and tablero[y-1][ x ]: n += 1 if y < filas-1 and x > 0 and tablero[y+1][ x ]: n += 1 if y > 0 and x < columnas-1 and tablero[y-1][x+1]: n += 1 if x < columnas-1 and tablero[ y ][x+1]: n += 1 if y < filas-1 and x < columnas-1 and tablero[y+1][x+1]: n += 1 # Aplicar las reglas. if tablero[y][x] and (n == 2 or n == 3): # Supervivencia nuevo[y][x] = True elif not tablero[y][x] and n == 3: # Nacimiento nuevo[y][x] = True else: # Superpoblaci´n y aislamiento o nuevo[y][x] = False # Actualizar el tablero. tablero = nuevo # Representar el tablero. print "Pulso", t+1 for y in range(filas): for x in range(columnas): if tablero[y][x]: print ’*’, else: print ’.’, print Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 225 225 Introducción a la programación con Python -cUJI UJI
    • Prueba a ejecutar el programa para comprobar que hace lo esperado. Introduzcamos alguna mejora. Inicializar el tablero es pesado. Ser´ mejor inicializarlo ıa con una matriz expl´ ıcita y deducir el n´mero de filas y columnas a partir de la propia u matriz. Podemos sustituir las 10 primeras l´ ıneas por estas otras: vida 10.py 1 2 3 4 5 6 7 8 9 10 11 12 13 vida.py configuracion = [ ’.....’, ’..*..’, ’..*..’, ’..*..’, ’.....’] filas = len(configuracion) columnas = len(configuracion[0]) tablero = [] for i in range(filas): tablero.append([False] * columnas) for j in range(columnas): tablero[i][j] = configuracion[i][j] == ’*’ . . . Y ahora vamos a mejorar el programa evitando la salida por pantalla en modo texto y mostrando gr´ficos con PythonG. Basta con que dimensionemos adecuadamente el a sistema de coordenadas y cambiemos la porci´n de c´digo encargada de representar el o o tablero. El nuevo sistema de coordenadas se puede determinar tan pronto conozcamos la dimensi´n de la matriz: o vida.py 9 window_coordinates(0,0, columnas,filas) Y aqu´ tienes c´mo representar el tablero: ı o E vida.py E # Representar el tablero. for y in range(filas): for x in range(columnas): if tablero[y][x]: create_filled_rectangle(x, y, x+1, y+1) La funci´n predefinida (en PythonG) create_filled_rectangle dibuja un rect´ngulo relleno o a con un color (que por defecto es negro). Ejecutemos el programa. Aqu´ tienes el resultado: ı Eso no es lo que esper´bamos. ¿Qu´ ha ido mal ahora? Muy f´cil: hemos dibujado las a e a c´lulas vivas, pero no hemos borrado las muertas. Recuerda que las funciones create_ de e PythonG devuelven un valor que puede usarse para borrar los elementos gr´ficos creados a cuando lo deseemos con la funci´n erase. Eso haremos: memorizar esos valores y borrar o los objetos gr´ficos con cada pulso. La primera l´ a ınea del programa se leer´ as´ a ı: vida.py cuadrados = [] Y el c´digo encargado de la representaci´n del tablero, as´ o o ı: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 226 226 Introducción a la programación con Python - cUJI UJI
    • vida.py # Representar el tablero. for cuadrado in cuadrados: erase(cuadrado) cuadrados = [] for y in range(filas): for x in range(columnas): if tablero[y][x]: cuadrados.append(create_filled_rectangle(x, y, x+1, y+1)) Ahora s´ Puedes probar algunas configuraciones del juego de la vida tan interesantes ı. que tienen nombre propio (conviene que los pruebes en tableros de gran dimensi´n): o La rana. ¿El juego del universo? El deslizador. El lanzador abeja reina. El juego de la vida fue inventado en 1970 por el matem´tico John H. Conway y popua larizado por Martin Gardner en su columna de Scientific American. El juego de la vida es un caso particular de aut´mata celular, un sistema en el que ciertas reglas deciden o acerca del valor que debe tomar una celda en un tablero a partir de los valores de sus vecinas. Los aut´matas celulares ilustran la denominada ˂˂complejidad emergente˃˃, un campo o relativamente reciente dedicado a estudiar la aparici´n de patrones complejos y la o autoorganizaci´n a partir de reglas simples. Parecen proporcionar un buen modelo para o numerosos fen´menos naturales, como la pigmentaci´n en conchas y otros animales. o o Una hip´tesis interesante es que la naturaleza no es m´s que un superordenador o a que est´ jugando alguna variante del juego de la vida. ¿Una idea extravagante? Stephen a Wolfram, el autor principal del celebrado programa Mathematica, se ha encerrado una d´cada para investigar esta cuesti´n. El resultado: un pol´mico libro titulado ˂˂A new kind e o e of science˃˃ en el que propone ˂˂un nuevo tipo de ciencia˃˃ para estudiar el funcionamiento del universo a partir del an´lisis y observaci´n de aut´matas celulares. a o o Internet est´ plagada de p´ginas web dedicadas al juego de la vida y a los aut´matas a a o celulares. B´scalas y divi´rtete con la infinidad de curiosos patrones que generan las u e formas m´s incre´ a ıbles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 257 ¿Funciona esta otra forma de contar los vecinos de la casilla de la fila y y columna x? n = -tablero[y][x] for i in [-1, 0, 1]: for j in [-1, 0, 1]: if y+i >= 0 and y+i < filas and x+j >= 0 and x+j <columnas: n += tablero[y+i,x+j] · 258 El ˂˂juego de la vida parametrizado˃˃ es una generalizaci´n del juego de la o vida. En ´l, el n´mero de vecinos vivos necesarios para activar las reglas de nacimiento, e u supervivencia, aislamiento y superpoblaci´n est´n parametrizados. Haz un programa que o a solicite al usuario el n´mero de c´lulas vecinas vivas necesarias para que se disparen las u e diferentes reglas y muestre c´mo evoluciona el tablero con ellas. o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 227 227 Introducción a la programación con Python - UJIUJI c
    • · 259 El juego de la vida toroidal se juega sobre un tablero de dimensi´n finita m × n o con unas reglas de vecindad diferentes. Una casilla de coordenadas (y, x) tiene siempre 8 vecinas, aunque est´ en un borde: e ((y − 1) mod m, (x − 1) mod n) (y, (x − 1) mod n) ((y + 1) mod m, (x − 1) mod n) ((y − 1) mod m, x) ((y − 1) mod m, (x + 1) mod n) (y, (x + 1) mod n) ((y + 1) mod m, (x + 1) mod n) ((y + 1) mod m, x) donde mod es el operador m´dulo (en Python, %). o Implementa el juego de la vida toroidal en el entorno PythonG. · 260 El juego de la vida es un tipo particular de aut´mata celular bidimensional. Hay o aut´matas celulares unidimensionales. En ellos, una lista de valores (en su versi´n m´s o o a simple, ceros y unos) evoluciona a lo largo del tiempo a partir del estado de sus celdas vecinas (solo las celdas izquierda y derecha en su versi´n m´s simple) y de ella misma o a en el instante anterior. Por ejemplo, una regla 001 → 1 se lee como ˂˂la c´lula est´ viva si en la iteraci´n e a o anterior estaba muerta y ten´ una c´lula muerta a la izquierda y una c´lula viva a la ıa e e derecha˃˃. Una especificaci´n completa tiene este aspecto: o 000 → 0 001 → 1 010 → 1 011 → 0 100 → 1 101 → 1 . . . . * * . . . . . . . . 110 → 0 111 → 0 Y aqu´ tienes una representaci´n (usando asteriscos para los unos y puntos para los ceros) ı o de la evoluci´n del sistema durante sus primeros pulsos partiendo de una configuraci´n o o muy sencilla (un solo uno): Pulso Pulso Pulso Pulso Pulso Pulso Pulso 0 1 2 3 4 5 6 : : : : : : : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . * . . . . . * . . . . . * * . . . . * . * . . . * * . . * . * . * . * . * * . . * * . . * . * . * . . . * * . . * . . . * . * . . . . . . * . . . . . . . * . . . . . . . . . . . . . . . . . . . . . Implementa un programa para estudiar la evoluci´n de aut´matas celulares unidimeno o sionales. El programa leer´ un conjunto de reglas por teclado y un n´mero de pulsos. a u A continuaci´n, mostrar´ en el t´rminal de texto la evoluci´n del aut´mata partiendo de o a e o o una configuraci´n con s´lo una celda viva que ocupa la posici´n central del universo. o o o Cuando tengas el programa, explora las siguientes reglas: 000 → 0 001 → 1 010 → 1 011 → 1 100 → 1 101 → 0 110 → 0 111 → 0 000 → 0 001 → 1 010 → 1 011 → 1 100 → 0 101 → 1 110 → 1 111 → 0 000 → 0 000 → 0 000 → 0 001 → 0 001 → 1 001 → 1 010 → 1 010 → 1 010 → 1 011 → 1 011 → 1 011 → 0 100 → 1 100 → 0 100 → 1 101 → 0 101 → 1 101 → 1 110 → 0 110 → 1 110 → 0 111 → 0 111 → 0 111 → 1 · 261 Modifica el programa del ejercicio anterior para obtener una representaci´n o gr´fica en PythonG. Tradicionalmente se muestra en cada fila el estado del ˂˂tablero a unidimensional˃˃ en cada pulso. As´ se puede estudiar mejor la evoluci´n del aut´mata. ı o o Aqu´ tienes lo que deber´ mostrar tu programa para el ultimo juego de reglas del ı ıa ´ ejercicio anterior: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 228 228 Introducción a la programación con Python - UJIUJI c
    • .................................................................................. 5.5. Una reflexi´n final o Repetimos mucho c´digo al escribir nuestros programas. A veces leemos tres matrices en o un mismo programa y cada inicializaci´n o lectura de matriz nos obliga a escribir tres o o cuatro l´ ıneas de c´digo. Las tres l´ o ıneas no son id´nticas, de acuerdo, pero son muy e parecidas. Por ejemplo, cuando inicializamos tres matrices, hacemos algo como esto: 1 2 3 4 5 6 7 8 9 10 11 A = [] for i in range(m): A.append( [0] * n ) B = [] for i in range(p): B.append( [0] * q ) C = [] for i in range(x): C.append( [0] * y ) ¿No se puede evitar copiar tres veces un fragmento de c´digo tan parecido? Ser´ o ıa deseable poder decirle a Python: ˂˂mira, cada vez que quiera inicializar una matriz me gustar´ pasarte su dimensi´n y que t´ me devolvieras una matriz ya construida, as´ que ıa o u ı aprende una nueva orden, llamada matriz_nula, como te indico ahora˃˃. Una vez aprendida esa nueva orden, podr´ ıamos inicializar las tres matrices as´ ı: 1 2 3 A = matriz_nula(m, n) B = matriz_nula(p, q) C = matriz_nula(x, y) No s´lo ganar´ o ıamos en comodidad, sino que, adem´s, el c´digo ser´ mucho m´s legible. a o ıa a Compara las dos versiones: en la primera has de descifrar tres l´ ıneas para averiguar que se est´ inicializando una matriz; en la segunda, cada l´ a ınea deja bien claro su cometido. Pues bien, Python permite que definamos nuestras propias nuevas ˂˂´rdenes˃˃. De o c´mo hacerlo nos ocupamos en el siguiente cap´ o ıtulo. Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 229 229 Introducción a la programación con Python - c UJI UJI
    • Cap´ ıtulo 6 Funciones Y ellos, naturalmente, responden a sus nombres, ¿no? observ´ al desgaire o el Mosquito. Nunca o´ decir tal cosa. ı ¿Pues de qu´ les sirve tenerlos pregunt´ el Mosquito si no responden e o a sus nombres? LEWIS CARROLL, Alicia a trav´s del espejo. e En cap´ ıtulos anteriores hemos aprendido a utilizar funciones. Algunas de ellas est´n a predefinidas (abs, round, etc.) mientras que otras deben importarse de m´dulos antes o de poder ser usadas (por ejemplo, sin y cos se importan del m´dulo math). En este o tema aprenderemos a definir nuestras propias funciones. Definiendo nuevas funciones estaremos ˂˂ense˜ando˃˃ a Python a hacer c´lculos que inicialmente no sabe hacer y, en n a cierto modo, adaptando el lenguaje de programaci´n al tipo de problemas que deseamos o resolver, enriqueci´ndolo para que el programador pueda ejecutar acciones complejas de e un modo sencillo: llamando a funciones desde su programa. Ya has usado m´dulos, es decir, ficheros que contienen funciones y variables de valor o predefinido que puedes importar en tus programas. En este cap´ ıtulo aprenderemos a crear nuestros propios m´dulos, de manera que reutilizar nuestras funciones en varios o programas resultar´ extremadamente sencillo: bastar´ con importarlas. a a 6.1. Uso de funciones Denominaremos activar, invocar o llamar a una funci´n a la acci´n de usarla. Las funciones o o que hemos aprendido a invocar reciben cero, uno o m´s argumentos separados por comas a y encerrados entre un par de par´ntesis y pueden devolver un valor o no devolver nada. e abs(round(2.45, 1)) ↱ from sys import exit exit() ↱ abs(-3) ↱ ↱ >>> 3 >>> 2.5 >>> >>> Podemos llamar a una funci´n desde una expresi´n. Como el resultado tiene un tipo o o determinado, hemos de estar atentos a que ´ste sea compatible con la operaci´n y tipo e o de los operandos con los que se combina: ↱ >>> 1 + (abs(-3) * 2) 7 Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 230 230 Introducción a la programación con Python - UJI
    • ↱ >>> 2.5 / abs(round(2.45, 1)) 1.0 >>> 3 + str(3) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: number coercion failed ↱ ¿Ves? En el ultimo caso se ha producido un error de tipos porque se ha intentado sumar ´ una cadena, que es el tipo de dato del valor devuelto por str, a un entero. Observa que los argumentos de una funci´n tambi´n pueden ser expresiones: o e ↱ >>> abs(round(1.0/9, 4/(1+1))) 0.11 6.2. Definici´n de funciones o 6.2.1. Definici´n y uso de funciones con un solo par´metro o a Vamos a estudiar el modo en que podemos definir (y usar) nuestras propias funciones Python. Estudiaremos en primer lugar c´mo definir y llamar a funciones que devuelven un o valor y pasaremos despu´s a presentar los denominados procedimientos: funciones que no e devuelven ning´n valor. Adem´s de los conceptos y t´cnicas que te iremos presentando, u a e es interesante que te fijes en c´mo desarrollamos los diferentes programas de ejemplo. o Empezaremos definiendo una funci´n muy sencilla, una que recibe un n´mero y devuelve o u el cuadrado de dicho n´mero. El nombre que daremos a la funci´n es cuadrado. Observa u o este fragmento de programa: cuadrado.py 1 2 def cuadrado(x): return x ** 2 Ya est´. Acabamos de definir la funci´n cuadrado que se aplica sobre un valor al que a o llamamos x y devuelve un n´mero: el resultado de elevar x al cuadrado. En el programa u aparecen dos nuevas palabras reservadas: def y return. La palabra def es abreviatura de ˂˂define˃˃ y return significa ˂˂devuelve˃˃ en ingl´s. Podr´ e ıamos leer el programa anterior como ˂˂define cuadrado de x como el valor que resulta de elevar x al cuadrado˃˃. En las l´ ıneas que siguen a su definici´n, la funci´n cuadrado puede utilizarse del o o mismo modo que las funciones predefinidas: cuadrado.py 1 2 3 4 5 6 cuadrado.py def cuadrado(x): return x ** 2 print cuadrado(2) a = 1 + cuadrado(3) print cuadrado(a * 3) En cada caso, el resultado de la expresi´n que sigue entre par´ntesis al nombre de la o e funci´n es utilizado como valor de x durante la ejecuci´n de cuadrado. En la primera o o llamada (l´ ınea 4) el valor es 2, en la siguiente llamada es 3 y en la ultima, 30. F´cil, ¿no? a ´ Deteng´monos un momento para aprender algunos t´rminos nuevos. La l´ a e ınea que empieza con def es la cabecera de la funci´n y el fragmento de programa que contiene o los c´lculos que debe efectuar la funci´n se denomina cuerpo de la funci´n. Cuando a o o Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 231 231 Introducción a la programación con Python - UJI c UJI
    • estamos definiendo una funci´n, su par´metro se denomina par´metro formal (aunque, por o a a abreviar, normalmente usaremos el t´rmino par´metro, sin m´s). El valor que pasamos a e a a una funci´n cuando la invocamos se denomina par´metro real o argumento. Las porciones o a de un programa que no son cuerpo de funciones forman parte del programa principal: son las sentencias que se ejecutar´n cuando el programa entre en acci´n. El cuerpo de las a o funciones s´lo se ejecutar´ si se producen las correspondientes llamadas. o a Cabecera def cuadrado ( x ): return x ** 2 print cuadrado( 2 ) Definir no es invocar Par´metro formal (o simplemente par´metro) a a Cuerpo Llamada, invocaci´n o activaci´n o o Argumento o par´metro real a Si intentamos ejecutar este programa: cuadrado.py cuadrado 4.py 1 2 def cuadrado(x): return x ** 2 no ocurrir´ nada en absoluto; bueno, al menos nada que aparezca por pantalla. La a definici´n de una funci´n s´lo hace que Python ˂˂aprenda˃˃ silenciosamente un m´todo o o o e de c´lculo asociado al identificador cuadrado. Nada m´s. Hagamos la prueba ejecutando a a el programa: ↱ $ python cuadrado.py ¿Lo ves? No se ha impreso nada en pantalla. No se trata de que no haya ning´n print, u sino de que definir una funci´n es un proceso que no tiene eco en pantalla. Repetimos: o definir una funci´n s´lo asocia un m´todo de c´lculo a un identificador y no supone o o e a ejecutar dicho m´todo de c´lculo. e a Este otro programa s´ muestra algo por pantalla: ı cuadrado.py cuadrado 5.py 1 2 3 4 def cuadrado(x): return x ** 2 print cuadrado(2) Al invocar la funci´n cuadrado (l´ o ınea 4) se ejecuta ´sta. En el programa, la invocaci´n de e o la ultima l´ ınea provoca la ejecuci´n de la l´ o ınea 2 con un valor de x igual a 2 (argumento ´ de la llamada). El valor devuelto con return es mostrado en pantalla como efecto de la sentencia print de la l´ ınea 4. Hagamos la prueba: ↱ $ python cuadrado.py 4 Las reglas para dar nombre a las funciones y a sus par´metros son las mismas que a seguimos para dar nombre a las variables: s´lo se pueden usar letras (del alfabeto ingl´s), o e Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 232 232 Introducción a la programación con Python - cUJI UJI
    • Definici´n de funciones desde el entorno interactivo o Hemos aprendido a definir funciones dentro de un programa. Tambi´n puedes definir e funciones desde el entorno interactivo de Python. Te vamos a ense˜ar paso a paso qu´ n e ocurre en el entorno interactivo cuando estamos definiendo una funci´n. o En primer lugar aparece el prompt. Podemos escribir entonces la primera l´ ınea: >>> def cuadrado(x): ... ↱ >>> def cuadrado(x): ... return x ** 2 ... ↱ >>> def cuadrado(x): ... return x ** 2 ... >>> ↱ ↱ Python nos responde con tres puntos (. .). Esos tres puntos son el llamado prompt . secundario: indica que la acci´n de definir la funci´n no se ha completado a´n y nos pide o o u m´s sentencias. Escribimos a continuaci´n la segunda l´ a o ınea respetando la indentaci´n o que le corresponde: ↱ ↱ Nuevamente Python responde con el prompt secundario. Es necesario que le demos una vez m´s al retorno de carro para que Python entienda que ya hemos acabado de a definir la funci´n: o ↱ ↱ Ahora aparece de nuevo el prompt principal o primario. Python ha aprendido la funci´n y est´ listo para que introduzcamos nuevas sentencias o expresiones. o a ↱ >>> def cuadrado(x): ... return x ** 2 ... >>> cuadrado(2) 4 >>> 1 + cuadrado(1+3) 17 >>> ↱ ↱ ↱ ↱ d´ ıgitos y el car´cter de subrayado; la primera letra del nombre no puede ser un n´mero; a u y no se pueden usar palabras reservadas. Pero, ¡cuidado!: no debes dar el mismo nombre a una funci´n y a una variable. En Python, cada nombre debe identificar claramente un o unico elemento: una variable o una funci´n.1 o ´ Al definir una funci´n cuadrado es como si hubi´semos creado una ˂˂m´quina de o e a calcular cuadrados˃˃. Desde la ´ptica de su uso, podemos representar la funci´n como una o o caja que transforma un dato de entrada en un dato de salida: cuadrado x2 x Cuando invocas a la funci´n, le est´s ˂˂conectando˃˃ un valor a la entrada, as´ que la o a ı ˂˂m´quina de calcular cuadrados˃˃ se pone en marcha y produce la soluci´n deseada: a o 1 M´s adelante, al presentar las variables locales, matizaremos esta afirmaci´n. a o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 233 233 Introducción a la programación con Python - cUJI UJI
    • ↱ >>> cuadrado(2) 4 2 cuadrado x 4 Ojo: no hay una unica forma de construir la ˂˂m´quina de calcular cuadrados˃˃. F´ a ıjate ´ en esta definici´n alternativa: o cuadrado 6.py 1 2 cuadrado.py def cuadrado(x): return x * x Se trata de un definici´n tan v´lida como la anterior, ni mejor, ni peor. Como usuarios de o a la funci´n, poco nos importa c´mo hace el c´lculo2 ; lo que importa es qu´ datos recibe y o o a e qu´ valor devuelve. e Vamos con un ejemplo m´s: una funci´n que calcula el valor de x por el seno de x: a o 1 2 3 4 from math import sin def xsin(x): return x * sin(x) Lo interesante de este ejemplo es que la funci´n definida, xsin, contiene una llamada a o otra funci´n (sin). No hay problema: desde una funci´n puedes invocar a cualquier otra. o o Una confusi´n frecuente o Supongamos que definimos una funci´n con un par´metro x como esta: o a 1 2 def cubo(x): return x ** 3 Es frecuente en los aprendices confundir el par´metro x con una variable x. As´ les a ı, parece extra˜o que podamos invocar as´ a la funci´n: n ı o 4 5 y=1 print cubo(y) ¿C´mo es que ahora llamamos y a lo que se llamaba x? No hay problema alguno. Al deo finir una funci´n, usamos un identificador cualquiera para referirnos al par´metro. Tanto o a da que se llame x como y. Esta otra definici´n de cubo es absolutamente equivalente: o 1 2 def cubo(z): return z ** 3 La definici´n se puede leer as´ ˂˂si te pasan un valor, digamos z, devuelve ese valor o ı: elevado al cubo˃˃. Usamos el nombre z (o x) s´lo para poder referirnos a ´l en el cuerpo o e de la funci´n. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . √ · 262 Define una funci´n llamada raiz_cubica que devuelva el valor de 3 x. o √ (Nota: recuerda que 3 x es x 1/3 y andate con ojo, no sea que utilices una divisi´n o ´ entera y eleves x a la potencia 0, que es el resultado de calcular 1/3.) 2 . . . por el momento. Hay muchas formas de hacer el c´lculo, pero unas resultan m´s eficientes (m´s a a a r´pidas) que otras. Naturalmente, cuando podamos elegir, escogeremos la forma m´s eficiente. a a Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 234 234 c UJI Introducción a la programación con Python - UJI
    • · 263 Define una funci´n llamada area_circulo que, a partir del radio de un c´ o ırculo, devuelva el valor de su area. Utiliza el valor 3.1416 como aproximaci´n de π o importa el o ´ valor de π que encontrar´s en el m´dulo math. a o (Recuerda que el area de un c´ ırculo es πr 2 .) ´ · 264 Define una funci´n que convierta grados Farenheit en grados cent´ o ıgrados. (Para calcular los grados cent´ ıgrados has de restar 32 a los grados Farenheit y multiplicar el resultado por cinco novenos.) · 265 Define una funci´n que convierta grados cent´ o ıgrados en grados Farenheit. · 266 Define una funci´n que convierta radianes en grados. o (Recuerda que 360 grados son 2π radianes.) · 267 Define una funci´n que convierta grados en radianes. o .................................................................................. En el cuerpo de una funci´n no s´lo pueden aparecer sentencias return; tambi´n o o e podemos usar estructuras de control: sentencias condicionales, bucles, etc. Lo podemos comprobar dise˜ando una funci´n que recibe un n´mero y devuelve un booleano. El valor n o u de entrada es la edad de una persona y la funci´n devuelve True si la persona es mayor o de edad y False en caso contrario: es mayor de edad edad True o False Cuando llamas a la funci´n, ´sta se activa para producir un resultado concreto (en nuestro o e caso, o bien devuelve True o bien devuelve False): a = es_mayor_de_edad(23) es mayor de edad 23 b = es_mayor_de_edad(12) 12 edad True es mayor de edad edad False Una forma usual de devolver valores de funci´n es a trav´s de un s´lo return ubicado o e o al final del cuerpo de la funci´n: o mayoria edad 4.py 1 2 3 4 5 6 mayoria edad.py def es_mayor_de_edad(edad): if edad < 18: resultado = False else: resultado = True return resultado Pero no es el unico modo en que puedes devolver diferentes valores. Mira esta otra ´ definici´n de la misma funci´n: o o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 235 235 Introducción a la programación con Python - UJIUJI c
    • mayoria edad.py mayoria edad.py def es_mayor_de_edad(edad): if edad < 18: return False else: return True 1 2 3 4 5 Aparecen dos sentencias return: cuando la ejecuci´n llega a cualquiera de ellas, finaliza o inmediatamente la llamada a la funci´n y se devuelve el valor que sigue al return. o Podemos asimilar el comportamiento de return al de break: una sentencia break fuerza a terminar la ejecuci´n de un bucle y una sentencia return fuerza a terminar la ejecuci´n o o de una llamada a funci´n. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 268 ¿Es este programa equivalente al que acabamos de ver? mayoria edad.py mayoria edad 5.py def mayoria_de_edad(edad): if edad < 18: return False return True 1 2 3 4 · 269 ¿Es este programa equivalente al que acabamos de ver? mayoria edad.py mayoria edad 6.py 1 2 def mayoria_de_edad(edad): return edad >= 18 · 270 La ultima letra del DNI puede calcularse a partir del n´mero. Para ello s´lo u o ´ tienes que dividir el n´mero por 23 y quedarte con el resto, que es un n´mero entre 0 y u u 22. La letra que corresponde a cada n´mero la tienes en esta tabla: u 0 T 1 R 2 W 3 A 4 G 5 M 6 Y 7 F 8 P 9 D 10 X 11 B 12 N 13 J 14 Z 15 S 16 Q 17 V 18 H 19 L 20 C Define una funci´n que, dado un n´mero de DNI, devuelva la letra que le corresponde. o u 21 K 22 E · 271 Dise˜a una funci´n que reciba una cadena y devuelva cierto si empieza por n o min´scula y falso en caso contrario. u · 272 Dise˜a una funci´n llamada es_repeticion que reciba una cadena y nos diga si n o la cadena est´ formada mediante la concatenaci´n de una cadena consigo misma. Por a o ejemplo, es_repeticion(’abab’) devolver´ True, pues la cadena ’abab’ est´ formada con a a la cadena ’ab’ repetida; por contra es_repeticion(’ababab’) devolver´ False. a .................................................................................. Y ahora, un problema m´s complicado. Vamos a dise˜ar una funci´n que nos diga si a n o un n´mero dado es o no es perfecto. Se dice que un n´mero es perfecto si es igual a la u u suma de todos sus divisores exclu´ ´l mismo. Por ejemplo, 28 es un n´mero perfecto, ıdo e u pues sus divisores (excepto ´l mismo) son 1, 2, 4, 7 y 14, que suman 28. e Empecemos. La funci´n, a la que llamaremos es_perfecto recibir´ un s´lo dato (el o a o n´mero sobre el que hacemos la pregunta) y devolver´ un valor booleano: u a es perfecto n La cabecera de la funci´n est´ clara: o a Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python True o False 236 236 Introducción a la programación con Python - UJIUJI c
    • perfecto.py 1 2 def es_perfecto(n): ... ¿Y por d´nde seguimos? Vamos por partes. En primer lugar estamos interesados en o conocer todos los divisores del n´mero. Una vez tengamos claro c´mo saber cu´les son, u o a los sumaremos. Si la suma coincide con el n´mero original, ´ste es perfecto; si no, no. u e Podemos usar un bucle y preguntar a todos los n´meros entre 1 y n-1 si son divisores u de n: perfecto.py 1 2 3 4 def es_perfecto(n): for i in range(1, n): if i es divisor de n: ... Observa c´mo seguimos siempre la reglas de indentaci´n de c´digo que impone Python. o o o ¿Y c´mo preguntamos ahora si un n´mero es divisor de otro? El operador m´dulo % o u o devuelve el resto de la divisi´n y resuelve f´cilmente la cuesti´n: o a o perfecto.py 1 2 3 4 def es_perfecto(n): for i in range(1, n): if n % i == 0: ... La l´ ınea 4 s´lo se ejecutar´ para valores de i que son divisores de n. ¿Qu´ hemos de o a e hacer a continuaci´n? Deseamos sumar todos los divisores y ya conocemos la ˂˂plantilla˃˃ o para calcular sumatorios: perfecto.py 1 2 3 4 5 6 def es_perfecto(n): sumatorio = 0 for i in range(1, n): if n % i == 0: sumatorio += i ... ¿Qu´ queda por hacer? Comprobar si el n´mero es perfecto y devolver True o False, seg´n e u u proceda: perfecto 3.py 1 2 3 4 5 6 7 8 9 perfecto.py def es_perfecto(n): sumatorio = 0 for i in range(1, n): if n % i == 0: sumatorio += i if sumatorio == n: return True else: return False Y ya est´. Bueno, podemos simplificar un poco las cuatro ultimas l´ a ıneas y convertirlas en ´ una sola. Observa esta nueva versi´n: o perfecto.py 1 2 3 4 5 6 def es_perfecto(n): sumatorio = 0 for i in range(1, n): if n % i == 0: sumatorio += i return sumatorio == n Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o perfecto.py 237 237 Introducción a la programación con Python - cUJI UJI
    • ¿Qu´ hace la ultima l´ e ınea? Devuelve el resultado de evaluar la expresi´n l´gica que o o ´ compara sumatorio con n: si ambos n´meros son iguales, devuelve True, y si no, devuelve u False. Mejor, ¿no? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 273 ¿En qu´ se ha equivocado nuestro aprendiz de programador al escribir esta e funci´n? o E perfecto.py E perfecto 4.py 1 2 3 4 5 6 def es_perfecto(n): for i in range(1, n): sumatorio = 0 if n % i == 0: sumatorio += i return sumatorio == n · 274 Mejora la funci´n es_perfecto haci´ndola m´s r´pida. ¿Es realmente necesario o e a a considerar todos los n´meros entre 1 y n-1? u · 275 Dise˜a una funci´n que devuelva una lista con los n´meros perfectos comprenn o u didos entre 1 y n, siendo n un entero que nos proporciona el usuario. · 276 Define una funci´n que devuelva el n´mero de d´ que tiene un a˜o determinado. o u ıas n Ten en cuenta que un a˜o es bisiesto si es divisible por 4 y no divisible por 100, excepto n si es tambi´n divisible por 400, en cuyo caso es bisiesto. e (Ejemplos: El n´mero de d´ de 2002 es 365: el n´mero 2002 no es divisible por u ıas u 4, as´ que no es bisiesto. El a˜o 2004 es bisiesto y tiene 366 d´ el n´mero 2004 es ı n ıas: u divisible por 4, pero no por 100, as´ que es bisiesto. El a˜o 1900 es divisible por 4, pero ı n no es bisiesto porque es divisible por 100 y no por 400. El a˜o 2000 s´ es bisiesto: el n ı n´mero 2000 es divisible por 4 y, aunque es divisible por 100, tambi´n lo es por 400.) u e .................................................................................. Hasta el momento nos hemos limitado a suministrar valores escalares como argumentos de una funci´n, pero tambi´n es posible suministrar argumentos de tipo secuencial. o e Ve´moslo con un ejemplo: una funci´n que recibe una lista de n´meros y nos devuelve el a o u sumatorio de todos sus elementos. sumatorio lista suma lista 4.py 1 2 3 4 5 suma de todos sus elementos suma lista.py def sumatorio(lista): s=0 for numero in lista: s += numero return s Podemos usar la funci´n as´ o ı: suma lista 5.py suma lista.py . . . 7 8 a = [1, 2, 3] print sumatorio(a) o as´ ı: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 238 238 Introducción a la programación con Python - UJIUJI c
    • suma lista.py suma lista 6.py . . . 7 print sumatorio([1, 2, 3]) En cualquiera de los dos casos, el par´metro lista toma el valor [1, 2, 3], que es el a argumento suministrado en la llamada: [1, 2, 3] sumatorio lista 6 Sumatorios Has aprendido a calcular sumatorios con bucles. Desde la versi´n 2.3, Python ofrece o una forma mucho m´s c´moda de calcular sumatorios: la funci´n predefinida sum, que a o o recibe una lista de valores y devuelve el resultado de sumarlos. ↱ >>> sum([1, 10, 20]) 31 ¿C´mo usarla para calcular el sumatorio de los 100 primeros n´meros naturales? o u Muy f´cil: pas´ndole una lista con esos n´mero, algo que resulta trivial si usas range. a a u ↱ >>> sum(range(101)) 5050 Mmmm. Ten cuidado: range construye una lista en memoria. Si calculas as´ el suı matorio del primer mill´n de n´meros es posible que te quedes sin memoria. Hay una o u funci´n alternativa, xrange, que no construye la lista en memoria, pero que hace creer a o quien la recorre que es una lista en memoria: ↱ >>> sum(xrange(1000001)) 500000500000L . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 277 Dise˜a una funci´n que calcule el sumatorio de la diferencia entre n´meros n o u contiguos en una lista. Por ejemplo, para la lista [1, 3, 6, 10] devolver´ 9, que es a 2 + 3 + 4 (el 2 resulta de calcular 3 − 1, el 3 de calcular 6 − 3 y el 4 de calcular 10 − 6). ¿Sabes efectuar el c´lculo de ese sumatorio sin utilizar bucles (ni la funci´n sum)? a o .................................................................................. Estudiemos otro ejemplo: una funci´n que recibe una lista de n´meros y devuelve el o u valor de su mayor elemento. maximo lista mayor elemento de lista La idea b´sica es sencilla: recorrer la lista e ir actualizando el valor de una variable a auxiliar que, en todo momento, contendr´ el m´ximo valor visto hasta ese momento. a a maximo 7.py 1 def maximo(lista): Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o E maximo.py E 239 239 Introducción a la programación con Python - UJIUJI c
    • 2 3 4 5 for elemento in lista: if elemento > candidato: candidato = elemento return candidato Nos falta inicializar la variable candidato. ¿Con qu´ valor? Podr´ e ıamos pensar en inicializarla con el menor valor posible. De ese modo, cualquier valor de la lista ser´ mayor a que ´l y es seguro que su valor se modificar´ tan pronto empecemos a recorrer la lista. e a Pero hay un problema: no sabemos cu´l es el menor valor posible. Una buena alternativa a es inicializar candidato con el valor del primer elemento de la lista. Si ya es el m´ximo, a perfecto, y si no lo es, m´s tarde se modificar´ candidato. a a maximo 8.py 1 2 3 4 5 6 def maximo(lista): candidato = lista[0] for elemento in lista: if elemento > candidato: candidato = elemento return candidato E maximo.py E . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 278 Haz una traza de la llamada maximo([6, 2, 7, 1, 10, 1, 0]). .................................................................................. ¿Ya est´? A´n no. ¿Qu´ pasa si se proporciona una lista vac´ como entrada? La a u e ıa l´ ınea 2 provocar´ un error de tipo IndexError, pues en ella intentamos acceder al primer a elemento de la lista. . . y la lista vac´ no tiene ning´n elemento. Un objetivo es, pues, ıa u evitar ese error. Pero, en cualquier caso, algo hemos de devolver como m´ximo elemento a de una lista, ¿y qu´ valor podemos devolvemos como m´ximo elemento de una lista vac´ e a ıa? Mmmm. A bote pronto, tenemos dos posibilidades: Devolver un valor especial, como el valor 0. Mejor no. Tiene un serio inconveniente: ¿c´mo distinguir´ el m´ximo de [-3, -5, 0, -4], que es un cero ˂˂leg´ o e a ıtimo˃˃, del m´ximo de []? a O devolver un valor ˂˂muy˃˃ especial, como el valor None. ¿Que qu´ es None? None e significa en ingl´s ˂˂ninguno˃˃ y es un valor predefinido en Python que se usa para e denotar ˂˂ausencia de valor˃˃. Como el m´ximo de una lista vac´ no existe, parece a ıa acertado devolver la ˂˂ausencia de valor˃˃ como m´ximo de sus miembros. a Nos inclinamos por esta segunda opci´n. En adelante, usaremos None siempre que queo ramos referirnos a un valor ˂˂muy˃˃ especial: a la ausencia de valor. maximo.py 1 2 3 4 5 6 7 8 9 maximo.py def maximo(lista): if len(lista) > 0: candidato = lista[0] for elemento in lista: if elemento > candidato: candidato = elemento else: candidato = None return candidato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 279 Dise˜a una funci´n que, dada una lista de n´meros enteros, devuelva el n´mero n o u u de ˂˂series˃˃ que hay en ella. Llamamos ˂˂serie˃˃ a todo tramo de la lista con valores id´nticos. e Por ejemplo, la lista [1, 1, 8, 8, 8, 8, 0, 0, 0, 2, 10, 10] tiene 5 ˂˂series˃˃ (ten en cuenta que el 2 forma parte de una ˂˂serie˃˃ de un solo elemento). Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 240 240 Introducción a la programación con Python - UJIUJI c
    • · 280 Dise˜a una funci´n que diga en qu´ posici´n empieza la ˂˂serie˃˃ m´s larga de n o e o a una lista. En el ejemplo del ejercicio anterior, la ˂˂serie˃˃ m´s larga empieza en la posici´n a o 2 (que es el ´ ındice donde aparece el primer 8). (Nota: si hay dos ˂˂series˃˃ de igual longitud y ´sta es la mayor, debes devolver la posici´n de la primera de las ˂˂series˃˃. Por ejemplo, e o para [8, 2, 2, 9, 9] deber´s devolver la posici´n 1.) a o · 281 Haz una funci´n que reciba una lista de n´meros y devuelva la media de dichos o u n´meros. Ten cuidado con la lista vac´ (su media es cero). u ıa · 282 Dise˜a una funci´n que calcule el productorio de todos los n´meros que componen n o u una lista. · 283 Dise˜a una funci´n que devuelva el valor absoluto de la m´xima diferencia entre n o a dos elementos consecutivos de una lista. Por ejemplo, el valor devuelto para la lista [1, 10, 2, 6, 2, 0] es 9, pues es la diferencia entre el valor 1 y el valor 10. · 284 Dise˜a una funci´n que devuelva el valor absoluto de la m´xima diferencia entre n o a cualquier par de elementos de una lista. Por ejemplo, el valor devuelto para la lista [1, 10, 2, 6, 8, 2 0] es 9, pues es la diferencia entre el valor 10 y el valor 0. (Pista: te puede convenir conocer el valor m´ximo y el valor m´ a ınimo de la lista.) · 285 Modifica la funci´n del ejercicio anterior para que devuelva el valor 0 tan pronto o encuentre un 0 en la lista. · 286 Define una funci´n que, dada una cadena x, devuelva otra cuyo contenido sea el o resultado de concatenar 6 veces x consigo misma. · 287 Dise˜a una funci´n que, dada una lista de cadenas, devuelva la cadena m´s n o a larga. Si dos o m´s cadenas miden lo mismo y son las m´s largas, la funci´n devolver´ a a o a una cualquiera de ellas. (Ejemplo: dada la lista [’Pepe’, ’Juan’, ’Mar´a’, ’Ana’], la funci´n devolver´ ı o a la cadena ’Mar´a’.) ı · 288 Dise˜a una funci´n que, dada una lista de cadenas, devuelva una lista con todas n o las cadenas m´s largas, es decir, si dos o m´s cadenas miden lo mismo y son las m´s a a a largas, la lista las contendr´ a todas. a (Ejemplo: dada la lista [’Pepe’, ’Ana’, ’Juan’, ’Paz’], la funci´n devolver´ la o a lista de dos elementos [’Pepe’, ’Juan’].) · 289 Dise˜a una funci´n que reciba una lista de cadenas y devuelva el prefijo com´n n o u m´s largo. Por ejemplo, la cadena ’pol’ es el prefijo com´n m´s largo de esta lista: a u a [’poliedro’, ’polic´a’, ’pol´fona’, ’polinizar’, ’polaridad’, ’pol´tica’] ı ı ı .................................................................................. 6.2.2. Definici´n y uso de funciones con varios par´metros o a No todas las funciones tienen un s´lo par´metro. Vamos a definir ahora una con dos o a par´metros: una funci´n que devuelve el valor del area de un rect´ngulo dadas su altura a o a ´ y su anchura: area rectangulo altura anchura Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o altura×anchura 241 241 Introducción a la programación con Python - UJIUJI c
    • Importaciones, definiciones de funci´n y programa principal o Los programas que dise˜es a partir de ahora tendr´n tres ˂˂tipos de l´ n a ınea˃˃: importaci´n o de m´dulos (o funciones y variables de m´dulos), definici´n de funciones y sentencias o o o del programa principal. En principio puedes alternar l´ ıneas de los tres tipos. Mira este programa, por ejemplo, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def cuadrado(x): return x**2 vector = [] for i in range(3): vector.append(float(raw_input(’Dame␣un␣n´mero:␣’))) u def suma_cuadrados(v): s=0 for e in v: s += cuadrado(e) return s y = suma_cuadrados(vector) from math import sqrt print ’Distancia␣al␣origen:’, sqrt(y) En ´l se alternan definiciones de funci´n, importaciones de funciones y sentencias del e o programa principal, as´ que resulta dif´ hacerse una idea clara de qu´ hace el proı ıcil e grama. No dise˜es as´ tus programas. n ı Esta otra versi´n del programa anterior pone en primer lugar las importaciones, o a continuaci´n, las funciones y, al final, de un tir´n, las sentencias que conforman el o o programa principal: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from math import sqrt def cuadrado(x): return x**2 def suma_cuadrados(v): s=0 for e in v: s += cuadrado(e) return s # Programa principal vector = [] for i in range(3): vector.append(float(raw_input(’Dame␣un␣n´mero:␣’))) u y = suma_cuadrados(vector) print ’Distancia␣al␣origen:’, sqrt(y) Es mucho m´s legible. Te recomendamos que sigas siempre esta organizaci´n en tus a o programas. Recuerda que la legibilidad de los programas es uno de los objetivos del programador. rectangulo.py 1 2 def area_rectangulo(altura, anchura): return altura * anchura Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 242 242 Introducción a la programación con Python -cUJI UJI
    • Observa que los diferentes par´metros de una funci´n deben separarse por comas. Al usar a o la funci´n, los argumentos tambi´n deben separarse por comas: o e rectangulo.py rectangulo 2.py 1 2 3 4 def area_rectangulo(altura, anchura): return altura * anchura print area_rectangulo(3, 4) 3 4 area rectangulo altura anchura 12 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 290 Define una funci´n que, dado el valor de los tres lados de un tri´ngulo, devuelva o a la longitud de su per´ ımetro. · 291 Define una funci´n que, dados dos par´metros b y x, devuelva el valor de logb (x), o a es decir, el logaritmo en base b de x. · 292 Dise˜a una funci´n que devuelva la soluci´n de la ecuaci´n lineal ax + b = 0 n o o o dados a y b. Si la ecuaci´n tiene infinitas soluciones o no tiene soluci´n alguna, la o o funci´n lo detectar´ y devolver´ el valor None. o a a · 293 Dise˜a una funci´n que calcule n o funci´n devolver´ el valor 0. o a b i=a i dados a y b. Si a es mayor que b, la · 294 Dise˜a una funci´n que calcule b i dados a y b. Si a es mayor que b, la n o i=a funci´n devolver´ el valor 0. Si 0 se encuentra entre a y b, la funci´n devolver´ tambi´n o a o a e el valor cero, pero sin necesidad de iterar en un bucle. √ · 295 Define una funci´n llamada raiz_n_esima que devuelva el valor de n x. (Nota: o √ recuerda que n x es x 1/n ). · 296 Haz una funci´n que reciba un n´mero de DNI y una letra. La funci´n devolver´ o u o a True si la letra corresponde a ese n´mero de DNI, y False en caso contrario. La funci´n u o debe llamarse comprueba_letra_dni. Si lo deseas, puedes llamar a la funci´n letra_dni, desarrollada en el ejercicio 270, o desde esta nueva funci´n. o · 297 Dise˜a una funci´n que diga (mediante la devoluci´n de True o False) si dos n o o n´meros son amigos. Dos n´meros son amigos si la suma de los divisores del primero u u (exclu´ ´l) es igual al segundo y viceversa. ıdo e .................................................................................. 6.2.3. Definici´n y uso de funciones sin par´metros o a Vamos a considerar ahora c´mo definir e invocar funciones sin par´metros. En realidad hay o a poco que decir: lo unico que debes tener presente es que es obligatorio poner par´ntesis e ´ a continuaci´n del identificador, tanto al definir la funci´n como al invocarla. o o En el siguiente ejemplo se define y usa una funci´n que lee de teclado un n´mero o u entero: lee entero.py 1 2 3 4 def lee_entero (): return int(raw_input ()) a = lee_entero () Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 243 243 Introducción a la programación con Python - UJIUJI c
    • Recuerda: al llamar a una funci´n los par´ntesis no son opcionales. Podemos representar o e esta funci´n como una caja que proporciona un dato de salida sin ning´n dato de entrada: o u lee entero n´mero entero u Mmmm. Te hemos dicho que la funci´n no recibe dato alguno y debes estar pensando o que te hemos enga˜ado, pues la funci´n lee un dato de teclado. Quiz´ este diagrama n o a represente mejor la entrada/salida funci´n: o lee entero n´mero entero u De acuerdo; pero no te equivoques: el dato le´ de teclado no es un dato que el programa ıdo suministre a la funci´n. o Par´metros o teclado a Un error frecuente al dise˜ar funciones consiste en tratar de obtener la informaci´n n o directamente de teclado. No es que est´ prohibido, pero es ciertamente excepcional que e una funci´n obtenga la informaci´n de ese modo. Cuando te pidan dise˜ar una funci´n o o n o que recibe uno o m´s datos, se sobreentiende que debes suministrarlos como argumentos a en la llamada, no leerlos de teclado. Cuando queramos que la funci´n lea algo de teclado, o lo diremos expl´ ıcitamente. Insistimos y esta vez ilustrando el error con un ejemplo. Imagina que te piden que dise˜es una funci´n que diga si un n´mero es par devolviendo True si es as´ y False en n o u ı caso contrario. Te piden una funci´n como ´sta: o e def es_par(n): return n % 2 == 0 Muchos programadores novatos escriben err´neamente una funci´n como esta otra: o o def es_par(): n = int(raw_input(’Dame␣un␣n´mero:␣’)) u return n % 2 == 0 E Est´ mal. Escribir esa funci´n as´ demuestra, cuando menos, falta de soltura en el dise˜o a o ı n de funciones. Si hubi´semos querido una funci´n como ´sa, te hubi´semos pedido una e o e e funci´n que lea de teclado un n´mero entero y devuelva True si es par y False en caso o u contrario. Esta otra funci´n lee un n´mero de teclado y se asegura de que sea positivo: o u lee positivo 2.py 1 2 3 4 5 6 7 lee positivo.py def lee_entero_positivo(): numero = int(raw_input()) while numero < 0: numero = int(raw_input()) return numero a = lee_entero_positivo() Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 244 244 Introducción a la programación con Python - cUJI UJI
    • Y esta versi´n muestra por pantalla un mensaje informativo cuando el usuario se o equivoca: lee positivo.py lee positivo.py 1 2 3 4 5 6 7 8 def lee_entero_positivo(): numero = int(raw_input()) while numero < 0: print ’Ha␣cometido␣un␣error:␣el␣n´mero␣debe␣ser␣positivo.’ u numero = int(raw_input()) return numero a = lee_entero_positivo() Los par´ntesis son necesarios e Un error t´ ıpico de los aprendices es llamar a las funciones sin par´metros omitiendo a los par´ntesis, pues les parecen innecesarios. Veamos qu´ ocurre en tal caso: e e ↱ ↱ >>> def saluda(): ... print ’Hola’ ... >>> saluda() Hola >>> saluda <function saluda at 0x8160854> ↱ ↱ ↱ Como puedes ver, el ultimo resultado no es la impresi´n del mensaje ˂˂Hola˃˃, sino o ´ otro encerrado entre s´ ımbolos de menor y mayor. Estamos llamando incorrectamente a la funci´n: saluda, sin par´ntesis, es un ˂˂objeto˃˃ Python ubicado en la direcci´n de o e o memoria 8160854 en hexadecimal (n´mero que puede ser distinto con cada ejecuci´n). u o Ciertas t´cnicas avanzadas de programaci´n sacan partido del uso del identificador e o de la funci´n sin par´ntesis, pero a´n no est´s preparado para entender c´mo y por o e u a o qu´. El cuadro ˂˂Un m´todo de integraci´n gen´rico˃˃ (p´gina 295) te proporcionar´ m´s e e o e a a a informaci´n. o Una posible aplicaci´n de la definici´n de funciones sin argumentos es la presentaci´n o o o de men´s con selecci´n de opci´n por teclado. Esta funci´n, por ejemplo, muestra un men´ u o o o u con tres opciones, pide al usuario que seleccione una y se asegura de que la opci´n o seleccionada es v´lida. Si el usuario se equivoca, se le informa por pantalla del error: a funcion menu.py 1 2 3 4 5 6 7 8 9 10 11 funcion menu.py def menu(): opcion = ’’ while not (’a’ <= opcion <= ’c’): print ’Cajero␣autom´tico.’ a print ’a)␣Ingresar␣dinero.’ print ’b)␣Sacar␣dinero.’ print ’c)␣Consultar␣saldo.’ opcion = raw_input(’Escoja␣una␣opci´n:␣’) o if not (opcion >= ’a’ and opcion <= ’c’): print ’S´lo␣puede␣escoger␣las␣letras␣a,␣b␣o␣c.␣Int´ntelo␣de␣nuevo.’ o e return opcion Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 245 245 Introducción a la programación con Python - cUJI UJI
    • menu cadena con valor ’a’, ’b’ o ’c’ Hemos dibujado una pantalla para dejar claro que uno de los cometidos de la esta funci´n o es mostrar informaci´n por pantalla (las opciones del men´). o u Si en nuestro programa principal se usa con frecuencia el men´, bastar´ con efectuar u a las correspondientes llamadas a la funci´n menu() y almacenar la opci´n seleccionada o o en una variable. As´ ı: accion = menu() La variable accion contendr´ la letra seleccionada por el usuario. Gracias al control que a efect´a la funci´n, estaremos seguros de que dicha variable contiene una ’a’, una ’b’ o u o una ’c’. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 298 ¿Funciona esta otra versi´n de menu? o funcion menu.py funcion menu 2.py 1 2 3 4 5 6 7 8 9 10 11 def menu(): opcion = ’’ while len(opcion) != 1 or opcion not in ’abc’: print ’Cajero␣autom´tico.’ a print ’a)␣Ingresar␣dinero.’ print ’b)␣Sacar␣dinero.’ print ’c)␣Consultar␣saldo.’ opcion = raw_input(’Escoja␣una␣opci´n:␣’) o if len(opcion) != 1 or opcion not in ’abc’: print ’S´lo␣puede␣escoger␣las␣letras␣a,␣b␣o␣c.␣Int´ntelo␣de␣nuevo.’ o e return opcion · 299 Dise˜a una funci´n llamada menu_generico que reciba una lista con opciones. n o Cada opci´n se asociar´ a un n´mero entre 1 y la talla de la lista y la funci´n mostrar´ o a u o a por pantalla el men´ con el n´mero asociado a cada opci´n. El usuario deber´ introducir u u o a por teclado una opci´n. Si la opci´n es v´lida, se devolver´ su valor, y si no, se le advertir´ o o a a a del error y se solicitar´ nuevamente la introducci´n de un valor. a o He aqu´ un ejemplo de llamada a la funci´n: ı o menu_generico([’Saludar’, ’Despedirse’, ’Salir’]) Al ejecutarla, obtendremos en pantalla el siguiente texto: 1) Saludar 2) Despedirse 3) Salir Escoja opci´n: o · 300 En un programa que estamos dise˜ando preguntamos al usuario numerosas cuesn tiones que requieren una respuesta afirmativa o negativa. Dise˜a una funci´n llamada n o si_o_no que reciba una cadena (la pregunta). Dicha cadena se mostrar´ por pantalla y a se solicitar´ al usuario que responda. S´lo aceptaremos como respuestas v´lidas ’si’, a o a ’s’, ’Si’, ’SI’, ’no’, ’n’, ’No’, ’NO’, las cuatro primeras para respuestas afirmativas y las cuatro ultimas para respuestas negativas. Cada vez que el usuario se equivoque, ´ en pantalla aparecer´ un mensaje que le recuerde las respuestas aceptables. La funci´n a o devolver´ True si la respuesta es afirmativa, y False en caso contrario. a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 246 246 Introducción a la programación con Python - UJIUJI c
    • .................................................................................. Hay funciones sin par´metros que puedes importar de m´dulos. Una que usaremos en a o varias ocasiones es random (en ingl´s ˂˂random˃˃ significa ˂˂aleatorio˃˃). La funci´n random, e o definida en el m´dulo que tiene el mismo nombre, devuelve un n´mero al azar mayor o o u igual que 0.0 y menor que 1.0. random valor x tal que 0.0 ≤ x < 1.0 Veamos un ejemplo de uso de la funci´n: o ↱ >>> from random import random >>> random() 0.73646697433706487 >>> random() 0.6416606281483086 >>> random() 0.36339080016840919 >>> random() 0.99622235710683393 ↱ ↱ ↱ ↱ ¿Ves? La funci´n se invoca sin argumentos (entre los par´ntesis no hay nada) y cada o e vez que lo hacemos obtenemos un resultado diferente. ¿Qu´ inter´s tiene una funci´n tan e e o extra˜a? Una funci´n capaz de generar n´meros aleatorios encuentra muchos campos de n o u aplicaci´n: estad´ o ıstica, videojuegos, simulaci´n, etc. Dentro de poco le sacaremos partido. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 301 Dise˜a una funci´n sin argumentos que devuelva un n´mero aleatorio mayor o n o u igual que 0.0 y menor que 10.0. Puedes llamar a la funci´n random desde tu funci´n. o o · 302 Dise˜a una funci´n sin argumentos que devuelva un n´mero aleatorio mayor o n o u igual que −10.0 y menor que 10.0. · 303 Para dise˜ar un juego de tablero nos vendr´ bien disponer de un ˂˂dado electr´nico˃˃. n a o Escribe una funci´n Python sin argumentos llamada dado que devuelva un n´mero entero o u aleatorio entre 1 y 6. .................................................................................. 6.2.4. Procedimientos: funciones sin devoluci´n de valor o No todas las funciones devuelven un valor. Una funci´n que no devuelve un valor se o denomina procedimiento. ¿Y para qu´ sirve una funci´n que no devuelve nada? Bueno, e o puede, por ejemplo, mostrar mensajes o resultados por pantalla. No te equivoques: mostrar algo por pantalla no es devolver nada. Mostrar un mensaje por pantalla es un efecto secundario. Ve´moslo con un ejemplo. Vamos a implementar ahora un programa que solicita al a usuario un n´mero y muestra por pantalla todos los n´meros perfectos entre 1 y dicho u u n´mero. u tabla perfectos m Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 247 247 Introducción a la programación con Python - UJIUJI c
    • Reutilizaremos la funci´n es_perfecto que definimos antes en este mismo cap´ o ıtulo. Como la soluci´n no es muy complicada, te la ofrecemos completamente desarrollada: o tabla perfectos 2.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 tabla perfectos.py def es_perfecto(n): # Averigua si el n´mero n es o no es perfecto. u sumatorio = 0 for i in range(1, n): if n % i == 0: sumatorio += i return sumatorio == n def tabla_perfectos(m): # Muestra todos los n´meros perfectos entre 1 y m. u for i in range(1, m+1): if es_perfecto(i): print i, ’es␣un␣n´mero␣perfecto’ u numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u tabla_perfectos(numero) F´ ıjate en que la funci´n tabla_perfectos no devuelve nada (no hay sentencia return): o es un procedimiento. Tambi´n resulta interesante la l´ e ınea 10: como es_perfecto devuelve True o False, podemos utilizarla directamente como condici´n del if. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 304 Dise˜a un programa que, dado un n´mero n, muestre por pantalla todas las n u parejas de n´meros amigos menores que n. La impresi´n de los resultados debe hacerse u o desde un procedimiento. Dos n´meros amigos s´lo deber´n aparecer una vez por pantalla. Por ejemplo, 220 y u o a 284 son amigos: si aparece el mensaje ˂˂220 y 284 son amigos˃˃, no podr´ aparecer el a mensaje ˂˂284 y 220 son amigos˃˃, pues es redundante. Debes dise˜ar una funci´n que diga si dos n´meros son amigos y un procedimiento n o u que muestre la tabla. · 305 Implementa un procedimiento Python tal que, dado un n´mero entero, muestre u por pantalla sus cifras en orden inverso. Por ejemplo, si el procedimiento recibe el n´mero u 324, mostrar´ por pantalla el 4, el 2 y el 3 (en l´ a ıneas diferentes). · 306 Dise˜a una funci´n es_primo que determine si un n´mero es primo (devolviendo n o u True) o no (devolviendo False). Dise˜a a continuaci´n un procedimiento muestra_primos n o que reciba un n´mero y muestre por pantalla todos los n´meros primos entre 1 y dicho u u n´mero. u .................................................................................. ¿Y qu´ ocurre si utilizamos un procedimiento como si fuera una funci´n con devoluci´n e o o de valor? Podemos hacer la prueba. Asignemos a una variable el resultado de llamar a tabla_perfectos y mostremos por pantalla el valor de la variable: tabla perfectos.py tabla perfectos.py . . . 12 13 14 15 numero = int(raw_input(’Dame␣un␣n´mero:␣’)) u resultado = tabla_perfectos(100) print resultado Por pantalla aparece lo siguiente: Dame un n´mero: 100 u 6 es un n´mero perfecto u 28 es un n´mero perfecto u None Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 248 248 Introducción a la programación con Python - UJIUJI c
    • Condicionales que trabajan directamente con valores l´gicos o Ciertas funciones devuelven directamente un valor l´gico. Considera, por ejemplo, esta o funci´n, que nos dice si un n´mero es o no es par: o u def es_par(n): return n % 2 == 0 Si una sentencia condicional toma una decisi´n en funci´n de si un n´mero es par o no, o o u puedes codificar as´ la condici´n: ı o if es_par(n): ... Observa que no hemos usado comparador alguno en la condici´n del if. ¿Por qu´? Porque o e la funci´n es_par(n) devuelve True o False directamente. Los programadores primerizos o tienen tendencia a codificar la misma condici´n as´ o ı: if es_par(n) == True : ... Es decir, comparan el valor devuelto por es_par con el valor True, pues les da la sensaci´n de que un if sin comparaci´n no est´ completo. No pasa nada si usas la o o a comparaci´n, pero es innecesaria. Es m´s, si no usas la comparaci´n, el programa es o a o m´s legible: la sentencia condicional se lee directamente como ˂˂si n es par˃˃ en lugar a de ˂˂si n es par es cierto˃˃, que es un extra˜o circunloquio. n Si en la sentencia condicional se desea comprobar que el n´mero es impar, puedes u hacerlo as´ ı: if not es_par(n): ... Es muy legible: ˂˂si no es par n˃˃. Nuevamente, los programadores que est´n empezando escriben: a if es_par(n) == False : ... que se lee como ˂˂si n es par es falso˃˃. Peor, ¿no? Acost´mbrate a usar la versi´n que no usa operador de comparaci´n. Es m´s legible. u o o a Mira la ultima l´ ınea, que muestra el contenido de resultado. Recuerda que Python usa ´ None para indicar un valor nulo o la ausencia de valor, y una funci´n que ˂˂no devuelve o nada˃˃ devuelve la ˂˂ausencia de valor˃˃, ¿no? Cambiamos de tercio. Sup´n que mantenemos dos listas con igual n´mero de eleo u mentos. Una de ellas, llamada alumnos, contiene una serie de nombres y la otra, llamada notas, una serie de n´meros flotantes entre 0.0 y 10.0. En notas guardamos la calificaci´n u o obtenida por los alumnos cuyos nombres est´n en alumnos: la nota notas[i] corresponde a al estudiante alumnos[i]. Una posible configuraci´n de las listas ser´ ´sta: o ıa e 1 2 alumnos = [’Ana␣Pi’, ’Pau␣L´pez’, ’Luis␣Sol’, ’Mar␣Vega’, ’Paz␣Mir’] o notas = [10, 5.5, 2.0, 8.5, 7.0] De acuerdo con ella, el alumno Pau L´pez, por ejemplo, fue calificado con un 5.5. o Nos piden dise˜ar un procedimiento que recibe como datos las dos listas y una cadena n con el nombre de un estudiante. Si el estudiante pertenece a la clase, el procedimiento imprimir´ su nombre y nota en pantalla. Si no es un alumno incluido en la lista, se a imprimir´ un mensaje que lo advierta. a Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 249 249 Introducción a la programación con Python - cUJI UJI
    • Valor de retorno o pantalla Te hemos mostrado de momento que es posible imprimir informaci´n directamente por o pantalla desde una funci´n (o procedimiento). Ojo: s´lo lo hacemos cuando el prop´sito o o o de la funci´n es mostrar esa informaci´n. Muchos aprendices que no han comprendido o o bien el significado de la sentencia return, la sustituyen por una sentencia print. Mal. Cuando te piden que dise˜es una funci´n que devuelva un valor, te piden que lo haga n o con la sentencia return, que es la unica forma v´lida (que conoces) de devolver un valor. a ´ Mostrar algo por pantalla no es devolver ese algo. Cuando quieran que muestres algo por pantalla, te lo dir´n expl´ a ıcitamente. Sup´n que te piden que dise˜es una funci´n que reciba un entero y devuelva su o n o ultima cifra. Te piden esto: ´ 1 2 def ultima_cifra(n): return n % 10 No te piden esto otro: 1 2 def ultima_cifra(n): print n % 10 E F´ ıjate en que la segunda definici´n hace que la funci´n no pueda usarse en expresiones o o como esta: 1 a = ultima_cifra(10293) + 1 Como ultima_cifra no devuelve nada, ¿qu´ valor se est´ sumando a 1 y guardando en e a a? ¡Ah! A´n se puede hace peor. Hay quien define la funci´n as´ u o ı: 1 2 3 def ultima_cifra(): n = int(raw_input(’Dame␣un␣n´mero:␣’)) u print n % 10 E E No s´lo demuestra no entender qu´ es el valor de retorno; adem´s, demuestra que o e a no tiene ni idea de lo que es el paso de par´metros. Evita dar esa impresi´n: lee bien lo a o que se pide y usa par´metros y valor de retorno a menos que se te diga expl´ a ıcitamente lo contrario. Lo normal es que la mayor parte de las funciones produzcan datos (devueltos con return) a partir de otros datos (obtenidos con par´metros) y que el programa principal a o funciones muy espec´ ıficas lean de teclado y muestren por pantalla. muestra nota de alumno alumnos notas alumno buscado Aqu´ tienes una primera versi´n: ı o clase 3.py 1 2 3 4 5 6 7 clase.py def muestra_nota_de_alumno(alumnos, notas, alumno_buscado): encontrado = False for i in range(len(alumnos)): if alumnos[i] == alumno_buscado: print alumno_buscado, nota[i] encontrado = True if not encontrado: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 250 250 Introducción a la programación con Python -cUJI UJI
    • 8 print ’El␣alumno␣%s␣no␣pertenece␣al␣grupo’ % alumno_buscado Lo podemos hacer m´s eficientemente: cuando hemos encontrado al alumno e impreso a el correspondiente mensaje, no tiene sentido seguir iterando: clase 4.py 1 2 3 4 5 6 7 8 9 Esta otra versi´n es a´n m´s breve3 : o u a clase.py 1 2 3 4 5 6 clase.py def muestra_nota_de_alumno(alumnos, notas, alumno_buscado): encontrado = False for i in range(len(alumnos)): if alumnos[i] == alumno_buscado: print alumno_buscado, nota[i] encontrado = True break if not encontrado: print ’El␣alumno␣%s␣no␣pertenece␣al␣grupo’ % alumno_buscado clase.py def muestra_nota_de_alumno(alumnos, notas, alumno_buscado): for i in range(len(alumnos)): if alumnos[i] == alumno_buscado: print alumno_buscado, nota[i] return print ’El␣alumno␣%s␣no␣pertenece␣al␣grupo’ % alumno_buscado Los procedimientos aceptan el uso de la sentencia return aunque, eso s´ sin expresi´n ı, o alguna a continuaci´n (recuerda que los procedimientos no devuelven valor alguno). ¿Qu´ o e hace esa sentencia? Aborta inmediatamente la ejecuci´n de la llamada a la funci´n. Es, o o en cierto modo, similar a una sentencia break en un bucle, pero asociada a la ejecuci´n o de una funci´n. o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 307 En el problema de los alumnos y las notas, se pide: a) Dise˜ar un procedimiento que reciba las dos listas y muestre por pantalla el nombre n de todos los estudiantes que aprobaron el examen. b) Dise˜ar una funci´n que reciba la lista de notas y devuelva el n´mero de aprobados. n o u c) Dise˜ar un procedimiento que reciba las dos listas y muestre por pantalla el nombre n de todos los estudiantes que obtuvieron la m´xima nota. a d) Dise˜ar un procedimiento que reciba las dos listas y muestre por pantalla el nombre n de todos los estudiantes cuya calificaci´n es igual o superior a la calificaci´n media. o o e) Dise˜ar una funci´n que reciba las dos listas y un nombre (una cadena); si el nombre n o est´ en la lista de estudiantes, devolver´ su nota, si no, devolver´ None. a a a · 308 Tenemos los tiempos de cada ciclista y etapa participantes en la ultima vuelta ´ ciclista local. La lista ciclistas contiene una serie de nombres. La matriz tiempos tiene una fila por cada ciclista, en el mismo orden con que aparecen en ciclistas. Cada fila tiene el tiempo en segundos (un valor flotante) invertido en cada una de las 5 etapas de la carrera. ¿Complicado? Este ejemplo te ayudar´: te mostramos a continuaci´n un ejemplo a o de lista ciclistas y de matriz tiempos para 3 corredores. 3 . . . aunque puede disgustar a los puristas de la programaci´n estructurada. Seg´n estos, s´lo debe haber o u o un punto de salida de la funci´n: el final de su cuerpo. Salir directamente desde un bucle les parece que o dificulta la comprensi´n del programa. o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 251 251 Introducción a la programación con Python - UJIUJI c
    • 1 2 3 4 ciclistas = [’Pere␣Porcar’, ’Joan␣Beltran’, ’Lled´␣Fabra’] o tiempo = [[10092.0, 12473.1, 13732.3, 10232.1, 10332.3], [11726.2, 11161.2, 12272.1, 11292.0, 12534.0], [10193.4, 10292.1, 11712.9, 10133.4, 11632.0]] En el ejemplo, el ciclista Joan Beltran invirti´ 11161.2 segundos en la segunda etapa. o Se pide: Una funci´n que reciba la lista y la matriz y devuelva el ganador de la vuelta (aquel o cuya suma de tiempos en las 5 etapas es m´ ınima). Una funci´n que reciba la lista, la matriz y un n´mero de etapa y devuelva el o u nombre del ganador de la etapa. Un procedimiento que reciba la lista, la matriz y muestre por pantalla el ganador de cada una de las etapas. .................................................................................. 6.2.5. Funciones que devuelven varios valores mediante una lista En principio una funci´n puede devolver un solo valor con la sentencia return. Pero o sabemos que una lista es un objeto que contiene una secuencia de valores. Si devolvemos una lista podemos, pues, devolver varios valores. Por ejemplo, una funci´n puede devolver al mismo tiempo el m´ o ınimo y el m´ximo de a 3 n´meros: u minmax.py minmax 6.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def minmax(a, b, c): if a < b: if a < c: min = a else: min = c else: if b < c: min = b else: min = c if a > b: if a > c: max = a else: max = c else: if b > c: max = b else: max = c return [min, max] Podemos representar a la funci´n con este diagrama: o minmax a b c aunque quiz´ sea m´s apropiado este otro: a a Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: m´ ınimo de a, b y c m´ximo de a, b y c a 252 252 Introducción a la programación con Python - c UJI UJI
    • minmax a b c una lista con el m´ ınimo y el m´ximo de a, b y c a ¿C´mo podr´ o ıamos llamar a esa funci´n? Una posibilidad es ´sta: o e minmax 7.py minmax.py . . . 24 25 26 a = minmax(10, 2, 5) print ’El␣m´nimo␣es’, a[0] ı print ’El␣m´ximo␣es’, a[1] a Y ´sta es otra: e minmax 8.py minmax.py . . . 24 25 26 [minimo, maximo] = minmax(10, 2, 5) print ’El␣m´nimo␣es’, minimo ı print ’El␣m´ximo␣es’, maximo a En este segundo caso hemos asignado una lista a otra. ¿Qu´ significa eso para e Python? Pues que cada elemento de la lista a la derecha del igual debe asignarse a cada variable de la lista a la izquierda del igual. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 309 ¿Qu´ aparecer´ por pantalla al ejecutar este programa? e a 1 2 3 4 a=1 b=2 [a, b] = [b, a] print a, b · 310 Dise˜a una funci´n que reciba una lista de enteros y devuelva los n´meros n o u m´ ınimo y m´ximo de la lista simult´neamente. a a · 311 Dise˜a una funci´n que reciba los tres coeficientes de una ecuaci´n de segundo n o o grado de la forma ax 2 + bx + c = 0 y devuelva una lista con sus soluciones reales. Si la ecuaci´n s´lo tiene una soluci´n real, devuelve una lista con dos copias de la misma. o o o Si no tiene soluci´n real alguna o si tiene infinitas soluciones devuelve una lista con dos o copias del valor None. · 312 Dise˜a una funci´n que reciba una lista de palabras (cadenas) y devuelva, sin o mult´neamente, la primera y la ultima palabras seg´n el orden alfab´tico. a u e ´ .................................................................................. 6.3. Un ejemplo: Memori´n o Ya es hora de hacer algo interesante con lo que hemos aprendido. Vamos a construir un sencillo juego solitario, Memori´n, con el que aprenderemos, entre otras cosas, a manejar o el rat´n desde PythonG. Memori´n se juega sobre un tablero de 4 filas y 6 columnas. o o Cada celda del tablero contiene un s´ ımbolo (una letra), pero no es visible porque est´ a tapada por una baldosa. De cada s´ ımbolo hay dos ejemplares (dos ˂˂a˃˃, dos ˂˂b˃˃, etc.) y hemos de emparejarlos. Una jugada consiste en levantar dos baldosas para ver las letras que hay bajo ellas. Primero se levanta una y despu´s otra. Si las letras que ocultan son e iguales, las baldosas se retiran del tablero, pues hemos conseguido un emparejamiento. Si las letras son diferentes, hemos de volver a taparlas. El objetivo es emparejar todas las letras en el menor n´mero de jugadas. u Esta figura te muestra una partida de Memori´n ya empezada: o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 253 253 Introducción a la programación con Python - UJIUJI c
    • Inicializaci´n m´ltiple o u Ahora que sabes que es posible asignar valores a varias variables simult´neamente, puea des simplificar algunos programas que empiezan con la inicializaci´n de varias variables. o Por ejemplo, esta serie de asignaciones: a=1 b=2 c=3 puede reescribirse as´ ı: [a, b, c] = [1, 2, 3] Mmmm. A´n podemos escribirlo m´s brevemente: u a a, b, c = 1, 2, 3 ¿Por qu´ no hacen falta los corchetes? Porque en este caso estamos usando una estruce tura ligeramente diferente: una tupla. Una tupla es una lista inmutable y no necesita ir encerrada entre corchetes. As´ pues, el intercambio del valor de dos variables puede escribirse as´ ı ı: a, b = b, a C´modo, ¿no crees? o ¿Por d´nde empezamos a escribir el programa? Pensemos en qu´ informaci´n neceo e o sitaremos. Por una parte, necesitaremos una matriz con 4 × 6 celdas para almacenar las letras. Por otra parte, otra matriz ˂˂paralela˃˃ que nos diga si una casilla tiene o no tiene baldosa. Inicialmente todas las casillas tienen baldosa. Nos vendr´ bien disponer de una a rutina que construya una matriz, pues la usaremos para construir la matriz de letras y la matriz de baldosas. En lugar de hacer que esta rutina construya siempre una matriz con 4 × 6, vamos a hacer que reciba como par´metros el n´mero de filas y columnas: a u memorion.py def crea_matriz(filas, columnas): matriz = [] for i in range(filas): matriz.append([None] * columnas) return matriz ... # Programa principal filas = 4 columnas = 6 simbolo = crea_matriz(filas, columnas) baldosa = crea_matriz(filas, columnas) Nuestro primer problema importante es inicializar la matriz de letras al azar. ¿C´mo o podemos resolverlo? Te sugerimos que consideres estas estrategias: Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 254 254 Introducción a la programación con Python - cUJI UJI
    • Como vamos a ubicar 12 letras diferentes (dos ejemplares de cada), un bucle va recorriendo los caracteres de la cadena ’abcdefghijkl’. Para cada letra, elegimos dos pares de coordenadas al azar (ahora veremos c´mo). Imagina que decidimos que o la letra ’f’ va a las posiciones (i, j) y (i , j ), donde i e i son n´meros de fila y j y u j son n´meros de columna. Hemos de asegurarnos de que las casillas (i, j) e (i , j ) u son diferentes y no est´n ya ocupadas con otras letras. (Ten en cuenta que hemos a generado esos pares de n´meros al azar, as´ que pueden caer en cualquier sitio y u ı e e ´ste no tiene por qu´ estar libre.) Mientras generemos un par de coordenadas que corresponden a una casilla ocupada, repetiremos la tirada. memorion.py from random import random ... def dimension(matriz): return [len(matriz), len(matriz[0])] def rellena_simbolos(simbolo): # Primera versi´n. o [filas, columnas] = dimension(simbolo) for caracter in ’abcdefghijkl’: for ejemplar in range(2): ocupado = True while ocupado: [i, j] = [int(filas * random()), int(columnas * random())] if simbolo[i][j] == None: ocupado = False simbolo[i][j] = caracter ¿Entiendes bien c´mo generamos el n´mero de fila y columna? Usamos random, o u que devuelve un valor mayor o igual que 0.0 y menor que 1.0. Si multiplicamos ese valor por filas, el valor aleatorio es mayor o igual que 0.0 y menor que filas. Y si nos quedamos con su parte entera, tenemos un valor entre 0 y filas-1. Perfecto. No ha sido demasiado complicado dise˜ar esta funci´n, pero el m´todo que implen o e menta presenta una serio problema: como genera coordenadas al azar hasta dar con una libre, ¿qu´ ocurre cuando quedan muy pocas libres? Imagina que seguimos e esta estrategia en un tablero de 1000 por 1000 casillas. Cuando s´lo queden dos o libres, probablemente tengamos que generar much´ ısimas ˂˂tiradas˃˃ de dado hasta dar con una casillas libres. La probabilidad de que demos con una de ellas es de una contra medio mill´n. Eso significa que, en promedio, har´ falta echar medio o a mill´n de veces los dados para encontrar una casilla libre. Ineficiente a m´s no o a poder. Creamos una lista con todos los pares de coordenadas posibles, o sea, una lista de listas: [[0,0], [0,1], [0,2], ..., [3, 5]]. A continuaci´n, desordenamos la o lista. ¿C´mo? Con escogiendo muchas veces (por ejemplo, mil veces) un par de o elementos de la lista e intercambi´ndolos. Una vez desordenada la lista, la usamos a para asignar los caracteres: memorion.py from random import random ... def rellena_simbolos(simbolo): # Segunda versi´n. o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 255 255 Introducción a la programación con Python -cUJI UJI
    • [filas, columnas] = dimension(simbolo) lista = [] for i in range(filas): for j in range(columnas): lista.append( [i, j] ) for vez in range(1000): [i, j] = [int(len(lista) * random()), int(len(lista) * random())] aux = lista[i] lista[i] = lista[j] lista[j] = aux i=0 for coords in lista: simbolo[coords[0]][coords[1]] = ’abcdefghijkl’[i/2] i += 1 Complicado, ¿verdad? No s´lo es complicado; adem´s, presenta un inconveniente: o a un elevado (y gratuito) consumo de memoria. Imagina que la matriz tiene dimensi´n o 1000 × 1000: hemos de construir una lista con un mill´n de elementos y barajarlos o (para lo que necesitaremos bastante m´s que 1000 intercambios). Una lista tan a grande ocupa mucha memoria. La siguiente soluci´n es igual de efectiva y no o consume tanta memoria. Ponemos las letras ordenadamente en la matriz. Despu´s, intercambiamos mil veces e un par de casillas escogidas al azar: memorion.py def rellena_simbolos(simbolo): [filas, columnas] = dimension(simbolo) numsimbolo = 0.0 for i in range(filas): for j in range(columnas): simbolo[i][j] = chr(ord(’a’)+int(numsimbolo)) numsimbolo += 0.5 for i in range(1000): [f 1, c1] = [int(filas * random()), int(columnas * random())] [f 2, c2] = [int(filas * random()), int(columnas * random())] tmp = simbolo[f 1][c1] simbolo[f 1][c1] = simbolo[f 2][c2] simbolo[f 2][c2] = tmp Estudia con cuidado esta funci´n. Es la que vamos a usar en nuestro programa. o Bueno. Ya le hemos dedicado bastante tiempo a la inicializaci´n de la matriz de o s´ ımbolos. Ahora vamos a dibujar en pantalla su contenido. Necesitamos inicializar en primer lugar el lienzo. memorion.py ... filas = 4 columnas = 6 window_coordinates(0,0,columnas,filas) window_size(columnas*40, filas*40) ... F´ ıjate: hemos definido un sistema de coordenadas que facilita el dibujo de la matriz: el eje x comprende el rango 0 ≤ x ≤ columnas y el eje y comprende el rango 0 ≤ y ≤ filas. Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 256 256 Introducción a la programación con Python - cUJI UJI
    • Por otra parte, hemos reservado un area de 40 × 40 p´ ıxels a cada celda. Dibujemos la ´ matriz de s´ ımbolos memorion.py def dibuja_simbolos(simbolo): [filas, columnas] = dimension(simbolo) for i in range(filas): for j in range(columnas): create_text(j+.5, i+.5, simbolo[i][j], 18) ... simbolo = crea_matriz(filas, columnas) baldosa = crea_matriz(filas, columnas) rellena_simbolos(simbolo) dibuja_simbolos(simbolo) El procedimiento dibuja_simbolos recibe la matriz de s´ ımbolos y crea en pantalla un elemento de texto por cada celda. En el programa principal se llama a este procedimiento una vez se ha generado el contenido de la matriz. Pongamos en un unico fichero todo lo que hemos hecho de momento. ´ memorion 2.py 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 29 30 31 32 33 34 35 36 37 memorion.py from random import random def crea_matriz(filas, columnas): matriz = [] for i in range(filas): matriz.append([None] * columnas) return matriz def dimension(matriz): return [len(matriz), len(matriz[0])] def rellena_simbolos(simbolo): filas = len(simbolo) columnas = len(simbolo[0]) numsimbolo = 0.0 for i in range(filas): for j in range(columnas): simbolo[i][j] = chr(ord(’a’)+int(numsimbolo)) numsimbolo += 0.5 for i in range(1000): [f 1, c1] = [int(filas * random()), int(columnas * random())] [f 2, c2] = [int(filas * random()), int(columnas * random())] tmp = simbolo[f 1][c1] simbolo[f 1][c1] = simbolo[f 2][c2] simbolo[f 2][c2] = tmp def dibuja_simbolos(simbolo): filas = len(simbolo) columnas = len(simbolo[0]) for i in range(filas): for j in range(columnas): create_text(j+.5, i+.5, simbolo[i][j], 18) # Programa principal filas = 4 columnas = 6 window_coordinates(0,0,columnas,filas) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 257 257 Introducción a la programación con Python - cUJI UJI
    • 38 39 40 41 42 43 window_size(columnas*40, filas*40) simbolo = crea_matriz(filas, columnas) baldosa = crea_matriz(filas, columnas) rellena_simbolos(simbolo) dibuja_simbolos(simbolo) Ejecuta el programa en el entorno PythonG y ver´s en pantalla el resultado de desordenar a las letras en la matriz. Sigamos. Ocup´monos ahora de las baldosas. Todas las celdas de la matriz han e de cubrirse con una baldosa. Una baldosa no es m´s que un rect´ngulo (de hecho, un a a cuadrado) que cubre una letra. Como la dibujamos despu´s de haber dibujado la letra e correspondiente, la tapar´. Ocurre que el juego consiste en ir destruyendo baldosas, as´ a ı que m´s adelante necesitaremos conocer el identificador de cada baldosa para poder a borrarla mediante una llamada a erase4 . Haremos una cosa: en la matriz de baldosas guardaremos el identificador de los identificadores gr´ficos. Cuando destruyamos una a baldosa, guardaremos el valor None en la celda correspondiente. memorion.py def dibuja_baldosas(baldosa): [filas, columnas] = dimension(baldosa) for i in range(filas): for j in range(columnas): baldosa[i][j] = create_filled_rectangle(j, i, j+1, i+1, ’black’, ’blue’) Este procedimiento crea todas las baldosas y memoriza sus identificadores. Para destruir la baldosa de la fila f y columna c bastar´ con llamar a erase(baldosa[f ][c]) y poner a en baldosa[f ][c] el valor None. Lo mejor ser´ preparar un procedimiento que elimine a una baldosa: memorion.py def borra_baldosa(baldosa, f , c): erase(baldosa[f ][c]) baldosa[f ][c] = None Durante la partida pincharemos grupos de dos baldosas para destruirlas y ver qu´ e letras esconden. Si las letras no coinciden, tendremos que ˂˂reconstruir˃˃ las baldosas, o sea, crear dos nuevas baldosas para volver a tapar las letras que hab´ ıamos descubierto: memorion.py def dibuja_baldosa(baldosa, f , c): baldosa[f ][c] = create_filled_rectangle(c, f , c+1, f +1, ’black’, ’blue’) Redefinamos dibuja_baldosas para que haga uso de dibuja_baldosa: memorion.py def dibuja_baldosas(baldosa): [filas, columnas] = dimension(baldosa) for i in range(filas): for j in range(columnas): dibuja_baldosa(baldosa, i, j) Pensemos ahora sobre c´mo se desarrolla una partida. Una vez inicializadas las o matrices de s´ ımbolos y de baldosas, el jugador empieza a hacer jugadas. Cada jugada consiste en, primero, pinchar con el rat´n en una baldosa y, despu´s, pinchar en otra. La o e partida finaliza cuando no hay m´s baldosas que descubrir. Una primera idea consiste a en disponer un ˂˂bucle principal˃˃ que itere mientras haya baldosas en el tablero: 4 Quiz´ te convenga repasar ahora lo que ya hemos aprendido de las funciones de gesti´n de gr´ficos a o a predefinidas en PythonG. Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 258 258 Introducción a la programación con Python - cUJI UJI
    • memorion.py def hay_baldosas(baldosas): [filas, columnas] = dimension(simbolo) for fila in range(filas): for columna in range(columnas): if baldosas[fila][columna] != None: return True return False while hay_baldosas(baldosa): ... ¿Ves? La funci´n auxiliar hay_baldosas, que nos informa de si hay o no baldosas en el o tablero, es de gran ayuda para expresar con mucha claridad la condici´n del bucle. o Ocup´monos ahora del contenido del bucle. Nuestro primer objetivo es ver si el usuario e pulsa o no el bot´n del rat´n. PythonG ofrece una funci´n predefinida para conocer el o o o estado del rat´n: mouse_state. Esta funci´n devuelve un lista5 con tres elementos: estado o o de los botones, coordenada x del puntero y coordenada y del puntero. ¡Ojo!: si el puntero del rat´n no est´ en el lienzo, la lista es [None, None, None]. Cuando el puntero est´ o a a en el lienzo, el ˂˂bot´n˃˃ vale 0 si no hay nada pulsado, 1 si est´ pulsado el primer bot´n, 2 o a o si el segundo y 3 si el tercero. Familiaric´monos con el manejo del rat´n antes de seguir e o con el programa: prueba raton.py 1 2 3 4 5 prueba raton.py while 1: [boton, x, y] = mouse_state() print boton, x, y if boton == 3: break Este programa muestra los valores devueltos por mouse_state hasta que pulsamos el bot´n 3 (el de m´s a la derecha). o a F´ ıjate en que el programa no se detiene a la espera de que se pulse un bot´n: o sencillamente, nos informa en cada instante del estado del rat´n. Esto es un problema o para nuestro programa: cada vez que pulsemos el bot´n, mouse_state reporta muchas o veces que el bot´n 1 est´ pulsado, pues es f´cil que nuestro programa pregunte cientos o a a de veces por el estado del rat´n en apenas unas d´cimas de segundo. Atenci´n: en o e o realidad, no queremos actuar cuando se pulsa el bot´n del rat´n, sino cuando ´ste se o o e suelta. La transici´n de ˂˂pulsado a no pulsado˃˃ ocurre una sola vez, as´ que no presenta o ı ese problema de repetici´n. Esta funci´n sin par´metros espera a que ocurra esa transici´n o o a o y, cuando ocurre, nos devuelve el n´mero de fila y n´mero de columna sobre los que se u u produjo la pulsaci´n: o memorion.py def pulsacion_raton(): boton_antes = 0 boton_ahora = 0 while not (boton_antes == 1 and boton_ahora == 0): boton_antes = boton_ahora [boton_ahora, x, y] = mouse_state() return [int(y), int(x)] Volvamos al bucle principal del juego. Recuerda: necesitamos obtener dos pinchazos y destruir las baldosas correspondientes: memorion.py while hay_baldosas(baldosa): En realidad, una tupla. No te preocupes: considera que es una lista. Las diferencias entre lista y tupla no nos afectan ahora. 5 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 259 259 Introducción a la programación con Python - cUJI UJI
    • while 1: [f 1, c1] = pulsacion_raton() if baldosa[f 1][c1] != None: borra_baldosa(baldosa, f 1, c1) break while 1: [f 2, c2] = pulsacion_raton() if baldosa[f 2][c2] != None: borra_baldosa(baldosa, f 2, c2) break F´ ıjate en que no damos por buena una pulsaci´n a menos que tenga lugar sobre una o baldosa. Ahora tenemos en f 1 y c1 las coordenadas de la primera casilla y en f 2 y c2 las de la segunda. Si ambas contienen letras diferentes, hemos de reconstruir las baldosas: memorion.py while hay_baldosas(baldosa): while 1: [f 1, c1] = pulsacion_raton() if baldosa[f 1][c1] != None: borra_baldosa(baldosa, f 1, c1) break while 1: [f 2, c2] = pulsacion_raton() if baldosa[f 2][c2] != None: borra_baldosa(baldosa, f 2, c2) break if simbolo[f 1][c1] != simbolo[f 2][c2]: dibuja_baldosa(baldosa, f 1, c1) dibuja_baldosa(baldosa, f 2, c2) ¡Casi! El tiempo transcurrido entre la destrucci´n de la segunda baldosa y su ˂˂reconstrucci´n˃˃ o o es tan corto que no llegamos a ver la letra que se escond´ ¿C´mo hacer que se detenıa. o ga la ejecuci´n brevemente? Es hora de aprender a usar una nueva funci´n: sleep, del o o m´dulo time. La funci´n sleep ˂˂duerme˃˃ al programa por el n´mero de segundos que le o o u indiquemos. La llamada sleep(0.5), por ejemplo, ˂˂duerme˃˃ al programa durante medio segundo: memorion.py while hay_baldosas(baldosa): while 1: [f 1, c1] = pulsacion_raton() if baldosa[f 1][c1] != None: borra_baldosa(baldosa, f 1, c1) break while 1: [f 2, c2] = pulsacion_raton() if baldosa[f 2][c2] != None: borra_baldosa(baldosa, f 2, c2) break sleep(0.5) Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 260 260 UJI Introducción a la programación con Python - cUJI
    • if simbolo[f 1][c1] != simbolo[f 2][c2]: dibuja_baldosa(baldosa, f 1, c1) dibuja_baldosa(baldosa, f 2, c2) Y ya casi hemos acabado. S´lo nos falta a˜adir un contador de jugadas e informar al o n jugador de cu´ntas realiz´ para completar la partida. Te mostramos el nuevo c´digo en a o o un listado completo de nuestra aplicaci´n: o memorion.py 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 memorion.py from random import random from time import sleep def crea_matriz(filas, columnas): matriz = [] for i in range(filas): matriz.append([None] * columnas) return matriz def dimension(matriz): return [len(matriz), len(matriz[0])] def rellena_simbolos(simbolo): [filas, columnas] = dimension(simbolo) numsimbolo = 0.0 for i in range(filas): for j in range(columnas): simbolo[i][j] = chr(ord(’a’)+int(numsimbolo)) numsimbolo += .5 for i in range(1000): [f 1, c1] = [int(filas * random()), int(columnas * random())] [f 2, c2] = [int(filas * random()), int(columnas * random())] tmp = simbolo[f 1][c1] simbolo[f 1][c1] = simbolo[f 2][c2] simbolo[f 2][c2] = tmp def hay_baldosas(baldosas): [filas, columnas] = dimension(baldosas) for fila in range(filas): for columna in range(columnas): if baldosas[fila][columna] != None: return True return False def dibuja_simbolos(simbolo): [filas, columnas] = dimension(simbolo) for i in range(filas): for j in range(columnas): create_text(j+.5, i+.5, simbolo[i][j], 18) def dibuja_baldosas(baldosa): [filas, columnas] = dimension(simbolo) for i in range(filas): for j in range(columnas): dibuja_baldosa(baldosa, i, j) def dibuja_baldosa(baldosa, f , c): baldosa[f ][c] = create_filled_rectangle(c, f , c+1, f +1, ’black’, ’blue’) def borra_baldosa(baldosa, f , c): erase(baldosa[f ][c]) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 261 261 Introducción a la programación con Python - cUJI UJI
    • 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 baldosa[f ][c] = None def pulsacion_raton(): boton_antes = 0 boton_ahora = 0 while not (boton_antes == 1 and boton_ahora == 0): boton_antes = boton_ahora [boton_ahora, x, y] = mouse_state() return [int(y), int(x)] # Programa principal filas = 4 columnas = 6 window_coordinates(0,0,columnas,filas) window_size(columnas*40, filas*40) simbolo = crea_matriz(filas, columnas) baldosa = crea_matriz(filas, columnas) rellena_simbolos(simbolo) dibuja_simbolos(simbolo) dibuja_baldosas(baldosa) jugadas = 0 while hay_baldosas(baldosa): while 1: [f 1, c1] = pulsacion_raton() if baldosa[f 1][c1] != None: borra_baldosa(baldosa, f 1, c1) break while 1: [f 2, c2] = pulsacion_raton() if baldosa[f 2][c2] != None: borra_baldosa(baldosa, f 2, c2) break sleep(0.5) if simbolo[f 1][c1] != simbolo[f 2][c2]: dibuja_baldosa(baldosa, f 1, c1) dibuja_baldosa(baldosa, f 2, c2) jugadas += 1 print "Lo␣hiciste␣en␣%s␣jugadas." % jugadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 313 Modifica Memori´n para que se ofrezca al usuario jugar con tres niveles de o dificultad: F´cil: tablero de 3 × 4. a Normal: tablero de 4 × 6. Dif´ tablero de 6 × 8. ıcil: · 314 Implementa Memori´n3, una variante de Memori´n en el que hay que emparejar o o grupos de 3 letras iguales. (Aseg´rate de que el n´mero de casillas de la matriz sea u u m´ltiplo de 3.) u Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 262 262 Introducción a la programación con Python - UJIUJI c
    • · 315 Construye el programa del Buscaminas inspir´ndote en la forma en que hemos a desarrollado el juego Memori´n. Te damos unas pistas para ayudarte en le implementao ci´n: o Crea una matriz cuyas casillas contengan el valor True o False. El primer valor indica que hay una mina en esa casilla. Ubica las minas al azar. El n´mero de u minas depender´ de la dificultad del juego. a Crea una matriz que contenga el n´mero de minas que rodean a cada casilla. Calcula u esos valores a partir de la matriz de minas. Ojo con las casillas ˂˂especiales˃˃: el n´mero de vecinos de las casillas de los bordes requiere un cuidado especial. u Dibuja las minas y baldosas que las tapan. Define adecuadamente el sistema de coordenadas del lienzo. Usa una rutina de control del rat´n similar a la desarrollada para Memori´n. Te o o interesa detectar dos pulsaciones de rat´n distintas: la del bot´n 1, que asociamos o o a ˂˂descubre casilla˃˃, y la del bot´n 3, que asociamos a ˂˂marcar posici´n˃˃. La marca o o de posici´n es una se˜al que dispone el usuario en una casilla para indicar que ´l o n e cree que oculta una mina. Necesitar´s una nueva matriz de marcas. a El programa principal es un bucle similar al de Memori´n. El bucle principal finaliza o cuando hay una coincidencia total entre la matriz de bombas y la matriz de marcas puestas por el usuario. Cada vez que se pulse el bot´n 1, destruye la baldosa correspondiente. Si ´sta o e escond´ una mina, la partida ha acabado y el jugador ha muerto. Si no, crea un ıa objeto gr´fico (texto) que muestre el n´mero de minas vecinas a esa casilla. a u Cada vez que se pulse el bot´n 3, a˜ade una marca a la casilla correspondiente si o n no la hab´ y elimina la que hab´ en caso contrario. ıa, ıa · 316 Modifica el Buscaminas para que cada vez que se pulse con el primer bot´n o en una casilla con cero bombas vecinas, se marquen todas las casillas alcanzables desde esta y que no tienen bomba. (Este ejercicio es dif´ Piensa bien en la estrategia que ıcil. has de seguir.) · 317 Dise˜a un programa que permita jugar a dos personas al tres en raya. n · 318 Dise˜a un programa que permita jugar al tres en raya enfrentando a una persona n al ordenador. Cuando el ordenador empiece una partida, debe ganarla siempre. (Este ejercicio es dif´ Si no conoces la estrategia ganadora, b´scala en Internet.) ıcil. u · 319 Dise˜a un programa que permita que dos personas jueguen a las damas. El n programa debe verificar que todos los movimientos son v´lidos. a · 320 Dise˜a un programa que permita que dos personas jueguen al ajedrez. El n programa debe verificar que todos los movimientos son v´lidos. a .................................................................................. 6.4. Variables locales y variables globales Observa que en el cuerpo de las funciones es posible definir y usar variables. Vamos a estudiar con detenimiento algunas propiedades de las variables definidas en el cuerpo de una funci´n y en qu´ se diferencian de las variables que definimos fuera de cualquier o e funci´n, es decir, en el denominado programa principal. o Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 263 263 Introducción a la programación con Python - UJIUJI c
    • Empecemos con un ejemplo. Definamos una funci´n que, dados los tres lados de un o tri´ngulo, devuelva el valor de su area. Recuerda que si a, b y c son dichos lados, el area a ´ ´ del tri´ngulo es a s(s − a)(s − b)(s − c), donde s = (a + b + c)/2. La funci´n se define as´ o ı: area triangulo a b c triangulo.py triangulo 6.py 1 2 3 4 5 area del tri´ngulo a ´ from math import sqrt def area_triangulo(a, b, c): s = (a + b + c) / 2.0 return sqrt( s * (s -a) * ( s-b) * ( s-c)) La l´ ınea 4, en el cuerpo de la funci´n, define la variable s asign´ndole un valor que o a es instrumental para el c´lculo del area del tri´ngulo, es decir, que no nos interesa por a a ´ s´ mismo, sino por ser de ayuda para obtener el valor que realmente deseamos calcular: ı el que resulta de evaluar la expresi´n de la l´ o ınea 5. La funci´n area_triangulo se usa como cabe esperar: o triangulo.py triangulo 7.py . . . 7 print area_triangulo(1, 3, 2.5) Ahora viene lo importante: la variable s s´lo existe en el cuerpo de la funci´n. Fuera o o de dicho cuerpo, s no est´ definida. El siguiente programa provoca un error al ejecutarse a porque intenta acceder a s desde el programa principal: triangulo 8.py 1 2 3 4 5 6 7 8 from math import sqrt E triangulo.py E def area_triangulo(a, b, c): s = (a + b + c) / 2.0 return sqrt(s * (s-a) * (s-b) * (s-c)) print area_triangulo(1, 3, 2.5) print s Cuando se ejecuta, aparece esto por pantalla: 1.1709371247 Traceback (innermost last): File "triangulo.py", line 8, in ? print s NameError: s La primera l´ ınea mostrada en pantalla es el resultado de ejecutar la l´ ınea 7 del programa. La l´ ınea 7 incluye una llamada a area_triangulo, as´ que el flujo de ejecuci´n ı o ha pasado por la l´ ınea 4 y s se ha creado correctamente. De hecho, se ha accedido a su valor en la l´ ınea 5 y no se ha producido error alguno. Sin embargo, al ejecutar la l´ ınea 8 Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 264 264 Introducción a la programación con Python - UJI c UJI
    • se ha producido un error por intentar mostrar el valor de una variable inexistente: s. La raz´n es que s se ha creado en la l´ o ınea 4 y se ha destruido tan pronto ha finalizado la ejecuci´n de area_triangulo. o Las variables que s´lo existen en el cuerpo de una funci´n se denominan variables o o locales. En contraposici´n, el resto de variables se llaman variables globales. o Tambi´n los par´metros formales de una funci´n se consideran variables locales, as´ e a o ı que no puedes acceder a su valor fuera del cuerpo de la funci´n. o F´ ıjate en este otro ejemplo: E triangulo.py E triangulo 9.py 1 2 3 4 5 6 7 8 from math import sqrt def area_triangulo( a, b, c): s = ( a + b + c) / 2.0 return sqrt(s * (s-a) * (s-b) * (s-c)) print area_triangulo(1, 3, 2.5) print a Al ejecutarlo obtenemos un nuevo error, pues a no existe fuera de area_triangulo: 1.1709371247 Traceback (innermost last): File "triangulo.py", line 8, in ? print a NameError: a ¿Y cu´ndo se crean a, b y c? ¿Con qu´ valores? Cuando llamamos a la funci´n con, por a e o ejemplo, area_triangulo(1, 3, 2.5), ocurre lo siguiente: los par´metros a, b y c se crean a como variables locales en la funci´n y apuntan a los valores 1, 3 y 2.5, respectivamente. o Se inicia entonces la ejecuci´n del cuerpo de area_triangulo hasta llegar a la l´ o ınea que contiene el return. El valor que resulta de evaluar la expresi´n que sigue al return se o devuelve como resultado de la llamada a la funci´n. Al acabar la ejecuci´n de la funci´n, o o o las variables locales a, b y c dejan de existir (del mismo modo que deja de existir la variable local s). Para ilustrar los conceptos de variables locales y globales con mayor detalle vamos a utilizar la funci´n area_triangulo en un programa un poco m´s complejo. o a Imagina que queremos ayudarnos con un programa en el c´lculo del area de un a ´ tri´ngulo de lados a, b y c y en el c´lculo del angulo α (en grados) opuesto al lado a. a a ´ b El angulo α se calcula con la f´rmula o ´ α= a α 180 · arcsin π c 2s bc , donde s es el area del tri´ngulo y arcsin es la funci´n arco-seno. (La funci´n matem´tica a o o a ´ ˂˂arcsin˃˃ est´ definida en el m´dulo math con el identificador asin.) a o Analiza este programa en el que hemos destacado las diferentes apariciones del identificador s: Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 265 265 Introducción a la programación con Python - UJI c UJI
    • area y angulo 3.py 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 29 30 31 area y angulo.py from math import sqrt, asin, pi def area_triangulo(a, b, c): s = (a + b + c) / 2.0 return sqrt( s * (s -a) * ( s-b) * ( s-c)) def angulo_alfa(a, b, c): s = area_triangulo(a, b, c) return 180 / pi * asin(2.0 * s / (b*c)) def menu(): opcion = 0 while opcion != 1 and opcion != 2: print ’1)␣Calcular␣´rea␣del␣tri´ngulo’ a a print ’2)␣Calcular␣´ngulo␣opuesto␣al␣primer␣lado’ a opcion = int(raw_input(’Escoge␣opci´n:␣’)) o return opcion lado1 = float(raw_input(’Dame␣lado␣a:␣’)) lado2 = float(raw_input(’Dame␣lado␣b:␣’)) lado3 = float(raw_input(’Dame␣lado␣c:␣’)) s = menu() if s == 1: resultado = area_triangulo(lado1, lado2, lado3) else: resultado = angulo_alfa(lado1, lado2, lado3) print ’Escogiste␣la␣opci´n’, s o print ’El␣resultado␣es:’, resultado Ejecutemos el programa: Dame lado a: 5 Dame lado b: 4 Dame lado c: 3 1) Calcular ´rea del tri´ngulo a a 2) Calcular ´ngulo opuesto al primer lado a Escoge opci´n: 1 o Escogiste la opci´n 1 o El resultado es: 6.0 Hagamos una traza del programa para esta ejecuci´n: o La l´ ınea 1 importa las funciones sqrt (ra´ cuadrada) y asin (arcoseno) y la variable ız pi (aproximaci´n de π). o Las l´ ıneas 3–5 ˂˂ense˜an˃˃ a Python c´mo se realiza un c´lculo determinado al que n o a denominamos area_triangulo y que necesita tres datos de entrada. Las l´ ıneas 7–9 ˂˂ense˜an˃˃ a Python c´mo se realiza un c´lculo determinado al que n o a denominamos angulo_alfa y que tambi´n necesita tres datos de entrada. e Las l´ ıneas 11–17 definen la funci´n menu. Es una funci´n sin par´metros cuyo o o a cometido es mostrar un men´ con dos opciones, esperar a que el usuario escoja una u y devolver la opci´n seleccionada. o Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 266 266 Introducción a la programación con Python - UJI c UJI
    • Las l´ ıneas 19–21 leen de teclado el valor (flotante) de tres variables: lado1, lado2 y lado3. En nuestra ejecuci´n, las variables valdr´n 5.0, 4.0 y 3.0, respectivamente. o a La l´ ınea 23 contiene una llamada a la funci´n menu. En este punto, Python memoriza o que se encontraba ejecutando la l´ ınea 23 cuando se produjo una llamada a funci´n o y deja su ejecuci´n en suspenso. Salta entonces a la l´ o ınea 12, es decir, al cuerpo de la funci´n menu. Sigamos el flujo de ejecuci´n en dicho cuerpo: o o • Se ejecuta la l´ ınea 12. La variable local opcion almacena el valor 0. • En la l´ ınea 13 hay un bucle while. ¿Es opcion distinto de 1 y de 2? S´ ı. Entramos, pues, en el bloque del bucle: la siguiente l´ ınea a ejecutar es la 14. • En la l´ ınea 14 se imprime un texto en pantalla (el de la primera opci´n). o • En la l´ ınea 15 se imprime otro texto en pantalla (el de la segunda opci´n). o • En la l´ ınea 16 se lee el valor de opcion de teclado, que en esta ejecuci´n es o 1. • Como el bloque del bucle no tiene m´s l´ a ıneas, volvemos a la l´ ınea 13. Nos volvemos a preguntar ¿es opcion distinto de 1 y a la vez distinto de 2? No: opcion vale 1. El bucle finaliza y saltamos a la l´ ınea 17. • En la l´ ınea 17 se devuelve el valor 1, que es el valor de opcion, y la variable local opcion se destruye. ¿Qu´ l´ e ınea se ejecuta ahora? La ejecuci´n de la llamada a la funci´n ha finalizado, o o as´ que Python regresa a la l´ ı ınea desde la que se produjo la llamada (la l´ ınea 23), cuya ejecuci´n hab´ quedado en suspenso. El valor devuelto por la funci´n (el o ıa o valor 1) se almacena ahora en una variable llamada s. La l´ ınea 25 compara el valor de s con el valor 1 y, como son iguales, la siguiente l´ ınea a ejecutar es la 26 (las l´ ıneas 27 y 28 no se ejecutar´n). a La l´ ınea 26 asigna a resultado el resultado de invocar a area_triangulo con los valores 5.0, 4.0 y 3.0. Al invocar la funci´n, el flujo de ejecuci´n del programa o o ˂˂salta˃˃ a su cuerpo y la ejecuci´n de la l´ o ınea 26 queda en suspenso. • Saltamos, pues, a la l´ ınea 4, con la que empieza el cuerpo de la funci´n o area_triangulo. ¡Ojo!, los par´metros a, b y c se crean como variables locales a y toman los valores 5.0, 4.0 y 3.0, respectivamente (son los valores de lado1, lado2 y lado3). En la l´ ınea 4 se asigna a s, una nueva variable local, el valor que resulte de evaluar (a + b + c)/2.0, es decir, 6.0. • En la l´ ınea 5 se devuelve el resultado de evaluar sqrt(s * (s-a) * (s-b) * (s-c)), que tambi´n es, casualmente, 6.0. Tanto s como los tres par´metros dejan de e a existir. Volvemos a la l´ ınea 26, cuya ejecuci´n estaba suspendida a la espera de conocer el o valor de la llamada a area_triangulo. El valor devuelto, 6.0, se asigna a resultado. La l´ ınea 30 muestra por pantalla el valor actual de s. . . ¿y qu´ valor es ´se? ¡Al e e ejecutar la l´ ınea 23 le asignamos a s el valor 1, pero al ejecutar la l´ ınea 4 le asignamos el valor 6.0! ¿Debe salir por pantalla, pues, un 6.0? No: la l´ ınea 23 asign´ el valor 1 a la variable global s. El 6.0 de la l´ o ınea 4 se asign´ a la variable o s local a la funci´n area_triangulo, que ya no existe. o Finalmente, el valor de resultado se muestra por pantalla en la l´ ınea 31. Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 267 267 Introducción a la programación con Python -cUJI UJI
    • Observa que llamamos s a dos variables diferentes y que cada una de ellas ˂˂recuerda˃˃ su valor sin interferir con el valor de la otra. Si accedemos a s desde area_triangulo, accedemos a la s local a area_triangulo. Si accedemos a s desde fuera de cualquier funci´n, accedemos a la s global. o Puede que te parezca absurdo que Python distinga entre variables locales y variables globales, pero lo cierto es que disponer de estos dos tipos de variable es de gran ayuda. Piensa en qu´ ocurrir´ si la variable s de la l´ e ıa ınea 4 fuese global: al acabar la ejecuci´n de o area_triangulo, s recordar´ el valor 6.0 y habr´ olvidado el valor 1. El texto impreso en la ıa ıa l´ ınea 30 ser´ err´neo, pues se leer´ as´ ˂˂Escogiste la opci´n 6.0000˃˃. Disponer ıa o ıa ı: o de variables locales permite asegurarse de que las llamadas a funci´n no modificar´n o a accidentalmente nuestras variables globales, aunque se llamen igual. La siguiente figura ilustra la idea de que cada elemento del programa tiene un identificador que lo hace accesible o visible desde un entorno o ambito diferente. ´ area y angulo.py area triangulo a b c s angulo alfa a b c s menu opcion s resultado lado1 lado2 lado3 Cada funci´n define un ambito local propio: su cuerpo. Los identificadores de las o ´ variables locales s´lo son visibles en su ambito local. Por ejemplo, la variable opcion o ´ definida en la funci´n menu s´lo es visible en el cuerpo de menu. En este diagrama o o marcamos en tono gris la regi´n en la que es visible esa variable: o area y angulo.py area triangulo a b c s angulo alfa a b c s menu opcion s resultado lado1 lado2 lado3 Fuera de la zona gris, tratar de acceder al valor de opcion se considera un error. ¿Qu´ pasa e con las variables o par´metros de nombre id´ntico definidas en area_triangulo y angua e lo_alfa? Considera, por ejemplo, el par´metro a o la variable s definida en area_triangulo: a s´lo es accesible desde el cuerpo de area_triangulo. o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 268 268 Introducción a la programación con Python - cUJI UJI
    • area y angulo.py area triangulo a b c s angulo alfa a b c s menu opcion s resultado lado1 lado2 lado3 No hay confusi´n posible: cuando accedes al valor de a en el cuerpo de area_triangulo, o accedes a su par´metro a. Lo mismo ocurre con la variable s o el par´metro a de ana a gulo_alfa: si se usan en el cuerpo de la funci´n, Python sabe que nos referimos esas o variables locales: area y angulo.py area triangulo a b c s angulo alfa a b c s menu opcion s resultado lado1 lado2 lado3 Hay un ambito global que incluye a aquellas l´ ıneas del programa que no forman ´ parte del cuerpo de una funci´n. Los identificadores de las variables globales son visibles o en el ambito global y desde cualquier ambito local. Las variables resultado o lado1, ´ ´ por ejemplo, son accesibles desde cualquier punto del programa (est´ dentro o fuera del e cuerpo de una funci´n). Podemos representar as´ su ˂˂zona de visibilidad˃˃, es decir, su o ı ambito: ´ area y angulo.py area triangulo a b c s angulo alfa a b c s menu opcion s resultado lado1 lado2 lado3 Hay una excepci´n a la regla de que las variables del ambito global sean accesibles o ´ desde cualquier punto del programa: si el identificador de una variable (o funci´n) definida o Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 269 269 Introducción a la programación con Python - cUJI UJI
    • en el ambito global se usa para nombrar una variable local en una funci´n, la variable o ´ (o funci´n) global queda ˂˂oculta˃˃ y no es accesible desde el cuerpo de la funci´n. Por o o ejemplo, la variable local s definida en la l´ ınea 4 hace que la variable global s definida en la l´ ınea 23 no sea visible en el cuerpo de la funci´n area_triangulo. Su ambito se o ´ reduce a esta regi´n sombreada: o area y angulo.py area triangulo a b c s angulo alfa a b c s menu opcion s resultado lado1 lado2 lado3 En el programa, la funci´n angulo_alfa presenta otro aspecto de inter´s: desde ella o e se llama a la funci´n area_triangulo. El cuerpo de una funci´n puede incluir llamadas a o o otras funciones. ¿Qu´ ocurre cuando efectuamos una llamada a angulo_alfa? Supongamos e que al ejecutar el programa introducimos los valores 5, 4 y 3 para lado1, lado2 y lado3 y que escogemos la opci´n 2 del men´. Al ejecutarse la l´ o u ınea 28 ocurre lo siguiente: Al evaluar la parte derecha de la asignaci´n de la l´ o ınea 28 se invoca la funci´n o angulo_alfa con los argumentos 5, 4 y 3, con lo que la ejecuci´n salta a la l´ o ınea 8 y a, b y c toman los valores 5, 4 y 3, respectivamente. Python recuerda que al acabar de ejecutar la llamada, debe seguir con la ejecuci´n de la l´ o ınea 28. • Se ejecuta la l´ ınea 8 y, al evaluar la parte derecha de su asignaci´n, se invoca o la funci´n area_triangulo con los argumentos 5, 4 y 3 (que son los valores de o a, b y c). La ejecuci´n salta, pues, a la l´ o ınea 4 y Python recuerda que, cuando acabe de ejecutar esta nueva llamada, regresar´ a la l´ a ınea 8. ◦ En la l´ ınea 4 la variable s local a area_triangulo vale 6.0. Los par´metros a a, b y c son nuevas variables locales con valor 5, 4, y 3, respectivamente. ◦ Se ejecuta la l´ ınea 5 y se devuelve el resultado, que es 6.0. • Regresamos a la l´ ınea 8, cuya ejecuci´n hab´ quedado suspendida a la espera o ıa de conocer el resultado de la llamada a area_triangulo. Como el resultado es 6.0, se asigna dicho valor a la variable s local a angulo_alfa. Se ejecuta la l´ ınea 9 y se devuelve el resultado de evaluar la expresi´n, que es 90.0. o Sigue la ejecuci´n en la l´ o ınea 28, que hab´ quedado en suspenso a la espera de ıa conocer el valor de la llamada a angulo_alfa. Dicho valor se asigna a resultado. Se ejecutan las l´ ıneas 30 y 31. Podemos representar gr´ficamente las distintas activaciones de funci´n mediante el a o denominado arbol de llamadas. He aqu´ el arbol correspondiente al ultimo ejemplo: ı ´ ´ ´ Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 270 270 Introducción a la programación con Python - cUJI UJI
    • programa principal 90.0 angulo alfa(5.0, 4.0, 3.0) 6.0 area triangulo(5.0, 4.0, 3.0) Las llamadas se producen de arriba a abajo y siempre desde la funci´n de la que parte o la flecha con trazo s´lido. La primera flecha parte del ˂˂programa principal˃˃ (fuera de cualo quier funci´n). El valor devuelto por cada funci´n aparece al lado de la correspondiente o o flecha de trazo discontinuo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 321 Haz una traza de area_y_angulo.py al solicitar el valor del angulo opuesto al ´ lado de longitud 5 en un tri´ngulo de lados con longitudes 5, 4 y 3. a · 322 ¿Qu´ aparecer´ por pantalla al ejecutar el siguiente programa? e a triangulo.py triangulo 10.py 1 2 3 4 5 6 7 8 9 10 from math import sqrt def area_triangulo(a, b, c): s = (a + b + c) / 2.0 return sqrt(s * (s-a) * (s-b) * (s-c)) s=4 print area_triangulo(s-1, s, s+1) print s print a · 323 La funci´n area_triangulo que hemos definido puede provocar un error en tiempo o de ejecuci´n: si el argumento de la ra´ cuadrada calculada en su ultima l´ o ız ınea es un ´ n´mero negativo, se producir´ un error de dominio. Haz que la funci´n s´lo llame a sqrt u a o o si su argumento es mayor o igual que cero. Si el argumento es un n´mero negativo, la u funci´n debe devolver el valor cero. Detecta tambi´n posibles problemas en angulo_alfa o e y modifica la funci´n para evitar posibles errores al ejecutar el programa. o · 324 Vamos a adquirir una vivienda y para eso necesitaremos una hipoteca. La cuota mensual m que hemos de pagar para amortizar una hipoteca de h euros a lo largo de n a˜os a un inter´s compuesto del i por cien anual se calcula con la f´rmula: n e o m= hr , 1 − (1 + r)−12n donde r = i/(100 · 12). Define una funci´n que calcule la cuota (redondeada a dos deo cimales) dados h, n e i. Utiliza cuantas variables locales consideres oportuno, pero al menos r debe aparecer en la expresi´n cuyo valor se devuelve y antes debe calcularse y o almacenarse en una variable local. Nota: puedes comprobar la validez de tu funci´n sabiendo que hay que pagar la o cantidad de 1 166.75 ¤ al mes para amortizar una hipoteca de 150 000 ¤ en 15 a˜os a n un inter´s del 4.75% anual. e · 325 Dise˜a una funci´n que nos devuelva la cantidad de euros que habremos pagado n o finalmente al banco si abrimos una hipoteca de h euros a un inter´s del i por cien en n e a˜os. Si te conviene, puedes utilizar la funci´n que definiste en el ejercicio anterior. n o Nota: con los datos del ejemplo anterior, habremos pagado un total de 210 015 ¤. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 271 271 Introducción a la programación con Python - UJIUJI c
    • · 326 Dise˜a una funci´n que nos diga qu´ cantidad de intereses (en euros) habremos n o e pagado finalmente al banco si abrimos una hipoteca de h euros a un inter´s del i por e cien en n a˜os. Si te conviene, puedes utilizar las funciones que definiste en los ejercicios n anteriores. Nota: con los datos del ejemplo anterior, habremos pagado un total de 210 015 − 150 000 = 60 015 ¤ en intereses. · 327 Dise˜a una funci´n que nos diga qu´ tanto por cien del capital inicial deberemos n o e pagar en intereses al amortizar completamente la hipoteca. Si te conviene, puedes utilizar las funciones que definiste en los ejercicios anteriores. Nota: con los datos del ejemplo anterior, habremos pagado un inter´s total del 40.01% e (60 015 ¤ es el 40.01% de 150 000 ¤). · 328 Dise˜a un procedimiento que muestre por pantalla la cuota mensual que corresn ponde pagar por una hipoteca para un capital de h euros al i% de inter´s anual durante e 10, 15, 20 y 25 a˜os. (Si te conviene, rescata ahora las funciones que dise˜aste como n n soluci´n de los ejercicios anteriores.) o · 329 Dise˜a un procedimiento que muestre por pantalla el capital total pagado al n banco por una hipoteca de h euros al i% de inter´s anual durante 10, 15, 20 y 25 a˜os. e n (Si te conviene, rescata ahora las funciones que dise˜aste como soluci´n de los ejercicios n o anteriores.) .................................................................................. Las variables locales tambi´n pueden contener valores secuenciales. Estudiemos un e ejemplo de funci´n con una variable local de tipo secuencial: una funci´n que recibe una o o lista y devuelve otra cuyos elementos son los de la primera, pero sin repetir ninguno; es decir, si la funci´n recibe la lista [1, 2, 1, 3, 2], devolver´ la lista [1, 2, 3]. o a Empecemos por definir el cuerpo de la funci´n: o sin repetidos.py 1 2 def sin_repetidos(lista): ... ¿C´mo procederemos? Una buena idea consiste en disponer de una nueva lista auxiliar o (una variable local) inicialmente vac´ en la que iremos insertando los elementos de la ıa lista resultante. Podemos recorrer la lista original elemento a elemento y preguntar a cada uno de ellos si ya se encuentra en la lista auxiliar. Si la respuesta es negativa, lo a˜adiremos a la lista: n sin repetidos 3.py 1 2 3 4 5 6 sin repetidos.py def sin_repetidos(lista): resultado = [] for elemento in lista: if elemento not in resultado: resultado.append(elemento) return resultado F´cil, ¿no? La variable resultado es local, as´ que su tiempo de vida se limita al de la a ı ejecuci´n del cuerpo de la funci´n cuando ´sta sea invocada. El contenido de resultado o o e se devuelve con la sentencia return, as´ que s´ ser´ accesible desde fuera. Aqu´ tienes un ı ı a ı ejemplo de uso: sin repetidos 4.py sin repetidos.py . . . 8 9 una_lista = sin_repetidos([1, 2, 1, 3, 2]) print una_lista Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 272 272 Introducción a la programación con Python - UJIUJI c
    • . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 330 Dise˜a una funci´n que reciba dos listas y devuelva los elementos comunes a n o ambas, sin repetir ninguno (intersecci´n de conjuntos). o Ejemplo: si recibe las listas [1, 2, 1] y [2, 3, 2, 4], devolver´ la lista [2]. a · 331 Dise˜a una funci´n que reciba dos listas y devuelva los elementos que pertenecen n o a una o a otra, pero sin repetir ninguno (uni´n de conjuntos). o Ejemplo: si recibe las listas [1, 2, 1] y [2, 3, 2, 4], devolver´ la lista [1, 2, 3, 4]. a · 332 Dise˜a una funci´n que reciba dos listas y devuelva los elementos que pertenecen n o a la primera pero no a la segunda, sin repetir ninguno (diferencia de conjuntos). Ejemplo: si recibe las listas [1, 2, 1] y [2, 3, 2, 4], devolver´ la lista [1]. a · 333 Dise˜a una funci´n que, dada una lista de n´meros, devuelva otra lista que s´lo n o u o incluya sus n´meros impares. u · 334 Dise˜a una funci´n que, dada una lista de nombres y una letra, devuelva una n o lista con todos los nombres que empiezan por dicha letra. · 335 Dise˜a una funci´n que, dada una lista de n´meros, devuelva otra lista con s´lo n o u o aquellos n´meros de la primera que son primos. u · 336 Dise˜a una funci´n que, dada una lista de n´meros, devuelva una lista con todos n o u los pares de n´meros que podemos formar con uno de la primera lista y otro de la segunda. u Por ejemplo, si se suministran las listas [1, 3, 5] y [2, 5], la lista resultante es [[1, 2], [1, 5], [3, 2], [3, 5], [5, 2], [5, 5]]. · 337 Dise˜a una funci´n que, dada una lista de n´meros, devuelva una lista con todos n o u los pares de n´meros amigos que podemos formar con uno de la primera lista y otro de u la segunda. .................................................................................. 6.5. El mecanismo de las llamadas a funci´n o 6.5.1. La pila de llamadas a funci´n y el paso de par´metros o a Hemos visto que desde una funci´n podemos llamar a otra funci´n. Desde esta ultima o o ´ funci´n podr´ o ıamos llamar a otra, y desde ´sta a´n a otra. . . Cada vez que se produce una e u llamada, la ejecuci´n del programa principal o de la funci´n ˂˂actual˃˃ queda suspendida o o a la espera de que finalice la llamada realizada y prosigue cuando ´sta finaliza. ¿C´mo e o recuerda Python qu´ funciones est´n ˂˂suspendidas˃˃ y en qu´ orden deben reanudarse? e a e Por otra parte, hemos visto que si una variable local a una funci´n tiene el mismo o nombre que una variable global, durante la ejecuci´n de la funci´n la variable local oculta o o a la global y su valor es inaccesible. ¿C´mo es posible que al finalizar la ejecuci´n de o o una funci´n se restaure el valor original? ¿D´nde se hab´ almacenado ´ste mientras la o o ıa e variable era invisible? Python utiliza internamente una estructura especial de memoria para recordar la informaci´n asociada a cada invocaci´n de funci´n: la pila de llamadas a funci´n. Una pila o o o o es una serie de elementos a la que s´lo podemos a˜adir y eliminar componentes por uno o n de sus dos extremos: el que denominamos la cima. Un mont´n de platos, por ejemplo, es una pila: s´lo puedes a˜adir un plato poni´ndolo o o n e encima de la pila (apilar) y s´lo puedes quitar el plato que est´ encima (desapilar). Aqu´ o a ı tienes una representaci´n gr´fica de una pila con cuatro elementos (cada uno de ellos es o a un n´mero entero). u Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 273 273 Introducción a la programación con Python - UJIUJI c
    • 4 3 2 1 S´lo podemos a˜adir nuevos elementos (apilar) por el extremo superior: o n 5 5 4 4 3 2 1 3 2 1 −→ Y s´lo podemos eliminar el elemento de la cima (desapilar): o 5 4 4 3 2 1 3 2 1 −→ Cada activaci´n de una funci´n apila un nuevo componente en la pila de llamadas a o o funci´n. Dicho componente, que recibe el nombre de trama de activaci´n, es una zona de o o memoria en la que Python dispondr´ espacio para los punteros asociados a par´metros, a a variables locales y otra informaci´n que se ha de recordar, como el punto exacto desde o el que se efectu´ la llamada a la funci´n. Cuando iniciamos la ejecuci´n de un programa, o o o Python reserva una trama especial para las variables globales, as´ que empezamos con ı un elemento en la pila. Estudiemos un ejemplo: una ejecuci´n particular del programa o area_y_angulo.py que reproducimos aqu´ ı: area y angulo 4.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 area y angulo.py from math import sqrt, asin, pi def area_triangulo(a, b, c): s = (a + b + c) / 2.0 return sqrt(s * (s-a) * (s-b) * (s-c)) def angulo_alfa(a, b, c): s = area_triangulo(a, b, c) return 180 / pi * asin(2.0 * s / (b*c)) def menu(): opcion = 0 while opcion != 1 and opcion != 2: print ’1)␣Calcular␣´rea␣del␣tri´ngulo’ a a print ’2)␣Calcular␣´ngulo␣opuesto␣al␣primer␣lado’ a opcion = int(raw_input(’Escoge␣opci´n:␣’)) o return opcion lado1 = float(raw_input(’Dame␣lado␣a:␣’)) lado2 = float(raw_input(’Dame␣lado␣b:␣’)) Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 274 274 UJI Introducción a la programación con Python - cUJI
    • 21 22 23 24 25 26 27 28 29 30 31 lado3 = float(raw_input(’Dame␣lado␣c:␣’)) s = menu() if s == 1: resultado = area_triangulo(lado1, lado2, lado3) else: resultado = angulo_alfa(lado1, lado2, lado3) print ’Escogiste␣la␣opci´n’, s o print ’El␣resultado␣es:’, resultado Aqu´ tienes un pantallazo con el resultado de dicha ejecuci´n: ı o Dame lado a: 5 Dame lado b: 4 Dame lado c: 3 1) Calcular ´rea del tri´ngulo a a 2) Calcular ´ngulo opuesto al primer lado a Escoge opci´n: 2 o Escogiste la opci´n 2 o El resultado es: 90.0 Cuando el programa arranca, Python prepara en la pila el espacio necesario para las variables globales: Programa principal lado3 lado2 lado1 s resultado El usuario introduce a continuaci´n el valor de lado1, lado2 y lado3. La memoria o queda as´ ı: Programa principal 3 4 5 lado3 lado2 lado1 s resultado Se produce entonces la llamada a la funci´n menu. Python crea una trama de actio vaci´n para la llamada y la dispone en la cima de la pila. En dicha trama se almacena o el valor de opcion y el punto desde el que se efectu´ la llamada a menu. Aqu´ tienes o ı una representaci´n de la pila cuando el usuario acaba de introducir por teclado la opci´n o o seleccionada: menu Programa principal Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o opcion 2 llamada desde l´ ınea 23 lado3 lado2 lado1 s 3 4 5 resultado 275 275 Introducción a la programación con Python - UJI c UJI
    • ¿Qu´ ocurre cuando finaliza la ejecuci´n de la funci´n menu? Ya no hace falta la trama e o o de activaci´n, as´ que se desapila, es decir, se elimina. Moment´neamente, no obstante, o ı a se mantiene una referencia al objeto devuelto, en este caso, el contenido de la variable opcion. Python recuerda en qu´ l´ e ınea del programa principal debe continuar (l´ ınea 23) porque se hab´ memorizado en la trama de activaci´n. La l´ ıa o ınea 23 dice: 23 s = menu() as´ que la referencia devuelta por menu con la sentencia return es apuntada ahora por ı la variable s: 2 return Programa principal lado3 lado2 lado1 s 3 4 5 resultado Y ahora que ha desaparecido completamente la trama de activaci´n de menu, podemos o reorganizar gr´ficamente los objetos apuntados por cada variable: a Programa principal lado3 lado2 lado1 s 3 4 5 2 resultado La ejecuci´n prosigue y, en la l´ o ınea 28, se produce una llamada a la funci´n anguo lo_alfa. Se crea entonces una nueva trama de activaci´n en la cima de la pila con espacio o para los punteros de los tres par´metros y el de la variable local s. A continuaci´n, cada a o par´metro apunta al correspondiente valor: el par´metro a apunta adonde apunta lado1, a a el par´metro b adonde lado2 y el par´metro c adonde lado3. Esta acci´n se denomina a a o paso de par´metros. a angulo alfa Programa principal s c b a llamada desde l´ ınea 28 lado3 lado2 lado1 s 3 4 5 2 resultado Desde el cuerpo de la funci´n angulo_alfa se efect´a una llamada a la funci´n o u o area_triangulo, as´ que se crea una nueva trama de activaci´n. F´ ı o ıjate en que los identificadores de los par´metros y las variables locales de las dos tramas superiores tienen los a mismos nombres, pero residen en espacios de memoria diferentes. En esta nueva imagen puedes ver el estado de la pila en el instante preciso en que se efect´a la llamada a u area_triangulo y se ha producido el paso de par´metros: a Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 276 276 Introducción a la programación con Python - cUJI UJI
    • area triangulo angulo alfa Programa principal s c b a llamada desde l´ ınea 8 s c b a llamada desde l´ ınea 28 lado3 lado2 lado1 s 3 4 5 2 resultado Como puedes comprobar, los par´metros a, b y c de area_triangulo apuntan al mismo a lugar que los par´metros del mismo nombre de angulo_alfa. a Cuando area_triangulo ejecuta su primera l´ ınea, la variable local s recibe el valor 6.0: area triangulo angulo alfa Programa principal s c 6.0 b a llamada desde l´ ınea 8 s c b a llamada desde l´ ınea 28 lado3 lado2 lado1 s 3 4 5 2 resultado La ejecuci´n de area_triangulo finaliza devolviendo el valor del area, que resulta ser o ´ 6.0. La variable s local a angulo_alfa apunta a dicho valor, pues hay una asignaci´n al o resultado de la funci´n en la l´ o ınea 8: 6.0 return angulo alfa Programa principal s c b a llamada desde l´ ınea 28 lado3 lado2 lado1 s 3 4 5 2 resultado Nuevamente podemos simplificar la figura as´ ı: Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 277 277 Introducción a la programación con Python - UJI c UJI
    • angulo alfa Programa principal s c 6.0 b a llamada desde l´ ınea 28 3 4 5 2 lado3 lado2 lado1 s resultado Y, ahora, una vez finaliza la ejecuci´n de angulo_alfa, el valor devuelto (90.0) se o almacena en la variable global resultado: 90.0 return Programa principal lado3 lado2 lado1 s resultado El estado final de la pila es, pues, ´ste: e Programa principal 3 4 5 2 lado3 lado2 lado1 s 3 4 5 2 90.0 resultado Observa que la variable s de la trama de activaci´n del programa principal siempre o ha valido 2, aunque las variables locales del mismo nombre han almacenado diferentes valores a lo largo de la ejecuci´n del programa. o 6.5.2. Paso del resultado de expresiones como argumentos Hemos visto que el paso de par´metros comporta que el par´metro apunte a cierto lugar a a de la memoria. Cuando el argumento es una variable, es f´cil entender qu´ ocurre: tanto a e el par´metro como la variable apuntan al mismo lugar. Pero, ¿qu´ ocurre si pasamos una a e expresi´n como argumento? Veamos un ejemplo: o parametros 4.py 1 2 3 4 5 6 7 parametros.py def incrementa(p): p=p+1 return p a=1 a = incrementa(2+2) print ’a:’, a Observa que no hemos pasado a incrementa una variable, sino el valor 4 (resultado de evaluar 2+2). He aqu´ el estado de la memoria en el preciso instante en el que se produce el paso ı de par´metros: a Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 278 278 Introducción a la programación con Python - UJI c UJI
    • incrementa Programa principal p 4 llamada desde l´ ınea 6 a 1 El par´metro p apunta a una nueva zona de memoria que contiene el resultado de evaluar a la expresi´n. o La operaci´n de incremento de la l´ o ınea 2 hace que p pase a valer 5: incrementa Programa principal p 5 return 5 llamada desde l´ ınea 6 y ´se es el valor devuelto en la l´ e ınea 3. Programa principal a 1 a As´ pues, la variable global a recibe el valor devuelto y es ´ste el que se muestra por ı e pantalla: a: 5 6.5.3. M´s sobre el paso de par´metros a a Hemos visto que el paso de par´metros comporta que cada par´metro apunte a un lugar de a a la memoria y que ´ste puede estar ya apuntado por una variable o par´metro perteneciente e a al ambito desde el que se produce la llamada. ¿Qu´ ocurre si el par´metro es modificado e a ´ dentro de la funci´n? ¿Se modificar´ igualmente la variable o par´metro del ambito desde o a a ´ el que se produce la llamada? Depende. Estudiemos unos cuantos ejemplos. Para empezar, uno bastante sencillo: parametros 5.py 1 2 3 4 5 6 7 8 9 parametros.py def incrementa(p): p=p+1 return p a=1 b = incrementa(a) print ’a:’, a print ’b:’, b Veamos qu´ sale por pantalla al ejecutarlo: e a: 1 b: 2 Puede que esperaras que tanto a como b tuvieran el mismo valor al final: a fin de cuentas la llamada a incrementa en la l´ ınea 6 hizo que el par´metro p apuntara al mismo a lugar que a y esa funci´n incrementa el valor de p en una unidad (l´ o ınea 2). ¿No deber´ ıa, pues, haberse modificado el valor de a? No. Veamos qu´ ocurre paso a paso. Inicialmente tenemos en la pila la reserva de memoria e para las variables a y b. Tras ejecutar la l´ ınea 5, a tiene por valor el entero 1: Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o 279 279 Introducción a la programación con Python - UJI c UJI
    • Programa principal b a 1 Cuando llamamos a incrementa el par´metro p recibe una referencia al valor apuntado a por a. As´ pues, tanto a como p apuntan al mismo lugar y valen 1: ı incrementa Programa principal p llamada desde l´ ınea 6 b a 1 p 2 El resultado de ejecutar la l´ ınea 2 ¡hace que p apunte a una nueva zona de memoria en la que se guarda el valor 2! incrementa Programa principal llamada desde l´ ınea 6 b a ¿Por qu´? Recuerda c´mo procede Python ante una asignaci´n: e o o 1 en primer lugar se eval´a la expresi´n a mano derecha del igual, u o y a continuaci´n se hace que la parte izquierda del igual apunte al resultado. o La evaluaci´n de una expresi´n proporciona una referencia a la zona de memoria que o o alberga el resultado. As´ pues, la asignaci´n tiene un efecto sobre la referencia de p, no ı o sobre el contenido de la zona de memoria apuntada por p. Cuando Python ha evaluado la parte derecha de la asignaci´n de la l´ o ınea 2, ha sumado al valor 1 apuntado por p el valor 1 que aparece expl´ ıcitamente. El resultado es 2, as´ que Python ha reservado una ı nueva celda de memoria con dicho valor. Finalmente, se ha asignado a p el resultado de la expresi´n, es decir, se ha hecho que p apunte a la celda de memoria con el resultado. o Sigamos con la ejecuci´n de la llamada a la funci´n. Al finalizar ´sta, la referencia o o e de p se devuelve y, en la l´ ınea 6, se asigna a b. Programa principal 2 return b a 1 Resultado: b vale lo que val´ p al final de la llamada y a no ve modificado su valor: ıa Programa principal b a 2 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 338 ¿Qu´ aparecer´ por pantalla al ejecutar este programa? e a parametros 6.py 1 2 3 4 def incrementa(a): a=a+1 return a Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 Introducci´n a la programaci´n con Python o o parametros.py 280 280 Introducción a la programación con Python - UJI c UJI
    • 5 6 7 8 9 a=1 b = incrementa(a) print ’a:’, a print ’b:’, b Hazte un dibujo del estado de la pila de llamadas paso a paso para entender bien qu´ e est´ pasando al ejecutar cada sentencia. a .................................................................................. Y ahora, la sorpresa: paso de listas.py paso de listas.py 1 2 3 4 5 6 7 8 9 10 11 12 13 def modifica(a, b): a.append(4) b = b + [4] return b lista1 = [1, 2, 3] lista2 = [1, 2, 3] lista3 = modifica(lista1, lista2) print lista1 print lista2 print lista3 Ejecutemos el programa: [1, 2, 3, 4] [1, 2, 3] [1, 2, 3, 4] ¿Qu´ ha ocurrido? La lista que hemos proporcionado como primer argumento se ha e modificado al ejecutarse la funci´n y la que sirvi´ de segundo argumento no. o o Ya deber´ tener suficientes datos para averiguar qu´ ha ocurrido. No obstante, ıas e nos detendremos brevemente a explicarlo. Veamos en qu´ estado est´ la memoria en el e a momento en el que se produce el paso de par´metros en la llamada a modifica: a modifica Programa principal b a llamada desde l´ ınea 9 lista3 0 lista2 1 2 1 2 3 0 lista1 1 2 1 2 3 ¿Qu´ ocurre cuando se ejecuta la l´ e ınea 2? Que la lista apuntada por a crece por el final (con append) con un nuevo elemento de valor 4: modifica Programa principal Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o b a llamada desde l´ ınea 9 lista3 0 lista2 1 2 1 2 3 0 lista1 1 2 3 1 2 3 4 281 281 Introducción a la programación con Python - UJI c UJI
    • Como esa lista est´ apuntada tanto por el par´metro a como por la variable global lista1, a a ambos ˂˂sufren˃˃ el cambio y ven modificado su valor. Pasemos ahora a la l´ ınea 3: una asignaci´n. Como siempre, Python empieza por evaluar la parte derecha de la asignaci´n, o o donde se indica que se debe crear una nueva lista con capacidad para cuatro elementos (los valores 1, 2 y 3 que provienen de b y el valor 4 que aporta la lista [4]). Una vez creada la nueva lista, se procede a que la variable de la parte izquierda apunte a ella: 0 modifica b 1 2 3 1 2 3 4 a llamada desde l´ ınea 9 Programa principal lista3 0 lista2 1 2 1 2 3 0 1 2 3 lista1 1 2 3 4 return 1 2 3 4 lista2 1 2 3 Cuando finaliza la ejecuci´n de modifica, lista3 pasa a apuntar a la lista devuelta por o la funci´n, es decir, a la lista que hasta ahora apuntaba b: o 0 Programa principal Y aqu´ tenemos el resultado final: ı Programa principal Recuerda, pues, que: lista3 0 0 lista1 1 1 1 2 3 2 2 3 1 2 3 4 0 1 2 3 lista3 1 2 3 4 lista1 1 2 3 4 0 lista2 1 2 1 2 3 0 1 2 3 La asignaci´n puede comportar un cambio del lugar de memoria al que apunta o una variable. Si un par´metro modifica su valor mediante una asignaci´n, (probaa o blemente) obtendr´ una nueva zona de memoria y perder´ toda relaci´n con el a a o argumento del que tom´ valor al efectuar el paso de par´metros. o a Operaciones como append, del o la asignaci´n a elementos indexados de listas o modifican a la propia lista, por lo que los cambios afectan tanto al par´metro como a al argumento. Con las cadenas ocurre algo similar a lo estudiado con las listas, solo que las cadenas son inmutables y no pueden sufrir cambio alguno mediante operaciones como append, del o asignaci´n directa a elementos de la cadena. De hecho, ninguna de esas operaciones o es v´lida sobre una cadena. a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 339 ¿Qu´ mostrar´ por pantalla el siguiente programa al ejecutarse? e a ejercicio parametros 4.py 1 2 def modifica(a, b): for elemento in b: ejercicio parametros.py Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 282 282 Introducción a la programación con Python - UJIUJI c
    • a.append(elemento) b = b + [4] a[-1] = 100 del b[0] return b[:] 3 4 5 6 7 8 lista1 = [1, 2, 3] lista2 = [1, 2, 3] 9 10 11 lista3 = modifica(lista1, lista2) 12 13 print lista1 print lista2 print lista3 14 15 16 · 340 ¿Qu´ muestra por pantalla este programa al ser ejecutado? e ejercicio parametros 5.py ejercicio parametros.py def modifica_parametros(x, y): x=1 y[0] = 1 1 2 3 4 a=0 b = [0, 1, 2] modifica_parametros(a, b) 5 6 7 8 print a print b 9 10 · 341 ¿Qu´ muestra por pantalla este programa al ser ejecutado? e ejercicio parametros 6.py 1 2 3 4 5 6 7 8 9 10 11 ejercicio parametros.py def modifica_parametros(x, y): x=1 y.append(3) y = y + [4] y[0] = 10 a=0 b = [0, 1, 2] modifica_parametros(a, b) print a print b · 342 Utiliza las funciones desarrolladas en el ejercicio 307 y dise˜a nuevas funciones n para construir un programa que presente el siguiente men´ y permita ejecutar las acciones u correspondientes a cada opci´n: o 1) 2) 3) 4) 5) 6) 7) 8) A˜adir estudiante y calificaci´n n o Mostrar lista de estudiantes con sus calificaciones Calcular la media de las calificaciones Calcular el n´mero de aprobados u Mostrar los estudiantes con mejor calificaci´n o Mostrar los estudiantes con calificaci´n superior a la media o Consultar la nota de un estudiante determinado FINALIZAR EJECUCI´N DEL PROGRAMA O .................................................................................. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 283 283 Introducción a la programación con Python - UJIUJI c
    • Ahora que sabemos que dentro de una funci´n podemos modificar listas vamos a o dise˜ar una funci´n que invierta una lista. ¡Ojo!: no una funci´n que, dada una lista, n o o devuelva otra que sea la inversa de la primera, sino un procedimiento (recuerda: una funci´n que no devuelve nada) que, dada una lista, la modifique invirti´ndola. o e El aspecto de una primera versi´n podr´ ser ´ste: o ıa e inversion 4.py 1 2 3 E inversion.py E def invierte(lista): for i in range(len(lista)): intercambiar los elementos lista[i] y lista[len(lista)-1-i] Intercambiaremos los dos elementos usando una variable auxiliar: inversion 5.py 1 2 3 4 5 6 7 8 9 E inversion.py E def invierte(lista): for i in range(len(lista)): c = lista[i] lista[i] = lista[len(lista)-1-i] lista[len(lista)-1-i] = c a = [1, 2, 3, 4] invierte(a) print a Ejecutemos el programa: [1, 2, 3, 4] No funciona. Parece que no la haya modificado. En realidad s´ que lo ha hecho, pero ı mal. Estudiemos paso a paso qu´ ha ocurrido: e 1. 2. Al llamar a la funci´n, el par´metro lista ˂˂apunta˃˃ (hace referencia) a la misma o a zona de memoria que la variable a. El bucle que empieza en la l´ ınea 2 va de 0 a 3 (pues la longitud de lista es 4). La variable local i tomar´ los valores 0, 1, 2 y 3. a a) Cuando i vale 0, el m´todo considera los elementos lista[0] y lista[3]: e 1 2 3 1 2 3 4 Z Z 0 La variable local c toma el valor 1 (que es el contenido de lista[0]), a continuaci´n lista[0] toma el valor de lista[3] y, finalmente, lista[3] toma el valor o de c. El resultado es que se intercambian los elementos lista[0] y lista[3]: 1 2 3 4 2 3 1 Z Z 0 b) Ahora i vale 1, as´ que se consideran los elementos lista[1] y lista[2]: ı 1 2 3 4 2 3 1 Z Z 0 Los dos elementos se intercambian y la lista queda as´ ı: Andrés a la programaci´n con ISBN: Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o 284 284 Introducción a la programación con Python - UJI c UJI
    • 0 1 2 3 4 3 2 1 Z Z 0 1 2 3 4 3 2 1 Z Z c) Ahora i vale 2, as´ que se consideran los elementos lista[2] y lista[1]: ı Tras el intercambio, la lista pasa a ser: 1 2 3 4 2 3 1 1 2 3 4 2 3 1 Z Z Z 0 d) Y, finalmente, i vale 3. Z 0 Se intercambian los valores de las celdas lista[3] y lista[0]: 1 2 3 1 2 3 4 Z Z 0 F´ ıjate en que al final de la segunda iteraci´n del bucle la lista estaba correctamente o invertida. Lo que ha ocurrido es que hemos seguido iterando y ¡hemos vuelto a invertir una lista que ya estaba invertida, dej´ndola como estaba al principio! Ya est´ claro c´mo a a o actuar: iterando la mitad de las veces. Vamos all´: a inversion.py 1 2 3 4 5 6 7 8 9 inversion.py def invierte(lista): for i in range(len(lista) /2): c = lista[i] lista[i] = lista[len(lista)-1-i] lista[len(lista)-1-i] = c a = [1, 2, 3, 4] invierte(a) print a Ahora s´ Si ejecutamos el programa obtenemos: ı. [4, 3, 2, 1] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 343 ¿Qu´ ocurre con el elemento central de la lista cuando la lista tiene un n´mero e u impar de elementos? ¿Nuestra funci´n invierte correctamente la lista? o · 344 Un aprendiz sugiere esta otra soluci´n. ¿Funciona? o inversion 6.py 1 2 3 4 5 def invierte(lista): for i in range(len(lista)/2): c = lista[i] lista[i] = lista[-i-1] lista[-i-1] = c Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o inversion.py 285 285 Introducción a la programación con Python - UJIUJI c
    • · 345 ¿Qu´ muestra por pantalla este programa al ser ejecutado? e abslista.py abslista 2.py 1 2 3 4 5 6 7 def abs_lista(lista): for i in range(len(lista)): lista[i] = abs(lista[i]) milista = [1, -1, 2, -3, -2, 0] abs_lista(milista) print milista · 346 ¿Qu´ mostrar´ por pantalla el siguiente programa al ejecutarse? e a intercambio 2.py 1 2 3 4 5 6 7 8 9 10 11 12 intercambio.py def intento_de_intercambio(a, b): aux = a a=b b = aux lista1 = [1, 2] lista2 = [3, 4] intento_de_intercambio(lista1, lista2) print lista1 print lista2 · 347 Dise˜a un procedimiento que, dada una lista de n´meros, la modifique para que n u s´lo sobrevivan a la llamada aquellos n´meros que son perfectos. o u · 348 Dise˜a una funci´n duplica que reciba una lista de n´meros y la modifique dun o u plicando el valor de cada uno de sus elementos. (Ejemplo: la lista [1, 2, 3] se convertir´ a en [2, 4, 6].) · 349 Dise˜a una funci´n duplica_copia que reciba una lista de n´meros y devuelva n o u otra lista en la que cada elemento sea el doble del que tiene el mismo ´ ındice en la lista original. La lista original no debe sufrir ninguna modificaci´n tras la llamada a o duplica_copia. · 350 Dise˜a una funci´n que reciba una lista y devuelva otra lista cuyo contenido n o sea el resultado de concatenar la lista original consigo misma. La lista original no debe modificarse. · 351 Dise˜a una funci´n que reciba una lista y devuelva otra lista cuyo contenido sea n o la lista original, pero con sus componentes en orden inverso. La lista original no debe modificarse. · 352 Dise˜a una funci´n que reciba una lista y devuelva una copia de la lista conn o catenada con una inversi´n de s´ misma. Puedes utilizar, si lo consideras conveniente, o ı funciones que has desarrollado en ejercicios anteriores. · 353 Dise˜a una funci´n que reciba una lista y devuelva una lista cuyo contenido sea n o la lista original concatenada con una versi´n invertida de ella misma. La lista original no o debe modificarse. · 354 Dise˜a una funci´n que reciba una lista y devuelva una copia de la lista con sus n o elementos ordenados de menor a mayor. La lista original no debe modificarse. · 355 Dise˜a un procedimiento que reciba una lista y ordene sus elementos de menor n a mayor. Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 286 286 Introducción a la programación con Python - UJIUJI c
    • · 356 Dise˜a una funci´n que reciba una matriz y, si es cuadrada (es decir, tiene igual n o n´mero de filas que de columnas), devuelva la suma de todos los componentes dispuestos u en la diagonal principal (es decir, todos los elementos de la forma Ai,i ). Si la matriz no es cuadrada, la funci´n devolver´ None. o a · 357 Guardamos en una matriz de m × n elementos la calificaci´n obtenida por m o estudiantes (a los que conocemos por su n´mero de lista) en la evaluaci´n de n ejercicios u o entregados semanalmente (cuando un ejercicio no se ha entregado, la calificaci´n es −1). o Dise˜a funciones y procedimientos que efect´en los siguiente c´lculos: n u a Dado el n´mero de un alumno, devolver el n´mero de ejercicios entregados. u u Dado el n´mero de un alumno, devolver la media sobre los ejercicios entregados. u Dado el n´mero de un alumno, devolver la media sobre los ejercicios entregados si u los entreg´ todos; en caso contrario, la media es 0. o Devolver el n´mero de todos los alumnos que han entregado todos los ejercicios y u tienen una media superior a 3.5 puntos. Dado el n´mero de un ejercicio, devolver la nota media obtenida por los estudiantes u que lo presentaron. Dado el n´mero de un ejercicio, devolver la nota m´s alta obtenida. u a Dado el n´mero de un ejercicio, devolver la nota m´s baja obtenida. u a Dado el n´mero de un ejercicio, devolver el n´mero de estudiantes que lo han u u presentado. Devolver el n´mero de abandonos en funci´n de la semana. Consideramos que u o un alumno abandon´ en la semana x si no ha entregado ning´n ejercicio desde o u entonces. Este procedimiento mostrar´ en pantalla el n´mero de abandonos para a u cada semana (si un alumno no ha entregado nunca ning´n ejercicio, abandon´ en u o la ˂˂semana cero˃˃). .................................................................................. 6.5.4. Acceso a variables globales desde funciones Por lo dicho hasta ahora podr´ pensar que en el cuerpo de una funci´n s´lo pueden ıas o o utilizarse variables locales. No es cierto. Dentro de una funci´n tambi´n puedes consultar o e y modificar variables globales. Eso s´ deber´s ˂˂avisar˃˃ a Python de que una variable ı, a usada en el cuerpo de una funci´n es global antes de usarla. Lo veremos con un ejemplo. o Vamos a dise˜ar un programa que gestiona una de las funciones de un cajero aun tom´tico que puede entregar cantidades que son m´ltiplo de 10 ¤. En cada momento, a u el cajero tiene un n´mero determinado de billetes de 50, 20 y 10 ¤. Utilizaremos una u variable para cada tipo de billete y en ella indicaremos cu´ntos billetes de ese tipo nos a quedan en el cajero. Cuando un cliente pida sacar una cantidad determinada de dinero, mostraremos por pantalla cu´ntos billetes de cada tipo le damos. Intentaremos darle a siempre la menor cantidad de billetes posible. Si no es posible darle el dinero (porque no tenemos suficiente dinero en el cajero o porque la cantidad solicitada no puede darse con una combinaci´n v´lida de los billetes disponibles) informaremos al usuario. o a Inicialmente supondremos que el cajero est´ cargado con 100 billetes de cada tipo: a Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 287 287 Introducción a la programación con Python - UJIUJI c
    • cajero.py 1 2 3 carga50 = 100 carga20 = 100 carga10 = 100 Dise˜aremos ahora una funci´n que, ante una petici´n de dinero, muestre por pantalla n o o los billetes de cada tipo que se entregan. La funci´n devolver´ una lista con el n´mero de o a u billetes de 50, 20 y 10 ¤ si se pudo dar el dinero, y la lista [0, 0, 0] en caso contrario. Intent´moslo. e cajero.py 1 2 3 4 5 6 7 8 9 10 11 carga50 = 100 carga20 = 100 carga10 = 100 def sacar_dinero(cantidad): de50 = cantidad / 50 cantidad = cantidad % 50 de20 = cantidad / 20 cantidad = cantidad % 20 de10 = cantidad / 10 return [de50, de20, de10] sacar dinero cantidad billetes de 50 billetes de 20 billetes de 10 ¿Entiendes las f´rmulas utilizadas para calcular el n´mero de billetes de cada tipo? o u Est´dialas con calma antes de seguir. u En principio, ya est´. Bueno, no; hemos de restar los billetes que le damos al usuario a de las variables carga50, carga20 y carga10, pues el cajero ya no los tiene disponibles para futuras extracciones de dinero: cajero 5.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 carga50 = 100 carga20 = 100 carga10 = 100 E cajero.py E def sacar_dinero(cantidad): de50 = cantidad / 50 cantidad = cantidad % 50 de20 = cantidad / 20 cantidad = cantidad % 20 de10 = cantidad / 10 carga50 = carga50 - de50 carga20 = carga20 - de20 carga10 = carga10 - de10 return [de50, de20, de10] Probemos el programa a˜adiendo, moment´neamente, un programa principal: n a cajero 1.py 19 20 cajero.py c = int(raw_input(’Cantidad␣a␣extraer:␣’)) print sacar_dinero(c) ¿Qu´ ocurrir´ con el acceso a carga50, carga20 y carga10? Puede que Python las tome e a por variables locales, en cuyo caso, no habremos conseguido el objetivo de actualizar la cantidad de billetes disponibles de cada tipo. Lo que ocurre es peor a´n: al ejecutar el u programa obtenemos un error. Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia Python 288 288 Introducción a la programación con Python - cUJI UJI
    • ↱ $ python cajero.py Cantidad a extraer: 70 Traceback (most recent call last): File "cajero.py", line 17, in ? print sacar_dinero(c) File "cajero.py", line 11, in sacar_dinero carga50 = carga50 - de50 UnboundLocalError: local variable ’carga50’ referenced before assignment El error es del tipo UnboundLocalError (que podemos traducir por ˂˂error de variable local no ligada˃˃) y nos indica que hubo un problema al tratar de acceder a carga50, pues es una variable local que no tiene valor asignado previamente. Pero, ¡carga50 deber´ ser ıa una variable global, no local, y adem´s s´ se le asign´ un valor: en la l´ a ı o ınea 1 asignamos a carga50 el valor 100! ¿Por qu´ se confunde? Python utiliza una regla simple para decidir e si una variable usada en una funci´n es local o global: si se le asigna un valor, es local; o si no, es global. Las variables carga50, carga20 y carga10 aparecen en la parte izquierda de una asignaci´n, as´ que Python supone que son variables locales. Y si son locales, no o ı est´n inicializadas cuando se eval´a la parte derecha de la asignaci´n. Hay una forma a u o de evitar que Python se equivoque en situaciones como ´sta: declarar expl´ e ıcitamente que esas variables son globales. F´ ıjate en la l´ ınea 6: E cajero.py E cajero 6.py 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 carga50 = 100 carga20 = 100 carga10 = 100 def sacar_dinero(cantidad): global carga50, carga20, carga10 de50 = cantidad / 50 cantidad = cantidad % 50 de20 = cantidad / 20 cantidad = cantidad % 20 de10 = cantidad / 10 carga50 = carga50 - de50 carga20 = carga20 - de20 carga10 = carga10 - de10 return [de50, de20, de10] c = int(raw_input(’Cantidad␣a␣extraer:␣’)) print sacar_dinero(c) ↱ $ python cajero.py Cantidad a extraer: 70 [1, 1, 0] ↱ 1 ¡Perfecto! Hagamos una prueba m´s: a ↱ ↱ $ python cajero.py Cantidad a extraer: 7000 [140, 0, 0] ¿No ves nada raro? ¡La funci´n ha dicho que nos han de dar 140 billetes de 50 ¤, cuando o s´lo hay 100! Hemos de refinar la funci´n y hacer que nos d´ la cantidad solicitada s´lo o o e o cuando dispone de suficiente efectivo: cajero 7.py 1 2 carga50 = 100 carga20 = 100 Introducci´n a la programaci´n con Python o o Andrés Marzal/Isabel Gracia - ISBN: 978-84-692-5869-9 E cajero.py E 289 289 c UJI Introducción a la programación con Python - UJI
    • 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 carga10 = 100 def sacar_dinero(cantidad): global carga50, carga20, carga10 if cantidad <= 50 * carga50 + 20 * carga20 + 10 * carga10: de50 = cantidad / 50 cantidad = cantidad % 50 de20 = cantidad / 20 cantidad = cantidad % 20 de10 = cantidad / 10 carga50 = carga50 - de50 carga20 = carga20 - de20 carga10 = carga10 - de10 return [de50, de20, de10] else: return [0, 0, 0] c = int(raw_input(’Cantidad␣a␣extraer:␣’)) print sacar_dinero(c) La l´ ınea 7 se encarga de averiguar si hay suficiente dinero en el cajero. Si no lo hay, la funci´n finaliza inmediatamente devolviendo la lista [0, 0, 0]. ¿Funcionar´ ahora? o a ↱ ↱ $ python cajero.py Cantidad a extraer: 7000 [140, 0, 0] ¡No! Sigue funcionando mal. ¡Claro!, hay 50 × 100 + 20 × 100 + 10 × 100 = 8000 ¤ en el cajero y hemos pedido 7000 ¤. Lo que deber´ ıamos controlar no (s´lo) es que haya o suficiente dinero, sino que haya suficiente cantidad de billetes de cada tipo: cajero 8.py 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 cajero.py carga50 = 100 carga20 = 100 carga10 = 100 def sacar_dinero(cantidad): global carga50, carga20, carga10 if cantidad <= 50 * carga50 + 20 * carga20 + 10 * carga10: de50 = cantidad / 50 cantidad = cantidad % 50 if de50 >= carga50: # Si no hay suficientes billetes de 50 cantidad = cantidad + (de50 - carga50) * 50 de50 = carga50 de20 = cantidad / 20 cantidad = cantidad % 20 if de20 >= carga20: # y no hay suficientes billetes de 20 cantidad = cantidad + (de20 - carga20) * 20 de20 = carga20 de10 = cantidad / 10 cantidad = cantidad % 10 if de10 >= carga10: # y no hay suficientes billetes de 10 cantidad = cantidad + (de10 - carga10) * 10 de10 = carga10 # Si todo ha ido bien, la cantidad que resta por entregar es nula: if cantidad == 0: # As´ que hacemos efectiva la extracci´n ı o carga50 = carga50 - de50 carga20 = carga20 - de20 Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: 290 290 Introducción a la programación con Python - UJI c UJI
    • carga10 = carga10 - de10 return [de50, de20, de10] else: # Y si no, devolvemos la lista con tres ceros: return [0, 0, 0] else: return [0, 0, 0] 28 29 30 31 32 33 34 35 36 c = int(raw_input(’Cantidad␣a␣extraer:␣’)) print sacar_dinero(c) Bueno, parece que ya tenemos la funci´n completa. Hagamos algunas pruebas: o ↱ ↱ ↱ ↱ $ python cajero.py Cantidad a extraer: 130 [2, 1, 1] $ python cajero.py Cantidad a extraer: 7000 [100, 100, 0] $ python cajero.py Cantidad a extraer: 9000 [0, 0, 0] ↱ ↱ ¡Ahora s´ ı! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 358 Hay dos ocasiones en las que se devuelve la lista [0, 0, 0]. ¿Puedes modificar el programa para que s´lo se devuelva esa lista expl´ o ıcita desde un punto del programa? .................................................................................. Como ya hemos dise˜ado y probado la funci´n, hagamos un ultimo esfuerzo y acan o ´ bemos el programa. Eliminamos las l´ ıneas de prueba (las dos ultimas) y a˜adimos el n ´ siguiente c´digo: o cajero.py cajero.py . . . 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 # Programa principal while 50*carga50 + 20*carga20 + 10*carga10 > 0: peticion = int(raw_input(’Cantidad␣que␣desea␣sacar:␣’)) [de50, de20, de10] = sacar_dinero(peticion) if [de50, de20, de10] != [0, 0, 0]: if de50 > 0: print ’Billetes␣de␣50␣euros:’, de50 if de20 > 0: print ’Billetes␣de␣20␣euros:’, de20 if de10 > 0: print ’Billetes␣de␣10␣euros:’, de10 print ’Gracias␣por␣usar␣el␣cajero.’ print else: print ’Lamentamos␣no␣poder␣atender␣su␣petici´n.’ o print print ’Cajero␣sin␣dinero.␣Avise␣a␣mantenimiento.’ Usemos esta versi´n final del programa: o ↱ cajero.py que desea sacar: 7000 de 50 euros: 100 de 20 euros: 100 Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o ↱ $ python Cantidad Billetes Billetes 291 291 Introducción a la programación con Python - UJIUJI c
    • Gracias por usar el cajero. ↱ Cantidad que desea sacar: 500 Billetes de 10 euros: 50 Gracias por usar el cajero. ↱ Cantidad que desea sacar: 600 Lamentamos no poder atender su petici´n. o ↱ Cantidad que desea sacar: 500 Billetes de 10 euros: 50 Gracias por usar el cajero. Cajero sin dinero. Avise a mantenimiento. Se supone que un cajero de verdad debe entregar dinero El programa del cajero autom´tico no parece muy util: se limita a imprimir por pantalla a ´ el n´mero de billetes de cada tipo que nos ha de entregar. Se supone que un cajero de u verdad debe entregar dinero y no limitarse a mostrar mensajes por pantalla. Los cajeros autom´ticos est´n gobernados por un computador. Las acciones del cajero a a pueden controlarse por medio de funciones especiales. Estas funciones acceden a puertos de entrada/salida del ordenador que se comunican con los perif´ricos adecuados. El e aparato que entrega billetes no es m´s que eso, un perif´rico m´s. a e a Lo l´gico ser´ disponer de un m´dulo, digamos dipensador_de_billetes, que nos dieo ıa o ra acceso a las funciones que controlan el perif´rico. Una funci´n podr´ por ejemplo, ene o ıa, tregar al usuario tantos billetes de cierto tipo como se indicara. Si dicha funci´n se llamao ra entrega, en lugar de una sentencia como ˂˂print "Billetes␣de␣50␣euros:", de50˃˃, realizar´ ıamos la llamada entrega(de50, 50). Acabaremos este apartado con una reflexi´n. Ten en cuenta que modificar variables o globales desde una funci´n no es una pr´ctica de programaci´n recomendable. La expeo a o riencia dice que s´lo en contadas ocasiones est´ justificado que una funci´n modifique o a o variables globales. Se dice que modificar variables globales desde una funci´n es un o efecto secundario de la llamada a la funci´n. Si cada funci´n de un programa largo moo o dificara libremente el valor de variables globables, tu programa ser´ bastante ilegible y, ıa por tanto, dif´ de ampliar o corregir en el futuro. ıcil 6.6. Ejemplos 6.6.1. Integraci´n num´rica o e Vamos ahora a desarrollar unos cuantos ejemplos de programas con funciones. As´ ponı dremos en pr´ctica lo aprendido. a Vamos a implementar un programa de integraci´n num´rica que aproxime el valor de o e con la f´rmula o n−1 i=0 Introducci´nMarzal/Isabel Gracia - Python978-84-692-5869-9 o o Andrés a la programaci´n con ISBN: a b x 2 dx ∆x · (a + i · ∆x)2 , 292 292 Introducción a la programación con Python - UJI c UJI
    • donde ∆x = (b − a)/n. El valor de n lo proporcionamos nosotros: a mayor valor de n, mayor precisi´n en la aproximaci´n. Este m´todo de aproximaci´n de integrales se basa o o e o en el c´lculo del area de una serie de rect´ngulos. a a ´ En la gr´fica de la izquierda de la figura que aparece a continuaci´n se marca en gris a o la regi´n cuya area corresponde al valor de la integral de x 2 entre a y b. En la gr´fica de o a ´ la derecha se muestra en gris el area de cada uno de los 6 rect´ngulos (n = 6) utilizados a ´ en la aproximaci´n. La suma de las 6 areas es el resultado de nuestra aproximaci´n. Si o o ´ en lugar de 6 rect´ngulos us´semos 100, el valor calculado ser´ m´s aproximado al real. a a ıa a x2 a x2 a b b La funci´n Python que vamos a definir se denominar´ integral_x2 y necesita tres datos o a de entrada: el extremo izquierdo del intervalo (a), el extremo derecho (b) y el n´mero de u rect´ngulos con los que se efect´a la aproximaci´n (n). a u o La cabecera de la definici´n de la funci´n ser´, pues, de la siguiente forma: o o a integral.py 1 2 def integral_x2(a, b, n): ... ¿Qu´ ponemos en el cuerpo? Pensemos. En el fondo, lo que se nos pide no es m´s e a que el c´lculo de un sumatorio. Los elementos que participan en el sumatorio son un a tanto complicados, pero esta complicaci´n no afecta a la forma general de c´lculo de o a un sumatorio. Los sumatorios se calculan siguiendo un patr´n que ya hemos visto con o anterioridad: integral.py 1 2 3 4 def integral_x2(a, b, n): sumatorio = 0 for i in range(n): sumatorio += lo que sea Ese ˂˂lo que sea˃˃ es, precisamente, la f´rmula que aparece en el sumatorio. En nuestro o caso, ese fragmento del cuerpo de la funci´n ser´ as´ o a ı: integral.py 1 2 3 4 def integral_x2(a, b, n): sumatorio = 0 for i in range(n): sumatorio += deltax * (a + i * deltax) ** 2 Mmmmm. . . En el bucle hacemos uso de una variable deltax que, suponemos, tiene el valor de ∆x. As´ pues, habr´ que calcular previamente su valor: ı a integral.py 1 2 3 4 5 def integral_x2(a, b, n): deltax = (b-a) / n sumatorio = 0 for i in range(n): sumatorio += deltax * (a + i * deltax) ** 2 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 293 293 Introducción a la programación con Python - cUJI UJI
    • La variable deltax (al igual que i y sumatorio) es una variable local. Ya casi est´. Faltar´ a˜adir una l´ a a n ınea: la que devuelve el resultado. integral 5.py 1 2 3 4 5 6 E integral.py E def integral_x2(a, b, n): deltax = (b-a) / n sumatorio = 0 for i in range(n): sumatorio += deltax * (a + i * deltax) ** 2 return sumatorio ¿Hecho? Repasemos, a ver si todo est´ bien. F´ a ıjate en la l´ ınea 2. Esa expresi´n puede o dar problemas: 1. ¿Qu´ pasa si n vale 0? e 2. ¿Qu´ pasa si tanto a, como b y n son enteros? e Vamos por partes. En primer lugar, evitemos la divisi´n por cero. Si n vale cero, el o resultado de la integral ser´ 0. a integral 6.py 1 2 3 4 5 6 7 8 9 integral.py def integral_x2(a, b, n): if n == 0: sumatorio = 0 else: deltax = (b-a) / n sumatorio = 0 for i in range(n): sumatorio += deltax * (a + i * deltax) ** 2 return sumatorio Y, ahora, nos aseguraremos de que la divisi´n siempre proporcione un valor flotante, aun o cuando las tres variables, a, b y n, tengan valores de tipo entero: integral 7.py 1 2 3 4 5 6 7 8 9 integral.py def integral_x2(a, b, n): if n == 0: sumatorio = 0 else: deltax = (b-a) / float(n) sumatorio = 0 for i in range(n): sumatorio += deltax * (a + i * deltax) ** 2 return sumatorio Ya podemos utilizar nuestra funci´n: o integral.py integral.py . . . 11 12 13 14 15 16 inicio = float(raw_input(’Inicio␣del␣intervalo:␣’)) final = float(raw_input(’Final␣del␣intervalo:␣’)) partes = int(raw_input(’N´mero␣de␣rect´ngulos:␣’)) u a print ’La␣integral␣de␣x**2␣entre␣%f␣y␣%f’ % (inicio, final), print ’vale␣aproximadamente␣%f’ % integral_x2(inicio, final, partes) Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 294 294 Introducción a la programación con Python - cUJI UJI
    • En la l´ ınea 16 llamamos a integral_x2 con los argumentos inicio, final y partes, variables cuyo valor nos suministra el usuario en las l´ ıneas 11–13. Recuerda que cuando llamamos a una funci´n, Python asigna a cada par´metro el valor de un argumento o a siguiendo el orden de izquierda a derecha. As´ el par´metro a recibe el valor que contiene ı, a el argumento inicio, el par´metro b recibe el valor que contiene el argumento final y el a par´metro n recibe el valor que contiene el argumento partes. No importa c´mo se llama a o cada argumento. Una vez se han hecho esas asignaciones, empieza la ejecuci´n de la o funci´n. o Un m´todo de integraci´n gen´rico e o e El m´todo de integraci´n que hemos implementado presenta un inconveniente: s´lo e o o puede usarse para calcular la integral definida de una sola funci´n: f (x) = x 2 . Si o queremos integrar, por ejemplo, g(x) = x 3 , tendremos que codificar otra vez el m´todo y e cambiar una l´ ınea. ¿Y por una s´la l´ o ınea hemos de volver a escribir otras ocho? Analiza este programa: integracion generica.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 integracion generica.py def cuadrado(x): return x**2 def cubo(x): return x**3 def integral_definida(f , a, b, n): if n == 0: sumatorio = 0 else: deltax = (b-a) / float(n) sumatorio = 0 for i in range(n): sumatorio += deltax * f (a + i * deltax) return sumatorio a=1 b=2 print ’Integraci´n␣entre␣%f␣y␣%f’ % (a, b) o print ’Integral␣de␣x**2:’, integral_definida(cuadrado , a, b, 100) print ’Integral␣de␣x**3:’, integral_definida(cubo , a, b, 100) ¡Podemos pasar funciones como argumentos! En la l´ ınea 20 calculamos la integral de x 2 entre 1 y 2 (con 100 rect´ngulos) y en la l´ a ınea 21, la de x 3 . Hemos codificado una sola vez el m´todo de integraci´n y es, en cierto sentido, ˂˂gen´rico˃˃: puede integrar e o e cualquier funci´n. o Pon atenci´n a este detalle: cuando pasamos la funci´n como par´metro, no usamos o o a par´ntesis con argumentos; s´lo pasamos el nombre de la funci´n. El nombre de la e o o funci´n es una variable. ¿Y qu´ contiene? Contiene una referencia a una zona de memoria o e en la que se encuentran las instrucciones que hemos de ejecutar al llamar a la funci´n. o Leer ahora el cuadro ˂˂Los par´ntesis son necesarios˃˃ (p´gina 245) puede ayudarte a e a entender esta afirmaci´n. o 6.6.2. Aproximaci´n de la exponencial de un n´mero real o u Vamos a desarrollar una funci´n que calcule el valor de ea , siendo a un n´mero real, con o u una restricci´n: no podemos utilizar el operador de exponenciaci´n **. o o Si a fuese un n´mero natural, ser´ f´cil efectuar el c´lculo: u ıa a a Andrés a la programaci´n con ISBN: Introducci´n Marzal/Isabel Gracia -Python 978-84-692-5869-9 o o 295 295 Introducción a la programación con Python - c UJI UJI
    • exponencial.py exponencial 8.py 1 2 3 4 5 6 7 from math import e def exponencial(a): exp = 1 for i in range(a): exp *= e return exp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 359 ¿Y si a pudiera tomar valores enteros negativos? Dise˜a una funci´n exponencial n o que trate tambi´n ese caso. (Recuerda que e−a = 1/ea .) e .................................................................................. Pero siendo a un n´mero real (bueno, un flotante), no nos vale esa aproximaci´n. u o a para Refrescando conocimientos matem´ticos, vemos que podemos calcular el valor de e a a real con la siguiente f´rmula: o ea = 1 + a + ak a2 a3 a4 + + + ··· + + ··· = 2 3! 4! k! ∞ n=0 an . n! La f´rmula tiene un n´mero infinito de sumandos, as´ que no la podemos codificar en o u ı Python. Haremos una cosa: dise˜aremos una funci´n que aproxime el valor de ea con n o tantos sumandos como nos indique el usuario. Vamos con una primera versi´n: o exponencial 9.py 1 2 3 4 5 E exponencial.py E def exponencial(a, n): sumatorio = 0.0 for k in range(n): sumatorio += a**k / ( k!) return sumatorio Mmmm. Mal. Por una parte, nos han prohibido usar el operador **, as´ que tendremos ı que efectuar el correspondiente c´lculo de otro modo. Recuerda que a ak = exponencial 10.py 1 2 3 4 5 6 7 8 9 10 k i=1 a. exponencial.py def exponencial(a, n): sumatorio = 0.0 for k in range(n): # C´lculo de ak . a numerador = 1.0 for i in range(1, k+1): numerador *= a # Adici´n de nuevo sumando al sumatorio. o sumatorio += numerador / k! return sumatorio Y por otra parte, no hay operador factorial en Python. Tenemos que calcular el factorial expl´ ıcitamente. Recuerda que Corregimos el programa anterior: Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python k! = k i=1 i. 296 296 Introducción a la programación con Python - UJIUJI c
    • exponencial 11.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Y ya est´. La verdad es que no queda muy legible. Analiza esta otra versi´n: a o exponencial 12.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 exponencial.py def exponencial(a, n): sumatorio = 0.0 for k in range(n): # C´lculo de ak . a numerador = 1.0 for i in range(1, k+1): numerador *= a # C´lculo de k!. a denominador = 1.0 for i in range(1, k+1): denominador *= i # Adici´n de nuevo sumando al sumatorio. o sumatorio += numerador / denominador return sumatorio exponencial.py def elevado(a, k): productorio = 1.0 for i in range(1, k+1): productorio *= a return productorio def factorial(k): productorio = 1.0 for i in range(1, k+1): productorio *= i return productorio def exponencial(a, n): sumatorio = 0.0 for k in range(n): sumatorio += elevado(a, k) / factorial(k) return sumatorio Esta versi´n es mucho m´s elegante que la anterior, e igual de correcta. Al haber separado o a el c´lculo de la exponenciaci´n y del factorial en sendas funciones hemos conseguido que a o la funci´n exponencial sea mucho m´s legible. o a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 360 ¿Es correcta esta otra versi´n? (Hemos destacado los cambios con respecto a la o ultima.) ´ exponencial 13.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 exponencial.py def elevado(a, k): productorio = 1.0 for i in range(k): productorio *= a return productorio def factorial(k): productorio = 1.0 for i in range(2, k): productorio *= i return productorio def exponencial(a, n): sumatorio = 0.0 Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 297 297 Introducción a la programación con Python - UJIUJI c
    • 15 16 17 for k in range(n): sumatorio += elevado(a, k) / factorial(k) return sumatorio · 361 Las funciones seno y coseno se pueden calcular as´ ı x3 x5 x7 sin(x) = x − + − + ··· = 3! 5! 7! cos(x) = 1 − x2 2! + x4 4! − x6 6! + ··· = ∞ n=0 ∞ n=0 (−1)n x 2n+1 (2n + 1)! (−1)n x 2n (2n)! Dise˜a sendas funciones seno y coseno para aproximar, respectivamente, el seno y el n coseno de x con n t´rminos del sumatorio correspondiente. e .................................................................................. El m´todo de c´lculo utilizado en la funci´n exponencial es ineficiente: el t´rmino e a o e elevado(a, k) / factorial(k) resulta costoso de calcular. Imagina que nos piden calcular exponencial(a, 8). Se producen la siguientes llamadas a elevado y factorial: elevado(a, 0) y factorial(0). elevado(a, 1) y factorial(1). elevado(a, 2) y factorial(2). elevado(a, 3) y factorial(3). elevado(a, 4) y factorial(4). elevado(a, 5) y factorial(5). elevado(a, 6) y factorial(6). elevado(a, 7) y factorial(7). Estas llamadas esconden una repetici´n de c´lculos que resulta perniciosa para la velocio a dad de ejecuci´n del c´lculo. Cada llamada a una de esas rutinas supone iterar un bucle, o a cuando resulta innecesario si aplicamos un poco de ingenio. F´ ıjate en que se cumplen estas dos relaciones: elevado(a, n) = a∗elevado(a, n-1), factorial(n) = n∗factorial(n-1), para todo n mayor que 0. Si n vale 0, tanto elevado(a, n) como factorial(n) valen 1. Este programa te muestra el valor de elevado(2, n) para n entre 0 y 7: elevado rapido.py elevado rapido.py 1 2 3 4 5 6 a=2 valor = 1 print ’elevado(%d,␣%d)␣=␣%d’ % (a, 0, valor) for n in range(1, 8): valor = a * valor print ’elevado(%d,␣%d)␣=␣%d’ % (a, n, valor) elevado(2, elevado(2, elevado(2, elevado(2, elevado(2, elevado(2, elevado(2, elevado(2, 0) 1) 2) 3) 4) 5) 6) 7) = = = = = = = = 1 2 4 8 16 32 64 128 Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 298 298 Introducción a la programación con Python - UJIUJI c
    • . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 362 Dise˜a un programa similar que muestre el valor de factorial(n) para n entre n 0 y 7. .................................................................................. Explotemos esta forma de calcular esa serie de valores en el c´mputo de exponencial: o exponencial.py exponencial 14.py 1 2 3 4 5 6 7 8 9 def exponencial(a, n): numerador = 1 denominador = 1 sumatorio = 1.0 for k in range(1, n): numerador = a * numerador denominador = k * denominador sumatorio += numerador / denominador return sumatorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 363 Modifica las funciones que has propuesto como soluci´n al ejercicio 361 aproo vechando las siguientes relaciones, v´lidas para n mayor que 0: a (−1)n x 2n+1 (2n + 1)! (−1)n x 2n (2n)! Cuando n vale 0, tenemos: x2 (n + 1) · n x2 = − n · (n − 1) = − (−1)n−1 x 2n−1 , (2n − 1)! (−1)n−1 x 2n · . (2n)! · (−1)0 x 1 (−1)0 x 0 = x, = 1. 1! 0! .................................................................................. Resolvamos ahora un problema ligeramente diferente: vamos a aproximar ea con tantos t´rminos como sea preciso hasta que el ultimo t´rmino considerado sea menor o igual que e e ´ un valor ε dado. Lo desarrollaremos usando, de nuevo, las funciones elevado y factorial. (Enseguida te pediremos que mejores el programa con las ultimas ideas presentadas.) ´ No resulta apropiado ahora utilizar un bucle for-in, pues no sabemos cu´ntas iteraciones a habr´ que dar hasta llegar a un ak /k! menor o igual que ε. Utilizaremos un bucle while: a exponencial.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def elevado(a, k): productorio = 1.0 for i in range(k): productorio *= a return productorio def factorial(n): productorio = 1.0 for i in range(1, n+1): productorio *= i return productorio def exponencial2(a, epsilon): sumatorio = 0.0 k=0 termino = elevado(a, k) / factorial(k) while termino > epsilon: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 299 299 Introducción a la programación con Python - UJIUJI c
    • 18 19 20 21 sumatorio += termino k += 1 termino = elevado(a, k) / factorial(k) return sumatorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 364 Modifica la funci´n exponencial2 del programa anterior para que no se efect´en o u las ineficientes llamadas a elevado y factorial. .................................................................................. 6.6.3. C´lculo de n´meros combinatorios a u Ahora vamos a dise˜ar una funci´n que calcule de cu´ntas formas podemos escoger m n o a elementos de un conjunto con n objetos. Recuerda que la formula es: n m = n! (n − m)! m! Esta funci´n es f´cil de codificar. . . ¡si reutilizamos la funci´n factorial del apartado ano a o terior! combinaciones 2.py 1 2 3 4 5 6 7 8 combinaciones.py def factorial(n): productorio = 1.0 for i in range(1, n+1): productorio *= i return productorio def combinaciones(n, m): return factorial(n) / (factorial(n-m) * factorial(m)) Observa cu´n apropiado ha resultado que factorial fuera una funci´n definida indepena o dientemente: hemos podido utilizarla en tres sitios diferentes con s´lo invocarla. Adem´s, o a una vez dise˜ada la funci´n factorial, podemos reutilizarla en otros programas con s´lo n o o ˂˂copiar y pegar˃˃. M´s adelante te ense˜aremos c´mo hacerlo a´n m´s c´modamente. a n o u a o 6.6.4. El m´todo de la bisecci´n e o El m´todo de la bisecci´n permite encontrar un cero de una funci´n matem´tica f (x) en e o o a un intervalo [a, b] si f (x) es continua en dicho intervalo y f (a) y f (b) son de distinto signo. El m´todo de la bisecci´n consiste en dividir el intervalo en dos partes iguales. e o Llamemos c al punto medio del intervalo. Si el signo de f (c) tiene el mismo signo que f (a), aplicamos el mismo m´todo al intervalo [c, b]. Si f (c) tiene el mismo signo que f (b), e aplicamos el m´todo de la bisecci´n al intervalo [a, c]. El m´todo finaliza cuando hallamos e o e un punto c tal que f (c) = 0 o cuando la longitud del intervalo de b´squeda es menor que u un ε determinado. En la figura de la izquierda te mostramos el instante inicial de la b´squeda: nos piden u hallar un cero de una funci´n continua f entre a y b y ha de haberlo porque el signo de o f (a) es distinto del de f (b). Calcular entonces el punto medio c entre a y b. f (a) y f (c) presentan el mismo signo, as´ que el cero no se encuentra entre a y c, sino entre c y b. ı La figura de la derecha te muestra la nueva zona de inter´s: a ha cambiado su valor y e ha tomado el que ten´ c. ıa Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o Andrés Marzal/Isabel Gracia - Python 300 300 Introducción a la programación con Python - UJIUJI c
    • a f(a) c f(c) f(b) a b f(a) f(b) b Deseamos dise˜ar un programa que aplique el m´todo de la bisecci´n a la b´squeda n e o u de un cero de la funci´n f (x) = x 2 −2x −2 en el intervalo [0.5, 3.5]. No debemos considerar o intervalos de b´squeda mayores que 10−5 . u Parece claro que implementaremos dos funciones: una para la funci´n matem´tica o a f (x) y otra para el m´todo de la bisecci´n. Esta ultima tendr´ tres par´metros: los dos e o a a ´ extremos del intervalo y el valor de ε que determina el tama˜o del (sub)intervalo de n b´squeda m´s peque˜o que queremos considerar: u a n biseccion.py 1 2 3 4 5 def f (x): return x**2 - 2*x -2 def biseccion(a, b, epsilon): ... El m´todo de la bisecci´n es un m´todo iterativo: aplica un mismo procedimiento e o e repetidas veces hasta satisfacer cierta condici´n. Utilizaremos un bucle, pero ¿un while o o un for-in? Obviamente, un bucle while: no sabemos a priori cu´ntas veces iteraremos. a ¿C´mo decidimos cu´ndo hay que volver a iterar? Hay que volver a iterar mientras no o a hayamos hallado el cero y, adem´s, el intervalo de b´squeda sea mayor que ε: a u biseccion.py 1 2 3 4 5 6 def f (x): return x**2 - 2*x -2 def biseccion(a, b, epsilon): while f (c) != 0 and b - a > epsilon: ... Para que la primera comparaci´n funcione c ha de tener asignado alg´n valor: o u biseccion.py 1 2 3 4 5 6 7 def f (x): return x**2 - 2*x -2 def biseccion(a, b, epsilon): c = (a + b) / 2.0 while f (c) != 0 and b - a > epsilon: ... Dentro del bucle hemos de actualizar el intervalo de b´squeda: u biseccion.py 1 2 def f (x): return x**2 - 2*x -2 Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 301 301 Introducción a la programación con Python - cUJI UJI
    • Par´metros con valor por defecto a La funci´n biseccion trabaja con tres par´metros. El tercero est´ relacionado con el o a a margen de error que aceptamos en la respuesta. Sup´n que el noventa por cien de las o veces trabajamos con un valor de ε fijo, pongamos que igual a 10−5 . Puede resultar pesado proporcionar expl´ ıcitamente ese valor en todas y cada una de las llamadas a la funci´n. Python nos permite proporcionar par´metros con un valor por defecto. Si damos o a un valor por defecto al par´metro epsilon, podremos llamar a la funci´n biseccion con a o tres argumentos, como siempre, o con s´lo dos. o El valor por defecto de un par´metro se declara en la definici´n de la funci´n: a o o 1 2 def biseccion(a, b, epsilon=1e-5): ... Si llamamos a la funci´n con biseccion(1, 2), es como si la llam´semos as´ biseco a ı: cion(1, 2, 1e-5). Al no indicar valor para epsilon, Python toma su valor por defecto. 3 4 5 6 7 8 9 10 11 def biseccion(a, b, epsilon): c = (a + b) / 2.0 while f (c) != 0 and b - a > epsilon: if (f (a) < 0 and f (c) < 0 ) or (f (a) > 0 and f (c) > 0): a=c elif (f (b) < 0 and f (c) < 0 ) or (f (b) > 0 and f (c) > 0): b=c ... Las condiciones del if-elif son complicadas. Podemos simplificarlas con una idea feliz: dos n´meros x e y tienen el mismo signo si su producto es positivo. u biseccion.py 1 2 3 4 5 6 7 8 9 10 11 def f (x): return x**2 - 2*x -2 def biseccion(a, b, epsilon): c = (a + b) / 2.0 while f (c) != 0 and b - a > epsilon: if f (a)*f (c) > 0: a=c elif f (b)*f (c) > 0: b=c ... A´n nos queda ˂˂preparar˃˃ la siguiente iteraci´n. Si no actualizamos el valor de c, la u o funci´n quedar´ atrapada en un bucle sin fin. ¡Ah! Y al finalizar el bucle hemos de o a devolver el cero de la funci´n: o biseccion 3.py 1 2 3 4 5 6 7 8 9 10 biseccion.py def f (x): return x**2 - 2*x -2 def biseccion(a, b, epsilon): c = (a + b) / 2.0 while f (c) != 0 and b - a > epsilon: if f (a)*f (c) > 0: a=c elif f (b)*f (c) > 0: b=c Andrés Marzal/Isabel Gracia Python Introducci´n a la programaci´n con - ISBN: 978-84-692-5869-9 o o 302 302 Introducción a la programación con Python - cUJI UJI
    • c = (a + b) / 2.0 return c 11 12 Ya podemos completar el programa introduciendo el intervalo de b´squeda y el valor de u ε: biseccion.py biseccion.py . . . 14 print ’El␣cero␣est´␣en:’, biseccion(0.5, 3.5, 1e-5) a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . EJERCICIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · 365 La funci´n biseccion a´n no est´ acabada del todo. ¿Qu´ ocurre si el usuario o u a e introduce un intervalo [a, b] tal que f (a) y f (b) tienen el mismo signo? ¿Y si f (a) o f (b) valen 0? Modifica la funci´n para que s´lo inicie la b´squeda cuando procede y, en caso o o u contrario, devuelva el valor especial None. Si f (a) o f (b) valen cero, biseccion devolver´ a el valor de a o b, seg´n proceda. u · 366 Modifica el programa para que solicite al usuario los valores a, b y ε. El programa s´lo aceptar´ valores de a y b tales que a < b. o a .................................................................................. 6.7. Dise˜o de programas con funciones n Hemos aprendido a dise˜ar funciones, cierto, pero puede que no tengas claro qu´ venn e tajas nos reporta trabajar con ellas. El programa de integraci´n num´rica que hemos o e desarrollado en la secci´n anterior podr´ haberse escrito directamente as´ o ıa ı: integral 8.py 1 2 3 4 5 6 7 8 9 10 11 12 13 integral.py a = float(raw_input(’Inicio␣del␣intervalo:␣’)) b = float(raw_input(’Final␣del␣intervalo:␣’)) n = int(raw_input(’N´mero␣de␣rect´ngulos:␣’)) u a if n == 0: sumatorio = 0 else: deltax = (b-a) / float(n) sumatorio = 0 for i in range(n): sumatorio += deltax * (a + i * deltax) ** 2 print ’La␣integral␣de␣x**2␣entre␣%f␣y␣%f␣es␣(aprox)␣%f’ % (a, b, sumatorio) Este programa ocupa menos l´ ıneas y hace lo mismo, ¿no? S´ as´ es. Con programas ı, ı peque˜os como ´ste apenas podemos apreciar las ventajas de trabajar con funciones. n e Imagina que el programa fuese mucho m´s largo y que hiciese falta aproximar el valor a de la integral definida de x 2 en tres o cuatro lugares diferentes; entonces s´ que ser´ ı ıa una gran ventaja haber definido una funci´n: habiendo escrito el procedimiento de c´lculo o a una vez podr´ ıamos ejecutarlo cuantas veces quisi´ramos mediante simples invocaciones. e No s´lo eso, habr´ o ıamos ganado en legibilidad. 6.7.1. Ahorro de tecleo Por ejemplo, sup´n que en un programa deseamos leer tres n´meros enteros y asegurarnos o u de que sean positivos. Podemos proceder repitiendo el bucle correspondiente tres veces: Andrés Marzal/Isabel Gracia - Python Introducci´n a la programaci´n con ISBN: 978-84-692-5869-9 o o 303 303 Introducción a la programación con Python - UJIUJI c
    • Evita las llamadas repetidas En nuestra ultima versi´n del programa biseccion.py hay una fuente de ineficiencia: o ´ f (c), para un c fijo, se calcula 3 veces por iteraci´n. o biseccion.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 def f (x): return x**2 - 2*x -2 def biseccion(a, b, epsilon): c = (a + b) / 2.0 while f (c) != 0 and b - a > epsilon: if f (a)* f (c) > 0 : a=c elif f (b)* f (c) > 0: b=c c = (a + b) / 2.0 return c print ’El␣cero␣est´␣en:’, biseccion(0.5, 3.5, 1e-5) a Llamar a una funci´n es costoso: Python debe dedicar un tiempo a gestionar la pila o de llamadas apilando una nueva trama activaci´n de funci´n (y ocupar, en consecueno o cia, algo de memoria), copiar las referencias a los valores de los argumentos en los par´metros formales, efectuar nuevamente un c´lculo que ya hemos hecho y devolver el a a valor resultante. Una optimizaci´n evidente del programa consiste en no llamar a f (c) m´s que una o a vez y almacenar el resultado en una variable temporal que usaremos cada vez que deber´ ıamos haber llamado a f (c): biseccion 4.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 biseccion.py def f (x): return x**2 - 2*x -2 def biseccion(a, b, epsilon): c = (a + b) / 2.0