Saltar a contenido

Condicionales

Banner

Imagen generada con Inteligencia Artificial

En esta sección estudiaremos las sentencias if y match-case de Python junto a las distintas variantes que pueden asumir, pero antes de eso introduciremos algunas cuestiones generales de escritura de código.

Definición de bloques

A diferencia de otros lenguajes que utilizan llaves para definir los bloques de código (véase C o Java), cuando Guido Van Rossum diseñó Python quiso evitar estos caracteres por considerarlos innecesarios.

Es por ello que en Python los bloques de código se definen a través de espacios en blanco, preferiblemente 4⃣ espacios en blanco.1

Dark image Light image

Adaptación

Esto puede resultar extraño e (incluso) incómodo a personas que vienen de otros lenguajes de programación pero desaparece rápido y se siente natural a medida que se escribe código.

Comentarios

Los comentarios son anotaciones que podemos incluir en nuestro programa y que nos permiten aclarar ciertos aspectos del código. Estas indicaciones son ignoradas por el intérprete de Python.

Los comentarios se incluyen usando el símbolo almohadilla # y comprenden desde ahí hasta el final de la línea.

# Universe age expressed in days
universe_age = 13800 * (10 ** 6) * 365

Los comentarios también pueden aparecer en la misma línea de código, aunque la guía de estilo de Python no aconseja usarlos en demasía:

stock = 0   # Release additional articles

Reglas para escribir buenos comentarios2:

  1. Los comentarios no deberían duplicar el código.
  2. Los buenos comentarios no arreglan un código poco claro.
  3. Si no puedes escribir un comentario claro, puede haber un problema en el código.
  4. Los comentarios deberían evitar la confusión, no crearla.
  5. Usa comentarios para explicar código no idiomático.
  6. Proporciona enlaces a la fuente original del código copiado.
  7. Incluye enlaces a referencias externas que sean de ayuda.
  8. Añade comentarios cuando arregles errores.
  9. Usa comentarios para destacar implementaciones incompletas.

Ancho del código

Los programas suelen ser más legibles cuando las líneas no son excesivamente largas. La longitud máxima de línea recomendada por la guía de estilo de Python es de 80 caracteres.

Sin embargo, esto genera una cierta controversia hoy en día, ya que los tamaños de pantalla han aumentado y las resoluciones son mucho mayores que hace años. Así las líneas de más de 80 caracteres se siguen visualizando correctamente. Hay personas que son más estrictas con este límite y otras más flexibles.

En caso de que queramos romper una línea de código demasiado larga, tenemos dos opciones:

>>> factorial = factorial(n) * factorial(n - 1) * factorial(n - 2) * factorial(n -3) * factorial(n - 4) * factorial(n - 5)

>>> factorial = factorial(n) * \
...             factorial(n - 1) * \
...             factorial(n - 2) * \
...             factorial(n - 3) * \
...             factorial(n - 4) * \
...             factorial(n - 5)
>>> factorial = factorial(n) * factorial(n - 1) * factorial(n - 2) * factorial(n -3) * factorial(n - 4) * factorial(n - 5)

>>> factorial = (factorial(n - 1) *
...              factorial(n - 2) *
...              factorial(n - 3) *
...              factorial(n - 4) *
...              factorial(n - 5))

La sentencia if

La sentencia condicional en Python (al igual que en muchos otros lenguajes de programación) es if. En su escritura debemos añadir una expresión de comparación terminando con dos puntos al final de la línea.

Veamos un ejemplo:

>>> temperature = 40

>>> if temperature > 35:
...     print('Aviso por alta temperatura')
...
Aviso por alta temperatura

Paréntesis

Nótese que en Python no es necesario incluir paréntesis ( y ) al escribir condiciones. Hay ocasiones que es recomendable por claridad o por establecer prioridades.

En el caso anterior se puede ver claramente que la condición se cumple y por tanto se ejecuta la instrucción que tenemos dentro del cuerpo de la condición. Pero podría no ser así. Para controlar ese caso existe la sentencia else.

Veamos el mismo ejemplo anterior pero añadiendo esta variante:

>>> temperature = 20

>>> if temperature > 35:
...     print('Aviso por alta temperatura')
... else:
...     print('Parámetros normales')
...
Parámetros normales

Podríamos tener incluso condiciones dentro de condiciones, lo que se viene a llamar técnicamente condiciones anidadas3.

Veamos un ejemplo ampliando el caso anterior:

>>> temperature = 28

>>> if temperature < 20:
...     if temperature < 10:
...         print('Nivel azul')
...     else:
...         print('Nivel verde')
... else:
...     if temperature < 30:
...         print('Nivel naranja')
...     else:
...         print('Nivel rojo')
...
Nivel naranja

Python nos ofrece una mejora en la escritura de condiciones anidadas cuando aparecen consecutivamente un else y un if. Podemos sustituirlos por la sentencia elif:

Dark image Light image

Apliquemos esta mejora al código del ejemplo anterior:

>>> temperature = 28

>>> if temperature < 20:
...     if temperature < 10:
...         print('Nivel azul')
...     else:
...         print('Nivel verde')
... elif temperature < 30:
...     print('Nivel naranja')
... else:
...     print('Nivel rojo')
...
Nivel naranja

Asignaciones condicionales

Supongamos que queremos asignar un nivel de riesgo de incendio en función de la temperatura.

En su versión clásica escribiríamos algo como:

>>> temperature = 35

>>> if temperature < 30:
...     fire_risk = 'LOW'
... else:
...     fire_risk = 'HIGH'
...

>>> fire_risk
'HIGH'

Sin embargo, esto lo podríamos abreviar con una asignación condicional de una única línea:

>>> fire_risk = 'LOW' if temperature < 30 else 'HIGH'

>>> fire_risk
'HIGH'

Con la experiencia, este tipo de construcciones cada vez son más utilizadas ya que condensan información pero mantienen legibilidad.

Operadores de comparación

Cuando escribimos condiciones debemos incluir alguna expresión de comparación. Para usar estas expresiones es fundamental conocer los operadores que nos ofrece Python:

Operador Símbolo
Igualdad ==
Desigualdad !=
Menor que <
Menor o igual que <=
Mayor que >
Mayor o igual que >=

A continuación veremos una serie de ejemplos con expresiones de comparación. Téngase en cuenta que estas expresiones habría que incluirlas dentro de la sentencia condicional en el caso de que quisiéramos tomar una acción concreta:

>>> value = 8

>>> value == 8
True

>>> value != 8
False

>>> value < 12
True

>>> value <= 7
False

>>> value > 4
True

>>> value >= 9
False

Python ofrece la posibilidad de ver si un valor está entre dos límites de una manera muy sencilla.

Así, por ejemplo, para descubrir si \(x \in [4, 12]\) haríamos:

>>> 4 <= x <= 12
True

Notas

  1. Una expresión de comparación siempre devuelve un valor "booleano", es decir True o False.
  2. El uso de paréntesis, en función del caso, puede aclarar la expresión de comparación.

Operadores lógicos

Podemos escribir condiciones más complejas usando los operadores lógicos:

Operador Símbolo
"Y" lógico and
"O" lógico or
"No" lógico not

A continuación veremos una serie de ejemplos con expresiones lógicas. Téngase en cuenta que estas expresiones habría que incluirlas dentro de la sentencia condicional en el caso de que quisiéramos tomar una acción concreta:

>>> x = 8

>>> x > 4 or x > 12  # True or False
True

>>> x < 4 or x > 12  # False or False
False

>>> x > 4 and x > 12  # True and False
False

>>> x > 4 and x < 12  # True and True
True

>>> not(x != 8)  # not False
True

Véanse las tablas de la verdad para cada operador lógico:

Tablas de la verdad

Ejercicio

pypas   leap-year

Cortocircuito lógico

Es interesante comprender que las expresiones lógicas no se evalúan por completo si se dan una serie de circunstancias. Aquí es donde surge el concepto de cortocircuito (lógico) que no es más que una forma de identificar este escenario.

Supongamos un ejemplo en el que utilizamos un teléfono celular que mide su nivel de batería mediante la variable power con valores que van desde 0% a 100% y su cobertura 4G mediante la variable signal_4g que va desde 0% a 100%.

Para poder enviar un mensaje por Telegram el teléfono necesita tener al menos un 25% de batería y al menos un 10% de cobertura:

>>> power = 10
>>> signal_4g = 60

>>> power > 25 and signal_4g > 10
False
graph LR
    and{<tt>and</tt>}
    power(<tt>power > 25</tt>)
    signal(<tt>signal_4g > 10</tt>)
    result(((<tt>False</tt>)))
    power -- <tt>False</tt> --> and
    and -.-> signal
    and ==> result

Dado que estamos en un and y la primera condición power > 25 no se cumple, se produce un cortocircuito y no se sigue evaluando el resto de la expresión porque ya se sabe que va a dar False.

Para poder hacer una llamada VoIP necesitamos tener al menos un 40% de batería o al menos un 30% de cobertura:

>>> power = 50
>>> signal_4g = 20

>>> power > 40 or signal_4g > 30
True
graph LR
    or{<tt>or</tt>}
    power(<tt>power > 40</tt>)
    signal(<tt>signal_4g > 30</tt>)
    result(((<tt>True</tt>)))
    power -- <tt>True</tt> --> or
    or -.-> signal
    or ==> result

Dado que estamos en un or y la primera condición power > 40 se cumple, se produce un cortocircuito y no se sigue evaluando el resto de la expresión porque ya se sabe que va a dar True.

Evaluación

Si no se produjera un cortocircuito en la evaluación de la expresión, se seguiría comprobando todas las condiciones posteriores hasta llegar al final de la misma.

"Booleanos" en condiciones

Cuando queremos preguntar por la veracidad de una determinada variable "booleana" en una condición, la primera aproximación que parece razonable es usar lo que ya conocemos.

Veamos un ejemplo:

>>> is_cold = True

>>> if is_cold == True:#(1)!
...     print('Coge chaqueta')
... else:
...     print('Usa camiseta')
...
Coge chaqueta

  1. No es la manera correcta pitónica.

Pero la manera "obvia" de hacerlo en Python es la siguiente:

>>> if is_cold:
...     print('Coge chaqueta')
... else:
...     print('Usa camiseta')
...
Coge chaqueta

Hemos visto una comparación para un valor "booleano" verdadero (True). En el caso de que la comparación fuera para un valor falso lo haríamos así:

>>> is_cold = False

>>> if not is_cold:#(1)!
...     print('Usa camiseta')
... else:
...     print('Coge chaqueta')
...
Usa camiseta

  1. if is_cold == False:

De hecho, si lo pensamos, estamos reproduciendo bastante bien el lenguaje natural:

  • Si hace frío coge chaqueta.
  • Si no hace frío usa camiseta.

Ejercicio

pypas   marvel-akinator

Valor nulo

None es un valor especial de Python que almacena el valor nulo4. Veamos cómo se comporta al incorporarlo en condiciones de veracidad.

Veamos un sencillo ejemplo para ilustrar su comportamiento:

>>> value = None

>>> if value:
...     print('Value has some useful value')
... else:
...     print('Value seems to be void')#(1)!
...
Value seems to be void

  1. value podría contener None, False o cualquier otra expresión cuya veracidad fuera falsa.

Para distinguir None de los valores propiamente booleanos, se recomienda el uso del operador is:

>>> value = None

>>> if value is None:
...     print('Value is clearly None')
... else:
...     print('Value has some useful value')
...
Value is clearly None

De igual forma, podemos usar esta construcción para el caso contrario. La forma "pitónica" de preguntar si algo no es nulo es la siguiente:

>>> value = 99

>>> if value is not None:
...     print(f'{value=}')
...
value=99

¿Por qué usar is?

Cabe preguntarse por qué utilizamos is en vez del operador == al comprobar si un valor es nulo, ya que ambas aproximaciones nos dan el mismo resultado5:

>>> value = None

>>> value is None
True

>>> value == None
True

La respuesta es que el operador is comprueba únicamente si los identificadores (posiciones en memoria) de dos objetos son iguales, mientras que la comparación == puede englobar muchas otras acciones. De este hecho se deriva que su ejecución sea mucho más rápida y que se eviten "falsos positivos".

Cuando ejecutamos un programa Python existe una serie de objetos precargados en memoria. Uno de ellos es None.

Lo podemos comprobar con el siguiente ejemplo:

>>> id(None)
4314501456

Cualquier variable que igualemos al valor nulo, únicamente será una referencia al mismo objeto None en memoria:

>>> value = None

>>> id(value)
4314501456

Por lo tanto, ver si un objeto es None es simplemente comprobar que su "id" coincida con el de None, que es exactamente el cometido del operador is:

>>> id(value) == id(None)
True

>>> value is None
True

Veracidad

Cuando trabajamos con expresiones que incorporan valores "booleanos", se produce una conversión implícita que transforma los tipos de datos involucrados a valores True o False.

Lo primero que debemos entender de cara a comprobar la veracidad son los valores que evalúan a falso o evalúan a verdadero.

A continuación se muestra un listado de los únicos items que evalúan a False en Python:

>>> bool(False)
False

>>> bool(None)
False

>>> bool(0)
False

>>> bool(0.0)
False

>>> bool('')#(1)!
False

>>> bool([])#(2)!
False

>>> bool(())#(3)!
False

>>> bool({})#(4)!
False

>>> bool(set())#(5)!
False

  1. La cadena vacía.
  2. La lista vacía.
  3. La tupla vacía.
  4. El diccionario vacío.
  5. El conjunto vacío.

El resto de objetos en Python evalúan a True.

Veamos algunos ejemplos de objetos que evalúan a True en Python:

>>> bool('False')
True

>>> bool(' ')
True

>>> bool(1e-10)
True

>>> bool([0])
True

>>> bool('🦆')
True

Asignación lógica

Es posible utilizar operadores lógicos en sentencias de asignación sacando partido de las tablas de la verdad que funcionan para estos casos.

Veamos un ejemplo de asignación lógica utilizando el operador and:

>>> b = 0
>>> c = 5

>>> a = b and c#(1)!

>>> a
0

  1. Se trata de una expresión lógica en la que se aplica conversión implícita de los valores enteros a valores "booleanos". En este sentido el valor de b evalúa a False ya que es 0. Al estar usando un operador and se produce un cortocircuito lógico y se asigna el valor de la b a la variable a.

Veamos un ejemplo de asignación lógica utilizando el operador or:

>>> b = 0
>>> c = 5

>>> a = b or c#(1)!

>>> a
5

  1. Se trata de una expresión lógica en la que se aplica conversión implícita de los valores enteros a valores "booleanos". En este sentido el valor de b evalúa a False ya que es 0. Al estar usando un operador or se continúa a la segunda parte donde el valor de la variable c evalúa a True ya que es 5. Por tanto se asigna dicho valor a la variable a.

Sentencia match-case

Una de las novedades más esperadas de Python 3.10 fue el llamado Structural Pattern Matching que introdujo en el lenguaje una nueva sentencia condicional. Ésta se podría asemejar a la sentencia "switch" que ya existe en otros lenguajes de programación.

Comparando valores

En su versión más simple, el "pattern matching" permite comparar un valor de entrada con una serie de literales. Algo así como un conjunto de sentencias "if" encadenadas.

Veamos esta primera aproximación mediante un ejemplo donde mostramos un color a partir de su codificación RGB:

>>> color = '#FF0000'

>>> match color:
...     case '#FF0000':
...         print('🔴')
...     case '#00FF00':
...         print('🟢')
...     case '#0000FF':
...         print('🔵')
...
🔴

¿Qué ocurre si el valor que comparamos no existe entre las opciones disponibles? Pues en principio, nada, ya que este caso no está cubierto. Si lo queremos controlar, hay que añadir una nueva regla utilizando el subguión _ como patrón:

>>> color = '#AF549B'

>>> match color:
...     case '#FF0000':
...         print('🔴')
...     case '#00FF00':
...         print('🟢')
...     case '#0000FF':
...         print('🔵')
...     case _:
...         print('Unknown color!')
...
Unknown color!

Hay que tener cuidado con un detalle. Si estás pensando en usar constantes para definir los valores que puede tomar el color, que sepas que esto te va a fallar:

>>> RED_HEXA = '#FF0000'
>>> GREEN_HEXA = '#00FF00'
>>> BLUE_HEXA = '#0000FF'

>>> match color:
...     case RED_HEXA:
...         print('🔴')
...     case GREEN_HEXA:
...         print('🟢')
...     case BLUE_HEXA:
...         print('🔵')
...     case _:
...         print('Unknown color!')
  Cell In[4], line 2
    case RED_HEXA:
         ^
SyntaxError: name capture 'RED_HEXA' makes remaining patterns unreachable

Esto se debe a que Python trata a las constantes RED_HEXA GREEN_HEXA BLUE_HEXA como nombres de variables y trata de aplicar el patrón de captura sobre match-case6.

Ejercicio

pypas   simple-op

Patrones avanzados

La sentencia match-case va mucho más allá de una simple comparación de valores. Con ella podremos deconstruir estructuras de datos, capturar elementos o mapear valores.

Vamos a plantear un ejemplo donde partimos de una tupla que representará un punto en el plano (2 coordenadas) o en el espacio (3 coordenadas). Lo primero que vamos a hacer es detectar en qué dimensión se encuentra el punto:

>>> point = (2, 5)

>>> match point:
...     case (x, y):
...         print(f'({x},{y}) is in plane')
...     case (x, y, z):
...         print(f'({x},{y},{z}) is in space')
...
(2,5) is in plane

>>> point = (3, 1, 7)

>>> match point:
...     case (x, y):
...         print(f'({x},{y}) is in plane')
...     case (x, y, z):
...         print(f'({x},{y},{z}) is in space')
...
(3,1,7) is in space

Sin embargo esta aproximación permitiría tratar un punto formado por cadenas de texto...

>>> point = ('2', '5')

>>> match point:
...     case (x, y):
...         print(f'({x},{y}) is in plane')
...     case (x, y, z):
...         print(f'({x},{y},{z}) is in space')
...
(2,5) is in plane

Por tanto debemos restringir nuestros patrones a valores enteros:

>>> point = ('2', '5')

>>> match point:
...     case (int(), int()):
...         print(f'{point} is in plane')
...     case (int(), int(), int()):
...         print(f'{point} is in space')
...     case _:
...         print('Unknown!')
...
Unknown!
>>> point = (3, 9, 1)

>>> match point:
...     case (int(), int()):
...         print(f'{point} is in plane')
...     case (int(), int(), int()):
...         print(f'{point} is in space')
...     case _:
...         print('Unknown!')
...
(3, 9, 1) is in space

Imaginemos ahora que nos piden calcular la distancia del punto al origen. Debemos tener en cuenta que, a priori, desconocemos si el punto está en el plano o en el espacio:

>>> point = (8, 3, 5)

>>> match point:
...     case (int(x), int(y)):
...         dist_to_origin = (x ** 2 + y ** 2) ** (1 / 2)
...     case (int(x), int(y), int(z)):
...         dist_to_origin = (x ** 2 + y ** 2 + z ** 2) ** (1 / 2)
...     case _:
...         print('Unknown!')
...

>>> dist_to_origin
9.899494936611665

Con este enfoque, nos aseguramos que los puntos de entrada deben tener todas sus coordenadas como valores enteros:

>>> point = ('8', 3, 5)  # Nótese el 8 como "string"

>>> match point:
...     case (int(x), int(y)):
...         dist_to_origin = (x ** 2 + y ** 2) ** (1 / 2)
...     case (int(x), int(y), int(z)):
...         dist_to_origin = (x ** 2 + y ** 2 + z ** 2) ** (1 / 2)
...     case _:
...         print('Unknown!')
...
Unknown!

Cambiando de ejemplo, veamos un fragmento de código en el que tenemos que comprobar la estructura de un bloque de autenticación definido mediante un diccionario. Los métodos válidos de autenticación son únicamente dos: bien usando nombre de usuario y contraseña, o bien usando correo electrónico y "token" de acceso. Además, los valores deben venir en formato cadena de texto:

>>> auths = [
...     {'username': 'sdelquin', 'password': '1234'},
...     {'email': 'sdelquin@gmail.com', 'token': '4321'},
...     {'email': 'test@test.com', 'password': 'ABCD'},
...     {'username': 'sdelquin', 'password': 1234}
... ]

>>> for auth in auths:
...     print(auth)
...     match auth:
...         case {'username': str(username), 'password': str(password)}:
...             print('Authenticating with username and password')
...             print(f'{username}: {password}')
...         case {'email': str(email), 'token': str(token)}:
...             print('Authenticating with email and token')
...             print(f'{email}: {token}')
...         case _:
...             print('Authenticating method not valid!')
...     print('---')
...
{'username': 'sdelquin', 'password': '1234'}
Authenticating with username and password
sdelquin: 1234
---
{'email': 'sdelquin@gmail.com', 'token': '4321'}
Authenticating with email and token
sdelquin@gmail.com: 4321
---
{'email': 'test@test.com', 'password': 'ABCD'}
Authenticating method not valid!
---
{'username': 'sdelquin', 'password': 1234}
Authenticating method not valid!
---

Aún un último ejemplo que determina, dada la edad de una persona, si puede o no beber alcohol:

>>> age = 21

>>> match age:
...     case 0 | None:#(1)!
...         print('Not a person')
...     case n if n < 17:#(2)!
...         print('Nope')
...     case n if n < 22:#(3)!
...         print('Not in the US')
...     case _:
...         print('Yes')
...
Not in the US

  1. Nótese el uso del OR...
  2. Uso de condicional en la propia expresión.
  3. Uso de condicional en la propia expresión.

Operador morsa

Python 3.8 introdujo el polémico operador morsa7 := que permitía unificar sentencias de asignación dentro de expresiones.

Supongamos un ejemplo en el que computamos el perímetro de una circunferencia, indicando al usuario que debe incrementarlo siempre y cuando no llegue a un mínimo establecido.

>>> radius = 4.25
... perimeter = 2 * 3.14 * radius
... if perimeter < 100:
...     print('Increase radius to reach minimum perimeter')
...     print('Actual perimeter: ', perimeter)
...
Increase radius to reach minimum perimeter
Actual perimeter:  26.69
>>> radius = 4.25
... if (perimeter := 2 * 3.14 * radius) < 100:
...     print('Increase radius to reach minimum perimeter')
...     print('Actual perimeter: ', perimeter)
...
Increase radius to reach minimum perimeter
Actual perimeter:  26.69

Equilibro

Como hemos comprobado, el operador morsa permite realizar asignaciones dentro de expresiones, lo que, en muchas ocasiones, permite obtener un código más compacto. Sería conveniente encontrar un equilibrio entre la expresividad y la legibilidad.

Renuncia de Guido van Rossum

La adopción del "walrus operator" en el lenguaje fue una de las polémicas más polarizadas en la historia reciente de Python. Tal es así, que al día siguiente de que Guido van Rossum aceptara su introducción en el lenguaje, tuvo un aluvión de críticas que colmaron la paciencia del creador holandés. Así las cosas, Guido escribió esta carta abandonando su puesto como líder y transfiriendo su poder de decisión sobre Python; y terminaba con un "I'm tired, and need a very long break."

Ejemplos resueltos

Clasificación de temperatura

Clasificar una temperatura ingresada por el usuario según los siguientes rangos:

Rango Clasificación
Menor a 0°C Bajo cero
0°C a 15°C Frío
16°C a 25°C Templado
26°C a 35°C Cálido
Mayor a 35°C Muy caluroso
Ver solución
flowchart TD
    A([INICIO]) --> B[/Ingresar temperatura/]
    B --> C{"temp < 0"}
    C -->|Sí| D[\"Mostrar: Bajo cero"\]
    C -->|No| E{"temp <= 15"}
    E -->|Sí| F[\"Mostrar: Frío"\]
    E -->|No| G{"temp <= 25"}
    G -->|Sí| H[\"Mostrar: Templado"\]
    G -->|No| I{"temp <= 35"}
    I -->|Sí| J[\"Mostrar: Cálido"\]
    I -->|No| K[\"Mostrar: Muy caluroso"\]
    D --> L([FIN])
    F --> L
    H --> L
    J --> L
    K --> L
temperatura = float(input("Ingrese la temperatura (°C): "))

if temperatura < 0:
    print("Bajo cero")
elif temperatura <= 15:
    print("Frío")
elif temperatura <= 25:
    print("Templado")
elif temperatura <= 35:
    print("Cálido")
else:
    print("Muy caluroso")

Descuento en materiales

Una ferretería aplica descuentos según el monto de compra:

Monto Descuento
Menos de $10.000 Sin descuento
$10.000 – $49.999 5%
$50.000 – $99.999 10%
$100.000 o más 15%
Ver solución
flowchart TD
    A([INICIO]) --> B[/Ingresar monto/]
    B --> C{"monto < 10000"}
    C -->|Sí| D["descuento = 0"]
    C -->|No| E{"monto < 50000"}
    E -->|Sí| F["descuento = 0.05"]
    E -->|No| G{"monto < 100000"}
    G -->|Sí| H["descuento = 0.10"]
    G -->|No| I["descuento = 0.15"]
    D --> J["total = monto * (1 - descuento)"]
    F --> J
    H --> J
    I --> J
    J --> K[\"Mostrar: total"\]
    K --> L([FIN])
monto = float(input("Ingrese el monto de compra: $"))

if monto < 10000:
    descuento = 0
elif monto < 50000:
    descuento = 0.05
elif monto < 100000:
    descuento = 0.10
else:
    descuento = 0.15

total = monto * (1 - descuento)
print(f"Descuento aplicado: {descuento * 100:.0f}%")
print(f"Total a pagar: ${total:,.0f}")

Clasificación de hormigón

Clasificar una muestra de hormigón según su resistencia a la compresión (\(f'c\) en MPa):

\(f'c\) (MPa) Clasificación
Menor a 17 No estructural
17 a 24 Resistencia normal
25 a 34 Alta resistencia
35 o más Ultra alta resistencia
Ver solución
fc = float(input("Ingrese la resistencia f'c (MPa): "))

if fc < 17:
    clasificacion = "No estructural"
elif fc <= 24:
    clasificacion = "Resistencia normal"
elif fc <= 34:
    clasificacion = "Alta resistencia"
else:
    clasificacion = "Ultra alta resistencia"

print(f"Clasificación: {clasificacion}")

Ejercicios

  1. Escribe un programa que solicite la nota de un estudiante (1.0 a 7.0) y muestre si está reprobado (menor a 4.0), aprobado (4.0 a 5.9) o distinguido (6.0 o más).

  2. Escribe un programa que solicite el año de nacimiento de una persona y muestre si es menor de edad (menos de 18 años), adulto (18 a 59 años) o adulto mayor (60 o más).

  3. Una obra de construcción cobra el acceso según el tipo de vehículo: camión ($8.000), camioneta ($4.000), automóvil ($2.000). Escribe un programa que solicite el tipo de vehículo y muestre el cobro correspondiente.

  4. Escribe un programa que reciba dos números y un operador (+, -, *, /) y muestre el resultado de la operación. Si el operador no es válido muestra un mensaje de error. Si se divide por cero muestra un mensaje de advertencia.

  5. Diseña el diagrama de flujo e implementa un programa que solicite la renta mensual de una persona y calcule el impuesto según los tramos:

    Renta mensual Impuesto
    Hasta $500.000 0%
    $500.001 – $1.000.000 5%
    $1.000.001 – $2.000.000 10%
    Más de $2.000.000 20%

  1. Reglas de indentación definidas en PEP 8

  2. Fuente: Best practices for writing code comments 

  3. El anidamiento (o "nesting") hace referencia a incorporar sentencias unas dentro de otras mediante la inclusión de diversos niveles de profunidad (indentación). 

  4. El valor nulo se conoce en otros lenguajes de programación como nil, null, nothing, ... 

  5. Uso de is en comparación de valores nulos explicada aquí por Jared Grubb. 

  6. El error está perfectamente analizado en esta respuesta de StackOverflow

  7. Se denomina así porque el operador := tiene similitud con los colmillos de una morsa.