Ficha 04 (2016) - Estructuras Condicionales (Python)
Ficha 04 (2016) - Estructuras Condicionales (Python)
Ficha 4
Estructuras Condicionales
1.] Fundamentos.
Todos los problemas y casos de anlisis que hasta aqu hemos presentado tenan en comn
el hecho de ser problemas simples de lgica lineal: el algoritmo para resolver a cualquiera de
esos problemas consista en una estructura secuencial de instrucciones o pasos (es decir, un
conjunto de instrucciones simples como asignaciones, visualizaciones y/o cargas por teclado,
una debajo de la otra). Sin embargo, como pronto veremos, esos casos son poco frecuentes
en la prctica real de la programacin.
En problemas que no sean absolutamente triviales, es muy comn que en algn punto se
requiera comprobar el valor de alguna condicin, y en funcin de ello proceder a dividir la
lgica del algoritmo en dos o ms ramas o caminos de ejecucin. Por ejemplo, en un
programa de control de acceso a un lugar seguro se debe pedir a cada usuario que cargue su
clave de identificacin. El programa entonces debera controlar si la clave cargada es
correcta y slo en ese caso habilitar el paso a esa persona. Pero si la clave fuese incorrecta,
el programa debera tomar alguna medida alternativa, como sacar un mensaje de alerta por
la consola de salida, bloquear una puerta, dar aviso a un supervisor, etc. Pero el hecho es
que si slo se emplean estructuras secuenciales de instrucciones, la situacin anterior no
podra resolverse.
Para casos as, los lenguajes de programacin proveen instrucciones especficamente
diseadas para el chequeo de una o ms condiciones, permitiendo que el programador
indique con sencillez lo que debe hacer el programa en cada caso. Esas instrucciones se
denominan estructuras condicionales, o bien, instrucciones condicionales1.
En general, una instruccin condicional contiene una expresin lgica que puede ser
evaluada por verdadera o por falsa, y dos bloques de instrucciones adicionales designados
en general como la salida o rama verdadera y la salida o rama falsa. Si un programa alcanza
una instruccin condicional y en ese momento la expresin lgica es verdadera, el programa
ejecutar las instrucciones de la rama verdadera (y slo esas). Pero si la expresin es falsa, el
programa ejecutar las instrucciones de la rama falsa (y slo esas). La forma de
funcionamiento tpica de una instruccin condicional se muestra en forma clara en su
representacin de diagrama de flujo (ver Figura 1):
Programar un computador para que sea capaz de responder preguntas hace un poco ms cercana la tarea de
imitar el pensamiento humano con ese computador, lo cual fue el pilar del trabajo y del sueo de Ada Byron. Y
si se trata de sueos combinados con preguntas, en 1968 el escritor Philip Dick public una novela corta de
ciencia ficcin llamada (en espaol): Pueden los androides soar con ovejas elctricas? en la cual se aborda el
tema de la lnea que separa a lo natural de lo artificial. Esta novela inspir el guion de la pelcula Blade Runner
(de 1982, dirigida por Ridley Scott y protagonizada por Harrison Ford y Rutger Hauer) en opinin de este
profesor, la mejor pelcula de ciencia ficcin de todos los tiempos.
falso
Expresin
lgica
Rama falsa
verdadero
Rama verdadera
En el lenguaje Python, una instruccin condicional tpica como la que mostramos en la figura
anterior, se escribe (esquemticamente) as [1]:
if expresin lgica:
instrucciones de la rama verdadera
else:
instrucciones de la rama falsa
Para determinar cul es el mayor entre ambos nmeros, se usa una instruccin condicional
cuya estructura est remarcada en rojo en el ejemplo. En este caso, la expresin lgica que
se evala es a > b, la cual puede ser verdadera o falsa dependiendo de los valores cargados
en a y en b. Si efectivamente el valor de a fuese mayor que el de b, entonces se ejecutar la
instruccin may = a (y slo esa instruccin). Pero si a no fuese mayor que b, entonces el
script saltear la rama verdadera y ejecutar la instruccin que figura en la rama else (la
rama falsa): may = b.
Note que nunca se ejecutan ambas ramas de una instruccin condicional para el mismo lote
de datos: si la expresin lgica es verdadera, se ejecuta la rama verdadera y slo la rama
verdadera, ignorando la rama falsa. Y si la expresin lgica fuese falsa, se ejecutar la rama
falsa (else) y slo la rama falsa, ignorando la rama verdadera.
Observe tambin la forma en que se escribi la instruccin print() de la ltima lnea: se
encolumn a la misma altura de la palabra if con la que abri la instruccin condicional, y no
en la misma columna de las instrucciones de la rama falsa. De esta forma, el programador
est indicando que ese llamado a print() no pertenece a la rama falsa de la condicin, sino
que est completamente fuera de la rama falsa y de la propia condicin. De hecho, en el
script anterior, el print() de la ltima lnea ser ejecutado siempre, sin importar si la
condicin entr por la rama verdadera o por la falsa (se dice por eso que esa instruccin es
de ejecucin incondicional). El diagrama de flujo del script anterior (ver Figura 2) permite
aclarar la idea:
Figura 2: Diagrama de flujo del script del clculo del mayor
Inicio
a, b
a>b
may = b
may = a
may
Fin
El diagrama de la figura anterior muestra en forma exacta el funcionamiento lgico del script
del clculo del mayor: si la expresin a > b es cierta, se ejecutar la instruccin may = a y
luego se mostrar el valor de may; pero si la expresin es falsa, se ejecutar la instruccin
may = b y luego tambin se mostrar el valor de may.
Recuerde que un diagrama de flujo se construye de arriba hacia abajo, tratando de incluir
slo un smbolo debajo de otro, y ahora que aparece la posibilidad de incluir alguna
condicin, es bueno incorporar nuevas convenciones de trabajo:
Por lo pronto, un diagrama de flujo bien planteado debera tener un nico punto
de comienzo y un nico punto de final (como el que se ve en la Figura 2). Slo
debera haber un nico smbolo de Inicio al comienzo y arriba, y un nico smbolo
de Fin al final y abajo.
Los distintos smbolos se conectan entre ellos con lneas rectas verticales. Si
aparece una condicin que abra la lgica en dos o ms ramas, se traza una lnea
horizontal a cada lado, pero apenas se disponga de espacio el trazo debe volver a
ser descendente.
En cada rama el programador debe especificar los procesos a realizar, y apenas le
sea posible debe volver a unir esas ramas en un nico camino descendente, para
llegar en algn momento a un nico final.
Y mantendremos la convencin de que al aparecer una condicin, haremos que la
salida por verdadero est siempre a la derecha, y la salida por falso a la izquierda.
Es muy importante que se comprenda el impacto en Python de escribir cada instruccin con
la indentacin o encolumnado correcto [2]. En otros lenguajes, como C, C++, Pascal o Java,
un bloque de instrucciones se delimita con smbolos o palabras reservadas especiales. Pero
en Pyhton, la pertenencia a un bloque se determina por su indentacin. A modo de ejemplo,
supongamos que el script del clculo del mayor hubiese sido escrito (incorrectamente) as:
a = int(input('A: '))
b = int(input('B: '))
if a > b:
may = a
else:
may = b
print('El mayor es:', may)
En la forma en que est escrito ahora el script, Python asumir que la instruccin print() para
visualizar el valor de may pertenece al bloque de la rama falsa de la instruccin condicional,
y por lo tanto, slo ser mostrado el valor de may en caso de ser falsa la condicin. Si la
condicin fuese verdadera, el script terminar sin mostrar nada en la consola de salida. Para
terminar de entenderlo, vea el diagrama de flujo que correspondera a este script incorrecto
(ver Figura 3).
Como se puede ver en esa figura, la lgica es diferente: en la forma en que fue indentada la
instruccin print() en la segunda versin del script, ser entendida como parte del bloque de
la rama falsa. Si la condicin fuese verdadera, se ejecutar la instruccin may = a, pero luego
el script terminar y no veremos el valor del mayor.
2.] Expresiones lgicas. Operadores relacionales y conectores lgicos.
En una ficha anterior hemos visto que en general, una expresin es una frmula compuesta
por variables y constantes (llamados operandos) y por smbolos que indican la aplicacin de
una accin (llamados operadores). Hemos analizado tambin el uso de los llamados
operadores aritmticos bsicos de Python (suma, resta, producto, etc.) y sabemos que en
funcin de esto, una expresin aritmtica es una expresin cuyo resultado es un nmero.
Todos los problemas y ejemplos que se analizaron en las tres primeras fichas de estudio,
incluan algn tipo de expresin aritmtica.
Figura 3: Diagrama de flujo del script incorrecto del clculo del mayor.
Inicio
a, b
a>b
may = b
may = a
may
Fin
Ahora bien: el hecho de que una expresin entregue como resultado un nmero, se debe a
que los operadores que aparecen en ella son operadores aritmticos y por lo tanto llevan a
la realizacin de alguna operacin cuyo resultado ser numrico. Sin embargo, en todo
lenguaje existen operadores cuya accin no implica la obtencin de un nmero como
resultado, sino, por ejemplo, valores lgicos de la forma verdadero o falso (True o False en
Python) y algunos otros operadores entregarn resultados de otros tipos (cadenas de
caracteres, por ejemplo). En ese sentido, como ya hemos indicado, una expresin lgica es
una expresin cuyo resultado esperado es un valor de verdad (True o False).
Como vimos, las instrucciones condicionales (y otros tipos de instrucciones que veremos,
como las instrucciones repetitivas) se basan tpicamente en chequear el valor de una
expresin lgica para determinar el camino que seguir el programa en su ejecucin. Pero
veremos oportunamente (seccin de Temas Avanzados de esta misma Ficha) que en Pyhton
es posible que la expresin a evaluar no sea necesariamente lgica y sera vlida una
expresin de cualquier tipo. Por razones de simplificacin del anlisis inicial, supondremos
por ahora que la expresin a evaluar en una instruccin condicional ser de tipo lgico.
Para el planteo de expresiones lgicas, todo lenguaje de programacin provee operadores
que implican la obtencin de un valor de verdad como resultado. Los ms elementales son
los llamados operadores relacionales u operadores de comparacin, que en Python son los
siguientes [1]:
Figura 4: Tabla de operadores relacionales (o de comparacin) en Python.
Operador
==
!=
>
<
>=
<=
Significado
igual que
distinto de
Ejemplo
Observaciones
a == b retorna True si a es igual que b, o False en caso contrario
a != b retorna True si a es distinto de b, o False en caso contrario
mayor que
a>b
menor que
a<b
a >= b
a <= b
Ahora bien: si se usan los operadores <, <=, >, o >= para comparar cadenas, Python har lo
que conoce como la comparacin lexicogrfica, que no es otra cosa que la forma de
comparacin de palabras que normalmente aplican las personas cuando intentan ordenar
alfabticamente un conjunto de palabras, o cuando buscan una palabra en un diccionario. En
ese sentido, y para simplificar, si se tienen dos cadenas de caracteres cad1 y cad2 y se
comparan en forma lexicogrfica, entonces cad1 ser considerada menor que cad2 si cad1
estuviese antes que cad2 en un diccionario. Considere a modo de ejemplo el siguiente script
sencillo:
cad1 = 'mesa'
cad2 = 'silla'
if cad1 < cad2:
print('Orden alfabtico:', cad1, cad2)
else:
print('Orden alfabtico:', cad2, cad1)
and
or
not
Significado
conjuncin lgica (y)
disyuncin lgica (o)
negacin lgica (no)
Ejemplo
a == b and y != x
n == 1 or n == 2
not x > 7
Observaciones
ver "Tablas de Verdad" en esta misma seccin
ver "Tablas de Verdad" en esta misma seccin
ver "Tablas de Verdad" en esta misma seccin
p and q
True
True
True
True
False
False
False
True
False
False
False
False
p or q
True
True
True
True
False
True
False
True
True
False
False
False
Podemos ver que en el caso del conector and la salida o respuesta obtenida slo ser
verdadera si las proposiciones conectadas son verdaderas al mismo tiempo, y en todo otro
caso, la salida ser falsa. Por lo tanto, un and es muy til cuando se quiere estar seguro que
todas las condiciones impuestas sean ciertas en un proceso. Por caso, suponga que se
Ing. Valerio Frittelli - 78
cargaron por teclado dos variables sueldo y antiguedad con los datos de un empleado, y se
quiere saber si ese empleado gana ms de 15000 pesos y tiene al mismo tiempo una
antigedad de por lo menos 10 aos, para decidir si se le otorga o no un crdito. Como
ambas condiciones son exigibles a la vez, la pregunta requiere un conector and, y en Python
puede plantearse as:
if sueldo > 15000 and antiguedad >= 10:
print('Crdito concedido')
else:
print('Crdito rechazado')
Note que si alguna de las dos proposiciones fuese falsa, la condicin completa sera falsa y se
activara la rama else, rechazando el crdito. Por supuesto, lo mismo ocurrira si ambas
proposiciones fuesen falsas al mismo tiempo. Slo si ambas fuesen ciertas, la condicin sera
cierta ella misma, y se activara la rama verdadera.
El conector or opera de forma diferente: la salida ser verdadera si al menos una de las
proposiciones es verdadera. Slo si todas las proposiciones al mismo tiempo son falsas, se
obtendr un falso como respuesta. El uso de un or es valioso (por ejemplo) cuando se quiere
determinar si una variable que se acaba de cargar por teclado vale uno de varios posibles
valores que se consideran correctos. Por ejemplo, supongamos que queremos saber si la
variable opcion fue cargada con un 1, un 3, o un 5 (cualquiera de los tres valores es correcto
en este ejemplo). En Python, podemos hacerlo as:
if opcion == 1 or opcion == 3 or opcion == 5:
print('Opcin correcta')
else:
print('Opcin incorrecta')
not p
True
False
False
True
En general, el uso indiscriminado del negador lgico suele llevar a condiciones difciles de
leer y entender por parte de otros programadores, por lo que sugerimos se aplique con
Ing. Valerio Frittelli - 79
cuidado y sentido comn. A modo de ejemplo, supongamos que se tiene una variable edad
con la edad de una persona, y se quiere saber si esa persona tiene al menos 18 aos para
decidir si puede acceder al permiso de conducir. Una forma de hacerlo en Python, sera
preguntar si la edad no es menor que 18:
if not edad < 18:
print('Puede acceder al permiso')
else:
print('No puede acceder al permiso')
Si bien lo anterior es correcto y cumple efectivamente con el requerimiento, queda claro que
la pregunta podra reformularse de forma de eliminar el negador, dejndola ms clara. Slo
debemos notar que preguntar si edad no es menor que 18, es exactamente lo mismo que
preguntar si edad es mayor o igual que 18. El script podra replantearse as:
if edad >= 18:
print('Puede acceder al permiso')
else:
print('No puede acceder al permiso')
3.] Precedencia de ejecucin de los operadores relacionales y de los conectores lgicos.
De esta forma, en cualquier expresin lgica sencilla o compleja el lenguaje agrupar los
trminos y resolver primero las operaciones aritmticas. Luego, aplicar los operadores de
comparacin, y finalmente ejecutar los conectores lgicos.
Sabemos que los operadores aritmticos tienen distinta precedencia (por ejemplo, las sumas
y las restas son de menor precedencia que los productos, los cocientes y los restos) y sern
aplicados de acuerdo a ella, de izquierda a derecha (salvo el operador de exponenciacin
(**) que aplica de derecha a izquierda).
Los operadores relacionales o de comparacin tienen la misma prioridad todos ellos, y sern
aplicados de izquierda a derecha. En particular, en Python es especialmente notable el
hecho de que estos operadores pueden aplicarse en forma idntica a como se hace en la
notacin algebraica normal: una instruccin condicional como:
if a > b > c:
en Python ejecutar sin problemas [1], significando exactamente lo que se quiere hacer:
preguntar si a > b y al mismo tiempo preguntar si b > c. La misma instruccin podra haber
sido escrita as, equivalentemente:
if a > b and b > c:
Adems, es oportuno indicar que tanto el conector and como el or en Python actan en
forma cortocircuitada, lo cual quiere decir que dependiendo del valor de la primera
proposicin evaluada, la segunda (o las restantes a partir de ella) podran no llegar a ser
evaluadas (y esto se deduce y se justifica a partir de las tablas de verdad de ambos
conectores). La idea es la siguiente [1]:
Conector
Ejemplo
and
or
if n < 0 or n > 9:
De acuerdo a las tablas de verdad, es fcil ver que si se tiene un and y la primera proposicin
ya es False, no importar el valor de la segunda: la salida ser False sea cual sea el valor de la
segunda, ya que en un and es suficiente un False en una de ellas para obtener una salida
False. En forma similar, si se tiene un or y la primera proposicin es True, la salida ser True
sin importar el valor de verdad de la segunda. En Python, estos hechos estn ya
incorporados en la forma en que el intrprete trabaja cuando evala una expresin lgica.
Incluso cuando la expresin est planteada en forma algebraica lineal:
if a > b > c:
el intrprete Python chequear la proposicin a > b, y si esta fuese False, no evaluar el valor
de b > c y retornar directamente un False como salida.
Con respecto a los conectores lgicos, el not es de mayor precedencia que el and, y este a su
vez es de mayor precedencia que el or. Si aparecen dos conectores de la misma precedencia,
se aplicarn de izquierda a derecha. Las precedencias pueden esquematizarse as:
precedencia(or) < precedencia(and) < precedencia(not)
Vale decir: si en una misma expresin lgica aparecen varios conectores and, or o not
entremezclados, sin parntesis que cambien las prioridades, los not se aplicarn primero,
luego los and, y finalmente los or. Mnemotcnicamente, puede decirse que el conector not
equivale a un signo menos cambiando el signo en una expresin matemtica, el and equivale
a un producto, y el or a una suma2.
Para el ejemplo que sigue, recuerde que cualquier expresin de cualquier tipo (aritmtica,
lgica, etc.) entrega un resultado y ese resultado puede ser asignado en una variable o usado
en el contexto que se requiera (como una instruccin condicional). En este caso, mostramos
una expresin lgica cuyo valor final (un True o un False) se asigna en la variable r1 (que en
consecuencia ser de tipo boolean) (En el desarrollo del ejemplo mostraremos todas las
evaluaciones de todas las proposiciones, para dejar en claro el orden en que proceden, pero
recuerde que los conectores and y or son cortocircuitados, por lo que algunos de los
chequeos de proposiciones que siguen, podran no llegar a efectuarse realmente):
De hecho, el operador and se designa tambin como el producto lgico, y el operador or como la suma lgica.
Desarrollo
r1 = False
r1 = False
r1 = False
r1 = True
Veamos ahora el mismo ejemplo, pero cambiando las precedencias con parntesis:
# Considere estas variables con estos valores:
a, b, c, d, e = 3, 5, 7, 2, 3
# Ejemplo: valor final asignado en r1: False
r1 = a > b and (c == 3*d or not e != a)
# Desarrollo paso a paso: reemplazo de variables por sus valores
# r1 = 3 > 5 and (7 == 3*2 or not 3 != 3)
# Desarrollo paso a paso: primero los operadores aritmticos
# r1 = 3 > 5 and (7 == 3*2 or not 3 != 3)
# r1 = 3 > 5 and (7 == 6 or not 3 != 3)
# Desarrollo paso a paso: segundo los operadores relacionales
# r1 = 3 > 5 and (7 == 6 or not 3 != 3)
# r1 = False and (False or not False)
#
#
#
#
#
#
Como cierre de esta seccin, considere que una variable de tipo boolean constituye en s
misma una expresin lgica trivial, por lo que si el programador necesita comprobar su valor
en una instruccin condicional no es necesario hacer explcitamente la comparacin
mediante operadores relaciones. La siguiente secuencia de instrucciones:
r1 = a > b and (c == 3*d or not e != a)
if r1 == True:
print('Verdadero...')
else:
print('Falso...')
Pero se puede hacer exactamente lo mismo con una condicin implcita, simplemente
negando el valor de la variable r1 con el operador not (cuya funcin es justamente esa:
invertir la lgica de una comprobacin):
r1 = a > b and (c == 3*d or not e != a)
if not r1:
print('Falso...')
else:
print('Verdadero...')
Tmese un par de minutos para analizar este ltimo script y comprender que es
estrictamente equivalente al anterior: si la variable r1 vale False, el operador not obtendr
un True y la instruccin condicional entrar por la rama verdadera. Y si vale True, el not
obtendr un False y el camino seguir por la salida falsa.
4.] Aplicaciones prcticas bsicas.
Resultados:
Datos:
Procesos:
Problema de ordenamiento de un conjunto. La idea es que dados
los dos nmeros originales n1 y n2, se obtengan otras dos variables men y may
que contengan respectivamente al menor y al mayor de los valores n1 y n2, y
luego se muestren los valores finales de men y may, siempre en ese orden para
lograr la visualizacin ordenada de los datos originales [4].
Esto puede lograrse en forma simple con una instruccin condicional como la que
sugerimos a continuacin:
si n1 >
may
men
sino:
may
men
n2:
= n1
= n2
= n2
= n1
Algoritmo:
1.) Cargar n1 y n2: dos nmeros enteros.
2.) Si n1 > n2:
2.1.) may = n1
2.2.) men = n2
3.) sino:
3.1.) may = n2
3.2.) men = n1
4.) Mostrar men y may: el menor y el mayor, siempre en ese orden.
Inicio
n1, n2
n1 > n2
may = n2
may = n1
men = n1
men = n2
men, may
Fin
c.) Desarrollo del programa: En base al diagrama y/o el pseudocdigo, el script o programa se
deduce en forma simple:
__author__ = 'Ctedra de AED'
# Ttulo general y carga de datos...
print('Problema del ordenamiento de dos nmeros')
n1 = int(input('N1: '))
n2 = int(input('N2: '))
# Procesos...
if n1 > n2:
may = n1
men = n2
else:
may = n2
men = n1
# Visualizacin de resultados..
print('Nmeros ordenados:', men, ' ', may)
La instruccin condicional que aparece en este script sigue fielmente la estructura del
pseudocdigo que mostramos ms arriba. Insistimos en hacer notar la importancia de la
correcta indentacin de las instrucciones, sobre todo las que aparecen en las ramas
verdadera y falsa de la condicin.
Problema 9.) Cargar por teclado tres nmeros enteros. Determinar si el primero que se carg es el
mayor de los tres (informe en pantalla con un mensaje tal como: Es el mayor o No es el mayor).
a.) Identificacin de componentes:
Resultados:
Un mensaje.
Datos:
Procesos:
Problema de determinacin del mayor de un conjunto. Si el
primero de los nmeros se carga en la variable n1, entonces lo que se debe hacer
es comprobar si el valor cargado en n1 result mayor al que se hubiese cargado
en n2 y n3.
Esto puede lograrse en con una instruccin condicional como la que sugerimos a
continuacin, empleando un conector tipo and (o sea, un y lgico):
si n1 > n2 y n1 > n3:
mensaje = 'El primero es el mayor'
sino:
mensaje = 'El primero no es el mayor'
Si la expresin lgica n1 > n2 y n1 > n3 es cierta, entonces el valor almacenado en
n1 es el mayor de los tres (recuerde que un y lgico slo es verdadero si todas las
proposiciones evaluadas son ciertas). En ese caso se asigna en la variable mensaje
la cadena de caracteres 'El primero es el mayor'. Y si la expresin n1 > n2 y n1 > n3
fuese falsa, entonces n1 no contiene al mayor de los tres: al menos uno de los
otros dos nmeros (n2, n3 o ambos) es mayor que n1 (pues el y lgico sali por
falso). En este caso entonces, la variable mensaje es asignada con la cadena 'El
primero no es el mayor'.
b.) Planteo del algoritmo: Mostramos tanto el pseudocdigo como el diagrama de flujo a
continuacin:
Figura 9: Pseudocdigo y diagrama de flujo del problema del ordenamiento de dos nmeros.
Algoritmo:
1.) Cargar n1, n2 y n3: tres nmeros enteros.
2.) Si n1 > n2 y n1 > n3:
2.1.) mensaje = 'El primero es el mayor'
3.) sino:
3.1.) mensaje = 'El primero no es el mayor'
4.) Mostrar mensaje.
Inicio
n1, n2, n3
n1 > n2 y
n1 > n3
mensaje = 'El primero no es el mayor'
mensaje
Fin
c.) Desarrollo del programa: En base al diagrama y/o el pseudocdigo, el script o programa se
deduce en forma simple:
__author__ = 'Ctedra de AED'
# Ttulo general y carga de datos...
print('Problema de determinar si el primero es el mayor')
n1 = int(input('N1: '))
n2 = int(input('N2: '))
n3 = int(input('N3: '))
# Procesos...
if n1 > n2 and n1 > n3:
mensaje = 'El primero es el mayor'
else:
mensaje = 'El primero no es el mayor'
# Visualizacin de resultados..
print('Conclusin:', mensaje)
Note que la instruccin print() que muestra en pantalla el mensaje pedido, est ubicada
luego de la instruccin condicional, cuando la misma ha terminado. Sea cual sea el valor de la
expresin lgica (True o False) la instruccin print() ser ejecutada y el valor de la variable
mensaje se mostrar correctamente.
Problema 10.) Cargar por teclado tres nmeros enteros que se supone representan las edades de
tres personas. Determinar si alguno de los valores cargados era negativ, en cuyo caso informe en
pantalla con un mensaje tal como: Alguna es incorrecta: negativa.Si todos los valores eran positivos
o cero, informe que todas eran correctas.
a.) Identificacin de componentes:
Resultados:
Un mensaje.
Datos:
Procesos:
Problema de validacin de valores de un conjunto. Una vez
cargados los tres valores se puede usar una condicin que chequee cada una de
las variables controlando si su valor es negativo, y usar un conector o lgico para
armar la expresin completa.
Esto puede lograrse en con una instruccin condicional como la que sugerimos a
continuacin:
si n1 < 0 o n2 < 0 o n3 < 0:
mensaje = 'Alguna es incorrecta: negativa'
sino:
mensaje = 'Todas son correctas'
Si la expresin lgica n1 < 0 o n2 < 0 o n3 < 0 es cierta, entonces alguno de los tres
valores es negativo (al menos uno lo es, aunque podran serlo dos de ellos o
incluso los tres). Recuerde que un o lgico es verdadero si al menos una de las
proposiciones evaluadas es cierta. En ese caso se asigna en la variable mensaje la
cadena de caracteres 'Alguna es incorrecta: negativa'. Y si la expresin fuese
falsa, entonces ninguno de los valores era negativo. En este caso la variable
mensaje es asignada con la cadena 'Etodas son correctas'.
b.) Planteo del algoritmo: Mostramos tanto el pseudocdigo como el diagrama de flujo a
continuacin:
Figura 10: Pseudocdigo y diagrama de flujo del problema del ordenamiento de dos nmeros.
Algoritmo:
1.) Cargar n1, n2 y n3: tres nmeros enteros (representan edades).
2.) Si n1 < 0 o n2 < 0 o n3 < 0:
2.1.) mensaje = ' Alguna es incorrecta: negativa '
3.) sino:
3.1.) mensaje = 'Todas son correctas'
4.) Mostrar mensaje.
n1 < 0 o
n2 < 0 o n3 < 0
mensaje = 'Todas son correctas'
mensaje
Fin
c.) Desarrollo del programa: En base al diagrama y/o el pseudocdigo, el script o programa se
deduce en forma simple:
__author__ = 'Ctedra de AED'
# Ttulo general y carga de datos...
print('Problema de determinar si alguna edad es negativa')
n1 = int(input('Edad 1: '))
n2 = int(input('Edad 2: '))
n3 = int(input('Edad 3: '))
# Procesos...
if n1 < 0 or n2 < 0 or n3 < 0:
mensaje = ' Alguna es incorrecta: negativa '
else:
mensaje = 'Todas son correctas'
# Visualizacin de resultados..
print('Resultado del control:', mensaje)
Otra vez, la instruccin print() que muestra en pantalla el mensaje pedido est ubicada luego
de la instruccin condicional, y sea cual sea el valor de la expresin lgica (True o False) la
instruccin print() ser ejecutada y el valor de la variable mensaje se mostrar
correctamente.
3
Para cerrar los temas generales de esta Ficha, introduciremos brevemente la forma prctica
de hacer que un programa en Python genere nmeros al azar (o nmeros aleatorios), lo cual
es de mucha utilidad en aplicaciones que se basan en el desarrollo probabilstico (como por
ejemplo, el desarrollo de juegos de computadora).
En muchos problemas, se requiere poder pedirle al programa que almacene en una o ms
variables algn nmero seleccionado al azar (o al menos, en una forma que no sea
3
Parte del contenido de esta seccin fue aportado por la ing. Romina Teicher en ocasin del planteo del
enunciado general del Trabajo Prctico 1.
predecible por el usuario ni por el mismo programador). Esto se conoce como generacin de
nmeros aleatorios (o nmeros random) y en general, todo lenguaje de programacin
provee un cierto nmero de funciones predefinidas que permiten hacer esto en forma
aceptable.
Conceptualmente hablando, estas funciones no generan realmente nmeros en forma
completamente aleatoria, sino que se basan en algn algoritmo que partiendo de un valor
inicial (llamado el valor semilla o seed del generador) es capaz de generar una secuencia de
aspecto aleatorio para cualquiera que no conozca el valor inicial (lo cual suele ser suficiente
para aplicaciones generales que requieran algn nivel de aleatoriedad, como los video
juegos). Esto se conoce como generacin de nmeros pseudo-aleatorios y en general los
lenguajes de programacin suelen tomar ese valor semilla desde el reloj interno del sistema.
Dejando de lado estos elementos (que por ahora tomaremos como tecnicismos), en Python
existe lo que se conoce como un mdulo (o una librera) llamado random, que contiene las
definiciones y funciones necesarias para poder acceder a la gestin de nmeros pseudoaleatorios [1]. Veremos en una ficha posterior la forma de gestionar mdulos en Python,
pero por ahora baste con saber que para poder usar el contenido del mdulo random en un
programa, debe usarse la instruccin import random al inicio del script en donde se requiera.
Luego de esto, el programa podr acceder a las funciones contenidas en ese mdulo
invocando a esas funciones pero precediendo la invocacin con el prefijo "random." A modo
de ejemplo, el siguiente script sencillo obtiene un valor aleatorio entre 0 y 1 con la funcin
random.random(), lo almacena en una variable x, y finalmente lo muestra:
__author__ = 'Ctedra de AED'
import random
x = random.random()
print(x)
El mdulo random provee muchas otras funciones para manejo de nmeros pseudoaleatorios, que en este momento escapan al alcance de lo visto hasta ahora en el curso. Sin
embargo, queda al menos una que puede ser de inters inmediato: La funcin
random.choice(sec) acepta como parmetro una secuencia (que aqu llamamos sec) (o sea,
una tupla, una cadena, una lista, etc.) y retorna un elemento cualquiera de esa secuencia,
elegido al azar. El siguiente script usa dos veces esta funcin: la primera vez para obtener al
azar un nmero cualquiera de la tupla sec1 = 2, 10, 7, 9, 3, 4 y la segunda vez para obtener
al azar una letra cualquiera de la cadena sec2 = 'ABCDEFGHI':
__author__ = 'Ctedra de AED'
import random
sec1 = 2, 10, 7, 9, 3, 4
r1 = random.choice(sec1)
print(r1)
sec2 = 'ABCDEFGHI'
r2 = random.choice(sec2)
print(r2)
Para finalizar esta seccin, mostramos nuevamente el programa que calcula ordena dos
nmeros (problema 8 en esta misma Ficha), pero modificado levemente para que los dos
nmeros de entrada sean generados en forma aleatoria (tomando nmeros entre 1 y 10), en
lugar de ser cargados por teclado:
__author__ = 'Ctedra de AED'
import random
# Ttulo general y generacin de datos...
print('Problema del ordenamiento de dos nmeros')
print('(los numeros de entrada son generados aleatoriamente...')
n1 = random.randint(1,10)
n2 = random.randint(1,10)
# Procesos...
if n1 > n2:
may = n1
men = n2
else:
may = n2
men = n1
# Visualizacin de resultados..
print('Nmeros ordenados:', men, ' ', may)
Hemos visto a lo largo de las secciones de esta Ficha la forma de plantear una instruccin
condicional en Python y hemos indicado que en general, la forma tpica de una instruccin
condicional incluye una expresin lgica cuyo valor True o False determina el camino que
seguir la ejecucin del programa. Hemos indicado adems, que una expresin lgica es una
frmula cuyo resultado es un valor de verdad, y este hecho surge de la utilizacin de
operadores relacionales (o de comparacin) combinados eventualmente con conectores
lgicos.
Esto es: si se aplican operadores relacionales y conectores lgicos, la expresin entregar un
resultado True o False y ser por ello una expresin lgica. Sin embargo, debemos hacer
notar que en Python pueden combinarse estos operadores en formas que podran resultar
extraas para los programadores poco experimentados. Esta seccin del anexo de Temas
Avanzados est dedicada a estudiar esas aplicaciones.
Especficamente, en Python, la aplicacin de conectores lgicos (u operadores booleanos)
como and, or o not hace que todo operando (constantes o variables) sea considerado como
booleano, incluso si su valor inicial no es de tipo boolean. En ese sentido, en una expresin
que contenga operadores booleanos, Python asumir que los siguientes valores equivalen a
un False [1]:
False
None
n:
Insistimos: en este ltimo ejemplo la variable n est siendo usada directamente en el lugar
donde Python esperara una expresin lgica, y por lo tanto, el valor de n es interpretado
segn ese contexto en forma booleana: si su valor fuese cero, Python lo tomar como un
False y activar la rama falsa de la instruccin condicional; pero si n valiese cualquier otro
nmero, Python lo interpretar como un True, activando la rama verdadera.
En forma similar, si la variable analizada fuese una cadena de caracteres, una tupla, una lista
u otro tipo de contenedor o variable estructurada se puede chequear en forma implcita si
esa variable est vaca o no. En el script siguiente, la variable cad representa una cadena de
caracteres (que asignamos en forma fija para hacer ms claro el ejemplo) y se chequea en
forma explcita si cad realmente contiene una cadena o est vaca (la cadena vaca se
representa en Python con la constante '' (dos comillas simples sin ningn caracter entre
ellas) o bien con la constante "" (dos comillas dobles sin ningn caracter entre ellas)):
cad = 'Hola'
if cad != '':
print('La cadena es:', cad)
else:
print('La cadena est vaca')
Pero como queda dicho, la cadena vaca ser interpretada por Python como un False en un
contexto lgico, por lo cual el script podra replantearse as, mediante una condicin
implcita:
cad = 'Hola'
if cad:
print('La cadena es:', cad)
else:
print('La cadena est vaca')
Como dijimos, el uso de conectores lgicos and, or y not convierte la expresin analizada en
una expresin lgica, sean cuales sean los tipos de las variables sobre las que se aplican
estos conectores, y sin importar el contexto. Un caso trivial pero muy ilustrativo ayuda a
comenzar a entender la idea:
a = 10
b = not a
print('b: ', b)
En el pequeo script anterior la variable a contiene un valor numrico (el 10) y por lo tanto,
no es booleana. Sin embargo, en la segunda lnea se aplica sobre ella el operador booleano
not, y se asigna en la variable b el resultado de la negacin lgica de a. Podra parecer que
esto no tiene sentido, pero en Python lo tiene: la aparicin del operador booleano not hace
que la expresin not a sea considerada como lgica, y por lo tanto el valor de la variable a
ser interpretado en forma booleana y no en forma numrica. Dado que el valor de a es 10,
en un contexto booleano como es este, Python lo interpretar como un True (ya que es
diferente de cero) y al negar ese valor con not, el resultado asignado en b ser un False. La
ejecucin de este script producir la siguiente salida en consola estndar:
b:
False
Por cierto, note que no es lo mismo hacer b = not a que hacer b = -a. La primera asignacin,
como vimos, toma el valor de a en forma booleana y asigna en b un False si a vala 10 o
cualquier otro nmero diferente de cero. Pero la segunda asignacin toma el valor de a y
cambia su signo, por lo que si a vala 10, el valor asignado en b ser un -10.
Y a partir de todo lo expuesto, prcticamente cualquier expresin que incluya operadores
booleanos ser vlida en una instruccin condicional o en cualquier otra que espere una
expresin lgica: los operadores booleanos and, or y not convertirn esa expresin en una
expresin lgica aplicando los criterios de transformacin de valores no booleanos en
booleanos segn vimos al inicio de esta seccin. A modo de ejemplo de cierre, analicemos
este modelo en el cual se asigna en la variable r el resultado (False) de una expresin lgica
basada en las ideas que hemos expuesto.
a, b, c, d, e = 10, 4, 5, 5, 3
#
r
#
r
#
#
r
r
#
#
r
r
#
#
r
r
El estudio y sistematizacin de las operaciones lgicas como and, or y not, forma parte de la
rama de la Matemtica denominada lgebra de Boole, la que toma su nombre del
matemtico ingls George Boole que fue quien sent sus bases en 1847. El planteo inicial fue
simplemente el de intentar generalizar las tcnicas del lgebra para el tratamiento de la
lgica proposicional, pero a lo largo del tiempo evolucion y hoy se utiliza ampliamente en el
campo de la electrnica, especficamente en el diseo de circuitos.
Como hemos visto en toda esta Ficha, los elementos fundamentales del lgebra de Boole se
utilizan tambin en el rea de la programacin de computadoras, ya que est contenida en
el planteo de las expresiones lgicas que se usan para el control de instrucciones tales como
las condicionales y las repetitivas, entre otras. El planteo y estudio de las ya citadas tablas de
verdad, y la demostracin de teoremas y propiedades relativas a la aplicacin de los
operadores booleanos, forman parte de esta disciplina.
Hemos visto que el planteo de expresiones lgicas que combinen operadores booleanos,
operadores relacionales, operadores aritmticos y variables y constantes de distintos tipos,
puede dar lugar a frmulas de aspecto realmente intimidante que podran poner a cualquier
programador (experto o inexperto) en serios problemas para interpretarlas correctamente.
Es comn encontrarse con casos de programas en fase de desarrollo que muestran fallas
ms o menos graves debidas al planteo incorrecto de una o ms expresiones lgicas. Por lo
tanto, uno de los tantos trabajos que un buen programador debe saber llevar a cabo, es el
de simplificar expresiones lgicas, de forma que la expresin simplificada sea ms clara, ms
breve, menos extensa y ms simple de entender (lo cual lleva a que finalmente sea ms
simple de modificar o ajustar si fuese el caso).
En esa direccin apuntan algunas reglas y teoremas del lgebra de Boole. Dos de esas reglas
son muy conocidas y aplicadas en la simplificacin de expresiones lgicas y en el diseo de
not(p and q)
not p or not q
not(p or q)
True
True
False
False
False
False
True
False
True
True
False
False
False True
True
True
False
False
False False
True
True
True
True
2.] Negacin de un or
Como se ve, las columnas 3 y 4 son equivalentes entre s y justamente esas columnas
corresponden a las expresiones de la regla 1 (negacin de un and). Y a su vez tambin las
columnas 5 y 6 son equivalentes entre s, correspondiendo ambas a las expresiones de la
regla 2 (negacin de un or).
La utilidad prctica de estas dos reglas en programacin se hace evidente por medio de un
ejemplo: Sin importar los valores que asuman las variables, supongamos una expresin
lgica como la que sigue:
r = not(a < b and c != b and d >= e and c <= 0)
En principio, no hay mayor problema en dejarla como est, pero el planteo en base a un not
inicial suele producir confusin, ya que el programador debe pensar la expresin completa
sin el negador, y finalmente negar la salida para terminar de verla. Dado que esta expresin
es la negacin de un encadenamiento de proposiciones con el conector and, se puede aplicar
la regla 1 de De Morgan, e intentar eliminar el negador inicial. En el consabido proceso "paso
a paso" que sigue, mostramos como se va reduciendo la expresin, hasta llegar a la versin
Ing. Valerio Frittelli - 95
final, ms simple (y siempre recuerde que tanto el and como el or son cortocircuitados, por
lo que en realidad, alguna de las proposiciones siguientes podra no llegar a chequearse
cuando sea ejecutada):
# Expresin inicial...
r = not(a < b and c != b and d >= e and c <= 0)
# Aplicar De Morgan regla 1... (no parece que ganemos nada...)
r = not a < b or not c != b or not d >= e or not c <= 0
# Reducir los not individuales... y entonces s...
# Expresin final, equivalente a la inicial, pero ms simple...
r = a >= b or c == b or d < e or c > 0
Crditos
El contenido general de esta Ficha de Estudio fue desarrollado por el Ing. Valerio Frittelli, para ser
utilizada como material de consulta general en el cursado de la asignatura Algoritmos y Estructuras
de Datos Carrera de Ingeniera en Sistemas de Informacin UTN Crdoba, en el ciclo lectivo 2016.
Actuaron como revisores (indicando posibles errores, sugerencias de agregados de contenidos y
ejercicios, sugerencias de cambios de enfoque en alguna explicacin, etc.) en general todos los
profesores de la citada asignatura como miembros de la Ctedra, y particularmente los ingenieros
Gustavo Federico Bett, Germn Romani, Marina Cardenas, Anala Guzmn, Julieta Fernndez, Karina
Ligorria y Romina Teicher, que realizaron aportes de contenidos, propuestas de ejercicios y sus
soluciones, y sugerencias de estilo de programacin, entre otros elementos.
Bibliografa
[1] Python Software Foundation, "Python Documentation,"
https://docs.python.org/3/. [Accessed 24 February 2016].
2015.
[Online].
Available:
[2] M. Pilgrim, "Dive Into Python - Python from novice to pro," 2004. [Online]. Available:
http://www.diveintopython.net/toc/index.html. [Accessed 6 March 2016].
[3] E. Gentile, Notas de lgebra I, Buenos Aires: Eudeba, 1976.
[4] V. Frittelli, Algoritmos y Estructuras de Datos, Crdoba: Universitas, 2001.