Aprenda a Pensar Como un Programador con Python PDF
Document Details
Uploaded by Deleted User
Allen Downey, Jeffrey Elkner, Chris Meyers
Tags
Related
Summary
Aprenda a Pensar Como un Programador con Python es un libro de texto que enseña la programación con el lenguaje Python. El libro se centra en los procesos de pensamiento involucrados y ofrece ejemplos y ejercicios para ayudar a los estudiantes a aprender. Es un excelente recurso para principiantes en programación, ideal para estudiantes universitarios.
Full Transcript
Aprenda a Pensar Como un Programador con Python Aprenda a Pensar Como un Programador con Python Allen Downey Jeffrey Elkner Chris Mey...
Aprenda a Pensar Como un Programador con Python Aprenda a Pensar Como un Programador con Python Allen Downey Jeffrey Elkner Chris Meyers Traducido por Miguel Ángel Vilella Ángel Arnal Iván Juanes Litza Amurrio Efrain Andia César Ballardini Green Tea Press Wellesley, Massachusetts c 2002 Allen Downey, Jeffrey Elkner, y Chris Meyers. Copyright ° Corregido por Shannon Turlington y Lisa Cutler. Diseño de la cubierta por Rebecca Gimenez. Green Tea Press 1 Grove St. P.O. Box 812901 Wellesley, MA 02482 Se permite copiar, distribuir, y/o modificar este documento bajo los términos de la GNU Free Documentation License, Versión 1.1 o cualquier versión posterior publicada por la Free Software Foundation; siendo las Secciones Invariantes “Prólogo”, “Prefacio”, y “Lista de Colaboradores”, sin texto de cubierta, y sin texto de contracubierta. Se incluye una copia de la licencia en el apéndice titulado “GNU Free Documentation License”. La GNU Free Documentation License está disponible en www.gnu.org o escri- biendo a la Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. La forma original de este libro es código fuente LATEX. La compilación de este fuente LATEX tiene el efecto de generar una representación independiente del dispositivo de un libro de texto, que puede convertirse a otros formatos e im- primirse. El fuente LATEX de este libro y más información sobre el proyecto de Libro de Texto de Código Abierto están disponibles en http://www.thinkpython.com La composición de este libro se realizó utilizando LATEX y LyX. Las ilustraciones se hicieron con xfig. Todos ellos son programas gratuitos de código abierto. Historia de la impresión: Abril 2002: Primera edición. ISBN 0-9716775-0-6 Prólogo Por David Beazley Como educador, investigador, y autor de libros, estoy encantado de ver la fi- nalización de este libro. Python es un lenguaje de programación divertido y extremadamente fácil de usar que en los últimos años se ha hecho muy popu- lar. Desarrollado hace diez años por Guido van Rossum, su sintaxis simple y la sensación general se deriva en gran parte del ABC, un lenguaje desarrollado en los 1980s para la enseñanza. Sin embargo, Python también se creó para resolver problemas reales y presenta una variedad amplia de caracterı́sticas de lenguajes de programación como C++, Java, Modula-3 y Scheme. Debido a esto, una de las caracterı́sticas notables de Python es su atractivo para los desarrolladores profesionales de progamación, cientı́ficos, investigadores, artistas, y educadores. A pesar del atractivo de Python para muchas comunidades diferentes, puede que aún se pregunte “¿por qué Python?” o “¿por qué enseñar programación con Python?”No es tarea fácil responder a estas preguntas, en especial cuando la opinión popular está del lado de alternativas más masoquistas como C++ y Java. Sin embargo, pienso que la respuesta más directa es que la progrmación en Python es simplemente más divertida y más productiva. Cuando imparto cursos de informática, quiero cubrir conceptos importantes, hacer el material interesante y enganchar a los estudiantes. Desgraciadamente, hay una tendencia en los cursos de introducción a la programación a prestar demasiada atención a la abstracción matemática que hace que los estudiantes se frustren con problemas farragosos relacionados con detalles nimios de la sin- taxis, compilación, y la aplicación de reglas aparentemente arcanas. Aunque tal abstración y formalismo son importantes para ingenieros profesionales de la programación y estudiantes que planean continuar sus estudios de informática, decidirse por este enfoque en un curso introductorio sólo tiene éxito en hacer aburrida la informática. Cuando imparto un curso, no quiero tener un aula de estudiantes sin inspiración. Quisiera verlos intentando resolver problemas in- teresantes, explorando ideas diferentes, probando enfoques no convencionales, vi Prólogo rompiendo las reglas, y aprendiendo de sus errores. Al hacerlo, no quiero perder la mitad del semestre tratando de sortear problemas con una sintaxis abstru- sa, mensajes de error del compilador incomprensibles, o los varios cientos de maneras que un programa puede generar un error de proteción general. Una de las razones por las que me gusta Python es por que proporciona un equi- librio muy bueno entre lo práctico y lo conceptual. Puesto que Python es un lenguaje interpretado, los principiantes pueden tomar el lenguaje y empezar a hacer cosas interesantes casi inmediato, sin perderse el los problemas de compila- ción y enlazado. Además, Python viene con una gran biblioteca de módulos que se pueden usar para hacer toda clase de tareas que abarcan desde programación para web a gráficos. Este enfoque práctico es una buena manera de enganchar a estudiantes y permite que completen proyectos significativos. Sin embargo, Pyt- hon también puede servir como una base excelente para intruducir conceptos importantes de informática. Puesto que Python soporta completamente proce- dimientos y clases, los estudiantes pueden introducirse gradualmente en temas como abstraccián procedural, estructuras de datos, y programación orientada objetos, que son aplicables a cursos posteriores en Java o C++. Python incluso toma prestada cierta cantidad de caracterı́sticas de lenguajes de programación funcionales y puede usarse para intruducir conceptos que pudieran ser cubiertos en mas detalle en cursos de Scheme o Lisp. Leendo, el prefacio de Jeffrey, me sorprenden sus comentarios sobre que Pyt- hon le permite ver un “más alto nivel de éxito y un bajo nivel de frustración 2 que puede “avanzar rápido con mejores resultados”. Aunque estos comentarios se refieren a sus cursos introductorios, a veces uso Python por estas mismas razones en cursos de informática avanzada en la Universidad de Chicago. En estos cursos me enfrento constantemente con la desalentadora tarea de cubrir un montón de material difı́cil en un agotador trimestre de nueve semanas. Aun- que es ciertamente posible para mı́ infligir mucho dolor y sufrimiento usando un lenguaje como C++, he visto a menudo que ese estilo es ineficaz, especialmente cuando el curso se trata de un asunto sin relación apenas con la “programación”. Encuentro que usar Python me permite dedicarme más al asunto en cuestión mientras permito a los estudiantes completar proyectos útiles. Aunque Python es todavı́a un lenguaje joven y en desarollo, creo que tiene un futuro brillante en la educación. Este libro es un paso importante en esa dirección. David Beazley Universidad de Chicago Autor de Python Essential Reference Prefacio Por Jeff Elkner Este libro debe su existencia a la colaboración hecha posible por la Internet y al movimiento de software libre. Sus tres autores, un profesor universitario, un profesor de instituto y un programador profesional, todavı́a tienen que conocerse cara a cara, pero hemos sido capaces de colaborar estrechamente y hemos reci- bido la ayuda de mucha gente maravillosa que han donado su tiempo y esfuerzo para ayudar a mejorar este libro. Creemos que este libro es un testamento a los beneficios y futuras posibilidades de este tipo de colaboración, cuyo marco han establecido Richard Stallman y la Free Software Foundation. Cómo y por qué vine a usar Python En 1999, el examen de Advanced Placement (AP) de Ciencias de la Computa- ción del Claustro Escolar se realizó por primera vez en C++. Como en muchos institutos en todo el paı́s, la decisión de cambiar de lenguaje tuvo un impacto directo sobre el curriculum de informática en el Insituto de Yorktown en Ar- lington, Virgina, donde doy clase. Hasta ese momento, el lenguaje de enseñanza era Pascal tanto en nuestro curso de primer año como en el AP. Al seguir con la práctica anterior de dar a los estudiantes dos años de exposición al mismo lenguaje, tomamos la decisión de cambiar a C++ en el aula de primer año del curso 1997-98 de modo que estarı́amos en sintonı́a con el cambio del Claustro Escolar para el curso AP del año siguiente. Dos años más tarde, me convencı́ de que C++ era una mala elección para iniciar a los estudiantes en la informática. Aunque es un lenguaje de programación muy poderoso, también es extremadamente difı́cil de aprender y enseñar. Me encontré luchando constantemente con la difı́cil sintaxis de C++ y sus múltiples formas de hacer las cosas, y como consecuencia perdı́a muchos estudiantes sin viii Prefacio necesidad. Convencido de que debı́a de haber una elección mejor para el lenguaje de nuestro curso de primer año, me puse a buscar una alternativa para C++. Necesitaba un lenguaje que funcionase tanto en las máquinas de nuestro labo- ratorio de Linux como en las plataformas Windows y Macintosh que la mayorı́a de los estudiantes tenı́an en casa. Querı́a que fuera de código abierto, para que los estudiantes pudieran usarlo en casa sin importar su nivel económico. Querı́a un lenguaje utilizado por programadores profesionales, y que tuviera una co- munidad activa de desarrolladores a su alrededor. Tenı́a que soportar tanto la programación procedural como la orientada a objetos. Y lo más importante, tenı́a que ser fácil de aprender y de enseñar. Cuando investigué las opciones con estos obejetivos en mente, Python destacó como el mejor candidato. Pedı́ a uno de los estudiantes más talentosos de Yorktown, Matt Ahrens, que probase Python. En dos meses, no sólo habı́a aprendido el lenguaje, sino que escribió una aplicación llamada pyTicket que permitı́a a nuestro personal infor- mar de problemas tecnológicos via Web. Sabı́a que Matt no podı́a terminar una aplicación de tal escala en tan poco tiempo con C++, y este logro, combinado con la positiva valoración de Python por parte de Matt, sugerı́a que Python era la solución que buscaba. Encontrar un libro de texto Una vez decidido a usar Python tanto en mis clases de informática básica como en el año siguiente, el problema más acuciante era la falta de un libro de texto disponible. El contenido libre vino al rescate. Anteriormente en ese año, Richard Stallman me presentó a Allen Downey. Ambos habı́amos escrito a Richard expresando nuestro interés en desarrollar conenidos educativos libres. Allen ya habı́a escrito un libro de texto de informática de primer año, How to Think Like a Com- puter Scientist. Cuando leı́ ese libro, supe inmediatamente que querı́a usarlo en mi clase. Era el libro de informática más claro y práctico que habı́a visto. Ponı́a el énfasis en los procesos de pensamiento involucrados en la programación más que en las caracterı́sticas de un lenguaje en particular. Su lectura me hizo inmediatamente un maestro mejor. How to Think Like a Computer Scientist no era sólo un libro excelente, sino que se publicó bajo la licencia pública GNU, lo que significaba que podı́a usarse y modificarse libremente para ajustarse a las necesidades de su usuario. Una vez que decidı́ usar Python, se me ocurrió que podrı́a traducir la versión original en Java del libro de Allen al nuevo lenguaje. Aunque no hubiera sido capaz de escribir un libro de texto por mi cuenta, tener el libro de Allen para trabajar a ix partir de él me hizo posible hacerlo, mostrando al mismo tiempo que el modelo cooperativo de desarrollo que tan buenos resultados habı́a dado en el software podı́a funcionar también para el contenido educativo. El trabajo en este libro durante los dos últimos años ha sido gratificante para mis estudiantes y para mı́, y mis estudiantes desempeñaron un importante papel en el proceso. Como podı́a hacer cambios instantáneos cuando alguien encontraba un error ortográfico o un pasaje difı́cil, los animé a buscar errores en el libro dándoles un punto extra cada vez que hacı́an una sugerencia que terminaba como un cambio en el texto. Esto tuvo el doble beneficio de animarlos a leer el texto con más atención y tener el texto revisado en profundidad por sus crı́ticos más importantes: los estudiantes que lo usan para aprender informática. Para la segunda mitad del libro, acerca de la programación orientada a objetos, sabı́a que necesitarı́a a alguien con más experiencia real en programación de la que yo tenı́a para hacerlo bien. El libro se estancó en un estado inacabado durante buena parte de un año hasta que la comunidad de código abierto de nuevo proporcionó los medios necesarios para su terminación. Recibı́ un correo electrónico de Chris Meyers expresando su interés en el li- bro. Chris es un programador profesional que empezó a impartir un curso de programación con Python el año pasado en el Colegio de Lane Community, en Eugene, Oregon. La perspectiva de impartir el curso llevó a Chris has- ta el libro, y empezó a colaborar con él inmediatamente. Hacia el final del año escolar habı́a creado un proyecto complementario en nuesto sitio web en http://www.ibiblio.org/obp llamado Python for Fun y estaba trabajando con algunos de mis estudiantes aventajados como profesor magistral, dirigiéndo- les más allá de donde yo podı́a llevarles. Presentando la programación con Python El proceso de traducir y usar How to Think Like a Computer Scientist duran- te los dos últimos años ha confirmado la idoneidad de Python para enseñar a estudiantes principiantes. Python simplifica enormemente los ejemplos de pro- gramación y facilita la enseñanza de los conceptos importantes en programación. x Prefacio El primer ejemplo del texto ilustra esta cuestión. Es el tradicional programa “hola, mundo”, que en la versión C++ del libro es ası́: #include void main() { cout > print 1 + 1 2 La primera lı́nea de este ejemplo es el comando que pone en marcha el intérprete Python. Las dos lı́neas siguientes son mensajes del intérprete. La tercera lı́nea comienza con >>>, que es la invitación del intérprete para indicar que está listo. Escribimos print 1 + 1 y el intérprete contestó 2. Alternativamente, se puede escribir el programa en un archivo y usar el intérpre- te para ejecutar el contenido de dicho archivo. El archivo se llama, en este ca- so, un guión. Por ejemplo, en un editor de texto se puede crear un archivo latoya.py que contenga esta lı́nea: print 1 + 1 Por acuerdo unánime, los archivos que contienen programas de Python tienen nombres que terminan con.py. Para ejecutar el programa, se le tiene que indicar el nombre del guión al intérpre- te. $ python latoya.py 2 En otros entornos de desarrollo los detalles de la ejecución de programas pueden ser diferentes. Aemás, la mayorı́a de programas son más interesantes que el mencionado. La mayorı́a de ejemplos en este libro se ejecutan desde en la lı́nea de comando. La lı́nea de comando es muy apropiada para el desarrollo de programas y para pruebas rápidas porque se pueden teclear las instrucciones de Python y se pue- den ejecutar inmediatamente. Una vez que un programa está completo, puede archivarse en un guión para ejecutarlo o modificarlo en el futuro. 1.2. ¿Qué es un programa? Un programa es una secuencia de instrucciones que especifican cómo ejecutar una computación. La computación puede ser algo matemático, como solucionar 4 El Camino del Programa un sistema de ecuaciones o determinar las raı́ces de un polinomio, pero también puede ser una computación simbólica, como buscar y reemplazar el texto de un documento o (aunque parezca raro) compilar un programa. Las instrucciones (comandos, órdenes) tienen una apariencia diferente en len- guajes de programación diferentes, pero existen algunas funciones básicas que se presentan en casi todo lenguaje: entrada: Recibir datos del teclado, o un archivo u otro aparato. salida: Mostrar datos en el monitor o enviar datos a un archivo u otro aparato. matemáticas: Ejecutar operaciones básicas de matemáticas como la adición y la multiplicación. operación condicional: Probar la veracidad de alguna condición y ejecutar una secuencia de instrucciones apropiada. repetición: Ejecutar alguna acción repetidas veces, normalmente con alguna variación. Lo crea o no, eso es todo. Todos los programas que existen, por complicados que sean, están formulados exclusivamente con tales instrucciones. Ası́, una manera de describir la programación es: El proceso de romper una tarea en tareas cada vez más pequeñas hasta que estas tareas sean suficientemente simples para ser ejecutadas con una de estas instrucciones simples. Quizás esta descripción sea un poco ambigua. No se preocupe. Lo explicaremos con más detalle con el tema de los algoritmos. 1.3. ¿Qué es la depuración (debugging)? La programación es un proceso complejo y, por ser realizado por humanos, a menudo desemboca en errores. Por razones caprichosas, esos errores se llaman bugs y el proceso de buscarlos y corregirlos se llama depuración (en inglés “debugging”). Hay tres tipos de errores que pueden ocurrir en un programa, de sintaxis, en tiempo de ejecución y semánticos. Es muy útil distinguirlos para encontrarlos mas rápido. 1.3 ¿Qué es la depuración (debugging)? 5 1.3.1. Errores sintácticos Python sólo puede ejecutar un programa si el programa es correcto sintáctica- mente. En caso contrario, es decir si el programa no es correcto sintácticamente, el proceso falla y devuelve un mensaje de error. El término sintaxis se refiere a la estructura de cualquier programa y a las reglas de esa estructura. Por ejem- plo, en español la primera letra de toda oración debe ser mayúscula, y todas las oraciones deben terminar con un punto. esta oración tiene un error sintáctico. Esta oración también Para la mayorı́a de lectores, unos pocos errores sintácticos no son significatvos, y por eso pueden leer la poesı́a de e. e. cummings sin anunciar errores de sin- taxis. Python no es tan permisivo. Si hay aunque sea un solo error sintáctico en el programa, Python mostrará un mensaje de error y abortará la ejecución del programa. Durante las primeras semanas de su carrera como programador pasará, seguramente, mucho tiempo buscando errores sintácticos. Sin embargo, tal como adquiera experiencia tendrá menos errores y los encontrará mas rápido. 1.3.2. Errores en tiempo de ejecución El segundo tipo de error es un error en tiempo de ejecución. Este error no aparece hasta que se ejecuta el programa. Estos errores también se llaman excepciones porque indican que algo excepcional (y malo) ha ocurrido. Con los programas que vamos a escribir al principio, los errores en tiempo de ejecución ocurrirán con poca frecuencia, ası́ que puede pasar bastante tiempo hasta que vea uno. 1.3.3. Errores semánticos El tercer tipo de error es el error semántico. Si hay un error de lógica en su programa, el programa se ejecutará sin ningún mensaje de error, pero el resul- tado no será el deseado. Será cualquier otra cosa. Concretamente, el programa hará lo que usted le dijo. A veces ocurre que el programa escrito no es el programa que se tenı́a en mente. El sentido o significado del programa (su semántica) no es correcto. Es difı́cil ha- llar errores de lógica, porque requiere trabajar al revés, observando el resultado del programa para averiguar lo que hace. 6 El Camino del Programa 1.3.4. Depuración experimental Una de las técnicas más importantes que usted aprenderá es la depuración. Aun- que a veces es frustrante, la depuración es una de las partes más intelectualmente ricas, interesantes y estimulantes de la programación. La depuración es una actividad parecida a la tarea de un investigador: se tie- nen que estudiar las claves para inducir los procesos y eventos llevaron a los resultados que tiene a la vista. La depuración también es una ciencia experimental. Una vez que se tiene la idea de cuál es el error, se modifica el programa y se intenta nuevamente. Si su hipótesis fue la correcta se pueden predecir los resultados de la modificación y estará más cerca de un programa correcto. Si su hipótesis fue errónea tendrá que idearse otra hipótesis. Como dijo Sherlock Holmes, “Cuando se ha descartado lo imposible, lo que queda, no importa cuan inverosı́mil, debe ser la verdad.” (A. Conan Doyle, The Sign of Four) Para algunas personas, la programación y la depuración son lo mismo: la pro- gramación es el proceso de depurar un programa gradualmente hasta que haga lo que usted quiera. La idea es que deberı́a usted comenzar con un programa que haga algo y hacer pequeñas modificaciones, depurándolas sobre la marcha, de modo que siempre tenga un programa que funcione. Por ejemplo, Linux es un sistema operativo que contiee miles de lı́neas de código, pero Linus Torvalds lo comenzó como un programa para explorar el microproce- sador Intel 80836. Según Larry Greenfield, “Uno de los proyectos tempranos de Linus fue un programa que alternaba la impresión de AAAA con BBBB. Este programa evolucionó en Linux” (de The Linux Users’Guide Versión Beta 1). Otros capı́tulos tratarán más acerca del tema de depuración y otras técnicas de programación. 1.4. Lenguajes formales y lenguajes naturales Los lenguajes naturales son los lenguajes hablados por seres humanos, como el español, el inglés y el francés. No los han diseñados personas (aunque se intente poner cierto orden en ellos), sino que se han desarrollado naturalmente. Los lenguajes formales son lenguajes diseñados por humanos y que tienen aplicaciones especı́ficas. La notación matemática, por ejemplo, es un lenguaje formal ya que se presta a la representación de las relaciones entre números y sı́mbolos. Los quı́micos utilizan un lenguaje formal para representar la estructura quı́mica de las moléculas. Y lo más importante: 1.4 Lenguajes formales y lenguajes naturales 7 Los lenguajes de programación son lenguajes formales de- sarrollados para expresar computaciones. Los lenguajes formales casi siempre tienen reglas sintácticas estrictas. Por ejem- plo, 3 + 3 = 6 es una expresión matemática correcta, pero 3 = +6$ no lo es. De la misma manera, H2 0 es una nomenclatura quı́mica correcta, pero 2 Zz no lo es. Existen dos clases de reglas sintácticas, en cuanto a unidades y estructura. Las unidades son los elementos básicos de un lenguaje, como lo son las palabras, los números y los elementos quı́micos. Por ejemplo, en 3=+6$, $ no es una unidad matemática aceptada (al menos hasta donde nosotros sabemos. Similarmente, 2 Xx no es formal porque no hay ningún elemento con la abreviatura Zz. La segunda clase de regla sintáctica está relacionada con la estructura de un elemento; o sea, el orden de las unidades. La estructura de la sentencia 3=+6$ no se acepta porque no se puede escribir el sı́mbolo de igualdad seguido de un sı́mbolo positivo. Similarmente, las fórmulas moleculares tienen que mostrar el número de subı́ndice después del elemento, no antes. A manera de práctica, trate de producir una oración con estructura aceptada pero que esté compuesta de unidades irreconocibles. Luego escriba otra oración con unidades aceptables pero con estructura no válida. Al leer una oración, sea en un lenguaje natural o una sentencia en un lenguaje técnico, se debe discernir la estructura de la oración. En un lenguaje natural este proceso, llamado análisis sintáctico ocurre subconscientemente. Por ejemplo cuando usted escucha la oración “El otro zapato cayó”, entiende que “el otro zapato” es el sujeto y “cayó” es el verbo. Cuando se ha analizado la oración sintácticamente, se puede deducir el significado, o la semántica, de la oración. Suponiendo que sepa lo ques es un zapato y lo que es caer, entenderá el significado de la oración. Aunque existen muchas cosas en común entre los lenguajes naturales y los lenguajes formales—por ejemplo las unidades, la estructura, la sintaxis y la semántica—también existen muchas diferencias: ambigüedad: Los lenguajes naturales tienen muchı́simas ambigüedades, que los hablantes sortean usando claves contextuales y otra información. Los lenguajes formales se diseñan para estar completamente libres de am- bigüedades o tanto como sea posible, lo que quiere decir que cualquier sentencia tiene sólo un significado, sin importar el contexto. 8 El Camino del Programa redundancia: Para reducir la ambigüedad y los malentendidos, las lenguas na- turales utilizan bastante redundancia. Como resultado suelen ser prolijos. Los lenguajes formales son menos redundantes y más concisos. literalidad: Los lenguajes naturales tienen muchas metáforas y frases hechas. El significado de un dicho, por ejemplo “Estirar la pata”, es diferente al significado de sus sustantivos y verbos. En este ejemplo, la oración no tiene nada que ver con un pie y significa ’morirse’. Los lenguajes formales no difieren de su significado literal. Los que aprenden a hablar un lenguaje natural—es decir, todo el mundo— muchas veces tienen dificultad en adaptarse a los lenguajes formales. A veces la diferencia entre los lenguajes formales y los naturales es comparable a la diferencia entre la prosa y la poesı́a: Poesı́a: Se utiliza una palabra por su cualidad auditiva tanto como por su signi- ficado. El poema, en su totalidad, produce un efecto o reacción emocional. La ambigüedad no es solo común sino utilizada a propósito. Prosa: El significado literal de la palabra es mas importante y la estructura da más significado aún. La prosa se presta al análisis más que la poesı́a, pero todavı́a contiene ambigüedad. Programas: El significado de un programa es inequı́voco y literal, y es enten- dido en su totalidad analizando las unidades y la estructura. He aquı́ unas sugerencias para la lectura de un programa (y de otros lenguajes formales). Primero, recuerde que los lenguajes formales son mucho más densos que los lenguajes naturales, y por consecuente lleva más tiempo leerlos. Tam- bién, la estructura es muy importante, ası́ que entonces no es una buena idea leerlo de pies a cabeza, de izquierda a derecha. En vez de eso, aprenda a sepa- rar las diferentes partes en su mente, identificar las unidades e interpretar la estructura. Finalmente, ponga atención a los detalles. Los fallos de puntuación y la ortografı́a, que puede obviar en el lenguaje natural, pueden suponer una gran diferencia en un lenguaje formal. 1.5. El primer programa Tradicionalmente el primer programa en un lenguaje nuevo se llama “Hola, mundo” (Hello world!) porque sólo muestra las palabras “Hola a todo el mundo”. En Python es ası́: print "Hola, mundo" 1.6 Glosario 9 Este es un ejemplo de una sentencia print, la cual no imprime nada en papel, más bien muestra un valor. En este caso, el resultado es las palabras Hola, mundo Las comillas señalan el comienzo y el final del valor; no aparecen en el resultado. Alguna gente evalúa la calidad de un lenguaje de programación por la simplici- dad del programa “Hola, mundo”. Si seguimos ese criterio, Python cumple con todas sus metas. 1.6. Glosario solución de problemas: El proceso de formular un problema, hallar la solu- ción y expresar esa solución. lenguaje de alto nivel: Un lenguaje como Python diseñado para ser fácil de leer y escribir para la gente. lenguaje de bajo nivel: Un lenguaje de programación diseñado para ser fácil de ejecutar para un computador; también se lo llama “lenguaje de máqui- na” o “lenguaje ensamblador”. portabilidad: La cualidad de un programa que le permite ser ejecutado en más de un tipo de computador. interpretar: Ejecutar un programa escrito en un lenguaje de alto nivel tradu- ciéndolo lı́nea por lı́nea compilar: Traducir un programa escrito en un lenguaje de alto nivel a un len- guaje de bajo nivel todo al mismo tiempo, en preparación para la ejecución posterior. código fuente: Un programa escrito en un lenguaje de alto nivel antes de ser compilado. código de objeto: La salida del compilador una vez que ha traducido el pro- grama. programa ejecutable: Otro nombre para el código de objeto que está listo para ejecutarse. guión: Un programa archivado (que va a ser interpretado). programa: Un conjunto de instrucciones que especifica una computación. algoritmo: Un proceso general para resolver una clase completa de problemas. 10 El Camino del Programa error (bug): Un error en un programa. depuración: El proceso de hallazgo y eliminación de los tres tipos de errores de programación. sintaxis: La estructura de un programa. error sintáctico: Un error en un programa que hace que el programa sea im- posible de analizar sintácticamente (e imposible de interpretar). error en tiempo de ejecución: Un error que no ocurre hasta que el progra- ma ha comenzado a ejecutarse e impide que el programa continúe. excepción: Otro nombre para un error en tiempo de ejecución. error semántico: Un error en un programa que hace que ejecute algo que no era lo deseado. semántica: El significado de un programa. language natural: Cualquier lenguaje hablado que evolucionó de forma natu- ral. lenguaje formal: Cualquier lenguaje diseñado por humanos que tiene un propósito especı́fico, como la representación de ideas matemáticas o pro- gramas de computadores; todos los lenguajes de programación son lengua- jes formales. unidad: Uno de los elementos básicos de la estructura sintáctica de un progra- ma, análogo a una palabra en un lenguaje natural. análisis sintáctico: La examinación de un programa y el análisis de su estruc- tura sintáctica. sentencia print: Una instrucción que causa que el intérprete Python muestre un valor en el monitor. Capı́tulo 2 Variables, expresiones y sentencias 2.1. Valores y tipos El valor es uno de los elementos fundamentales (como por ejemplo una letra o un número) que manipula un programa. Los valores que hemos visto hasta el momento son 2 (el resultado de sumar 1 + 1) y Hola, mundo. Estos valores son de distintos tipos: 2 es un entero y Hola, mundo es una cadena, llamada ası́ porque contiene una “cadena” de letras. Usted (y el intérprete) puede identificar las cadenas porque están encerradas entre comi- llas. La sentencia print también funciona con enteros: >>> print 4 4 Si no está seguro del tipo que tiene un determinado valor, puede preguntárselo al intérprete de Python. >>> type("Hola, mundo") >>> type(17) No es sorprendente que las cadenas sean de tipo string (cadena en inglés) y los enteros sean de tipo int (por integer en inglés). De forma menos obvia, los 12 Variables, expresiones y sentencias números con decimales (separados por medio de un punto en inglés) son de tipo float debido a la representación de estos números en el formato llamado de coma flotante (floating-point). >>> type(3.2) ¿Qué ocurre con los valores como "17" y "3.2"? Parecen números, pero están entre comillas como las cadenas. >>> type("17") >>> type("3.2") Son cadenas. Cuando escriba un entero largo, podrı́a estar tentado de usar comas entre grupos de tres dı́gitos, como en 1,000,000. Éste no es un entero legal en Python, pero es una expresión legal: >>> print 1,000,000 1 0 0 En fin, no era eso lo que querı́amos. Python interpreta 1,000,000 como una lista de tres números que debe imprimir. Ası́ que recuerde no insertar comas en sus enteros. 1 2.2. Variables Una de las caracterı́sticas más potentes de los lenguajes de programación es la capacidad de manipular variables. Una variable es un nombre que hace referencia a un valor. La sentencia de asignación crea nuevas variables y les asigna un valor: >>> mensaje = "Que onda?" >>> n = 17 >>> pi = 3.14159 Este ejemplo muestra tres asignaciones. La primera de ellas asigna el valor "Que onda?" a una variable nueva, de nombre mensaje. La segunda le da el 1 Eluso de la coma y el punto en número es en inglés el contrario al uso español, como se apuntó en una nota anterior 2.3 Nombres de variables y palabras reservadas 13 valor entero 17 a n, y la tercera le da el valor de número en coma flotante 3.14159 a pi. Una forma habitual de representar variables sobre el papel es escribir el nombre con una flecha señalando al valor de la variable. Este tipo de representación se llama diagrama de estado, ya que muestra en qué estado se halla cada una de las variables (considérelo como el “estado de ánimo” de la variable”). El siguiente diagrama muestra el efecto de las tres sentencias de asignación anteriores: mensaje "Que onda?" n 17 pi 3.14159 La sentencia print también funciona con variables. >>> print mensaje "Que onda?" >>> print n 17 >>> print pi 3.14159 En cada caso, el resultado es el valor de la variable. Las variables también tienen tipo. De nuevo, podemos preguntar al intérprete lo que son. >>> type(mensaje) >>> type(n) >>> type(pi) El tipo de una variable es el tipo del valor al que se refiere. 2.3. Nombres de variables y palabras reservadas Como norma general, los programadores eligen nombres significativos para sus variables: esto permite documentar para qué se usa la variable. Los nombres de las variables pueden tener una longitud arbitraria. Pueden estar formados por letras y números, pero deben comenzar con una letra. Aunque es 14 Variables, expresiones y sentencias aceptable usar mayúsculas, por convención no lo hacemos. Si lo hace, recuerde que la distinción es importante: Bruno y bruno son dos variables diferentes. El guión bajo ( ) también es legal y se utiliza a menudo para separar nombres con múltiples palabras, como mi nombre o precio del cafe colombiano. Si intenta darle a una variable un nombre ilegal, obtendrá un error de sintaxis. >>> 76trombones = "gran desfile" SyntaxError: invalid syntax >>> mas$ = 1000000 SyntaxError: invalid syntax >>> class = "Curso de Programación 101" SyntaxError: invalid syntax 76trombones es ilegal porque no comienza por una letra. mas$ es ilegal porque contiene un carácter ilegal, el signo del dólar. Pero ¿qué tiene de malo class? Resulta que class es una de las palabras reservadas de Python. El lenguaje usa las palabras reservadas para definir sus reglas y estructura, y no pueden usarse como nombres de variables. Python tiene 28 palabras reservadas: and continue else for import not raise assert def except from in or return break del exec global is pass try class elif finally if lambda print while Tal vez quiera mantener esta lista a mano. Si el intérprete se queja de alguno de sus nombres de variable, y usted no sabe por qué, compruebe si está en esta lista. 2.4. Sentencias Una sentencia es una instrucción que puede ejecutar el intérprete de Python. Hemos visto dos tipos de sentencias: print y la asignación. Cuando usted escribe una sentencia en la lı́nea de comandos, Python la ejecuta y muestra el resultado, si lo hay. El resultado de una sentencia print es un valor. Las sentencias de asignación no entregan ningún resultado. Normalmente un guión contiene una secuencia de sentencias. Si hay más de una sentencia, los resultados aparecen de uno en uno tal como se van ejecutando las sentencias. 2.5 Evaluar expresiones 15 Por ejemplo, el guión print 1 x = 2 print x prsenta la salida 1 2 De nuevo, la sentencia de asignación no produce ninguna salida. 2.5. Evaluar expresiones Una expresión es una combinación de valroes, variables y operadores. Si teclea una expresión en la lı́nea de comandos, el intérprete la evalúa y muestra el resultado: >>> 1 + 1 2 Un valor, y también una variable, se considera una expresión por sı́ mismo. >>> 17 17 >>> x 2 Para complicar las cosas, evaluar una expresión no es del todo lo mismo que imprimir un valor. >>> mensaje = "Que onda?" >>> mensaje "Que onda?" >>> print mensaje Que onda? Cuando Python muestra el valor de una expresión, usa el mismo formato que usted usarı́a para introducir un valor. En el caso de las cadenas, eso significa que incluye las comillas. Pero la sentencia print imprime el valor de la expresión, lo que en este caso es el contenido de la cadena. En un guión, una expresión sin más es una sentencia válida, pero no hace nada. El guión 16 Variables, expresiones y sentencias 17 3.2 "Hola, mundo" 1 + 1 no presenta ninguna salida. ¿Cómo cambiarı́a usted el guión para mostrar los valores de estas cuatro expresiones? 2.6. Operadores y expresiones Los operadores son sı́mbolos especiales que representan cálculos simples, como la suma y la multiplicación. Los valores que usa el operador se llaman operan- dos. Las siguientes expresione son legales en Python y su significado es más o menos claro: 20+32 hora-1 hora*60+minuto minuto/60 5**2 (5+9)*(15-7) Los sı́mbolos +, -, /, y el uso de los paréntesis para el agrupamiento, se usan todos de la misma forma que en matemáticas. El asterisco (*) es el signo de multiplicación y ** el sı́mbolo para exponenciación. Cuando aparece el nombre de una variable en el lugar de un operando, se sus- tituye con su valor antes de realizar la operación. La suma, resta, multiplicación y exponenciación hacen lo esperado, pero la divi- sión le puede sorprender. La operación que sigue tiene un resultado inesperado: >>> minuto = 59 >>> minuto/60 0 El valor de la variable minuto es 59, y 59 dividido entre 60 es 0.98333 y no 0. El motivo de la discrepancia reside en que Python está llevando a cabo una división de enteros. Cuando ambos operandos son enteros, el resultado ha de ser también un entero; por convención, la división de enterios simpre se redondea a la baja, incluso en casos como estos en los que el siguiente entero está muy próximo. Una alternativa posible en este caso es el cálculo de un porcentaje y no el de una fracción: >>> minuto*100/60 98 2.7 El orden de las operaciones 17 De nuevo se redondea el resultado a la baja, pero al menos ahora la respuesta es aproximadamente correcta. Otra alternativa es la división de coma flotante, que veremos en el Capı́tulo 3. 2.7. El orden de las operaciones Cuando aparece más de un operador en una expresión, el orden de evaluación depende de las reglas de precedencia. Python sigue las mismas reglas de precedencia que los propios matemáticos para sus operaciones matemáticas. Los ingleses usan el acrónimo PEMDAS como regla parea recordar el orden de las operaciones: Paréntesis: tienen la precedencia más alta y pueden usarse para forzar que una expresión se evalúe en el orden que queramos nosotros. Puesto que las expresiones entre paréntesis se evalúan primero, 2 * (3-1) es igual a 4, y (1+1)**(5-2) es igual a 8. También puede usar paréntesis para que una expresión sea más legible; por ejemplo (minuto * 100) / 60, aunque el resultado no cambie de todas formas. Exponenciación tiene la siguiente precedencia más alta; ası́ pues 2**1+1 es igual a 3 y no a 4, y 3*1**3 es igual a 3 y no a 27. La Multiplicación y la División tienen la misma precedencia, que es más alta que la de la Adición y la Sustracción, que tienen también la misma precedencia. Por tanto 2*3-1 devuelve 5 y no 4, y 2/3-1 da -1, y no 1 (recuerde que en la división de enteros 2/3 da 0). Los operadores que tienen la misma precedencia se evalúan de izquierda a derecha. Ası́, en la expresión minuto*100/60, tiene lugar primero la multiplicación, devolviendo tt 5900/60, que a su vez da como resultado 98. Si las operaciones se hubiesen realizado de derecha a izquierda, el resultado habrı́a sido 59/1 que da 59, y que es incorrecto. 2.8. Las operaciones sobre cadenas En general no es posible realizar operaciones matemáticas con cadenas, incluso si las cadenas parecen números. Las siguientes sentencias son ilegales (suponiendo que mensaje sea de tipo string) mensaje-1 "Hola"/123 mensaje*"Hola" "15"+2 18 Variables, expresiones y sentencias Es curioso que el operador + funcione con cadenas, aunque no haga exactamente lo que usted esperarı́a. Para cadenas, el operador + representa la concatena- ción, lo que significa que se unen los dos operandos uniéndolos extremo con extremo. Por ejemplo: fruta = "plátano" bizcochoBueno = " pan de leche" print fruta + bizcochoBueno La salida del programa es plátano pan de leche. El espacio delante de pan es parte de la cadena, y es necesario para introducir el espacio que separa las cadenas concatenadas. El operador * también funciona con cadenas; lleva a cabo la repetición. Por ejemplo ’Chiste’*3 es ’ChisteChisteChiste’. Uno de los operandos ha de ser una cadena, el otro ha de ser un entero. Por un lado, esta interpretación de + y * cobra sentido por analogı́a con la suma y la multimplicación. Igual que 4*3 es equivalente a 4+4+4, esperamos que ’Chiste’*3 sea lo mismo que ’Chiste’+’Chiste’+’Chiste’, y ası́ es. Por otro lado, la concatenación y la repetición son de alguna manera muy diferentes de la adición y la multiplicación de enteros. ¿Puede encontrar una propiedad que tienen la suma y la multiplicación de enteros y que no tengan la concatenación y la repetición de cadenas? 2.9. Composición Hasta ahora hemos examinado los elementos de un programa (variables, expre- siones y sentencias) por separado, sin hablar de cómo combinarlos. Una de las caracterı́sticas más útiles de los lenguajes de programación es su capacidad de tomar pequeños bloques de construcción y ensamblarlos. Por ejemplo, sabemos cómo sumar números y cómo imprimirlos; resulta que pode- mos hacer las dos cosas a un tiempo: >>> print 17 + 3 20 En realidad, no debemos decir “al mismo tiempo”, puesto que en realidad la suma tiene que realizarse antes de la impresión, pero la cuestión es que cualquier expresión relacionada con números, cadenas y variables puede usarse dentro de una sentencia print. Ya hemos visto un ejemplo de ello: print "Número de minutos desde la medianoche: ", hora*60+minuto 2.10 Los comentarios 19 Y también puede poner expresiones arbitrarias en la parte derecha de una sen- tencia de asignación: porcentaje = (minuto * 100) / 60 Esta capacidad puede no resultar muy sorprendente, pero ya veremos otros ejemplos donde la composición hace posible expresar cálculos complejos con limpieza y brevedad. ATENCIÓN: Hay lı́mites al lugar donde pueden usarse ciertas expresiones. Por ejemplo, la parte izquierda de una sentencia de asignación tiene que ser un nombre de variable, no una exrpresión. Por tanto es ilegal lo siguiente: minute+1 = hour. 2.10. Los comentarios Conforme los programas van creciendo de tamaño y complicándose, se vuelven más complicados de leer. Los lenguajes formales son densos y con frecuencia es difı́cil observar un trozo de código y averiguar lo que hace, o por qué lo hace. Por ello es una buena idea añadir notas a su programa que expliquen, en un lenguaje natural, qué hace el programa. Estas notas se llaman comentarios y se marcan con el sı́mbolo #: # calcula el porcentaje de la hora que ha pasado ya porcentaje = (minuto * 100) / 60 En este caso, el comentario aparece en una lı́nea propia. También puede poner comentarios al final de otras lı́neas: porcentaje = (minuto * 100) / 60 # ojo: división de enteros Todo lo que va del # al final de la lı́nea se ignora (no tiene efecto sobre el programa). El mensaje está destinado al programador, o a futuros programa- dores que podrı́an tener que usar el código. En este caso avisa al lector sobre el sorprendente comportamiento de la división de enteros. 2.11. Glosario valor: un número o cadena (o cualquier otra cosa que se especifique poste- riormente) que puede almacenarse en una variable o calcularse en una expresión. 20 Variables, expresiones y sentencias tipo: un conjunto de valores. El tipo de un valor determina cómo puede usarse en las expresiones. Hasta ahora, los tipos que hemos visto son enteros (tipo int), números de coma flotante (tipo float) y cadenas (tipo string). coma flotante: un formato para representar números con decimales. variable: nombre que hace referencia a un valor. sentencia: es una porción de código que representa una orden o acción. Hasta ahora, las sentencias que hemos vistos son las asignaciones y las sentencias print. asignación: sentencia que asigna un valor a una variable. diagrama de estado: representación gráfica de un conjunto de variables y de los valores a los que se refiere. palabra reservada: es una palabra clave que usa el compilador para analizar sintácticamente los programas. No pueden usarse palabras reservadas, por ejemplo if, def y while como nombres de variables. operador: un sı́mbolo especial que representa un cálculo sencillo, como la su- ma, la multiplicación o la concatenación de cadenas. operando: uno de los valores sobre los que actúa un operador. expresión: una combinación de variables, operadores y valores. Dicha combi- nación representa un único valor como resultado. evaluar: simplificar una expresión ejecutando las operaciones para entregar un valor único. división de enteros: es una operación que divide un entero entre otro y de- vuelve un entero. La división de enteros devuelve sólo el número entero de veces que el numerador es divisible por en denominador, y descarta el resto. reglas de precedencia: la serie de reglas que especifican el orden en el que las expresiones con mútiples operadores han de evaluarse. concatenar: unir dos operandos extremo con extremo. composición: la capacidad de combinar expresiones sencillas y sentencias has- ta crear sentencias y expresiones compuestas, con el fin de representar cálculos complejos de forma concisa. comentario: un segmento de información en un programa, destinado a otros programadores (o cualquiera que lea el código fuente) y que no tiene efecto sobre la ejecución del programa. Capı́tulo 3 Funciones 3.1. Llamadas a funciones Ya hemos visto un ejemplo de una llamada a una función: >>> type("32") El nombre de la función es type, y muestra el tipo de un valor o de una variable. El valor o variable, llamado el argumento de la función, ha de estar encerrado entre paréntesis. Es habitual decir que una función “toma” un argumento y “devuelve” un resultado. El resultado se llama valor de retorno. En lugar de imprimir el valor de retorno, podemos asignárselo a una variable. >>> nereida = type("32") >>> print nereida Otro ejemplo más: la función id toma como argumento un valor o una variable y devuelve un entero que actúa como identificador único de ese valor. >>> id(3) 134882108 >>> yanira = 3 >>> id(yanira) 134882108 Cada valor tiene un id, que es un valor único relacionado con dónde se almacena en la memoria del computador. El id de una variable es el id del valor al que hace referencia. 22 Funciones 3.2. Conversión de tipos Python proporciona una colección de funciones internas que convierten valores de un tipo a otro. La función int toma un valor y lo convierte a un entero, si es posible, o da un error si no es posible. >>> int("32") 32 >>> int("Hola") ValueError: invalid literal for int(): Hola int también convierte valores de coma flotante a enteros, pero recuerde que siempre redondea hacia abajo: >>> int(3.99999) 3 La función float que convierte enteros y cadenas en números en coma flotante: >>> float(32) 32.0 >>> float("3.14159") 3.14159 Finalmente, está la función str, que convierte a tipo string: >>> str(32) ’32’ >>> str(3.14149) ’3.14149’ Pudiera parecer extraño que Python distinga entre el valor entero 1 y el valor de coma flotante 1.0. Tal vez representen el mismo número, pero pertenecen a tipos distintos. El motivo es que se representan de forma distinta dentro del computador. 3.3. Coerción de tipos Ahora que ya sabemos convertir entre tipos, tenemos otra forma de enfrentarnos a la división de enteros. Volviendo al ejemplo del capı́tulo anterior, suponga que queremos calcular qué fracción de una hora habı́a transcurrido. La expresión más obvia, minuto / 60, realiza una división de enteros, por lo que el resultado es siempre 0, incluso 59 minutos después de la hora. Una alternativa es convetir minuto a tipo float (coma flotante) y luego efectuar una división de coma flotante: 3.4 Funciones matemáticas 23 >>> minuto = 59 >>> float(minuto) / 60.0 0.983333333333 O bien podemos sacar provecho de las reglas de la conversión automática de tipos, llamada coerción de tipos. Para los operadores matemáticos, si uno de los operandos matemáticos es tipo float, el otro se convierte automáticamente en float. >>> minuto = 59 >>> minuto / 60.0 0.983333333333 Al usar un denomidador que es float, obligamos a Python a hacer división de coma flotante. 3.4. Funciones matemáticas Es posible que ya haya visto usted en matemáticas funciones como sin (seno) y log, y que haya aprendido a evaluar expresiones como sin(pi/2) y log(1/x). Primero evalúa la expresión entre paréntesis, (el argumento). Por ejemplo, pi/2 es aproximadamente 1.571, y 1/x es 0.1 (si x es igual a 10.0). Luego evalúa la función en sı́ misma, bien mirándola en una tabla, bien llevando a cabo diversos cálculos. El sin (seno) de 1.571 es 1, y el log de 0.1 es -1 (suponiendo que log indique el logaritmo de base 10). Este proceso puede aplicarse repetidamente para evaluar expresiones más com- plicadas como log(1/sin(pi/2)). Primero evaluamos el argumento de la fun- ción más interna, luego se evalúa la función, y ası́ sucesivamente. Python dispone de un módulo matemático que proporciona la mayorı́a de las funciones matemáticas habituales. Un módulo es un archivo que contiene una colección de funciones agrupadas juntas. Antes de poder usar las funciones de un módulo, tenemos que importarlo: >>>import math Para llamar a una de las funciones, tenemos que especificar el nombre del módulo y el nombre de la función, separados por un punto. A esto se le llama notación de punto: decibelio = math.log10 (17.0) angulo = 1.5 altura = math.sin(angulo) 24 Funciones La primera sentencia da a decibelio el valor del logaritmo de 17, en base 10. Hay también una función llamada log que toma logaritmos en base e. La tercera sentencia halla el seno del valor de la variable angulo. sin y las otras funciones trigonométricas (cos, tan, etc.) toman sus argumentos en radianes. Para convertir de grados a radianes, puede dividir por 360 y multiplicar por 2*pi. Por ejemplo, para hallar el seno de 45 grados, calcule primero el ángulo en radianes y luego halle el seno: grados = 45 angulo = grados * 2 * math.pi / 360.0 math.sin(angulo) La constante pi también es parte del módulo math. Si se sabe la geometrı́a, puede verificar el resultado comparándolo con el de la raı́z cuadrada de 2, dividida entre 2. >>> math.sqrt(2) / 2.0 0.707106781187 3.5. Composición Igual que con las funciones matemáticas, las funciones de Python se pueden componer; eso quiere decir que se usa una expresión como parte de otra. Por ejemplo, puede usar cualquier expresión como argumento de una función: x = math.cos(angulo + pi/2) Esta sentencia toma el valor de pi, lo divide entre dos y le añade el resultado al valor de angulo. La suma se pasa luego como argumento a la función cos. También puede tomar el resultado de una función y pasárselo como argumento a otra: x = math.exp(math.log(10.0)) Esta sentencia encuentra el logaritmo en base e de 10 y luego eleva e a ese exponente. El resultado queda asignado a x. 3.6. Añadir funciones nuevas Hasta ahora sólo hemos usado las funciones que vienen incluidas con Python, pero también es posible añadir nuevas funciones. La creación de nuevas funciones para resolver sus problemas partigulares es una de las cosas más útiles de los lenguajes de programación de propósito general. 3.6 Añadir funciones nuevas 25 En contextos de programación, función es una secuencia de instrucciones con nombre, que lleva a cabo la operación deseada. Esta operación se especifica en una definición de función. Las funciones que hemos usado hsta ahora las han definido por nosotros, y esas definiciones están ocultas. Eso es bueno, ya que nos permite usar funciones sin preocuparnos sobre los detalles de sus definiciones. La sintaxis de la definición de una función es: def NOMBRE( LISTA DE PARAMETROS ): SENTENCIAS Puede inventarse el nombre que desee para su función, con la excepción de que no puede usar las palabras reservadas de Python. La lista de parámetros especifica qué información, en caso de haberla, ha de proporcionar para usar la función nueva. Puede haber cualquier número de sentencias dentro de la función, pero tienen que estar indentadas desde el margen izquierdo. En los ejemplos de este libro se usará una indentación de dos espacios. El primer par de funciones que escribiremos no tienen parámetros, de manera que su sintaxis es: def nueva_linea(): print Esta función se llama nueva linea. Los paréntesis vacı́os indican que no tiene parámetros. Contiene una única sentencia, que muestra como salida un carácter de nueva lı́nea (es lo que sucede cuando utiliza una orden print sin argumentos). Llamamos entonces a la función nueva usando la misma sintaxis que usamos para las funciones internas: print "Primera linea." nueva_linea() print "Segunda linea." The output of this program is Primera linea. Segunda linea. Observe el espacio añadido que hay entre las dos lı́neas. Si quisiéramos más espacios, entre las lı́neas, ¿qué harı́amos? Podemos llamar varias veces a la misma función: print "Primera linea." nueva_linea() nueva_linea() nueva_linea() print "Segunda linea." 26 Funciones O bien podemos escribir una nueva función que llamaremos tresLineas, y que imprima tres nuevas lı́neas: def tresLineas(): nueva_linea() nueva_linea() nueva_linea() print "Primera Linea." tresLineas() print "Segunda Linea." Esta función contiene tres sentencias, las cuales están todas indentadas con dos espacios. Puesto que la siguiente sentencia no está indentada, Python sabe que no es parte de la función. Observe los siguientes puntos con respecto a este programa: 1. Se puede llamar al mismo procedimiento repetidamente. De hecho es bas- tante útil hacerlo, además de habitual. 2. Se puede llamar a una función desde dentro de otra función: en este caso tresLineas llama a nueva linea. Hasta ahora puede no haber quedar claro por qué vale la pena crear todas estas funciones nuevas. En realidad hay muchı́simas razones, pero este ejemplo demuestra dos: Crear una nueva función le da la oportunidad de dar un nombre a un grupo de sentencias. Las funciones simplifican su programa al ocultar cálculos complejos detrás de órdenes sencillas, y usar palabras de su propia lengua en vez de código arcano. Crear una nueva función hace que el programa sea más pequeño, al elimi- nar código repetitivo. Por ejemplo, una manera de imprimir nueve lı́neas consecutivas es llamar a tresLineas tres veces. Como actividad, escriba una función llamada nueveLineas que use tresLineas para imprimir nueve lı́neas en blanco. ¿Cómo impri- mirı́a 27 lı́neas nuevas? 3.7. Las definiciones y el uso Juntando los fragmentos de código de la sección anterior, el programa completo queda de la siguiente manera: 3.8 Flujo de ejecución 27 def nueva_linea(): print def tresLineas(): nueva_linea() nueva_linea() nueva_linea() print "Primera Linea." tresLineas() print "Segunda Linea." El presente programa contiene dos definiciones de funciones: nueva linea y tresLineas. Las definiciones de funciones se ejecutan como el resto de senten- cias, pero el efecto es crear una nueva función. Las sentencias del interior de la función no se ejecutan hasta que se llama a la función, y la definición de la función no genera salida. Como era de esperar, tiene que crear una función antes de poder ejecutarla. En otras palabras, la definición de la función tiene que ejecutarse antes de la primera vez que se la invoque. Como actividad, pruebe a ejecutar este programa moviendo las tres últimas sentencias al principio del programa. Registre qué mensaje de error obtiene usted. Como segunda actividad, pruebe a tomar la versión del programa que funcionaba y a mover la definción de nueva linea más abajo que la definición de tresLineas. ¿Qué ocurre cuando ejecuta el programa? 3.8. Flujo de ejecución Para asegurarse de que una función se define antes de su primer uso, tiene que conocer el orden en el que se ejecutan las sentencias; a esto se le llama flujo de ejecución. La ejecución comienza siempre por la primera sentencia del programa. Las sen- tencias se ejecutan a razón de una cada vez, en orden, hasta que se alcanza una llamada a una función. Las definiciones de funciones no alteran el flujo de ejecución del programa, pero recuerde que las sentencias que hay dentro de la función no se ejecutan hasta que se hace la llamada a la función. Aunque no es habitual, puede definir una 28 Funciones función dentro de otra. En este caso, la definición de función interior no se ejecuta hasta que no se llama a la función exterior. Las llamadas a funciones son como un desvı́o en el flujo de ejecución. En lugar de ir a la siguiente sentencia, el flujo salta hasta la primera lı́nea de la función a la que se llama, ejecuta todas las sentencias que encuentre allı́, y vuelve a retomar la ejecución en el punto donde lo dejó. Esto suena bastante sencillo... hasta que se acuerda de que una función puede llamar a otra. Mientras estamos en medio de una función, podrı́amos vernos obligados a abandonarla e ir a ejecutar sentencias en otra función más. Pero mientras estamos en esta nueva función, ¡podrı́amos salirnos y ejecutar otra función más! Afortunadamente, a Python se le da bien tomar nota de dónde está, de manera que cada vez que se completa una función, el programa retoma el punto en donde lo dejó en la función que hizo la llamada. Cuando llega al final del programa, termina. ¿Cuál es la moraleja de toda esta historia? Cuando esté leyendo un programa, no lo lea desde la parte superior a la inferior. En lugar de eso, siga el flujo de ejecución. 3.9. Parámetros y argumentos Algunas de las funciones internas que hemos usado precisan de argumentos, los valores que controlan cómo la función lleva a cabo su tarea. Por ejemplo, si desea encontrar el seno de un número, tiene que indicar de qué número se trata. Ası́ pues, sin toma como argumento un valor numérico. Algunas funciones toman más de un argumento, como pow, que toma dos argu- mentos: la base y el exponente. Dentro de la función, los valores que se le han pasado se asignan a variables llamadas parámetros. He aquı́ un ejemplo de una función definida por el usuario, que toma un paráme- tro: def imprimeDoble(paso): print paso, paso Esta función toma un único argumento y se lo asigna a un parámetro llamado paso. El valor del parámetro (en este punto todavı́a no tenemos ni idea de cuál será) se imprime dos veces, seguido por un carácter de nueva lı́nea. El nombre paso se eligió para sugerir que el nombre que le dé a un parámetro depende de usted, pero en general es mejor que elija un nombre más ilustrativo que paso. 3.10 Las variables y los parámetros son locales 29 La función imprimeDoble sirve con cualquier tipo (de dato) que se pueda im- primir: >>> imprimeDoble(’Jamón’) Jamón Jamón >>> imprimeDoble(5) 5 5 >>> imprimeDoble(3.14159) 3.14159 3.14159 En la primera llamada a la función, el argumento es una cadena; en la segunda es un entero, y en la tercera es un número de coma flotante. Las mismas reglas de composición que se aplican a las funciones internas se aplican también a las funciones definidas por el usuario, ası́ que puede usar cualquier tipo de expresión como argumento de imprimeDoble. >>> imprimeDoble(’Jamón’*4) JamónJamónJamónJamón JamónJamónJamónJamón >>> imprimeDoble(math.cos(math.pi)) -1.0 -1.0 Como de costumbre, se evalúa la expresión antes de ejecutar la función, de modo que imprimeDoble devuelve JamónJamónJamónJamón JamónJamónJamónJamón en lugar de ’Jamón’*4’Jamón’*4. Asimismo podemos usar una variable como argumento: >>> latoya = ’Dafne, es mitad laurel mitad ninfa’ >>> imprimeDoble(latoya) Dafne, es mitad laurel mitad ninfa. Dafne, es mitad laurel mitad ninfa. Observe un aspecto realmente importante en este caso: el nombre de la variable que pasamos como argumento (latoya) no tiene nada que ver con el nombre del parámetro (paso). No importa cómo se llamaba el valor en su lugar original (el lugar desde donde se invocó); aquı́ en imprimeDoble llamamos a todo el mundo paso. 3.10. Las variables y los parámetros son locales Cuando crea una variable dentro de una función, sólo existe dentro de dicha función, y no puede usarla fuera de ella. Por ejemplo, la función >>> def catDoble(parte1, parte2):... cat = parte1 + parte2... imprimeDoble(cat)... >>> 30 Funciones toma dos argumentos, los concatena y luego imprime el resultado dos veces. Podemos llamar a la función con dos cadenas: >>> cantus1 = "Die Jesu domine, " >>> cantus2 = "Dona eis requiem." >>> catDoble(cantus1, cantus2) Die Jesu domine, Dona eis requiem. Die Jesu domine, Dona eis requiem. Cuando catDoble termina, la variable cat se destruye. Si tratásemos de impri- mirla, obtendrı́amos un error: >>> print cat NameError: cat Los parámetros también son locales. Por ejemplo, una vez fuera de la función imprimeDoble, no existe nada llamado paso. Si trata de usarla, Python se que- jará. 3.11. Diagramas de pila Para mantener el rastro de qué variables pueden usarse y dónde, a veces es útil dibujar un diagrama de pila. Como los diagramas de estado, los diagramas de pila muestran el valor de cada variable, pero también muestran la función a la que cada variable pertenece. Cada función se representa por una caja con el nombre de la función junto a él. Los parámetros y variables que pertenecen a una función van dentro. Por ejemplo, el diagrama de stack para el programa anterior tiene este aspecto: __main__ chant1 "Pie Jesu domine," chant2 "Dona eis requiem." catTwice part1 "Pie Jesu domine," part2 "Dona eis requiem." cat "Pie Jesu domine, Dona eis requiem." printTwice bruce "Pie Jesu domine, Dona eis requiem." El orden de la pila muestra el flujo de ejecución. imprimeDoble fue llamado por catDoble y a catDoble lo invocó main , que es un nombre especial de la 3.12 Funciones con resultado 31 función más alta. Cuando crea una variable fuera de cualquier función, pertenece a main. En cada caso, el parámetro se refiere al mismo valor que el argumento corres- pondiente. Ası́ que parte1 en catDoble tiene el mismo valor que cantus1 en main. Si sucede un error durante la llamada a una función, Python imprime el nombre de la función y el nombre de la función que la llamó, y el nombre de la función que llamó a ésa, y ası́ hasta main. Por ejemplo, si intentamos acceder a cat desde imprimeDoble, provocaremos un NameError: Traceback (innermost last): File "test.py", line 13, in __main__ catDoble(cantus1, cantus2) File "test.py", line 5, in catDoble imprimeDoble(cat) File "test.py", line 9, in imprimeDoble print cat NameError: cat Esta lista de funciones de llama traceback (traza inversa). Le dice a usted en qué archivo de programa sucedió el error, y en qué lı́nea, y qué funciones se ejecutaban en ese momento. También muestra la lı́nea de código que causó el error. Fı́jese en la similaridad entre la traza inversa y el diagrama de pila. No es una coincidencia. 3.12. Funciones con resultado Seguramente ha notado ya que algunas de las funciones que estamos usando, igual que las funciones matemáticas, devuelven un resultado. Otras funciones, como nueva linea, llevan a cabo una acción pero no devuelven un valor. Ello suscita varias preguntas: 1. ¿Qué sucede si llama usted a uana función y no hace nada con el resultado (es decir, no lo asigna a una variable ni lo usa como parte de una expresión más amplia)? 2. ¿Qué sucede si usa una función sin resultado como parte de una expresión, por ejemplo nueva linea() + 7? 32 Funciones 3. ¿Se pueden escribir funciones que devuelvan resultados, o debemos limi- tarnos a funcinoes simples como nueva linea e imprimeDoble? La respuesta a la tercera pregunta es “sı́, puede escribir funciones que devuelvan valores”, y lo haremos en el capı́tulo 5. Como actividad final, consteste a las otras dos preguntas intentando hacerlas en la práctica. Cada vez que tenga una duda sobre lo que es legal o ilegal en Python, perguntar al intérprete será una buena manera de averiguarlo. 3.13. Glosario llamada a función: Una sentencia que ejecuta una función. Está compuesta por el nombre de la función más una lista de argumentos encerrados entre paréntesis. argumento: Valor que se le pasa a una función cuando se la llama. El valor se asigna al parámetro correspondiente de la función. valor de retorno: Es el resultado de una función. Si se usa una llamada a función a modo de expresión, el valor de retorno es el valor de la expresión. conversión de tipo: Una sentencia explı́cita que toma un valor de un tipo y calcula el valor correspondiente de otro tipo. coerción: Conversión tipos que ocurre automáticamente de acuerdo con las reglas de coerción de Python. módulo: Fichero que contiene una colección de funciones y clases relacionadas. notación de punto: La sintaxis para llamar a una función de otro módulo, especificando el nombre del módulo, seguido por un punto y el nombre de la función. función: Secuencia de sentencias etiquetadas que llevan a cabo determinada operación de utilidad. Las funciones pueden tomar parámetros o no, y pueden producir un resultado o no. definición de función: Sentencia que crea una nueva función, especificando su nombre, parámetros y las sentencias que ejecuta. flujo de ejecución: Orden en el que se ejecutan las sentencias durante la eje- cución de un programa. 3.13 Glosario 33 parámetro: Nombre que se usa dentro de una función para referirse a el valor que se le pasa como argumento. variable local: variable definida dentro de una función. Las variables locales sólo pueden usarse dentro de su función. diagrama de pila: Representación gráfica de una pila de funciones, sus varia- bles y los valores a los que se refieren. traza inversa: (traceback en inglés) Una lista de las funciones en curso de ejecución, presentadas cuando sucede un error en tiempo de ejecución. notación de punto traza inversa Capı́tulo 4 Condicionales y recursividad 4.1. El operador módulo El operador módulo funciona con enteros (y expresiones enteras), y devuelve el resto de dividir el primer operando entre el segundo. En Python, el operador de módulo es el signo de tanto por ciento ( %). La sintaxis es la misma de los otros operadores: >>> cociente = 7 / 3 >>> print cociente 2 >>> resto = 7 % 3 >>> print resto 1 Ası́, 7 dividido entre 3 da 2 con 1 de resto. El operador de módulo resulta ser soprendentemente útil. Por ejemplo, puede comprobar si un número es divisible entre otro: si x % y es cero, entonces x es divisible entre y. También puede usar el operador módulo para extraer el dı́gito más a la derecha de un número. Por ejemplo, x % 10 devuelve el dı́gito más a la derecha de x (en base 10). De forma similar, x % 100 devuelve los dos últimos dı́gitos. 36 Condicionales y recursividad 4.2. Expresiones booleanas Una expresión booleana es una expresión que es cierta o falsa. En Python, una expresión que es cierta tiene el valor 1, y una expresión que es falsa tiene el valor 0. El operador == compara dos valores y entrega una expresión booleana: >>> 5 == 5 1 >>> 5 == 6 0 En la primera sentencia, los dos operandos son iguales, ası́ que la expresión se evalúa como 1 (verdadero); en la segunda sentencia, 5 no es igual a 6, ası́ que obtenemos 0 (falso). El operador == es uno de los operadores de comparación; los otros son: x != y # x no es igual a y x > y # x es mayor que y x < y # x es menor que y x >= y # x es mayor o igual que y x. 4.3. Operadores lógicos Hay tres operadores lógicos: and, or, y not. La semántica (significado) de estos operadores es similar a sus significados en inglés. Por ejemplo, x >0 and x y) es cierto si (x >y) es falso, o sea, si x es menor o igual que y. Hablando estrictamente, los operandos de los operadores lógicos deberı́an ser expresiones booleanas, pero Python no es muy estricto. Cualqueir número que no sea cero se interpreta como “verdadero”. 4.4 Ejecución condicional 37 >>> x = 5 >>> x and 1 1 >>> y = 0 >>> y and 1 0 En general, este tipo de cosas no se considera buen estilo. Si quiere comparar un valor con cero, deberı́a hacerlo explı́citamente. 4.4. Ejecución condicional Para escribir programas útiles, casi siempre necesitamos la capacidad de com- probar ciertas condiciones y cambiar el comportamiento del programa en conso- nancia. Las sentencias condicionales nos dan esta capacidad. La forma más sencilla es la sentencia if: if x > 0: print "x es positivo" La expresión booleana tras el if se llama condición. Si es verdadera, entonces la sentencia indentada se ejecuta. Si la condición no es verdadera, no pasa nada. Como otras sentencias compuestas, if consta de una cabecera y un bloque de sentencias: CABECERA: PRIMERA SENTENCIA... ULITMA SENTENCIA La cabecera comienza con una nueva lı́nea y termina con el signo de dos puntos. Los elementos indentados que siguen se llaman bloque de la sentencia. La primera sentencia no indentada marca el fin del bloque. Un bloque de sentencias dentro de una sentencia compuesta recibe el nombre de cuerpo de la sentencia. No hay lı́mite a la cantidad de sentencias que pueden aparecer en el cuerpo de una sentencia if, pero debe haber al menos una. A veces, es útil tener un cuerpo sin sentencias, (normalmente como reserva de espacio para algo de código que todavı́a no ha escrito). En tales casos, puede usted utilizar la sentencia pass, que no hace nada. 4.5. Ejecución alternativa Una segunda forma de la sentencia if es la ejecución alternativa, en la que hay dos posibilidades, y la condición determina cuál de ellas se ejecuta. La sintaxis 38 Condicionales y recursividad tiene este aspecto: if x%2 == 0: print x, "es par" else: print x, "es impar" Si el resto cuando se divide x entre 2 es cero, entonces sabemos que x es par, y este programa muestra un mensaje a tal efecto. Si la condición es falsa, se ejecuta el segundo lote de sentencias. Puesto que la condición debe ser verdadera o falsa, se ejecutará exactamente una de las alternativas. Llamamos ramas a las posibilidades porque son ramas del flujo de ejecución. Como un aparte, si piensa que querrá comprobar con frecuencia la paridad de números, quizá desee “envolver” este código en una función: def imprimeParidad(x): if x%2 == 0: print x, "es par" else: print x, "es impar" Ahora tiene una función llamada imprimeParidad que muestra el mensaje apro- piado para cada número entero que usted le pase. Llame a esta función de la manera siguiente: >>> imprimeParidad(17) >>> imprimeParidad(y+1) 4.6. Condiciones encadenadas A veces hay más de dos posibilidades y necesitamos más de dos ramas. Una forma de expresar tal computación es un conditional encadenado: if x < y: print x, "es menor que", y elif x > y: print x, "es mayor que", y else: print x, "y", y, "son iguales" elif es una abreviatura de ”else if”. De nuevo, sólo se ejecutará una rama. No hay lı́mite al número de sentencias elif, pero sólo se permite una sentencia else (que puede omitirse) y debe ser la última rama de la sentencia: if eleccion == ’A’: funcionA() elif eleccion == ’B’: 4.7 Condiciones anidadas 39 funcionB() elif eleccion == ’C’: funcionC() else: print "Eleccion no valida." Las condiciones se comprueban en orden. Si la primera es falsa, se comprueba la siguiente, y ası́. Si una de ellas es cierta, se ejecuta la rama correspondiente y termina la sentencia. Incluso si es cierta más de una condición, sólo se ejecuta la primera rama verdadera. Como ejercicio, envuelva estos ejemplos en funciones llamadas compara(x, y) y resuelve(eleccion). 4.7. Condiciones anidadas Una condición puede estar anidada dentro de otra. Podı́amos haber escrito ası́ el ejemplo de tricotomı́a: ~~if x == y: ~~~~print x, "y", y, "son iguales" ~~else: ~~~~if x < y: ~~~~~~print x, "es menor que", y ~~~~else: ~~~~~~print x, "es mayor que", y La condición externa que contiene dos ramas. La primera rama contiene una sentencia simple de salida. La segunda rama contiene otra sentencia if, que tiene dos ramas en sı́ misma. Estas dos ramas son ambas sentencias de salida de datos, aunque podrı́an ser igualmente sentencias condicionales. Aunque la indentación de las sentencias hace la estructura evidente, las condi- ciones anidadas en seguida se vuelven difı́ciles de leer. En general es una buena idea evitarlas cuando pueda. Los operadores lógicos suelen facilitar un modo de simplificar las sentencias condicionales anidadas. Por ejemplo, podemos reescribir el código siguiente con un sólo condicional: if 0 < x: if x < 10: print "x es un número positivo de un dı́gito." La sentencia print sólo se ejecuta si conseguimos superar ambos condicionales, ası́ que podemos usar el operador and: 40 Condicionales y recursividad if 0 < x and x < 10: print "x es un número positivo de un dı́gito." Estos tipos de condiciones son habituales, por lo que Python nos proporciona una sintaxis alternativa similar a la notación matemática: if 0 < x < 10: print "x es un número positivo de un dı́gito." Esta condición es semánticamente la misma que la expresión booleana compues- ta y que el condicional anidado. 4.8. La sentencia return La sentencia return le permite terminar la ejecución de una función antes de alcanzar su final. Una razón para usarla es detectar una condición de error: import math def imprimeLogaritmo(x): if x >> cuenta_atras(3) La ejecución de cuenta atras comienza con n=3, y puesto que n no es cero, da como salida el valor 3, y luego se llama a sı́ misma... La ejecución de cuenta atras comienza con n=2, y puesto que n no es cero, muestra el valor 2 y luego se llama a sı́ misma... La ejecución de cuenta atras comienza con n=1, y puesto que n no es cero, muestra el valor 1, y luego se llama a sı́ misma... La ejecución de cuenta atras comienza con n=0, y puesto que n es cero, muestra la palabra “Des- pegando!” y luego retorna. La cuenta atras que dio n=1 retorna. La cuenta atras que dio n=2 retorna. La cuenta atras que dio n=3 retorna. Y entonces ya está de vuelta en main (menudo viaje). De manera que la salida completa presenta el siguiente aspecto: 3 2 1 Despegando! Como segundo ejemplo, consideremos de nuevo las funciones nuevaLinea and tresLineas. def nuevaLinea(): print 42 Condicionales y recursividad def tresLineas(): nuevaLinea() nuevaLinea() nuevaLinea() Aunque todas funcionan, no serı́an de mucha ayuda si quisiera mostrar 2 lı́neas nuevas o 106. Una mejor alternativa será: def nLineas(n): if n > 0: print nLineas(n-1) Este programa es parecido a cuenta atras; mientras n sea mayor que cero, muestra una nueva lı́nea, y luego se llama a sı́ misma para mostrar >n-1 nuevas lı́neas más. De esta manera, el número total de nuevas lı́neas es 1 + (n-1), que si rescata su álgebra verá que es n. El proceso por el que una función se llama a sı́ misma se llama recursividad, y dichas funciones se denominan recursivas. 4.10. Diagramas de pila para funciones recursi- vas El la Sección 3.11 utilizamos un diagrama de pila para representar el estado de un programa durante la llamada de una función. El mismo tipo de diagrama puede hacer más fácil interpretar una función recursiva. Cada vez que se llama a una función, Python crea un nuevo marco para la función, que contiene sus variables locales y parámetros. En el caso de una función recursiva, puede haber más de un marco en la pila al mismo tiempo. La figura muestra un diagrama de pila para cuenta atras, invocada con n = 3: 4.11 Recursividad infinita 43 __main__ countdown n 3 countdown n 2 countdown n 1 countdown n 0 Como es habitual, en lo alto de la pila está el marco de main. Está vacı́a porque no hemos ninguna variable sobre main ni le hemos pasado ningún parámetro. Los cuatro marcos de cuenta atras tienen valores diferentes para el parámetro n. El fondo de la pila, donde n=0, se llama caso base. No hace una llamada recursiva, de manera que no hay más marcos. Como actividad, dibuje un diagrama de pila para nLineas, invocada con el parámetro n=4. 4.11. Recursividad infinita Si una recursión no alcanza nunca el caso base, seguirá haciendo llamadas re- cursivas para siempre y nunca terminará. Esta circunstancia se conoce como recursividad infinita, y generalmente no se la considera una buena idea. Este es un programa mı́nimo con recursividad infinita: def recurre(): recurre() El la mayorı́a de los entornos de programación, un programa con recursividad infinita no se ejecutará realmente para siempre. Python informará de un mensaje de error cuando se alcance el nivel máximo de recursividad: File "", line 2, in recurse (98 repetitions omitted) File "", line 2, in recurse RuntimeError: Maximum recursion depth exceeded 44 Condicionales y recursividad Esta traza inversa es un poco mayor que la que vimos en el capı́tulo anterior. ¡Cuando sucede el error, hay 100 marcos recurre en la pila! Como actividad, escriba una función con recursividad infinita y ejecútela en el intérprete de Python. 4.12. Entrada por teclado Los programas que hemos escrito hasta ahora son un poco maleducados en el sentido de que no aceptan entradas de datos del usuario. Simplemente hacen lo mismo siempre. Python proporciona funciones internas que obtienen entradas desde el teclado. La más sencilla se llama raw input. Cuando llamamos a esta función, el pro- grama se detiene y espera a que el usuario escriba algo. Cuando el usuario pulsa la tecla Return o Enter, el programa se reanuda y raw input devuelve lo que el usuario escribió como tipo string: >>> entrada = raw_input () A qué estás esperando? >>> print entrada A qué estás esperando? Antes de llamar a raw input es conveniente mostrar un mensaje que le pida al usuario el dato solicitado. Este mensaje se llama indicador (prompt en inglés). Puede proporcionarle un indicador a raw input como argumento: >>> nombre = raw_input ("Cómo te llamas? ") Cómo te llamas? Héctor, héroe de los Troyanos! >>> print nombre Héctor, héroe de los Troyanos! Si espera que la entrada sea un entero, utilice la función input. Por ejemplo: >>> indicador = \... "Cuál es la velocidad de una golondrina sin carga?\n" >>> velocidad = input (indicador) Si el usuario teclea una cadena de números, se convertirá en un entero y se asignará a velocidad. Por desgracia, si el usuario escribe algo que no sea un dı́gito, el programa dará un error: >>> velocidad = input (indicador) Cuál es la velocidad de una golondrina sin carga? Se refiere usted a la golondrina europea o a la africana? SyntaxError: invalid syntax Para evitar este tipo de error, generalmente es buena idea usar raw input para obtener una cadena y usar entonces las funciones de conversión para convertir a otros tipos. 4.13 Glosario 45 4.13. Glosario operador módulo: Operador, señalado con un signo de tanto por ciento ( %), que trabaja sobre enteros y devuelve el resto cuando un número se divide entre otro. expresión booleana: Una exprersión que es cierta o falsa. operador de comparación: Uno de los operadores que comparan dos valores: ==, !=, >, = y 0: return x Este programa no es correcto porque si resulta que x vale 0, entonces no se cum- ple ninguna de ambas condiciones y la función termina sin alcanzar la setencia return. En este caso, el valor de retorno es un valor especial llamado None: >>> print valorAbsoluto(0) None Como actividad, escriba una función comparar que devuelva 1 si x >y , 0 si x == y , y -1 si x >> def distancia(x1, y1, x2, y2):... return 0.0... >>> distancia(1, 2, 4, 6) 0.0 >>> Elegimos estos valores de tal forma que la distancia horizontal sea igual a 3 y la distancia vertical sea igual a 4; de esa manera el resultado es 5 (la hipotenusa del triángulo 3-4-5). Cuando se comprueba una función, es útil saber la respuesta correcta. Hasta el momento, hemos comprobado que la función es sintácticamente correc- ta, ası́ que podemos empezar a añadir lı́neas de código. Después de cada cambio 50 Funciones productivas incremental, comprobamos de nuevo la función. Si en un momento dado apare- ce un error, sabremos dónde está exactamente: en la última lı́nea que hayamos añadido. El siguiente paso en el cálculo es encontrar las diferencias entre x2 −x1 y y2 −y1. Almacenaremos dichos valores en variables temporales llamadas dx y dy y las imprimiremos. def distancia(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 print "dx es", dx print "dy es", dy return 0.0 Si la función funciona, valga la redundancia, las salidas deberı́an ser 3 y 4. Si es ası́, sabemos que la función recibe correctamente los parámetros y realiza correctamente el primer cálculo. Si no, sólo hay unas pocas lı́neas que revisar. Ahora calculamos la suma de los cuadarados de dx y dy: def distancia(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 dalcuadrado = dx**2 + dy**2 print "dalcuadrado es: ", dalcuadrado return 0.0 Fı́jese en que hemos eliminado las sentencias print que escribimos en el pa- so anterior. Este código se llama andamiaje porque es útil para construir el programa pero no es parte del producto final. De nuevo querremos ejecutar el programa en este estado y comprobar la salida (que deberı́a dar 25). Por último, si hemos importado el módulo math, podemos usar la función sqrt para calcular y devolver el resultado: def distancia(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 dalcuadrado = dx**2 + dy**2 resultado = math.sqrt(dalcuadrado) return resultado Si esto funciona correctamente, ha terminado. Si no, podrı́a ser que quisiera usted imprimir el valor de resultado antes de la sentencia return. 5.3 Composición 51 Al principio, deberı́a añadir solamente una o dos lı́neas de código cada vez. Conforme vaya ganando experiencia, puede que se encuentre escribiendo y de- purando trozos mayores. Sin embargo, el proceso de desarrollo incremental puede ahorrarle mucho tiempo de depurado. Los aspectos fundamentales del proceso son: 1. Comience con un programa que funcione y hágale pequeños cambios in- crementales. Si hay un error, sabrá exactamente dónde está. 2. Use variables temporales para mantener valores intermedios, de tal manera que pueda mostrarlos por pantalla y comprobarlos. 3. Una vez que el programa esté funcionando, tal vez prefiera eliminar parte del andamiaje o aglutinar múltiples sentencias en expresiones compuestas, pero sólo si eso no hace que el programa sea difı́cil de leer. Como actividad, utilice el desarrollo incremental para escribir una función de nombre hipotenusa que devuelva la longitud de la hipo- tenusa de un triángulo rectángulo, dando como parámetros los dos catetos. Registre cada estado del desarrollo incremental según vaya avanzando. 5.3. Composición Como seguramente a estas alturas ya supondrá, se puede llamar a una función desde dentro de otra. Esta habilidad se llama composición. Como ejemplo, escribiremos una función que tome dos puntos, el centro del cı́rculo y un punto del perı́metro, y calcule el área del cı́rculo. Supongamos que el punto central está almacenado en las variables xc e yc, y que el punto del perı́metro lo está en xp e yp. El primer paso es hallar el radio del cı́rculo, que es la distancia entre los dos puntos. Afortunadamente hay una función, distancia, que realiza esta tarea: radio = distancia(xc, yc, xp, yp) El segundo paso es encontrar el área de un cı́rculo con ese radio y devolverla: resultado = area(radio) return resultado Envolviendo todo esto en una función, obtenemos: def area2(xc, yc, xp, yp): radio = distancia(xc, yc, xp, yp) resultado = area(radio) return resultado 52 Funciones productivas Hemos llamado a esta función area2 para distinguirla de la función area definida anteriormente. Sólo puede haber una única función con un determinado nombre dentro de un módulo. Las variables temporales radio y area son útiles para el desarrollo y el depu- rado, pero una vez que el programa está funcionando, podemos hacerlo más conciso integrando las llamadas a las funciones en una sola lı́nea: def area2(xc, yc, xp, yp): return area(distancia(xc, yc, xp, yp)) Como actividad, escriba una función pendiente(x1, y1, x2, y2) que devuelva la pendiente de la lı́nea que atraviesa los puntos (x1, y1) y (x2, y2). Luego use esta función en una función que se llame intercepta(x1, y1, x2, y2) que devuelva la [[y-intercepta]] de la lı́nea a través de los puntos (x1, y1) y (x2, y2). 5.4. Funciones booleanas Las funciones pueden devolver valores booleanos, lo que a menudo es conveniente para ocultar complicadas comprobaciones dentro de funciones. Por ejemplo: def esDivisible(x, y): if x % y == 0: return 1 # it’s true else: return 0 # it’s false La función lleva por nombre esDivisible. Es habitual dar a las funciones boo- leanas nombres que suenan como preguntas sı́/no. Devuelve 1 ó 0 para indicar si la x es o no divisibelo por y. Podemos reducir el tamaño de la función aprovechándonos del hecho de que la sentencia condicional que hay después del if es en sı́ misma una expresión booleana. Podemos devolverla directamente, evitando a la vez la sentencia if: def esDivisible(x, y): return x % y == 0 La siguiente sesión muestra a la nueva función en acción: >>> esDivisible(6, 4) 0 >>> esDivisible(6, 3) 1 El uso más común para las funciones booleanas es dentro de sentencias condi- cionales: 5.5 Más recursividad 53 if esDivisible(x, y): print "x es divisible entre y" else: print "x no es divisible entre y" Puede parecer tentador escribir algo como: if esDivisible(x, y) == 1: Pero la comparación extra es innecesaria. Como actividad, escriba una función estaEntre(x, y, z) que de- vuelva 1 en caso de que y > factorial (1.5) RuntimeError: Maximum recursion depth exceeded Tiene todo el aspecto de una recursión infinita. Pero, ¿cómo ha podido ocurrir? Hay una condición de salida o caso base: cuando n == 0. El problema es que el valor de n yerra el caso base. En la primera llamada recursiva, el valor de n es 0.5. En la siguiente vez su valor es -0.5. A partir de ahı́, se vuelve más y más pequeño, pero nunca será 0. Tenemos dos opciones. Podemos intentar generalizar la función factorial para que trabaje con números de coma flotante, o podemos hacer que factorial compruebe el tipo de su parámetro. La primera opción se llama función gamma, y está más allá del objetivo de este libro. Ası́ pues, tomemos la segunda. Podemos usar la función type para comparar el tipo del parámetro con el tipo de un valor entero conocido (por ejemplo 1). Ya que estamos en ello, podemos asegurarnos de que el parámetro sea positivo: def factorial (n): if type(n) != type(1): print "El factorial está definido sólo para enteros." return -1 elif n < 0: print "El factorial está definido sólo para enteros\ positivos." return -1 elif n == 0: return 1 else: return n * factorial(n-1) 58 Funciones productivas Ahora tenemos tres condiciones de salida o casos base. El primero filtra los números no enteros. El segundo evita los enteros negativos. En ambos casos, se muestra un mensaje de error y se devuelve un valor especial, -1, para indicar a quien hizo la llamada a la función que algo fue mal: >>> factorial (1.5) El factorial esta definido solo para enteros. -1 >>> factorial (-2) El factorial esta definido solo para enteros positivos. -1 >>> factorial ("paco") El factorial esta definido solo para enteros. -1 Si pasamos ambas comprobaciones, entonces sabemos que n es un entero positivo y podemos probar que la recursión termina. Este programa muestra un patrón que se llama a veces guardián. Las primeras dos condicionales actúan como guardianes, protegiendo al código que sigue de los valores que pudieran causar errores. Los guardianes hacen posible demostrar la corrección del código. 5.9. Glosario función productiva: Función que devuelve un valor de retorno. valor de retorno: El valor obtenido como resultado de una llamada a una función. variable temporal: Variable utilizada para almacenar un valor intermedio en un cálculo complejo. código muerto: Parte de un programa que no podrá ejecutarse nunca, a me- nudo debido a que aparece tras una sentencia de return. None: Valor especial de Python que devuelven funciones que o bien no tienen sentencia de return o bien tienen una sentencia de return sin argumento. desarrollo incremental: Un método de desarrollo de programas que busca evitar el depurado añadiendo y probando una pequeña cantidad de código en cada paso. andamiaje: El código que se usa durante el desarrollo del programa pero que no es parte de la versión final. 5.9 Glosario 59 guardián: Una condición que comprueba y maneja circunstancias que pudieran provocar un error. Capı́tulo 6 Iteración 6.1. Asignación múltiple Es posible que haya descubierto que es posible hacer más de una asignación a una misma variable. El efecto de la nueva asignación es redirigir la variable de manera que deje de remitir al valor antiguo y empieze a remitir al valor nuevo. bruno = 5 print bruno, bruno = 7 print bruno La salida del programa es 5 7, ya que la primera vez que imprimimos bruno su valor es 5, y la segunda vez su valor es 7. La coma al final de la primera sentencia print impide que se imprima una nueva lı́nea en ese punto, por eso ambos valores aparecen en la misma lı́nea. He aquı́ el aspecto de una asignación múltiple en un diagrama de estado: 5 bruce 7 Cuando hay asignaciones múltiples a una variable, es especialmente importante distinguir entre una sentencia de asignación y una sentencia de igualdad. Puesto que Python usa el sı́mbolo = para la asignación, es tentador interpretar una sentencia como a = b como sentencia de igualdad. Pero no lo es. 62 Iteración Para empezar, la igualdad es commutativa, y la asignación no lo es. Por ejemplo en matemáticas si a = 7 entonces 7 = a. Pero en Python la sentencia a = 7 es legal, y 7 = a no lo es. Y lo que es más, en matemáticas, una sentencia de igualdad es verdadera todo el tiempo. Si a = b ahora, entonces a siempre será igual a b. En Python, una sentencia de asignación puede hacer que dos variables sean iguales, pero no tienen por qué quedarse ası́. a = 5 b = a # a y b son ahora iguales a = 3 # a y b ya no son iguales La tercera lı́nea cambia el valor de a pero no cambia el valor de b, y por lo tanto ya dejan de ser iguales. En algunos lenguajes de programación, se usa para la asignación un sı́mbolo distinto, como 0: print n n = n-1 print "Despegando!" Como eliminamos la llamada recursiva, esta función no es recursiva. Casi podrı́a leer una sentencia while como si fuera inglés (castellano “mien- tras”). Quiere decir que “Mientras n sea mayor que cero, continúa mostrando el valor de n y después restándole 1 al valor de n. Cuando llegues a cero, muestra la palabra “Despegando!”. 6.2 La sentencia while 63 Más formalmente, el flujo de ejecución de una sentencia while es el siguiente: 1. Evaluar la condición, devolviendo 0 o 1. 2. Si la condición es falsa (0), salir de la sentencia while y continuar la ejecución en la siguiente sentencia. 3. Si la condición es verd