1. El camino del programa

El objetivo de este libro es enseñarle a pensar como lo hacen los científicos informáticos. Esta manera de pensar combina algunas de las mejores características de la matemática, la ingeniería y las ciencias naturales. Como los matemáticos, los científicos informáticos usan lenguajes formales para denotar ideas (específicamente, cómputos). Como los ingenieros, ellos diseñan cosas, construyendo sistemas mediante el ensamble de componentes y evaluando las ventajas y desventajas de cada una de las alternativas de construcción. Como los científicos, ellos observan el comportamiento de sistemas complejos, forman hipótesis, y prueban sus predicciones.

La habilidad más importante del científico informático es la resolución de problemas. La resolución de problemas incluye poder formular problemas, pensar en soluciones de manera creativa, y expresar soluciones claras y precisas. Como se verá, el proceso de aprender a programar es la oportunidad perfecta para desarrollar la habilidad de resolver problemas. Por esa razón este capítulo se llama “El Camino del programa.”

A cierto nivel, usted aprenderá a programar, lo cual es una habilidad muy útil por sí misma. A otro nivel, usted utilizará la programación para obtener algún resultado. Ese resultado se verá más claramente durante el proceso.

1.1. El lenguaje de programación Python

El lenguaje de programación que aprenderá es Python. Python es un ejemplo de lenguaje de alto nivel; otros lenguajes de alto nivel de los que quizá ha oído hablar son C++, PHP y Java.

Como se puede deducir, además de “lenguajes de alto nivel” también existen lenguajes de bajo nivel, que también se denominan “lenguajes de máquina” o “lenguajes ensambladores.” A propósito, las computadoras sólo ejecutan programas escritos en lenguajes de bajo nivel. Así, los programas escritos en lenguajes de alto nivel tienen que ser traducidos antes de ser ejecutados. Esta traducción lleva tiempo, lo que es una pequeña desventaja de los lenguajes de alto nivel.

Aun así, las ventajas son enormes. En primer lugar, la programación en lenguajes de alto nivel es mucho más fácil; escribir programas en un lenguaje de alto nivel toma menos tiempo, los programas son más cortos y más fáciles de leer, y es más probable que estos programas queden correctos. En segundo lugar, los lenguajes de alto nivel son portables, lo que significa que los programas escritos con estos lenguajes pueden ser ejecutados en diferentes tipos de computadoras sin modificación alguna o con pocas modificaciones. Los programas escritos en lenguajes de bajo nivel sólo pueden ser ejecutados en un tipo de computadora y deben ser reescritos para ser ejecutados en otra.

Debido a estas ventajas, casi todo programa se escribe en un lenguaje de alto nivel. Los lenguajes de bajo nivel son sólo usados para unas pocas aplicaciones especiales.

Hay dos tipos de programas que traducen lenguajes de alto nivel a lenguajes de bajo nivel: intérpretes y compiladores. Un intérprete lee un programa de alto nivel y lo ejecuta, lo que significa que lleva a cabo lo que indica el programa. Es decir, traduce el programa poco a poco, leyendo y ejecutando cada comando.

Un compilador lee el programa y lo traduce completo antes de su ejecución. En este caso, al programa de alto nivel se le llama código fuente, y el programa traducido es llamado código objeto o programa ejecutable. Una vez que un programa ha sido compilado, puede ser ejecutado repetidamente sin necesidad de más traducción.

Muchos de los lenguajes modernos usan ambos tipos de programas de traducción. Estos lenguajes se traducen primero a un lenguaje de bajo nivel, llamado código de bytes, y después son interpretados por un programa denominado máquina virtual. Aunque Python usa ambos tipos de programas de traducción, usualmente se le considera un lenguaje interpretado debido a la manera en que los programadores interactúan con él.

Existen dos maneras de usar el intérprete de Python: en modo de comandos y en modo de guión. En modo de comandos se escriben sentencias en lenguaje Python en el intérprete de comandos de Python y éste muestra el resultado inmediatamente:

$ python
Python 2.5.1 (r251:54863, May  2 2007, 16:56:35)
[GCC 4.1.2 (Ubuntu 4.1.2-0ubuntu4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 1 + 1
2

La primera línea de este ejemplo es el comando que pone en marcha al intérprete de Python — en el indicador de comandos de sistemas tipo UNIX. Las tres líneas siguientes son mensajes del intérprete. La quinta línea comienza con >>>, que es el indicador del intérprete de comandos de Python para indicar que está listo. Si escribimos print 1 + 1 el intérprete contestará 2.

Alternativamente, se puede escribir el programa en un archivo y usar el intérprete para ejecutar el contenido de dicho archivo. El archivo, en este caso, se denomina archivo guión. Por ejemplo, en un editor de texto se puede crear un archivo con el nombre primerprograma.py que contenga lo siguiente:

print 1 + 1

Por convención, los archivos que contienen programas de Python tienen nombres que terminan con .py.

Para ejecutar el programa, se le tiene que indicar al intérprete el nombre del guión:

$ python primerprograma.py
2

Estos ejemplos muestran a Python corriendo desde la línea de comandos de sistemas tipo Unix. En otros entornos de desarrollo los detalles de la ejecución de programas diferirán. También, la mayoría de los programas son más interesantes que el mencionado.

En los ejemplos de este libro se usa tanto el intérprete de Python como los guiones. Usted será capaz de identificar cualquiera de ellos, puesto que los ejemplos en modo de comandos siempre empezarán con el indicador del intérprete de comandos de Pyhton (>>>).

En la realización de pruebas de segmentos cortos de código programado en Python, es más conveniente trabajar en el modo de comandos porque se obtienen resultados inmediatos. Piense en esto como un borrador que se utiliza para ayudarle a resolver problemas. Cualquier segmento de código más allá de unas pocas líneas debe incluirse en un guión.

1.2. ¿Qué es un programa?

Un programa es una secuencia de instrucciones que especifican cómo ejecutar un cómputo. El cómputo puede ser algo matemático, como solucionar un sistema de ecuaciones o determinar las raíces de un polinomio, pero también puede ser un cómputo simbólico, 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 lenguajes de programación distintos, pero existen algunas que son básicas, que se presentan en casi todo lenguaje, y que pueden agruparse en los siguientes conceptos:

entrada
Reciben datos del teclado, de un archivo o de algún otro dispositivo.
salida
Muestran datos en el monitor o los envían a un archivo u otro dispositivo.
matemáticas
Ejecutan operaciones básicas de matemáticas como la adición y la multiplicación.
operación condicional
Prueban la veracidad de alguna condición y ejecutan la secuencia de instrucciones apropiada.
repetición
Ejecutan alguna acción repetidas veces, usualmente con alguna variación.

Aunque sea difícil de creer, estos conceptos agrupan más o menos todas las instrucciones que hay en los lenguajes de programación. Todos los programas en existencia, sin importar su complejidad, son formulados exclusivamente con tales instrucciones. Así, la programación se puede describir como el proceso de dividir una tarea amplia y compleja en tareas cada vez más pequeñas hasta que éstas sean lo suficientemente sencillas como para ser ejecutadas con estas instrucciones básicas.

Quizás esta descripción sea un poco imprecisa, pero volveremos a este tema más adelante cuando hablemos de algoritmos .

1.3. ¿Qué es la depuración?

La programación es un proceso complejo y, debido a que es realizada por seres humanos, a veces conlleva la aparición de errores. Por caprichos del destino, estos errores de programación se denominan bichos (del inglés ‘bugs’) y el proceso de buscarlos y corregirlos es llamado depuración (del inglés ‘debugging’).

Hay tres tipos de errores que pueden ocurrir en un programa: errores de sintaxis, errores en tiempo de ejecución y errores semánticos. Es muy útil distinguirlos para encontrarlos más rápido.

1.4. Errores de sintaxis

Python sólo puede ejecutar un programa si el programa está correcto sintácticamente; de lo contrario, el proceso falla y devuelve un mensaje de error. La palabra sintaxis se refiere a la estructura de cualquier programa y a las reglas de esa estructura. Por ejemplo, en español, la primera letra de toda oración debe ser mayúscula, y el fin de toda oración debe llevar un punto. esta oración tiene un error de sintaxis. Esta otra oración también

Para la mayoría de los lectores unos pocos errores de sintaxis no representan un problema significativo, es por eso que pueden leer la poesía de e. e. cummings sin proferir algún mensaje de error. Python no es así. Si hay aunque sea un error de sintaxis en el programa, Python mostrará un mensaje de error y abortará la ejecución del programa. Durante las primeras semanas en su carrera de programador empleará bastante tiempo buscando errores de sintaxis. Sin embargo, conforme vaya adquiriendo experiencia, no tendrá tantos errores y los encontrará más rápido.

1.5. Errores en tiempo de ejecución

El segundo tipo de error es un error en tiempo de ejecución. Este error aparece sólo cuando se ejecuta un programa. Estos errores también se llaman excepciones porque indican que algo excepcional (y malo) ha ocurrido.

Los errores en tiempo de ejecución son raros en los programas simples que veremos en los primeros capítulos, por lo que pasará un buen tiempo antes de encontrar el primer error de este tipo.

1.6. Errores semánticos

El tercer tipo de error es el error semántico . Si hay un error semántico en su programa, el programa será ejecutado sin ningún mensaje de error, pero el resultado no será el deseado. El programa ejecutará exactamente lo que usted le dijo que ejecutara.

A veces ocurre que el programa escrito no es el programa que se tenía en mente. El sentido o significado del programa (su valor semántico) no es correcto. Identificar errores semánticos es difícil porque requiere trabajar al revés: comenzar por los resultados de salida y tratar de descifrar lo que el programa está realizando.

1.7. Depuración experimental

Una de las técnicas más importantes que usted aprenderá es la depuración. Aunque a veces es frustrante, la depuración es una de las partes de la programación intelectualmente más exigentes, desafiantes e interesantes.

La depuración es una actividad parecida a la labor realizada por detectives: se tienen que estudiar las pistas para inferir los procesos y eventos que han generado los resultados que se han encontrado.

La depuración es como una ciencia experimental. Una vez que se tiene conciencia de un error, se modifica el programa y se intenta nuevamente. Si la hipótesis fue la correcta se pueden predecir los resultados de la modificación y se estará más cerca a un programa correcto. Si la 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 programación es el proceso de depurar un programa gradualmente hasta que el programa realice lo deseado. Esto quiere decir que el programa debe ser, desde el principio, un programa que funcione y que realice algo; a este programa se le hacen pequeñas modificaciones y se le depura mateniéndolo siempre funcionando.

Por ejemplo, aunque el sistema operativo Linux contenga miles de líneas de instrucciones, Linus Torvalds lo comenzó como un programa para explorar el microprocesador Intel 80386. Según Larry Greenfield,uno de los primeros proyectos de Linus fue un programa que intercambiaría la impresión de AAAA y BBBB. Este programa se convirtió en Linux(de The Linux Users’ Guide Versión Beta 1).

En capítulos posteriores se tratará más el tema de la depuración y de otras técnicas de programación.

1.8. 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. Estos no han sido diseñados artificialmente (aunque se trate de imponer cierto orden en ellos), pues se han desarrollado naturalmente.

Los Lenguajes formales son diseñados por seres humanos para 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 en programación:

Los Lenguajes de programación son lenguajes formales que han sido desarrollados para expresar cómputos.

Los lenguajes formales casi siempre tienen reglas sintácticas estrictas. Por ejemplo, 3+3=6 es una expresión matemática sintácticamente correcta, pero 3=+6$ no lo es. De la misma manera, H2O es una nomenclatura química sintácticamente correcta, pero 2Zz`` no lo es.

Existen dos clases de reglas sintácticas: unidades léxicas y estructura. Las unidades léxicas 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 (hasta donde sabemos) una unidad matemática aceptada. De manera similar, 2Zz no es formal porque no hay ningún elemento químico con la abreviación Zz.

La segunda clase de regla sintáctica está relacionada con la estructura de una sentencia; es decir, con el orden de las unidades léxicas. La estructura de la sentencia 3=+6$ no es aceptada porque no se puede escribir el símbolo de igualdad seguido del signo de la adición. Similarmente, las fórmulas moleculares tienen que mostrar el número de subíndice después del elemento, no antes.

Al leer una oración, sea en un lenguaje natural o una sentencia en un lenguaje formal, 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 se escucha una oración simple comoel otro zapato se cayó, se puede distinguir el predicadoel otro zapatoy el verbose cayó. Cuando se ha analizado la oración sintácticamente, se puede deducir el significado, o la semántica, de la oración. Si usted sabe lo que es un zapato y el significado de caer, comprenderá 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 lexicas, la estructura, la sintaxis y la semántica — también existen muchas diferencias:

ambigüedad
Los lenguajes naturales tienen muchísimas ambigüedades que se superan usando claves contextuales e información adicional. Los Lenguajes formales son diseñados para estar completamente libres de ambigüedades, tanto como sea posible, lo que quiere decir que cualquier sentencia tiene sólo un significado sin importar el contexto en el que se encuentra.
redundancia
Para reducir la ambigüedad y los malentendidos, los lenguajes naturales utilizan bastante redundancia. Como resultado tienen una abundancia de posibilidades para expresarse. Los lenguajes formales son menos redundantes y más concisos.
literalidad
Los lenguajes naturales tienen muchas metáforas y frases comunes. El significado de un dicho, por ejemploestiró 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 ‘murió’. En los lenguajes formales sólo existe el 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 la palabra por su cualidad auditiva tanto como por su significado. El poema, en su totalidad, produce un efecto o reacción emocional. La ambigüedad no es sólo común sino utilizada a propósito.
Prosa
El significado literal de la palabra es más importante y la estructura contribuye aún más al significado. La prosa se presta más al análisis que la poesía pero todavía contiene ambigüedad.
Programas
El significado de un programa es inequívoco y literal, y es entendido en su totalidad analizando las unidades léxicas 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 en consecuencia toma más tiempo dominarlos. Además, la estructura es muy importante, entonces usualmente no es una buena idea leerlo de arriba a abajo y de izquierda a derecha. En lugar de ésto, aprenda a separar las diferentes partes en su mente, identificar las unidades léxicas e interpretar la estructura. Finalmente, ponga atención a los detalles. La fallas de puntuación y la ortografía afectarán negativamente la ejecución de su programa.

1.9. El primer programa

Tradicionalmente el primer programa en un lenguaje nuevo se llama “¡Hola todo el mundo!” porque sólo muestra las palabras¡Hola todo el mundo!. En el lenguaje Python es así:

print "¡Hola todo el mundo!"

Este es un ejemplo de una sentencia print , la cual no imprime nada en papel, mas bien muestra un valor. En este caso, el resultado es las palabras:

¡Hola todo el mundo!

Las comillas señalan el comienzo y el final del valor; ellas no aparecen en el resultado.

Algunas personas evalúan la calidad de un lenguaje de programación por la simplicidad del programa¡Hola todo el mundo!. Si seguimos ese criterio, Python cumple con este cometido bastante bien.

1.10. Glosario

algoritmo
Un proceso general para resolver una clase completa de problemas.
análisis sintáctico
Escudriñamiento de un programa y realización del análisis de su estructura sintáctica.
bicho
Un error en un programa.
código de bytes
Un lenguaje intermedio entre el código fuente y el código objeto. Muchos de los lenguajes modernos traducen el código fuente en código de bytes y después interpretan el código de bytes mediante un programa denominado máquina virtual.
código fuente
Un programa escrito en un lenguaje de alto nivel antes de ser compilado.
código objeto
La salida del compilador una vez que el programa ha sido traducido.
compilar
Traducir un programa escrito en un lenguaje de alto nivel a un lenguaje de bajo nivel de una vez, en preparación para la ejecución posterior.
depuración
El proceso de hallazgo y eliminación de los tres tipos de errores de programación.
error de sintaxis
Un error estructural que hace que un programa sea imposible de analizar sintácticamente (e imposible de interpretar).
error en tiempo de ejecución
Un error que no ocurre hasta que el programa ha comenzado su ejecución e impide que éste continue.error semántico:Un error en un programa que hace que se ejecute algo que no era lo deseado.
excepción
Otro nombre para un error en tiempo de ejecución.
guión
Un programa almacenado en un archivo (que usualmente será interpretado).
interpretar
Ejecutar un programa escrito en un lenguaje de alto nivel traduciéndolo línea por línea.
lenguaje de alto nivel
Un lenguaje de programación como Python que está diseñado para ser fácil de leer y escribir.
lenguaje de bajo nivel
Un lenguaje de programación que está diseñado para ser fácil de ejecutar para una computadora; también se le llamalenguaje de máquinaolenguaje ensamblador.
lenguaje formal
Cualquier lenguaje diseñado que tiene un propósito específico, como la representación de ideas matemáticas o programas de computadoras; todos los lenguajes de programación son lenguajes formales.
lenguaje natural
Cualquier lenguaje hablado que evolucionó de forma natural.
portabilidad
La cualidad de un programa que puede ser ejecutado en más de un tipo de computadora.
programa
Secuencia de instrucciones que especifica a una computadora las acciones y cálculos que debe realizar.
programa ejecutable
Otro nombre para el código de objeto que está listo para ser ejecutado.
resolución de problemas
El proceso de plantear un problema, hallar la solución y expresarla.
semántica
El significado de un programa
sentencia print
Una instrucción que causa que el intérprete de Python muestre un valor en el monitor.
sintaxis
La estructura de un programa.
terminal de Python
Interfase interactiva del intérprete de Python. El usuario de la terminal de Python escribe los comandos en el indicador (>>>), y presiona la tecla Entrar para enviar inmediatamente estos comandos al intérprete para su procesamiento.
unidad léxica
Uno de los elementos básicos de la estructura sintáctica de un programa, análogo a una palabra en un lenguaje natural.

1.11. Ejercicios

  1. Escriba en español una oración semánticamente comprensible pero sintácticamente incorrecta. Escriba otra oración que sea sintácticamente correcta pero que contenga errores semánticos.

  2. Inicie la terminal de Python. Escriba 1 + 2 y luego presione la tecla Entrar. Python evalúa esta expresión, presenta el resultado, y enseguida muestra otro indicador. Considerando que el símbolo * es el signo de multiplicación y el doble símbolo ** es el signo de potenciación, realice ejercicios adicionales escribiendo diferentes expresiones y observando lo mostrado por el intérprete de Python. ¿Qué sucede si utiliza el signo de división (/)? ¿Son los resultados obtenidos los esperados? Explique.

  3. Escriba 1 2 y presione la tecla Entrar. Python trata de evaluar esta expresión, pero no puede, porque la expresión es sintácticamente incorrecta. Así, Python responde con el siguiente mensaje de error:

      File "<stdin>", line 1
        1 2
          ^
    SyntaxError: invalid syntax

    Muchas veces Python indica la ubicación del error de sintaxis, sin embargo, no siempre es precisa, por lo que no proporciona suficiente información sobre cuál es el problema. De esta manera, el mejor antídoto es que usted aprenda la sintaxis de Python.

    En este caso, Python protesta porque no encuentra signo de operación alguno entre los números.

    Escriba tres ejemplos adicionales de cadenas que produzcan mensajes de error cuando se introducen en el indicador de Python. Explique por qué cada ejemplo no tiene una sintaxis de Python válida.

  4. Escriba print 'hola'. Python ejecuta esta sentencia que muestra las letras h-o-l-a. Nótese que las comillas simples en los extremos de la cadena no son parte de la salida mostrada. Ahora escriba print '"hola"' y describa y explique el resultado.

  5. Escriba print queso sin comillas. La salida será algo como esto:

    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    NameError: name 'queso' is not defined

    Este es un error en tiempo de ejecución; específicamente, es un NameError, y más específicamente, es un error porque el nombre queso no está definido. Si aún no sabe qué significa esto, lo sabrá pronto.

  6. Escriba 'Esta es una prueba...' en el indicador de Python y presione la tecla Entrar. Observe lo que pasa. Ahora cree un guión de Python con el nombre prueba1.py que contenga lo siguiente (asegúrese de guardar el archivo antes de intentar correrlo):

    'Este es una prueba...'
    

    ¿Qué pasa cuando corre este guión? Ahora cambie el contenido del guión a:

    print 'Este es una prueba...'
    

    y córralo de nuevo.

    ¿Qué pasó esta vez?

    Cuando se escribe una <em>expresión</em> en el indicador de Python, ésta es evaluada y el resultado es mostrado en la línea siguiente. 'Esta es una prueba...' es una expresión, que se evalúa con 'Esta es una prueba...' (de la misma manera que 42 se evalúa con 42). Sin embargo, la evaluación de expresiones en un guión no se envía a la salida del programa, por lo que es necesario mostrarla explícitamente.