4. Condicionales

4.1. El operador módulo

El operador módulo funciona con enteros (y expresiones enteras), y devuelve el residuo de dividir el primer operando entre el segundo. En Python, el operador módulo es el signo de tanto por ciento (%). La sintaxis es la misma que para otros operadores:

>>> cociente = 7 / 3
>>> print cociente
2
>>> residuo = 7 % 3
>>> print residuo
1

Así que 7 dividido entre 3 da 2 con residuo 1.

El operador residuo resulta ser sorprendentemente ú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 manera similar, x % 100 devuelve los dos últimos dígitos.

4.2. Expresiones y valores booleanos

El almacenamiento de valores verdaderos y falsos en Python es del tipo bool, nombrado así debido al matemático Británico George Boole. George Boole creó el Algebra booleana, que es la base de toda la aritmética computacional moderna.

Solo hay dos valores booleanos: True y False. Las mayúsculas son importantes, ya que true y false no son valores booleanos. La traducción al español de true y false es verdadero y falso, respectivamente.

>>> type(True)
<type 'bool'>
>>> type(true)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'true' is not defined

Una expresión booleana es una expresión cuya evaluación produce un valor booleano. El operador == compara dos valores y produce un valor booleano:

>>> 5 == 5
True
>>> 5 == 6
False

En la primera sentencia, los dos operandos son iguales, así que la evaluación de la expresión produce True; en la segunda sentencia, 5 no es igual a 6, así que obtenemos False.

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 <= y     # x es menor o igual que y

Aunque probablemente estas operaciones le resulten familiares, los símbolos en Python son diferentes de los matemáticos. Un error habitual es utilizar un signo igual sencillo (=) en lugar del doble (==). Recuerde que el símbolo = es un operador de asignación y que el símbolo == es un operador de comparación. Además, en Python no existe el símbolo =< ni el símbolo =>.

4.3. Operadores lógicos

Existen tres operadores lógicos: and, or, y not. La semántica (significado) de estos operadores es similar a sus significados en inglés (en español “y”, “o” y “no”). Por ejemplo, x > 0 and x < 10 es verdadero sólo si x es mayor que 0 y menor que 10.

n % 2 == 0 or n % 3 == 0 es verdadero si cualquiera de las condiciones es verdadera, o sea, si el número es divisible por 2 o por 3.

Finalmente, el operador not niega una expresión booleana, de forma que not(x > y) es verdadero si (x > y) es falso, o sea, si x es menor o igual que y.

4.4. Ejecución condicional

Para escribir programas útiles, casi siempre necesitamos la capacidad de comprobar ciertas condiciones y cambiar el comportamiento del programa como corresponda. 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 que sigue a la sentencia if se llama condición. Si es verdadera, entonces la sentencia sangrada se ejecuta. Si no lo es, no pasa nada.

La sintaxis para una sentencia if se ve así:

if EXPRESION BOOLEANA:
    SENTENCIAS

Así como la definición de función del capítulo anterior y otras sentencias compuestas, la sentencia if consiste de un encabezado y un cuerpo. El encabezado empieza con la palabra reservada if seguida por una expresión booleana y termina con dos puntos (:).

Al conjunto de sentencias sangradas que siguen se le llama bloque. La primera sentencia no sangrada marca el fin del bloque. Un bloque de sentencias dentro de una sentencia compuesta recibe el nombre de cuerpo de la sentencia.

Cada una de las sentencias dentro del cuerpo se ejecuta en orden si la expresión booleana produce el valor True. El bloque completo es ignorado si la expresión booleana produce el valor False.

No hay límite en el número de sentencias que puede 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 código que todavía no ha escrito). En ese caso puede usar la sentencia pass, que no hace nada.

if True:          # Esto siempre es verdadero
    pass          # por lo que esto siempre se ejecuta, pero 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 se ve así:

if x % 2 == 0:
    print x, "es par"
else:
    print x, "es impar"

Si el residuo de dividir x entre 2 es 0, entonces sabemos que x es par, y el programa muestra un mensaje anunciando esto. Si la condición es falsa, la segunda sentencia se ejecuta. Puesto que la condición debe ser verdadera o falsa, se ejecutará exactamente una de las alternativas. Estas alternativas se denominan ramas, porque son ramas en el flujo de ejecución.

Como comentario al margen, si piensa que querrá comprobar con frecuencia la paridad (pares o nones) de números, quizá desee “envolver” este código en una función:

def muestra_paridad(x):
    if x % 2 == 0:
        print x, "es par."
    else:
        print x, "es non."

Para cualquier valor de x, la función muestra_paridad produce un mensaje apropiado. Cuando se llama a la función, se le puede pasar cualquier expresión entera como argumento.

>>> muestra_paridad(17)
17 es non.
>>> y = 41
>>> muestra_paridad(y+1)
42 es par.

4.6. Condicionales encadenadas

A veces hay más de dos posibilidades y necesitamos más de dos ramas. Una forma de expresar tal cómputo es una condicional encadenada:

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 es opcional) y debe ser la última rama de la sentencia:

if eleccion == 'a':
    funcion_a()
elif eleccion == 'b':
    funcion_b()
elif eleccion == 'c':
    funcion_c()
else:
    print "Elección inválida."

Las condiciones se comprueban en orden. Si la primera es falsa, se comprueba la siguiente, y así se sigue con las demás. 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.

4.7. Condicionales anidadas

Una condicional puede estar anidada dentro de otra. Podríamos haber escrito el ejemplo de tricotomía como sigue:

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 condicional externa contiene dos ramas. La primera rama contiene una sentencia simple de salida. La segunda rama contiene otra sentencia if, que tiene dos ramas propias. Estas dos ramas son ambas sentencias de salida, aunque podrían ser igualmente sentencias condicionales.

Aunque el sangrado de las sentencias hace la estructura evidente, las condicionales anidadas muy pronto se vuelven difíciles de leer. En general es una buena idea evitarlas cuando pueda.

Los operadores lógicos proporcionan a menudo formas de simplificar las sentencias condicionales anidadas. Por ejemplo, podemos reescribir el siguiente código con un sólo condicional:

if 0 < x:
    if x < 10:
        print "x es un número positivo de un solo dígito."

La sentencia print sólo se ejecuta si conseguimos superar ambas condicionales, así que podemos usar el operador and:

if 0 < x and x < 10:
    print "x es un número positivo de un solo dígito."

Este tipo de condiciones son comunes, 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 solo dígito."

Semánticamente esta condición es la misma que la expresión booleana compuesta y que la condicional anidada.

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:

def muestra_raiz_cuadrada(x):
    if x <= 0:
        print "Por favor, use sólo números positivos."
        return

    resultado = x**0.5
    print "La raíz cuadrada de x es", resultado

La función muestra_raiz_cuadrada toma un parámetro llamado x. Lo primero que hace es comprobar si x es menor o igual que cero, en cuyo caso muestra un mensaje de error y luego usa return para salir de la función. El flujo de la ejecución vuelve inmediatamente a la sentencia de llamada a función y no se ejecutan las líneas restantes de la función.

4.9. Entrada por teclado

En Introducción de datos vimos las funciones de biblioteca de Python que reciben entradas desde el teclado: raw_input e input. Veamos ahora estas funciones con mayor detalle.

Cuando alguna de estas funciones es llamada, el programa se detiene y espera que el usuario escriba algo. Cuando el usuario presiona la tecla Retorno o Entrar, el programa se reanuda y raw_input devuelve como tipo cadena (str) lo que el usuario escribió:

>>> mi_entrada = raw_input()
¿Qué estás esperando?
>>> print mi_entrada
¿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. Podemos proporcionarle un indicador a raw_input como argumento:

>>> nombre = raw_input("¿Cómo te llamas? ")
¿Cómo te llamas? Arturo, ¡Rey de los británicos!
>>> print nombre
Arturo, ¡Rey de los británicos!

Note que el indicador es una cadena, por lo que debe ir encerrada entre paréntesis.

Si esperamos que la respuesta sea un entero, podemos usar la función input que evalúa la respuesta como una expresión de Python:

indicador = "¿Cuál es la velocidad de una golondrina sin carga?\n"
velocidad = input(indicador)

Si el usuario escribe una cadena de números, se convertirá en un entero y se asignará a velocidad. Por desgracia, si el usuario escribe caracteres que no sean una expresión válida de Python, el programa dará un error:

>>> velocidad = input(indicador)
¿Cuál es la velocidad de una golondrina sin carga?
¿Se refiere a la golondrina europea o a la africana?
...
SyntaxError: invalid syntax

Si en este último ejemplo el usuario hubiese escrito una expresión válida de Python colocando comillas en su respuesta, no habría obtenido un error:

>>> velocidad = input(indicador)
¿Cuál es la velocidad de una golondrina sin carga?
"¿Se refiere a la golondrina europea o a la africana?"
>>> velocidad
'¿Se refiere a la golondrina europea o a la africana?'
>>>

Para evitar este tipo de error, es buena idea usar raw_input para obtener una cadena y usar entonces las funciones de conversión para transformarla en otros tipos.

4.10. Conversión de tipos

Cada tipo en Python viene con un comando de biblioteca que convierte los valores de un tipo en el tipo asociado al comando. El comando int(ARGUMENTO), por ejemplo, toma cualquier valor y lo convierte, si es posible, en un entero, si no, dará un mensaje de error:

>>> int("32")
32
>>> int("Hola")
ValueError: invalid literal for int() with base 10: 'Hola'

El comando int también puede convertir valores de punto flotante en enteros, pero recuerde que este comando trunca las fracciones:

>>> int(-2.3)
-2
>>> int(3.99999)
3
>>> int("42")
42
>>> int(1.0)
1

El comando float(ARGUMENTO) convierte enteros y cadenas en números de punto flotante:

>>> float(32)
32.0
>>> float("3.14159")
3.14159
>>> float(1)
1.0

Pareciera extraño que Python distinga el valor entero 1 del valor en punto flotante 1.0; son el mismo número, pero pertenecen a tipos distintos. La razón es que se representan en la computadora de manera diferente.

El comando str(ARGUMENTO) convierte cualquier argumento dado, en tipo cadena (str):

>>> str(32)
'32'
>>> str(3.14149)
'3.14149'
>>> str(True)
'True'
>>> str(true)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'true' is not defined

El comando str(ARGUMENTO) trabaja con cualquier valor y lo convierte en una cadena. Como se mencionó antes, True es un valor booleano; true no lo es.

La situación es especialmente interesante para valores booleanos:

>>> bool(1)
True
>>> bool(0)
False
>>> bool("¡No!")
True
>>> bool("")
False
>>> bool(3.14159)
True
>>> bool(0.0)
False

Python asigna valores booleanos a los valores de otros tipos. Para tipos numéricos como enteros y de punto flotante, los valores cero son valores falsos y los valores diferentes de cero son valores verdaderos. Para cadenas, las cadenas vacías son falsas y las no vacías son verdaderas.

4.11. GASP

GASP (Graphics API for Students of Python - Gráficas API para Estudiantes de Python) nos permitirá escribir programas que involucren gráficas. Antes de se puede utilizar el GASP, se necesita instalarlo en su máquina. Si está ejecutando Ubuntu GNU/Linux, véase GASP en Apéndice A.

Para iniciar gasp intente lo siguiente:

>>> from gasp import *
>>> begin_graphics()
>>> Circle((200, 200), 60)
Circle instance at (200, 200) with radius 60
>>> Line((100, 400), (580, 200))
Line instance from (100, 400) to (590, 250)
>>> Box((400, 350), 120, 100)
Box instance at (400, 350) with width 120 and height 100
>>> end_graphics()
>>>

Antes del último comando, que cierra la ventana de gráficos, debería verla luciendo así:

GASP ilustración 1

A partir de ahora estaremos usando gasp para ilustrar (en el más amplio sentido de la palabra) los conceptos de programación de computadoras, y para divertirnos mientras aprendemos.

4.12. Glosario

operador módulo
Operador que, denotado por el signo de tanto por ciento (%), trabaja sobre enteros y devuelve el residuo cuando un número es dividido por otro.
valor booleano
Existen exactamente dos valores booleanos: True y False. Los valores booleanos se obtienen cuando una expresión booleana es evaluada por el intérprete de Python. Estos valores son del tipo bool.
expresión booleana
Una expresión que es falsa o verdadera.
operador de comparación
Uno de los operadores que comparan dos valores: ==, !=, >, <, >=, y <=.
operador lógico
Uno de los operadores que combinan expresiones booleanas: and, or, y not.
sentencia condicional
Sentencia que controla el flujo de ejecución dependiendo de cierta condición. En Python las palabras reservadas if, elif, y else son usadas por las sentencias condicionales.
condición
En una sentencia condicional es una expresión booleana que determina cuál rama se ejecutará.
bloque
Grupo de sentencias consecutivas con el mismo sangrado.
cuerpo
En una sentencia compuesta es el bloque que está después del encabezado.
rama
Uno de los posibles caminos del flujo de ejecución determinado por la ejecución condicional.
condicional encadenada
Rama condicional con más de dos posibles flujos de ejecución. En Python las condicionales encadenadas se escriben con las sentencias if ... elif ... else.
anidamiento
Estructura de un programa dentro de otra, tal como una sentencia condicional dentro de una rama de otra sentencia condicional.
indicador
Indicación visual que invita al usuario a introducir datos.
conversión de tipos
Sentencia explícita que toma un valor de un tipo y calcula el valor correspondiente a otro tipo.

4.13. Ejercicios

  1. Intente evaluar mentalmente las siguientes expresiones numéricas, luego use el intérprete de Python para verificar sus respuestas:

    1. >>> 5 % 2
    2. >>> 9 % 5
    3. >>> 15 % 12
    4. >>> 12 % 15
    5. >>> 6 % 6
    6. >>> 0 % 7
    7. >>> 7 % 0

    ¿Qué pasó con el último ejemplo? ¿Por qué? Si pudo anticipar correctamente todas las respuestas de la computadora — excepto la última, es el momento de continuar con los demás ejercicios, si no, tómese un tiempo para realizar ejemplos similares por su cuenta. Explore el operador módulo hasta que tenga plena confianza que ha entendido cómo funciona.

  2. 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"
    

    Envuelva este código en una función llamada comparar(x, y). Llame a la función comparar tres veces: una en la que el primer argumento sea menor que el segundo, otra en la que aquel sea mayor que éste, y una tercera en la que los argumentos sean iguales.

  3. Para entender mejor las expresiones booleanas es útil la construcción de tablas de verdad. Dos expresiones booleanas son lógicamente equivalentes si y solo si tienen la misma tabla de verdad.

    El siguiente guión de Python muestra la tabla de verdad para cualquier expresión booleana de dos variables, p y q:

    expresion = raw_input("Introduzca una expresión booleana de dos variables, p y q: ")
    
    print " p      q      %s"  % expresion
    longitud = len( " p      q      %s"  % expresion)
    print longitud*"="
    
    for p in True, False:
        for q in True, False:
            print "%-7s %-7s %-7s" % (p, q, eval(expresion))
    

    En capítulos posteriores usted aprenderá cómo trabaja este guión. Por ahora lo usará para aprender sobre expresiones booleanas. Copie este programa en un archivo llamado p_y_q.py, luego ejecútelo desde la línea de comandos, y cuando el indicador solicite una expresión booleana escriba: p or q. Debería obtener la siguiente salida:

     p      q      p or q
    =====================
    True    True    True
    True    False   True
    False   True    True
    False   False   False

    Ahora que sabemos cómo trabaja el guión, pongámoslo en una función para facilitar su uso:

    def tabla_de_verdad(expresion):
        print " p      q      %s"  % expresion
        longitud = len( " p      q      %s"  % expresion)
        print longitud*"="
    
        for p in True, False:
            for q in True, False:
                print "%-7s %-7s %-7s" % (p, q, eval(expresion))
    

    Luego podemos importar el archivo en una terminal de Python y llamar la función tabla_de_verdad con una cadena que contenga nuestra expresión booleana con p y q como argumento:

    >>> from p_y_q import *
    >>> tabla_de_verdad("p or q")
     p      q      p or q
    =====================
    True    True    True
    True    False   True
    False   True    True
    False   False   False
    >>>
    

    Use la función tabla_de_verdad con las siguientes expresiones booleanas, guardando la tabla de verdad producida cada vez:

    1. not(p or q)
    2. p and q
    3. not(p and q)
    4. not(p) or not(q)
    5. not(p) and not(q)

    ¿Cuáles de estas expresiones son lógicamente equivalentes?

  4. Introduzca las siguientes expresiones en la terminal de Python:

    True or False
    True and False
    not(False) and True
    True or 7
    False or 7
    True and 0
    False or 8
    "feliz" and "triste"
    "feliz" or "triste"
    "" and "triste"
    "feliz" and ""
    

    Analice los resultados. ¿Qué observaciones tiene sobre los diferentes tipos de valores y los operadores lógicos? ¿Puede escribir sus observaciones en forma de reglas simples sobre las expresiones que usan and y or?

  5. if eleccion == 'a':
        funcion_a()
    elif eleccion == 'b':
        funcion_b()
    elif eleccion == 'c':
        funcion_c()
    else:
        print "Elección inválida."
    

    Envuelva este código en una función llamada aviso(eleccion). Luego defina las funciones funcion_a, funcion_b, y funcion_c de forma tal que muestren un aviso de que fueron llamadas. Por ejemplo:

    def funcion_a():
        print "la funcion_a fue llamada..."
    

    Coloque las cuatro funciones (aviso, funcion_a, funcion_b, y funcion_c) en un guión llamado cap4ejer5.py. Al final de este guión agregue una llamada a aviso('b'). Su salida debería ser:

    la funcion_b fue llamada...

    Finalmente, modifique el guión para que el usuario pueda introducir ‘a’, ‘b’, o ‘c’. Pruébelo importando su guión en la terminal de Python.

  6. Escriba una función llamada es_divisible_entre_3 que tome un valor entero como un argumento y muestre “Este número es divisible entre tres.” si el argumento es exactamente divisible entre 3, y que muestre “Este número no es divisible entre tres.” en caso contrario.

    Ahora escriba una función similar llamada es_divisible_entre_5.

  7. Generalice las funciones que escribió en el ejercicio anterior en una función llamada es_divisible_entre_n(x, n) que tome dos enteros como argumentos y muestre cuándo el primero es divisible por el segundo y cuándo no. Guarde esta función en un archivo llamado cap04e07.py. Importe el archivo en una terminal y úselo. Una muestra de su sesión sería:

    >>> from cap04e07 import *
    >>> es_divisible_entre_n(20, 4)
    Sí, 20 es divisible entre 4
    >>> es_divisible_entre_n(21, 8)
    No, 21 no es divisible entre 8
    

    ¿Cuál será la salida de lo siguiente?

    if "¡No!":
        print 'Somos los caballeros que dicen "¡No!"'
    else:
        print "¡Basta! ¡No más!"
    
    if 0:
        print "Y ahora algo completamente diferente..."
    else:
        print "Entonces, ¿qué es todo esto?"
    

    Explique qué sucede y por qué sucede.

  8. El siguiente guión de gasp — escrito en un archivo llamado casa.py — dibuja una casa simple en una ventana de gasp:

    from gasp import *          # importa todas las funciones del módulo gasp
    
    begin_graphics()            # abre la ventana de gráficos
    
    Box((20, 20), 100, 100)     # la casa
    Box((55, 20), 30, 50)       # la puerta
    Box((40, 80), 20, 20)       # la ventana izquierda
    Box((80, 80), 20, 20)       # la ventana derecha
    Line((20, 120), (70, 160))  # la azotea izquierda
    Line((70, 160), (120, 120)) # la azotea derecha
    
    update_when('key_pressed')  # mantiene la ventana abierta hasta que
    end_graphics()              # presione una tecla cierra la ventana (lo
                                # que pasará de cualquier manera puesto que
                                # el guión termina aquí, pero es mejor ser
                                # explícito).
    

    Ejecute este guión y confirme que obtiene una ventana que se ve como esta:

    GASP ilustración 1
    1. Envuelva el código de la casa en una función que se llame dibuja_casa().
    2. Ahora ejecute el guión. ¿Ve la casa? ¿Por qué no?
    3. Agregue una llamada a dibuja_casa() al final del guión, tal que la casa vuelva a la pantalla.
    4. Parametrice la función con los parámetros x y y — el encabezado debería ser def dibuja_casa(x, y):, de forma tal que pueda pasar la localización de la casa a la ventana de gasp.
    5. Use dibuja_casa para ubicar cinco casas en la ventana de gasp en diferentes localizaciones.