Python
Python
Ahora, se va a mostrar un nuevo lado de la función print(). Ya se sabe que la función es capaz de mostrar los
valores de los literales que le son pasados por los argumentos.
Deberías de ver el número cuatro. Tómate la libertad de experimentar con otros operadores.
Sin tomar esto con mucha seriedad, has descubierto que Python puede ser utilizado como una calculadora. No
una muy útil, y definitivamente no una de bolsillo, pero una calculadora sin duda alguna.
Tomando esto más seriamente, nos estamos adentrado en el terreno de los operadores y expresiones.
Un operador es un símbolo del lenguaje de programación, el cual es capaz de realizar operaciones con los
valores.
Por ejemplo, como en la aritmética, el signo de + (más) es un operador el cual es capaz de sumar dos números,
dando el resultado de la suma.
Sin embargo, no todos los operadores de Python son tan simples como el signo de más, veamos algunos de los
operadores disponibles en Python, las reglas que se deben seguir para emplearlos, y como interpretar las reglas
que realizan.
Se comenzará con los operadores que están asociados con las operaciones aritméticas más conocidas:
El orden en el que aparecen no es por casualidad. Hablaremos más de ello cuando se hayan visto todos.
Recuerda: Cuando los datos y operadores se unen, forman juntos expresiones. La expresión más sencilla es el
literal.
EXPONENCIACIÓN
Observa los ejemplos en la ventana del editor:
Nota: En los ejemplos, los dobles asteriscos están rodeados de espacios, no es obligatorio hacerlo, pero hace que
el código sea más legible.
Los ejemplos muestran una característica importante de los operadores numéricos de Python.
Ejecuta el código y observa cuidadosamente los resultados que arroja. ¿Puedes observar algo?
Recuerda: Es posible formular las siguientes reglas con base en los resultados:
MULTIPLICACIÓN
El resultado producido por el operador de división siempre es flotante, sin importar si a primera vista el
resultado es flotante: 1 / 2, o si parece ser completamente entero: 2 / 1.
¿Esto ocasiona un problema? Sí, en ocasiones se podrá necesitar que el resultado de una división sea entero, no
flotante. Afortunadamente, Python puede ayudar con eso.
DIVISIÓN ENTERA
Un símbolo de // (doble diagonal) es un operador de división entera. Difiere del operador estándar / en dos
detalles:
El resultado carece de la parte fraccionaria, está ausente (para los enteros), o siempre es igual a cero
(para los flotantes); esto significa que los resultados siempre son redondeados;
Se ajusta a la regla entero vs flotante.
Ejecuta el ejemplo debajo y observa los resultados:
Como se puede observar, una división de entero entre entero da un resultado entero. Todos los demás casos
producen flotantes.
El resultado de la división entera siempre se redondea al valor entero inferior más cercano del resultado de la
división no redondeada.
El resultado es un par de dos negativos. El resultado real (no redondeado) es -1.5 en ambo casos. Sin embargo,
los resultados se redondean. El redondeo se hace hacia el valor inferior entero, dicho valor es -2, por lo tanto,
los resultados son: -2 y -2.0.
La división entera también se le suele llamar en inglés floor division. Más adelante te cruzarás con este término.
RESIDUO (MÓDULO)
El siguiente operador es uno muy peculiar, porque no tiene un equivalente dentro de los operadores aritméticos
tradicionales.
Su representación gráfica en Python es el símbolo de % (porcentaje), lo cual puede ser un poco confuso.
Piensa en el como una diagonal (operador de división) acompañado por dos pequeños círculos.
En otras palabras, es el valor que sobra después de dividir un valor entre otro para producir un resultado entero.
¿Cuál es el resultado?
12 // 4.5 da 2.0,
2.0 * 4.5 da 9.0,
12 - 9.0 da 3.0.
COMO NO DIVIDIR
SUMA
El símbolo del operador de suma es el + (signo de más), el cual está completamente alineado a los estándares
matemáticos.
El símbolo del operador de resta es obviamente - (el signo de menos), sin embargo, debes notar que este
operador tiene otra función - puede cambiar el signo de un número.
Esta es una gran oportunidad para mencionar una distinción muy importante entre operadores unarios y
binarios.
En aplicaciones de resta, el operador de resta espera dos argumentos: el izquierdo (un minuendo en términos
aritméticos) y el derecho (un sustraendo).
Por esta razón, el operador de resta es considerado uno de los operadores binarios, así como los demás
operadores de suma, multiplicación y división.
Pero el operador negativo puede ser utilizado de una forma diferente - observa la última línea de código del
siguiente fragmento:
Por cierto: también hay un operador + unario. Se puede utilizar de la siguiente manera
Aunque dicha construcción es sintácticamente correcta, utilizarla no tiene mucho sentido, y sería difícil encontrar
una buena razón para hacerlo.
Hasta ahora, se ha tratado cada operador como si no tuviera relación con los otros. Obviamente, dicha situación
tan simple e ideal es muy rara en la programación real.
También, muy seguido encontrarás más de un operador en una expresión, y entonces esta presunción ya no es
tan obvia.
Seguramente recordarás que primero se debe multiplicar 3 por 5, mantener el 15 en tu memoria y después
sumar el 2, dando como resultado el 17.
El fenómeno que causa que algunos operadores actúen antes que otros son conocido como la jerarquía de
prioridades.
Python define la jerarquía de todos los operadores, y asume que los operadores de mayor jerarquía deben
realizar sus operaciones antes que los de menor jerarquía.
Entonces, si se sabe que la * tiene una mayor prioridad que la +, el resultado final debe de ser obvio.
El enlace de un operador determina el orden en que se computan las operaciones de los operadores con la
misma prioridad, los cuales se encuentran dentro de una misma expresión.
La mayoría de los operadores de Python tienen un enlazado hacia la izquierda, lo que significa que el cálculo de
la expresión es realizado de izquierda a derecha.
El resultado debe ser 1. El operador tiene un enlazado del lado izquierdo. Pero hay una excepción interesante.
Repite el experimento, pero ahora con exponentes.
El resultado muestra claramente que el operador de exponenciación utiliza enlazado del lado derecho.
Esto contiene una excepción interesante. Si el operador de exponenciación usa el enlazado del lado derecho,
¿puedes adivinar el resultado del siguiente fragmento?
LISTA DE PRIORIDADES
Como eres nuevo a los operadores de Python, no se presenta por ahora una lista completa de las prioridades de
los operadores. En lugar de ello, se mostrarán solo algunos, y se irán expandiendo conforme se vayan
introduciendo operadores nuevos. Observa la siguiente tabla:
Nota: se han enumerado los operadores en orden de la más alta (1) a la más baja (4) prioridad.
Ambos operadores (* y %) tienen la misma prioridad, el resultado solo se puede obtener conociendo el sentido
del enlazado. ¿Cuál será el resultado?
OPERADORES Y PARÉNTESIS
Por supuesto, se permite hacer uso de paréntesis, lo cual cambiará el orden natural del cálculo de la operación.
De acuerdo con las reglas aritméticas, las subexpresiones dentro de los paréntesis siempre se calculan primero.
Se pueden emplear tantos paréntesis como se necesiten, y seguido son utilizados para mejorar la legibilidad de
una expresión, aun si no cambian el orden de las operaciones.
1. Una expresión es una combinación de valores (o variables, operadores, llamadas a funciones, aprenderás de
ello pronto) las cuales son evaluadas y dan como resultado un valor, por ejemplo, 1 + 2.
2. Los operadores son símbolos especiales o palabras clave que son capaces de operar en los valores y realizar
operaciones matemáticas, por ejemplo, el * multiplica dos valores: x * y.
3. Los operadores aritméticos en Python: + (suma), - (resta), * (multiplicación), / (división clásica: regresa un
flotante siempre), % (módulo: divide el operando izquierdo entre el operando derecho y regresa el residuo de la
operación, por ejemplo, 5 % 2 = 1), ** (exponenciación: el operando izquierdo se eleva a la potencia del
operando derecho, por ejemplo, 2 ** 3 = 2 * 2 * 2 = 8), // (división entera: retorna el número resultado de la
división, pero redondeado al número entero inferior más cercano, por ejemplo, 3 // 2.0 = 1.0)
4. Un operador unario es un operador con solo un operando, por ejemplo, -1, o +3.
8. Los operadores de exponenciación utilizan enlazado del lado derecho, por ejemplo, 2 ** 2 ** 3 = 256.
Pregunta 1: ¿Cuál es la salida del siguiente fragmento de código? print((2 ** 4), (2 * 4.), (2 * 4))
R// 16 8.0 8
Pregunta 2: ¿Cuál es la salida del siguiente fragmento de código? print((-2 / 4), (2 / 4), (2 // 4), (-2 // 4))
Pregunta 3: ¿Cuál es la salida del siguiente fragmento de código? print((2 % -4), (2 % 4), (2 ** 3 ** 2))
R//-2 2 512
Es justo que Python nos permita codificar literales las cuales contengan valores numéricos y cadenas.
Ya hemos visto que se pueden hacer operaciones aritméticas con estos números: sumar, restar, etc. Esto se hará
una infinidad de veces en un programa.
Pero es normal preguntar cómo es que se pueden almacenar los resultados de estas operaciones, para poder
emplearlos en otras operaciones, y así sucesivamente.
¿Cómo almacenar los resultados intermedios, y después utilizarlos de nuevo para producir resultados
subsecuentes?
Python ayudará con ello. Python ofrece "cajas" (o "contenedores") especiales para este propósito, estas cajas
son llamadas variables ‒ el nombre mismo sugiere que el contenido de estos contenedores puede variar en casi
cualquier forma.
Un nombre;
Un valor (el contenido del contenedor)
El nombre de la variable debe de estar compuesto por MAYÚSCULAS, minúsculas, dígitos, y el carácter _
(guion bajo)
El nombre de la variable debe comenzar con una letra;
El carácter guion bajo es considerado una letra;
Las mayúsculas y minúsculas se tratan de forma distinta (un poco diferente que en el mundo real - Alicia
y ALICIA son el mismo nombre, pero en Python son dos nombres de variable distintos,
subsecuentemente, son dos variables diferentes);
El nombre de las variables no puede ser igual a alguna de las palabras reservadas de Python (las palabras
clave - explicará más de esto pronto).
Python no impone restricciones en la longitud de los nombres de las variables, pero eso no significa que un
nombre de variable largo sea mejor que uno corto
Aquí se muestran algunos nombres de variable que son correctos, pero que no siempre son convenientes:
Python te permite usar no solo letras latinas sino también caracteres específicos de idiomas que usan otros
alfabetos.
Los nombres de las variables deben estar en minúsculas, con palabras separadas por guiones bajos para mejorar
la legibilidad (por ejemplo, var, my_variable)
Los nombres de las funciones siguen la misma convención que los nombres de las variables (por ejemplo, fun,
my_function)
También es posible usar letras mixtas (por ejemplo, myVariable), pero solo en contextos donde ese ya es el estilo
predominante, para mantener la compatibilidad retroactiva con la convención adoptada.
PALABRAS CLAVE
Observa las palabras que juegan un papel muy importante en cada programa de Python
Son llamadas palabras clave o (mejor dicho) palabras clave reservadas. Son reservadas porque no se deben
utilizar como nombres: ni para variables, ni para funciones, ni para cualquier otra cosa que se desee crear.
Afortunadamente, debido al hecho de que Python es sensible a mayúsculas y minúsculas, cualquiera de estas
palabras se puede modificar cambiando una o varias letras de mayúsculas a minúsculas o viceversa, creando una
nueva palabra, la cual no está reservada.
Por ejemplo - no se puede nombrar a la variable así , No se puede tener una variable con ese nombre - está
prohibido. pero se puede hacer lo siguiente: . Estas palabras podrían parecer un misterio ahorita, pero pronto se
aprenderá acerca de su significado.
Cualquier cosa.
Se puede utilizar una variable para almacenar cualquier tipo de los valores que ya se han mencionado, y muchos
más de los cuales aún no se han explicado.
El valor de la variable en lo que se ha puesto dentro de ella. Puede variar tanto como se necesite o requiera. El
valor puede ser entero, después flotante, y eventualmente ser una cadena.
Hablemos de dos cosas importantes - como son creadas las variables, y como poner valores dentro de ellas (o,
mejor dicho, como dar o pasarles valores).
RECUERDA: Una variable se crea cuando se le asigna un valor. A diferencia de otros lenguajes de programación,
no es necesario declararla.
Si se le asigna cualquier valor a una variable no existente, la variable será automáticamente creada. No se
necesita hacer algo más.
La creación (o su sintaxis) es muy simple: solo utiliza el nombre de la variable deseada, después el signo de
igual (=) y el valor que se desea colocar dentro de la variable.
La primera crea una variable llamada var, y le asigna un literal con un valor entero de 1.
La segunda imprime el valor de la variable recientemente creada en la consola.
Como puedes ver, print() tiene otro lado: también puede manejar variables. ¿Sabes cuál será el resultado del
fragmento?
Se tiene permitido utilizar cuantas declaraciones de variables sean necesarias para lograr el objetivo del
programa, por ejemplo:
Sin embargo, no se permite utilizar una variable que no exista, (en otras palabras, una variable a la cual no se le
ha dado un valor).
Se ha tratado de utilizar la variable llamada Var, la cual no tiene ningún valor (nota: var y Var son entidades
diferentes, y no tienen nada en común dentro de Python).
RECUERDA: Se puede utilizar print() para combinar texto con variables utilizando el operador + para mostrar
cadenas con variables, por ejemplo:
¿Cómo se le asigna un valor nuevo a una variable que ya ha sido creada? De la misma manera. Solo se necesita el
signo de igual.
El signo de igual es de hecho un operador de asignación. Aunque esto suene un poco extraño, el operador tiene
una sintaxis simple y una interpretación clara y precisa.
Asigna el valor del argumento de la derecha al de la izquierda, aun cuando el argumento de la derecha sea una
expresión arbitraria compleja que involucre literales, operadores y variables definidas anteriormente.
La sentencia se lee de la siguiente manera: asigna el valor de 1 a una variable llamada var.
La tercera línea le asigna a la misma variable un nuevo valor tomado de la variable misma, sumándole 1.Al ver
algo así, un matemático probablemente protestaría - ningún valor puede ser igualado a si mismo más uno. Esto
es una contradicción. Pero Python trata el signo = no como igual a, sino como asigna un valor.
En efecto, el valor de la variable var ha sido incrementado por uno, lo cual no está relacionado con comparar la
variable con otro valor.
Ahora deberías poder construir un programa corto que resuelva problemas matemáticos simples como el
teorema de Pitágoras:
El siguiente código evalúa la longitud de la hipotenusa (es decir, el lado más largo de un triángulo rectángulo, el
opuesto al ángulo recto) usando el teorema de Pitágoras:
Nota: necesitamos hacer uso del operador ** para evaluar la raíz cuadrada como:
ESCENARIO
A continuación, una historia:
Érase una vez en la Tierra de las Manzanas, Juan tenía tres manzanas, María tenía cinco manzanas, y Adán tenía
seis manzanas. Todos eran muy felices y vivieron por muchísimo tiempo. Fin de la Historia.
Tu tarea es:
Es tiempo de explicar el siguiente conjunto de operadores que harán la vida del programador/desarrollador más
fácil. Muy seguido, se desea utilizar la misma variable al lado derecho y al lado izquierdo del operador = operator.
Por ejemplo, si se necesita calcular una serie de valores sucesivos de la potencia de 2, se puede usar el siguiente
código:
También, puedes utilizar una expresión como la siguiente si no puedes dormir y estas tratando de resolverlo con
alguno de los métodos tradicionales:
Python ofrece una manera más corta de escribir operaciones como estas, lo cual se puede codificar de la
siguiente manera:
A continuación, se intenta presentar una descripción general para este tipo de operaciones. Si op es un operador
de dos argumentos (esta es una condición muy importante) y el operador es utilizado en el siguiente contexto...:
ESCENARIO
Millas y kilómetros son unidades de longitud o distancia.
Teniendo en mente que 1 milla equivale aproximadamente a 1.61 kilómetros, complementa el programa en el
editor para que convierta de:
Millas a kilómetros;
Kilómetros a millas.
No se debe cambiar el código existente. Escribe tu código en los lugares indicados con ###. Prueba tu programa
con los datos que han sido provistos en el código fuente.
Pon mucha atención a lo que está ocurriendo dentro de la función print(). Analiza cómo es que se proveen
múltiples argumentos para la función, y como es que se muestra el resultado.
Nota que algunos de los argumentos dentro de la función print() son cadenas (por ejemplo, "millas son", y otros
son variables (por ejemplo, miles).
Consejo
Hay una cosa interesante más que está ocurriendo. ¿Puedes ver otra función dentro de la función print()? Es la
función round(). Su trabajo es redondear la salida del resultado al número de decimales especificados en el
paréntesis, y regresar un valor flotante (dentro de la función round() se puede encontrar el nombre de la
variable, el nombre, una coma, y el número de decimales que se desean mostrar). Se hablará más de esta
función muy pronto, no te preocupes si no todo queda muy claro. Solo se quiere impulsar tu curiosidad.
Después de completar el laboratorio, abre Sandbox, y experimenta más. Intenta escribir diferentes
convertidores, por ejemplo, un convertidor de USD a EUR, un convertidor de temperatura, etc. - ¡Deja que tu
imaginación vuele! Intenta mostrar los resultados combinando cadenas y variables. Intenta utilizar y
experimentar con la función round() para redondear tus resultados a uno, dos o tres decimales. Revisa que es lo
que sucede si no se provee un dígito al redondear. Recuerda probar tus programas.
SALIDA ESPERADA
2.4.10 LAB OPERADORES Y EXPRESIONES
Escenario
Observa el código en el editor: lee un valor float, lo coloca en una variable llamada x, e imprime el valor de la
variable llamada y. Tu tarea es completar el código para evaluar la siguiente expresión:
Mantén tu código limpio y legible, y pruébalo utilizando los datos que han sido proporcionados. No te desanimes
por no lograrlo en el primer intento. Se persistente y curioso.
2.4.11 RESUMEN DE SECCIÓN
Una variable es una ubicación nombrada reservada para almacenar valores en la memoria. Una variable es
creada o inicializada automáticamente cuando se le asigna un valor por primera vez. (2.1.4.1)
Cada variable debe de tener un nombre único - un identificador. Un nombre válido debe ser aquel que no
contiene espacios, debe comenzar con un guion bajo(_), o una letra, y no puede ser una palabra reservada de
Python. El primer carácter puede estar seguido de guiones bajos, letras, y dígitos. Las variables en Python son
sensibles a mayúsculas y minúsculas.
Python es un lenguaje de tipo dinámico, lo que significa que no se necesita declarar variables en él. Para asignar
valores a las variables, se utiliza simplemente el operador de asignación, es decir el signo de igual (=), por
ejemplo, var = 1.
También es posible utilizar operadores de asignación compuesta (operadores abreviados) para modificar los
valores asignados a las variables, por ejemplo: var += 1, o var /= 5 * 2.
Se les puede asignar valores nuevos a variables ya existentes utilizando el operador de asignación o un operador
abreviado, por ejemplo:
Puedes combinar texto y variables usando el operador + y emplear la función print() para generar cadenas y
variables, por ejemplo:
R// 3
Pregunta 2: ¿Cuáles de los siguientes nombres de variables son ilegales en Python? (Selecciona tres respuestas
R// 101, m 101, del
Pregunta 3: ¿Cuál es el resultado del siguiente fragmento?
R// 11
R//1.0
Quizá en algún momento será necesario poner algunas palabras en el código dirigidas no a Python, sino a las
personas quienes estén leyendo el código con el fin de explicarles cómo es que funciona, o tal vez especificar el
significado de las variables, también para documentar quien es el autor del programa y en qué fecha fue escrito.
¿Cómo se colocan este tipo de comentarios en el código fuente? Tiene que ser hecho de cierta manera para que
Python no intente interpretarlo como parte del código.
En Python, un comentario es un texto que comienza con el símbolo # y se extiende hasta el final de la línea.
Si se desea colocar un comentario que abarca varias líneas, se debe colocar este símbolo en cada línea. Justo
como en el siguiente código:
Los desarrolladores buenos y responsables describen cada pieza importante de código, por ejemplo, el explicar
el rol de una variable. Aunque la mejor manera de comentar una variable es dándole un nombre que no sea
ambiguo.
Por ejemplo, si una variable determinada está diseñada para almacenar el área de un cuadrado, el nombre
square_area será muchísimo mejor que aunt_jane.
Los comentarios pueden ser útiles en otro aspecto – se pueden utilizar para marcar un fragmento de código que
actualmente no se necesita, cual sea la razón. Observa el siguiente ejemplo, sí se des comenta la línea resaltada,
esto afectara la salida o resultado del código:
Esto es frecuentemente realizado cuando se está probando un programa, con el fin de aislar un fragmento de
código donde posiblemente se encuentra un error.
CONSEJO: Si deseas comentar o descomentar rápidamente varias líneas(s) de código, selecciona las líneas que
deseas modificar y utiliza el siguiente método abreviado de teclado: CTRL + / (Windows) or CMD + / (Mac OS). Es
un truco muy útil, ¿no?
ESCENARIO
El código en el editor contiene comentarios. Intenta mejorarlo: agrega o quita comentarios donde consideres
que sea apropiado (en ocasiones el remover un comentario lo hace más legible), y cambia el nombre de las
variables donde consideres que esto mejorará la comprensión del código.
Nota: Los comentarios son muy importantes. No solo hacen que el programa sea más fácil de entender, pero
también sirven para deshabilitar aquellas partes de código que no son necesarias (por ejemplo, cuando se
necesita probar cierta parte del código, e ignorar el resto). Los buenos programadores describen cada parte
importante del código, y dan nombres significativos a variables, debido a que en ocasiones es mucho más
sencillo dejar el comentario dentro del código mismo.
Es bueno utilizar nombres de variables legibles, y en ocasiones es mejor dividir el código en partes con nombres
(por ejemplo, en funciones). En algunas situaciones, es una buena idea escribir los pasos de cómo se realizaron
los cálculos de una forma sencilla y clara.
Una cosa más: puede ocurrir que un comentario contenga una pieza de información incorrecta o errónea -
¡nunca se debe de hacer eso a propósito!
2.5.4 RESUMEN DE SECCIÓN
1. Los comentarios pueden ser utilizados para colocar información adicional en el código. Son omitidos al
momento de la ejecución. Dicha información es para los lectores que están manipulando el código. En
Python, un comentario es un fragmento de texto que comienza con un #. El comentario se extiende hasta el
final de la línea.
2. Si deseas colocar un comentario que abarque varias líneas, es necesario colocar un # al inicio de cada línea.
Además, se puede utilizar un comentario para marcar un fragmento de código que no es necesario en el
momento y no se desea ejecutar. (observa la última línea de código del siguiente fragmento), por ejemplo:
3. Cuando sea posible, se deben auto comentar los nombres de las variables, por ejemplo, si se están
utilizando dos variables para almacenar la altura y longitud de algo, los nombres length y width son una
mejor elección que myvar1 y myvar2.
4. Es importante utilizar los comentarios para que los programas sean más fáciles de entender, además de
emplear variables legibles y significativas en el código. Sin embargo, es igualmente importante no utilizar
nombres de variables que sean confusos, o dejar comentarios que contengan información incorrecta.
5. Los comentarios pueden ser muy útiles cuando tú estás leyendo tu propio código después de un tiempo (es
común que los desarrolladores olviden lo que su propio código hace), y cuando otros están leyendo tu
código (les puede ayudar a comprender que es lo que hacen tus programas y como es que lo hacen).
R// Cadena #2
Pregunta 2: ¿Qué pasará cuando se ejecute el siguiente código?
Ahora se introducirá una nueva función, la cual pareciese ser un reflejo de la función print().
print() no tiene un resultado utilizable. La importancia de esta nueva función es que regresa un valor muy
utilizable.
La función input() es capaz de leer datos que fueron introducidos por el usuario y pasar esos datos al programa
en ejecución.
El programa entonces puede manipular los datos, haciendo que el código sea verdaderamente interactivo.
Todos los programas leen y procesan datos. Un programa que no obtiene datos de entrada del usuario es un
programa sordo.
Observa el ejemplo:
Nota:
El programa solicita al usuario que inserte algún dato desde la consola (seguramente utilizando el teclado,
aunque también es posible introducir datos utilizando la voz o alguna imagen);
La función input() es invocada sin argumentos (es la manera más sencilla de utilizar la función); la función
pondrá la consola en modo de entrada; aparecerá un cursor que parpadea, y podrás introducir datos con el
teclado, al terminar presiona la tecla Enter; todos los datos introducidos serán enviados al programa a través
del resultado de la función;
Nota: el resultado debe ser asignado a una variable; esto es crucial, si no se hace los datos introducidos se
perderán; Después se utiliza la función print() para mostrar los datos que se obtuvieron, con algunas
observaciones adicionales.
La función input() puede hacer otra cosa: puede avisar al usuario sin ninguna ayuda de print().
Nota:
la función input() se invoca con un argumento: es una cadena que contiene un mensaje;
el mensaje se mostrará en la consola antes de que el usuario tenga la oportunidad de ingresar algo;
input() entonces hará su trabajo.
Se ha dicho antes, pero hay que decirlo sin ambigüedades una vez más: el resultado de la función input() es una
cadena.
Una cadena que contiene todos los caracteres que el usuario introduce desde el teclado. No es un entero ni un
flotante.
Esto significa que no se debe utilizar como un argumento para operaciones matemáticas, por ejemplo, no se
pueden utilizar estos datos para elevarlos al cuadrado, para dividirlos entre algo o por algo.
2.6.4 LA FUNCIÓN INPUT() - OPERACIONES PROHIBIDAS
La última línea lo explica todo, se intentó aplicar el operador ** a 'str' (una cadena) acompañado por un 'float'.
Esto debe de ser obvio. ¿Puedes predecir el valor de "ser o no ser" elevado a la potencia 2?
¿Habremos llegado a un punto muerto? ¿Existirá alguna solución? Claro que la hay.
Python ofrece dos simples funciones para especificar un tipo de dato y resolver este problema, aquí están: int() y
float().
Esto es muy simple y efectivo. Sin embargo, estas funciones se pueden invocar directamente pasando el
resultado de la función input() directamente. No hay necesidad de emplear variables como almacenamiento
intermedio.
Se ha implementado esta idea en el editor - observa el código.
¿Puedes imaginar como la cadena introducida por el usuario fluye desde la función input() hacía la función
print()?
Prueba con diferentes valores, pequeños, grandes, negativos y positivos. El cero también es un buen valor para
introducir.
Eventualmente serás capaz de escribir programas completos, los cuales acepten datos en forma de números, los
cuales serán procesados y se mostrarán los resultados.
Por supuesto, estos programas serán muy primitivos y no muy utilizables, debido a que no pueden tomar
decisiones, y consecuentemente no son capaces de reaccionar acorde a cada situación.
El siguiente ejemplo hace referencia al programa anterior que calcula la longitud de la hipotenusa. Vamos a
reescribirlo, para que pueda leer las longitudes de los catetos desde la consola.
El programa desafortunadamente no reacciona correctamente a este error. Vamos a ignorar esto por ahora.
Regresaremos a ello pronto.
Toma en cuenta que en el programa que puede ver en el editor, la variable hypo se usa con un solo propósito -
guardar el valor calculado entre la ejecución de la línea de código contigua.
Debido a que la función print() acepta una expresión como argumento, se puede quitar la variable del código.
Ambos tienen una función secundaría. Son capaces de hacer algo más que sumar y multiplicar.
Los hemos visto en acción cuando sus argumentos son (flotantes o enteros, no hay diferencia).
Ahora veremos que son capaces también de manejar o manipular cadenas, aunque, en una manera muy
específica.
Simplemente concatena (junta) dos cadenas en una. Por supuesto, puede ser utilizado más de una vez en una
misma expresión, y en tal contexto se comporta con enlazado del lado izquierdo.
En contraste con el operador aritmético, el operador de concatenación no es conmutativo, por ejemplo, "ab" +
"ba" no es lo mismo que "ba" + "ab".
No olvides, si se desea que el signo + sea un concatenador, no un sumador, solo se debe asegurar que ambos
argumentos sean cadenas.
Nota: el usar + para concatenar cadenas te permite construir la salida de una manera más precisa que con una
función print() pura, incluso si está enriquecida con end= y sep= argumentos de palabras clave.
REPLICACIÓN
El signo de * (asterisco), cuando es aplicado a una cadena y a un número (o a un número y cadena) se convierte
en un operador de replicación:
Por ejemplo:
Recuerda: Un número menor o igual a cero produce una cadena vacía. Este sencillo programa "dibuja" un
rectángulo, haciendo uso del antiguo operador (+) en un nuevo rol:
Toma en cuenta la forma en que hemos usado los paréntesis en la segunda línea del código.
str()
A estas alturas ya sabes cómo emplear las funciones int() y float() para convertir una cadena a un número.
Este tipo de conversión no es en un solo sentido. También se puede convertir un numero a una cadena, lo cual
es más fácil y seguro - esta operación es posible hacerla siempre.
Sinceramente, puede hacer mucho más que transformar números en cadenas, eso lo veremos después.
Ya conoces los tipos de datos básicos y un conjunto de operadores fundamentales. Sabes cómo organizar la
salida y cómo obtener datos del usuario. Estos son fundamentos muy sólidos para el Módulo 3. Pero antes de
pasar al siguiente módulo, hagamos unos cuantos laboratorios y resumamos todo lo que has aprendido en esta
sección.
ESCENARIO
Tu tarea es completar el código para evaluar los resultados de cuatro operaciones aritméticas básicas.
Es posible que no puedas proteger el código de un usuario que quiera dividir entre cero. Está bien, no te
preocupes por eso por ahora.
ESCENARIO
Tu tarea es completar el código para poder evaluar la siguiente expresión:
El resultado debe de ser asignado a y. Se cauteloso, observa los operadores y priorízalos. Utiliza cuantos
paréntesis sean necesarios.
Puedes utilizar variables adicionales para acortar la expresión (sin embargo, no es muy necesario). Prueba tu
código cuidadosamente.
DATOS DE PRUEBA
Entrada de muestra: 1
Salida esperada: y = 0.6000000000000001
Salida esperada: 10
Salida esperada: y = 0.09901951266867294
Entrada de muestra: 100
Salida esperada: y = 0.009999000199950014
Entrada de muestra: -5
Salida Esperada: y = -0.19258202567760344
2.6.11 LAB OPERADORES Y EXPRESIONES –2
ESCENARIO
La tarea es preparar un código simple para evaluar o encontrar el tiempo final de un periodo de tiempo dado,
expresándolo en horas y minutos. La hora de inicio se da como un par de horas (0..23) y minutos (0..59). El
resultado debe ser mostrado en la consola.
Por ejemplo, si el evento comienza a las 12:17 y dura 59 minutos, terminará a las 13:16.
No te preocupes si tu código no es perfecto - está bien si acepta una hora invalida - lo más importante es que el
código produzca una salida correcta acorde a la entrada dada.
Prueba el código cuidadosamente. Pista: utilizar el operador % puede ser clave para el éxito.
DATOS DE PRUEBA
Entrada de muestra: 12 17 59
Salida Esperada: 13:16
Entrada de muestra: 23 58 642
Salida Esperada: 10:40
Entrada de muestra: 0 1 2939
Salida Esperada: 1: 0
2.6.12 RESUMEN DE SECCIÓN
1. La función print() envía datos a la consola, mientras que la función input() obtiene datos de la consola.
2. La función input() viene con un parámetro opcional: la cadena de mensaje. Te permite escribir un mensaje
antes de que el usuario ingrese algo, por ejemplo:
3. Cuando la función input() es llamada o invocada, el flujo del programa se detiene, el símbolo del cursor se
mantiene parpadeando (le está indicando al usuario que tome acción ya que la consola está en modo de
entrada) hasta que el usuario haya ingresado un dato y/o haya presionado la tecla Enter.
NOTA
Puedes probar la funcionalidad completa de la función input() localmente en tu máquina. Por razones de
optimización, se ha limitado el máximo número de ejecuciones en Edube a solo algunos segundos únicamente.
Ve a Sandbox, copia-pega el código que está arriba, ejecuta el programa, y espera unos segundos. Tu programa
debe detenerse después de unos segundos. Ahora abre IDLE, y ejecuta el mismo programa ahí -¿Puedes notar
alguna diferencia?
Tip: la característica mencionada anteriormente de la función input() puede ser utilizada para pedirle al usuario
que termine o finalice el programa. Observa el siguiente código:
4. El resultado de la función input() es una cadena. Se pueden unir cadenas unas con otras a través del operador
de concatenación (+). Observa el siguiente código:
R// 55
Una computadora ejecuta el programa y proporciona las respuestas. El programa debe ser capaz de reaccionar
de acuerdo con las respuestas recibidas.
Nunca obtendrás una respuesta como Déjame pensar…, no lo sé, o probablemente sí, pero no lo sé con
seguridad.
Para hacer preguntas, Python utiliza un conjunto de operadores muy especiales. Revisemos uno tras otro,
ilustrando sus efectos en algunos ejemplos simples.
Es un operador binario con enlazado del lado izquierdo. Necesita dos argumentos y verifica si son iguales.
3.1.3 Ejercicios
3.1.4 OPERADORES
El operador == (igual a) compara los valores de dos operandos. Si son iguales, el resultado de la comparación es
True. Si no son iguales, el resultado de la comparación es False.
Toma en cuenta que no podemos encontrar la respuesta si no sabemos qué valor está almacenado actualmente
en la variable var.
Si la variable se ha cambiado muchas veces durante la ejecución del programa, o si se ingresa su valor inicial
desde la consola, Python solo puede responder a esta pregunta en el tiempo de ejecución del programa.
Ahora imagina a un programador que sufre de insomnio, y tiene que contar las ovejas negras y blancas por
separado siempre y cuando haya exactamente el doble de ovejas negras que de las blancas.
Debido a la baja prioridad del operador ==, la pregunta será tratada como la siguiente:
Entonces, vamos a practicar la comprensión del operador == - ¿puedes adivinar la output del código a
continuación?
El operador != (no es igual a) también compara los valores de dos operandos. Aquí está la diferencia: si son
iguales, el resultado de la comparación es False. Si no son iguales, el resultado de la comparación es True.
Ahora echa un vistazo a la comparación de desigualdad a continuación - ¿puedes adivinar el resultado de esta
operación?
Si deseas saber si hay más ovejas negras que blancas, puedes escribirlo de la siguiente manera:
Ambos operadores (estrictos y no estrictos), así como los otros dos que se analizan en la siguiente sección, son
operadores binarios con enlazado del lado izquierdo, y su prioridad es mayor que la mostrada por == y !=.
Si queremos saber si tenemos que usar un gorro o no, nos hacemos la siguiente pregunta:
Vamos a comprobar si existe un riesgo de ser multados por la ley (la primera pregunta es estricta, la segunda no).
Existen al menos dos posibilidades: primero, puedes memorizarlo (almacenarlo en una variable) y utilizarlo más
tarde. ¿Cómo haces eso? Bueno, utilizarías una variable arbitraria como esta:
La segunda posibilidad es más conveniente y mucho más común: puedes utilizar la respuesta que obtengas para
tomar una decisión sobre el futuro del programa.
Necesitas una instrucción especial para este propósito, y la discutiremos muy pronto.
Ahora necesitamos actualizar nuestra tabla de prioridades, y poner todos los nuevos operadores en ella. Ahora
se ve como a continuación:
:
3.1.6 LAB VARIABLES ‒ PREGUNTAS Y RESPUESTAS
Escenario
Usando uno de los operadores de comparación en Python, escribe un programa simple de dos líneas que tome el
parámetro n como entrada, que es un entero, e imprime False si n es menor que 100, y True si n es mayor o
igual que 100.
No debes crear ningún bloque if (hablaremos de ellos muy pronto). Prueba tu código usando los datos que te
proporcionamos.
DATOS DE PRUEBA
Entrada de muestra: 55
Salida esperada: False
Entrada de muestra: 99
Salida esperada: False
Entrada de muestra: 100
Salida esperada: True
Entrada de muestra: 101
Salida esperada: True
Entrada de muestra: -5
Salida esperada: False
Entrada de muestra: +123
Salida esperada: True
Ya sabes cómo hacer preguntas a Python, pero aún no sabes cómo hacer un uso razonable de las respuestas. Se
debe tener un mecanismo que le permita hacer algo si se cumple una condición, y no hacerlo si no se cumple.
Es como en la vida real: haces ciertas cosas o no cuando se cumple una condición específica, por ejemplo, sales a
caminar si el clima es bueno, o te quedas en casa si está húmedo y frío.
Para tomar tales decisiones, Python ofrece una instrucción especial. Debido a su naturaleza y su aplicación, se
denomina instrucción condicional (o sentencia condicional).
Existen varias variantes de esta. Comenzaremos con la más simple, aumentando la dificultad lentamente.
La primera forma de una sentencia condicional, que puede ver a continuación, está escrita de manera muy
informal pero figurada:
Esta sentencia condicional consta de los siguientes elementos, estrictamente necesarios en este orden:
Si la expresión true_or_not representa la verdad (es decir, su valor no es igual a cero), las sentencias con
sangría se ejecutarán;
Si la expresión true_or_not no representa la verdad (es decir, su valor es igual a cero), las sentencias con
sangría se omitirán (ignorado), y la siguiente instrucción ejecutada será la siguiente al nivel de la sangría
original.
Como puedes ver, almorzar no es una actividad condicional y no depende del clima.
Sabiendo que condiciones influyen en nuestro comportamiento y asumiendo que tenemos las funciones sin
parámetros go_for_a_walk() y have_lunch(), podemos escribir el siguiente fragmento de código:
Si un determinado desarrollador de Python sin dormir se queda dormido cuando cuenta 120 ovejas, y el
procedimiento de inducción del sueño se puede implementar como una función especial llamada
sleep_and_dream(), el código toma la siguiente forma:
Puedes leerlo como sigue: si sheep_counter es mayor o igual que 120, entonces duerme y sueña (es decir,
ejecuta la función sleep_and_dream).
Hemos dicho que las sentencias condicionales deben tener sangría. Esto crea una estructura muy legible,
demostrando claramente todas las rutas de ejecución posibles en el código.
Como puedes ver, tender la cama, tomar una ducha y dormir y soñar se ejecutan condicionalmente - cuando
sheep_counter alcanza el límite deseado.
Alimentar a los perros, sin embargo, siempre se hace (es decir, la función feed_the_sheepdogs() no tiene sangría
y no pertenece al bloque if, lo que significa que siempre se ejecuta).
Ahora vamos a discutir otra variante de la sentencia condicional, que también permite realizar una acción
adicional cuando no se cumple la condición.
EJECUCIÓN CONDICIONAL: LA SENTENCIA IF-ELSE
Comenzamos con una frase simple que decía: Si el clima es bueno, saldremos a caminar.
Nota: no hay una palabra sobre lo que sucederá si el clima es malo. Solo sabemos que no saldremos al aire libre,
pero no sabemos que podríamos hacer. Es posible que también queramos planificar algo en caso de mal tiempo.
Podemos decir, por ejemplo: Si el clima es bueno, saldremos a caminar, de lo contrario, iremos al cine.
Ahora sabemos lo que haremos si se cumplen las condiciones, y sabemos lo que haremos si no todo sale como
queremos. En otras palabras, tenemos un "Plan B".
Python nos permite expresar dichos planes alternativos. Esto se hace con una segunda forma, ligeramente mas
compleja, de la sentencia condicional, la sentencia if-else:
Por lo tanto, hay una nueva palabra: else - esta es una palabra clave reservada.
La parte del código que comienza con else dice que hacer si no se cumple la condición especificada por el if
(observa los dos puntos después de la palabra).
Al utilizar esta forma de sentencia condicional, podemos describir nuestros planes de la siguiente manera:
Si el clima es bueno, saldremos a caminar. De lo contrario, iremos al cine. No importa si el clima es bueno o malo,
almorzaremos después (después de la caminata o después de ir al cine).
Todo lo que hemos dicho sobre la sangría funciona de la misma manera dentro de la rama else:
SENTENCIAS IF-ELSE ANIDADAS
Primero, considera el caso donde la instrucción colocada después del if es otro if.
Lee lo que hemos planeado para este Domingo. Si hay buen clima, saldremos a caminar. Si encontramos un buen
restaurante, almorzaremos allí. De lo contrario, vamos a comer un sandwich. Si hay mal clima, iremos al cine. Si
no hay boletos, iremos de compras al centro comercial más cercano.
1. Este uso de la sentencia if se conoce como anidamiento; recuerda que cada else se refiere al if que se
encuentra en el mismo nivel de sangría; se necesita saber esto para determinar cómo se relacionan los
ifs y los else;
2. Considera como la sangría mejora la legibilidad y hace que el código sea más fácil de entender y
rastrear.
LA SENTENCIA elif
El segundo caso especial presenta otra nueva palabra clave de Python: elif. Como probablemente sospechas, es
una forma más corta de else if.
elif se usa para verificar más de una condición, y para detener cuando se encuentra la primera sentencia
verdadera.
Nuestro siguiente ejemplo se parece a la anidación, pero las similitudes son muy leves. Nuevamente,
cambiaremos nuestros planes y los expresaremos de la siguiente manera: si hay buen clima, saldremos a
caminar, de lo contrario, si obtenemos entradas, iremos al cine, de lo contrario, si hay mesas libres en el
restaurante, vamos a almorzar; si toda falla, regresaremos a casa y jugaremos ajedrez.
¿Has notado cuantas veces hemos usado las palabras de lo contrario? Esta es la etapa en la que la palabra clave
reservada elif desempeña su función.
Esto puede sonar un poco desconcertante, pero ojalá que algunos ejemplos simples ayuden a comprenderlo
mejor.
Ahora te mostraremos algunos programas simples pero completos. No los explicaremos a detalle, porque
consideramos que los comentarios (y los nombres de las variables) dentro del código son guías suficientes.
Todos los programas resuelven el mismo problema - encuentran el número mayor de una serie de números y lo
imprimen.
Ejemplo 1:
Comenzaremos con el caso más simple - ¿cómo identificar el mayor de los dos números?:
El fragmento de código anterior debe estar claro - lee dos valores enteros, los compara y encuentra cuál es el
más grande.
Ejemplo 2:
Ahora vamos a mostrarte un hecho intrigante. Python tiene una característica interesante - mira el código a
continuación:
Nota: si alguna de las ramas de if-elif-else contiene una sola instrucción, puedes codificarla de forma más
completa (no es necesario que aparezca una línea con sangría después de la palabra clave), pero solo continúa la
línea después de los dos puntos).
Sin embargo, este estilo puede ser engañoso, y no lo vamos a usar en nuestros programas futuros, pero
definitivamente vale la pena saber si quieres leer y entender los programas de otra persona.
Ejemplo 3:
Es hora de complicar el código - encontremos el mayor de los tres números. ¿Se ampliará el código? Un poco.
Suponemos que el primer valor es el más grande. Luego verificamos esta hipótesis con los dos valores restantes.
Este método es significativamente más simple que tratar de encontrar el número más grande comparando todos
los pares de números posibles (es decir, el primero con el segundo, el segundo con el tercero y el tercero con el
primero). Intenta reconstruir el código por ti mismo.
Ahora deberías poder escribir un programa que encuentre el mayor de cuatro, cinco, seis o incluso diez números.
Ya conoces el esquema, por lo que ampliar el tamaño del problema no será particularmente complejo.
¿Pero qué sucede si te pedimos que escribas un programa que encuentre el mayor de doscientos números? ¿Te
imaginas el código?
Necesitarás doscientas variables. Si doscientas variables no son lo suficientemente complicadas, intenta imaginar
la búsqueda del número más grande de un millón.
Imagina un código que contiene 199 sentencias condicionales y doscientas invocaciones de la función input().
Por suerte, no necesitas lidiar con eso. Hay un enfoque más simple.
Por ahora ignoraremos los requisitos de la sintaxis de Python e intentaremos analizar el problema sin pensar en
la programación real. En otras palabras, intentaremos escribir el algoritmo, y cuando estemos contentos con él,
lo implementaremos.
En este caso, utilizaremos un tipo de notación que no es un lenguaje de programación real (no se puede
compilar ni ejecutar), pero está formalizado, es conciso y se puede leer. Se llama pseudocódigo.
En primer lugar, podemos simplificar el programa si, al principio del código, le asignamos a la variable
largest_number un valor que será más pequeño que cualquiera de los números ingresados. Usaremos
-999999999 para ese propósito.
En segundo lugar, asumimos que nuestro algoritmo no sabrá por adelantado cuántos números se entregarán al
programa. Esperamos que el usuario ingrese todos los números que desee - el algoritmo funcionará bien con
cien y con mil números. ¿Cómo hacemos eso?
Hacemos un trato con el usuario: cuando se ingresa el valor-1, será una señal de que no hay más datos y que el
programa debe finalizar su trabajo.
De lo contrario, si el valor ingresado no es igual a -1, el programa leerá otro número, y así sucesivamente.
El truco se basa en la suposición de que cualquier parte del código se puede realizar más de una vez -
precisamente, tantas veces como sea necesario.
La ejecución de una determinada parte del código más de una vez se denomina bucle. El significado de este
término es probablemente obvio para ti.
Las líneas 02 al 08 forman un bucle. Los pasaremos tantas veces como sea necesario para revisar todos los
valores ingresados.
¿Puedes usar una estructura similar en un programa escrito en Python? Si, si puedes
INFORMACIÓN ADICIONAL
Python a menudo viene con muchas funciones integradas que harán el trabajo por ti. Por ejemplo, para
encontrar el número más grande de todos, puede usar una función incorporada de Python llamada max().
Puedes usarlo con múltiples argumentos. Analiza el código de abajo:
De la misma manera, puedes usar la función min() para devolver el número más pequeño. Puedes reconstruir el
código anterior y experimentar con él en Sandbox.
Vamos a hablar sobre estas (y muchas otras) funciones pronto. Por el momento, nuestro enfoque se centrará en
la ejecución condicional y los bucles para permitirte ganar más confianza en la programación y enseñarte las
habilidades que te permitirán comprender y aplicar los dos conceptos en tu código. Entonces, por ahora, no
estamos tomando atajos.
ESCENARIO
Espatifilo, más comúnmente conocida como la planta de Cuna de Moisés o flor de la paz, es una de las plantas
para interiores más populares que filtra las toxinas dañinas del aire. Algunas de las toxinas que neutraliza
incluyen benceno, formaldehído y amoníaco.
Imagina que tu programa de computadora ama estas plantas. Cada vez que recibe una entrada en forma de la
palabra Espatifilo, grite involuntariamente a la consola la siguiente cadena: "¡Espatifilo es la mejor planta de
todas!"
Escribe un programa que utilice el concepto de ejecución condicional, tome una cadena como entrada y que:
imprima el enunciado "Si - ¡El Espatifilo! es la mejor planta de todos los tiempos!" en la pantalla si la
cadena ingresada es "ESPATIFILIO" (mayúsculas)
imprima "No, ¡quiero un gran Espatifilo!" si la cadena ingresada es "espatifilo" (minúsculas)
imprima "¡Espatifilo!, ¡No [entrada]!" de lo contrario. Nota: [entrada] es la cadena que se toma como
entrada.
Prueba tu código con los datos que te proporcionamos. ¡Y hazte de un Espatifilo también!
Datos de Prueba:
Entrada de muestra: espatifilo
Salida esperada: No, ¡quiero un gran Espatifilo!
Entrada de muestra: pelargonio
Salida esperada: ¡Espatifilo!, ¡No pelargonio!
Entrada de muestra: Espatifilo
Salida esperada: Si, ¡El Espatifilo! es la mejor planta de todos los tiempos!
ESCENARIO
Érase una vez una tierra de leche y miel - habitada por gente feliz y próspera. La gente pagaba impuestos, por
supuesto - su felicidad tenía límites. El impuesto más importante, denominado Impuesto Personal de Ingresos
(IPI, para abreviar) tenía que pagarse una vez al año y se evaluó utilizando la siguiente regla:
si el ingreso del ciudadano no era superior a 85,528 pesos, el impuesto era igual al 18% del ingreso
menos 556 pesos y 2 centavos (esta fue la llamada exención fiscal).
si el ingreso era superior a esta cantidad, el impuesto era igual a 14,839 pesos y 2 centavos, más el 32%
del excedente sobre 85,528 pesos.
Observa el código en el editor - solo lee un valor de entrada y genera un resultado, por lo que debes completarlo con
algunos cálculos inteligentes.
DATOS DE PRUEBA
Entrada de muestra: 10000
Salida esperada: El impuesto es: 1244.0 pesos
Entrada de muestra: 100000
Salida esperada: El impuesto es: 19470.0 pesos
Entrada de muestra: 1000
Salida esperada: El impuesto es: 0.0 pesos
Entrada de muestra: -100
Salida esperada: El impuesto es: 0.0 pesos
ESCENARIO
Como seguramente sabrás, debido a algunas razones astronómicas, el año puede ser bisiesto o común. Los
primeros tienen una duración de 366 días, mientras que los últimos tienen una duración de 365 días.
Desde la introducción del calendario Gregoriano (en 1582), se utiliza la siguiente regla para determinar el tipo de
año:
si el número del año no es divisible entre cuatro, es un año común.
de lo contrario, si el número del año no es divisible entre 100, es un año bisiesto.
de lo contrario, si el número del año no es divisible entre 400, es un año común.
de lo contrario, es un año bisiesto.
Observa el código en el editor - solo lee un número de año y debe completarse con las instrucciones que
implementan la prueba que acabamos de describir.
El código debe mostrar uno de los dos mensajes posibles, que son Año Bisiesto o Año Común, según el valor
ingresado.
Sería bueno verificar si el año ingresado cae en la era Gregoriana y emitir una advertencia de lo contrario: No
dentro del período del calendario Gregoriano. Consejo: utiliza los operadores != y %.
DATOS DE PRUEBA:
Entrada de muestra: 2000
Salida esperada: Año bisiesto
Entrada de muestra: 2015
Salida esperada: Año común
Entrada de muestra: 1999
Salida esperada: Año común
Entrada de muestra: 1996
Salida esperada: Año bisiesto
Entrada de muestra: 1580
Salida esperada: No dentro del período del calendario gregoriano
1. Los operadores de comparación (o también denominados operadores relacionales) se utilizan para comparar
valores. La siguiente tabla ilustra cómo funcionan los operadores de comparación, asumiendo que x = 0, y =
1, y z = 0:
2. Cuando deseas ejecutar algún código solo si se cumple una determinada condición, puedes usar una
sentencia condicional:
Cada sentencia if se prueba por separado. El cuerpo del else es ejecutado si el último if es False.
Toma en cuenta que este registro también declara que, si no hay nada que hacer, nada ocurrirá.
Si observas algunas similitudes con la instrucción if, está bien. De hecho, la diferencia sintáctica es solo una: usa
la palabra while en lugar de la palabra if.
La diferencia semántica es más importante: cuando se cumple la condición, if realiza sus sentencias sólo una vez;
while repite la ejecución siempre que la condición se evalúe como True.
Nota: todas las reglas relacionadas con sangría también se aplican aquí. Te mostraremos esto pronto.
Un bucle infinito, también denominado bucle sin fin, es una secuencia de instrucciones en un programa que se
repite indefinidamente (bucle sin fin).
Nota
Si deseas obtener la mejor experiencia de aprendizaje al ver cómo se comporta un bucle infinito, inicia IDLE, crea
un nuevo archivo, copia y pega el código anterior, guarda tu archivo y ejecuta el programa. Lo que verás es la
secuencia interminable de cadenas impresas de "Estoy atrapado dentro de un bucle." en la ventana de la
consola de Python. Para finalizar tu programa, simplemente presiona Ctrl-C (o Ctrl-Break en algunas
computadoras). Esto provocará la excepción KeyboardInterrupt y permitirá que tu programa salga del bucle.
Hablaremos de ello más adelante en el curso.
Volvamos al bosquejo del algoritmo que te mostramos recientemente. Te mostraremos como usar este bucle
recién aprendido para encontrar el número más grande de un gran conjunto de datos ingresados.
Analiza el programa cuidadosamente. Localiza donde comienza el bucle (línea 8) y descubre como se sale del
cuerpo del bucle:
Veamos otro ejemplo utilizando el bucle while. Sigue los comentarios para descubrir la idea y la solución.
La condición que verifica si un número es impar también puede codificarse en estas formas equivalentes:
if number % 2 == 1: y if number % 2:
Este código está destinado a imprimir la cadena "Dentro del bucle." y el valor almacenado en la variable counter
durante un bucle dado exactamente cinco veces. Una vez que la condición se haya cumplido (la variable counter
ha alcanzado 0), se sale del bucle y aparece el mensaje "Fuera del bucle." así como también el valor almacenado
en counter se imprime.
Pero hay una cosa que se puede escribir de forma más compacta - la condición del bucle while.
¿Es más compacto que antes? Un poco. ¿Es más legible? Eso es discutible.
RECUERDA
No te sientas obligado a codificar tus programas de una manera que siempre sea la más corta y la más compacta.
La legibilidad puede ser un factor más importante. Mantén tu código listo para un nuevo programador
ESCENARIO
Un mago junior ha elegido un número secreto. Lo ha escondido en una variable llamada secret_number. Quiere
que todos los que ejecutan su programa jueguen el juego Adivina el número secreto, y adivina qué número ha
elegido para ellos. ¡Quiénes no adivinen el número quedarán atrapados en un bucle sin fin para siempre!
Desafortunadamente, él no sabe cómo completar el código.
Tu tarea es ayudar al mago a completar el código en el editor de tal manera que el código:
pedirá al usuario que ingrese un número entero;
utilizará un bucle while;
comprobará si el número ingresado por el usuario es el mismo que el número escogido por el mago. Si el
número elegido por el usuario es diferente al número secreto del mago, el usuario debería ver el
mensaje "¡Ja, ja! ¡Estás atrapado en mi bucle!" y se le solicitará que ingrese un número nuevamente. Si
el número ingresado por el usuario coincide con el número escogido por el mago, el número debe
imprimirse en la pantalla, y el mago debe decir las siguientes palabras: "¡Bien hecho, muggle! Eres libre
ahora."
¡El mago está contando contigo! No lo decepciones.
INFO EXTRA
Por cierto, observa la función print(). La forma en que lo hemos utilizado aquí se llama impresión multilínea.
Puedes utilizar comillas triples para imprimir cadenas en varias líneas para facilitar la lectura del texto o crear un
diseño especial basado en texto. Experimenta con ello.
Otro tipo de bucle disponible en Python proviene de la observación de que a veces es más importante contar los
"giros o vueltas" del bucle que verificar las condiciones.
Imagina que el cuerpo de un bucle debe ejecutarse exactamente cien veces. Si deseas utilizar el bucle while para
hacerlo, puede tener este aspecto:
Sería bueno si alguien pudiera hacer esta cuenta aburrida por ti. ¿Es eso posible?
Por supuesto que lo es - hay un bucle especial para este tipo de tareas, y se llama for.
En realidad, el bucle for está diseñado para realizar tareas más complicadas, puede "explorar" grandes
colecciones de datos elemento por elemento. Te mostraremos como hacerlo pronto, pero ahora presentaremos
una variante más sencilla de su aplicación.
la palabra reservada for abre el bucle for; nota - No hay condición después de eso; no tienes que pensar
en las condiciones, ya que se verifican internamente, sin ninguna intervención.
cualquier variable después de la palabra reservada for es la variable de control del bucle; cuenta los
giros del bucle y lo hace automáticamente.
la palabra reservada in introduce un elemento de sintaxis que describe el rango de valores posibles que
se asignan a la variable de control.
la función range() (esta es una función muy especial) es responsable de generar todos los valores
deseados de la variable de control; en nuestro ejemplo, la función creará (incluso podemos decir que
alimentará el bucle con) valores subsiguientes del siguiente conjunto: 0, 1, 2 ... 97, 98, 99; nota: en este
caso, la función range() comienza su trabajo desde 0 y lo finaliza un paso (un número entero) antes del
valor de su argumento.
nota la palabra clave pass dentro del cuerpo del bucle - no hace nada en absoluto; es una instrucción
vacía - la colocamos aquí porque la sintaxis del bucle for exige al menos una instrucción dentro del
cuerpo (por cierto - if, elif, else y while expresan lo mismo).
Nuestros próximos ejemplos serán un poco más modestos en el número de repeticiones de bucle.
Nota:
El bucle se ha ejecutado diez veces (es el argumento de la función range())
El valor de la última variable de control es 9 (no 10, ya que comienza desde 0 , no desde 1)
La invocación de la función range() puede estar equipada con dos argumentos, no solo uno:
En este caso, el primer argumento determina el valor inicial (primero) de la variable de control.
Nota: la función range() solo acepta enteros como argumentos y genera secuencias de enteros.
¿Puedes adivinar el output del programa? Ejecútalo para comprobar si ahora también estabas en lo cierto.
3.2.6 MÁS ACERCA DEL BUCLE for Y LA FUNCIÓN range() CON TRES ARGUMENTOS
La función range() también puede aceptar tres argumentos: Echa un vistazo al código del editor.
El tercer argumento es un incremento - es un valor agregado para controlar la variable en cada giro del bucle
(como puedes sospechar, el valor predeterminado del incremento es 1).
¿Sabes por qué? El primer argumento pasado a la función range() nos dice cuál es el número de inicio de la
secuencia (por lo tanto 2 en el output). El segundo argumento le dice a la función dónde detener la secuencia (la
función genera números hasta el número indicado por el segundo argumento, pero no lo incluye). Finalmente, el
tercer argumento indica el paso, que en realidad significa la diferencia entre cada número en la secuencia de
números generados por la función.
2 (número inicial) → 5 (2 incremento por 3 es igual a 5 - el número está dentro del rango de 2 a 8) → 8 (5
incremento por 3 es igual a 8 - el número no está dentro del rango de 2 a 8, porque el parámetro de parada no
está incluido en la secuencia de números generados por la función).
Nota: si el conjunto generado por la función range() está vacío, el bucle no ejecutará su cuerpo en absoluto.
Nota: el conjunto generado por range() debe ordenarse en un orden ascendente. No hay forma de forzar el
range() para crear un conjunto en una forma diferente. Esto significa que el segundo argumento de range() debe
ser mayor que el primero.
Echemos un vistazo a un programa corto cuya tarea es escribir algunas de las primeras potencias de dos:
Echemos un vistazo a un programa corto cuya tarea es escribir algunas de las primeras potencias de dos:
ESCENARIO
¿Sabes lo que es Mississippi? Bueno, es el nombre de uno de los estados y ríos en los Estados Unidos. El río
Mississippi tiene aproximadamente 2,340 millas de largo, lo que lo convierte en el segundo río más largo de los
Estados Unidos (el más largo es el río Missouri). ¡Es tan largo que una sola gota de agua necesita 90 días para
recorrer toda su longitud!
La palabra Mississippi también se usa para un propósito ligeramente diferente: para contar mississippily
(mississippimente).
Si no estás familiarizado con la frase, estamos aquí para explicarte lo que significa: se utiliza para contar
segundos.
La idea detrás de esto es que agregar la palabra Mississippi a un número al contar los segundos en voz alta hace
que suene más cercano al reloj, y por lo tanto "un Mississippi, dos Mississippi, tres Mississippi" tomará
aproximadamente unos tres segundos reales de tiempo. A menudo lo usan los niños que juegan al escondite
para asegurarse de que el buscador haga un conteo honesto.
Tu tarea es muy simple aquí: escribe un programa que use un bucle for para "contar de forma mississippi" hasta
cinco. Habiendo contado hasta cinco, el programa debería imprimir en la pantalla el mensaje final "¡Listos o no,
ahí voy!"
INFO EXTRA
Ten en cuenta que el código en el editor contiene dos elementos que pueden no ser del todo claros en este
momento: la sentencia import time y el método sleep(). Vamos a hablar de ellos pronto.
Por el momento, nos gustaría que supieras que hemos importado el módulo time y hemos utilizado el método
sleep() para suspender la ejecución de cada función posterior de print() dentro del bucle for durante un
segundo, de modo que el mensaje enviado a la consola se parezca a un conteo real. No te preocupes - pronto
aprenderás más sobre módulos y métodos.
Salida esperada:
Hasta ahora, hemos tratado el cuerpo del bucle como una secuencia indivisible e inseparable de instrucciones
que se realizan completamente en cada giro del bucle. Sin embargo, como desarrollador, podrías enfrentar las
siguientes opciones:
parece que no es necesario continuar el bucle en su totalidad; se debe abstener de seguir ejecutando el
cuerpo del bucle e ir más allá;
parece que necesitas comenzar el siguiente giro del bucle sin completar la ejecución del turno actual.
Python proporciona dos instrucciones especiales para la implementación de estas dos tareas. Digamos por
razones de precisión que su existencia en el lenguaje no es necesaria - un programador experimentado puede
codificar cualquier algoritmo sin estas instrucciones. Tales adiciones, que no mejoran el poder expresivo del
lenguaje, sino que solo simplifican el trabajo del desarrollador, a veces se denominan dulces sintácticos o azúcar
sintáctica.
Ahora te mostraremos dos ejemplos simples para ilustrar cómo funcionan las dos instrucciones. Mira el código
en el editor. Ejecuta el programa y analiza el output. Modifica el código y experimenta.
Regresemos a nuestro programa que reconoce el más grande entre los números ingresados. Lo convertiremos
dos veces, usando las instrucciones de break y continue.
Observa con atención, el usuario ingresa el primer número antes de que el programa ingrese al bucle
while. El número siguiente se ingresa cuando el programa ya está en el bucle.
ESCENARIO
Diseña un programa que use un bucle while y le pida continuamente al usuario que ingrese una palabra a menos
que ingrese "chupacabra" como la palabra de output secreta, en cuyo caso el mensaje "Has dejado el bucle con
éxito." debe imprimirse en la pantalla y el bucle debe terminar.
No imprimas ninguna de las palabras ingresadas por el usuario. Utiliza el concepto de ejecución condicional y la
sentencia break.
ESCENARIO
La sentencia continue se usa para omitir el bloque actual y avanzar a la siguiente iteración, sin ejecutar las
sentencias dentro del bucle.
Tu tarea aquí es muy especial: ¡Debes diseñar un devorador de vocales! Escribe un programa que use:
un bucle for;
el concepto de ejecución condicional (if-elif-else).
la sentencia continue.
Tu programa debe:
DATOS DE PRUEBA:
Entrada de muestra: Gregory
Salida esperada: G R G R Y
Entrada de muestra: abstemious
Salida esperada: B S T M S
Entrada de muestra: IOUEA
Salida esperada:
ESCENARIO
Tu tarea aquí es aún más especial que antes: ¡Debes rediseñar el devorador de vocales (feo) del laboratorio
anterior y crear un mejor devorador de vocales (lindo) mejorado! Escribe un programa que use:
un bucle for.
el concepto de ejecución condicional (if-elif-else).
la instrucción continue.
Tu programa debe:
pedir al usuario que ingrese una palabra.
utilizar user_word = user_word.upper() para convertir la palabra ingresada por el usuario a mayúsculas;
hablaremos sobre los llamados métodos de cadena y el upper() muy pronto, no te preocupes.
emplea la ejecución condicional y la instrucción continue para "devorar" las siguientes vocales A , E , I , O
, U de la palabra ingresada.
asigna las letras no consumidas a la variable word_without_vowels e imprime la variable en la pantalla.
Analiza el código en el editor. Hemos creado word_without_vowels y le hemos asignado una cadena vacía. Utiliza
la operación de concatenación para pedirle a Python que combine las letras seleccionadas en una cadena más
larga durante los siguientes giros de bucle, y asignarlo a la variable word_without_vowels.
DATOS DE PRUEBA:
Entrada de muestra: Gregory
Salida esperada: G R G R Y
Entrada de muestra: abstemious
Salida esperada: B S T M S
Entrada de muestra: IOUEA
Salida esperada:
Ambos bucles while y for, tienen una característica interesante (y rara vez se usa).
Te mostraremos cómo funciona - intenta juzgar por ti mismo si es utilizable.
En otras palabras, trata de convencerte si la función es valiosa y útil, o solo es azúcar sintáctica.
Echa un vistazo al fragmento en el editor. Hay algo extraño al final - la palabra reservada else.
Como pudiste haber sospechado, los bucles también pueden tener la rama else, como los if.
La rama else del bucle siempre se ejecuta una vez, independientemente de si el bucle ha entrado o no en su
cuerpo.
¿Puedes adivinar el output? Ejecuta el programa para comprobar si tenías razón.
Modifica el fragmento un poco para que el bucle no tenga oportunidad de ejecutar su cuerpo ni una sola vez:
El estado del while es False al principio - ¿puedes verlo?
Los bucles for se comportan de manera un poco diferente - echa un vistazo al fragmento en el editor y ejecútalo.
El cuerpo del bucle no se ejecutará aquí en absoluto. Nota: hemos asignado la variable i antes del bucle.
Cuando el cuerpo del bucle no se ejecuta, la variable de control conserva el valor que tenía antes del bucle.
Nota: si la variable de control no existe antes de que comience el bucle, no existirá cuando la ejecución llegue
a la rama else branch.
Ahora vamos a informarte sobre otros tipos de variables. Nuestras variables actuales solo pueden almacenar un
valor a la vez, pero hay variables que pueden hacer mucho más - pueden almacenar tantos valores como desees.
Pero primero hagamos algunos laboratorios.
Escucha esta historia: Un niño y su padre, un programador de computadoras, juegan con bloques de madera.
Están construyendo una pirámide.
Su pirámide es un poco rara, ya que en realidad es una pared en forma de pirámide - es plana. La pirámide se
apila de acuerdo con un principio simple: cada capa inferior contiene un bloque más que la capa superior.
Tu tarea es escribir un programa que lea la cantidad de bloques que tienen los constructores, y generar la altura
de la pirámide que se puede construir utilizando estos bloques.
Nota: La altura se mide por el número de capas completas - si los constructores no tienen la cantidad suficiente
de bloques y no pueden completar la siguiente capa, terminan su trabajo inmediatamente.
Prueba tu código con los datos que hemos proporcionado.
DATOS DE PRUEBA
Entrada de muestra: 6
Salida esperada: La altura de la pirámide es: 3
Entrada de muestra: 20
Salida esperada: La altura de la pirámide: 5
Entrada de muestra: 1000
Salida esperada: La altura de la pirámide: 44
Entrada de muestra: 2
Salida esperada: La altura de la pirámide: 1
2. Puedes usar las sentencias break y continue para cambiar el flujo de un bucle:
Utiliza break para salir de un bucle, por ejemplo:
Utiliza continue para omitir la iteración actual, y continuar con la siguiente iteración, por ejemplo:
3. Los bucles while y for también pueden tener una cláusula else en Python. La cláusula else se ejecuta después
de que el bucle finalice su ejecución siempre y cuando no haya terminado con break, por ejemplo:
4. La función range() genera una secuencia de números. Acepta enteros y devuelve objetos de rango. La sintaxis
de range() tiene el siguiente aspecto: range(start, stop, step), donde:
start es un parámetro opcional que especifica el número de inicio de la secuencia (0 por defecto)
stop es un parámetro opcional que especifica el final de la secuencia generada (no está incluido).
y step es un parámetro opcional que especifica la diferencia entre los números en la secuencia es (1 por
defecto.)
Código de ejemplo:
R//
Pregunta 2: Crea un bucle while que cuente de 0 a 10, e imprima números impares en la pantalla. Usa el
esqueleto de abajo:
R//
Pregunta 3: Crea un programa con un bucle for y una sentencia break. El programa debe iterar sobre los
caracteres en una dirección de correo electrónico, salir del bucle cuando llegue al símbolo @ e imprimir la parte
antes de @ en una línea. Usa el esqueleto de abajo:
R//
Pregunta 4: Crea un programa con un bucle for y una sentencia continue. El programa debe iterar sobre una
cadena de dígitos, reemplazar cada 0 con x, e imprimir la cadena modificada en la pantalla. Usa el esqueleto de
abajo:
R//
R//
R//
R//
Hemos utilizado la conjunción and (y), lo que significa que salir a caminar depende del cumplimiento simultáneo
de estas dos condiciones. En el lenguaje de la lógica, tal conexión de condiciones se denomina conjunción. Y
ahora otro ejemplo:
Si tú estás en el centro comercial o yo estoy en el centro comercial, uno de nosotros le comprará un regalo a
mamá.
La aparición de la palabra or (o) significa que la compra depende de al menos una de estas condiciones. En
lógica, este compuesto se llama una disyunción.
Está claro que Python debe tener operadores para construir conjunciones y disyunciones. Sin ellos, el poder
expresivo del lenguaje se debilitaría sustancialmente. Se llaman operadores lógicos.
EL OPERADOR and
Un operador de conjunción lógica en Python es la palabra and. Es un operador binario con una prioridad inferior
a la expresada por los operadores de comparación. Nos permite codificar condiciones complejas sin el uso de
paréntesis como este:
El resultado proporcionado por el operador and se puede determinar sobre la base de la tabla de verdad.
EL OPERADOR or
Un operador de disyunción es la palabra or. Es un operador binario con una prioridad más baja que and (al igual
que + en comparación con *). Su tabla de verdad es la siguiente:
EL OPERADOR not
Además, hay otro operador que se puede aplicar para condiciones de construcción. Es un operador unario que
realiza una negación lógica. Su funcionamiento es simple: convierte la verdad en falso y lo falso en verdad.
Este operador se escribe como la palabra not, y su prioridad es muy alta: igual que el unario + y -. Su tabla de
verdad es simple:
Creemos una variable llamada var y asignémosle 1. Las siguientes condiciones son equivalentes a pares:
Observa cómo se han utilizado los paréntesis para codificar las expresiones - las colocamos allí para mejorar la
legibilidad.
Deberíamos agregar que ninguno de estos operadores de dos argumentos se puede usar en la forma abreviada
conocida como op=. Vale la pena recordar esta excepción.
Sin embargo, hay cuatro operadores que le permiten manipular bits de datos individuales. Se denominan
operadores bit a bit.
Cubren todas las operaciones que mencionamos anteriormente en el contexto lógico, y un operador adicional.
Este es el operador xor (significa o exclusivo ), y se denota como ^ (signo de intercalación).
Agreguemos un comentario importante: los argumentos de estos operadores deben ser enteros; no debemos
usar flotantes aquí.
La diferencia en el funcionamiento de los operadores lógicos y de bits es importante: los operadores lógicos no
penetran en el nivel de bits de su argumento. Solo les interesa el valor entero final.
Los operadores bit a bit son más estrictos: tratan con cada bit por separado. Si asumimos que la variable entera
ocupa 64 bits (lo que es común en los sistemas informáticos modernos), puede imaginar la operación a nivel de
bits como una evaluación de 64 veces del operador lógico para cada par de bits de los argumentos. Su analogía
es obviamente imperfecta, ya que en el mundo real todas estas 64 operaciones se realizan al mismo tiempo
(simultáneamente).
OPERACIONES LÓGICAS VS OPERACIONES DE BIT
Ahora te mostraremos un ejemplo de la diferencia en la operación entre las operaciones lógicas y de bit.
Supongamos que se han realizado las siguientes tareas:
Si asumimos que los enteros se almacenan con 32 bits, la imagen a nivel de bits de las dos variables será la
siguiente:
Se ejecuta la asignación:
Estamos tratando con una conjunción lógica aquí. Vamos a trazar el curso de los cálculos. Ambas variables i y j no
son ceros, por lo que se considerará que representan a True. Al consultar la tabla de verdad para el operador
and, podemos ver que el resultado será True. No se realizan otras operaciones.
El operador & operará con cada par de bits correspondientes por separado, produciendo los valores de los bits
relevantes del resultado. Por lo tanto, el resultado será el siguiente
Puede ser un poco sorprendente: el valor de la variable bitneg es -16. Esto puede parecer extraño, pero no lo es
en absoluto. Si deseas obtener más información, debes consultar el sistema de números binarios y las reglas que
rigen los números de complemento de dos.
Cada uno de estos operadores de dos argumentos se puede utilizar en forma abreviada. Estos son los ejemplos
de sus notaciones equivalentes:
3.3.5 ¿CÓMO TRATAR CON BITS INDIVIDUALES?
Ahora te mostraremos para que puedas usar los operadores de bit a bit. Imagina que eres un desarrollador
obligado a escribir una pieza importante de un sistema operativo. Se te ha dicho que puedes usar una variable
asignada de la siguiente forma:
La variable almacena la información sobre varios aspectos de la operación del sistema. Cada bit de la variable
almacena un valor de si/no. También se te ha dicho que solo uno de estos bits es tuyo - el tercero (recuerda que
los bits se numeran desde cero y el número de bits cero es el más bajo, mientras que el más alto es el número
31). Los bits restantes no pueden cambiar, porque están destinados a almacenar otros datos. Aquí está tu bit
marcado con la letra x:
1. Comprobar el estado de tu bit - deseas averiguar el valor de su bit; comparar la variable completa con cero
no hará nada, porque los bits restantes pueden tener valores completamente impredecibles, pero puedes
usar la siguiente propiedad de conjunción:
Si aplicas la operación & a la variable flag_register junto con la siguiente imagen de bits:
(observa el 1 en la posición de tu bit) como resultado, obtendrás una de las siguientes cadenas de bits:
Dicha secuencia de ceros y unos, cuya tarea es tomar el valor o cambiar los bits seleccionados, se denomina
máscara de bits.
Construyamos una máscara de bits para detectar el estado de tus bits. Debería apuntar a el tercer bit. Ese bit
tiene el peso de . Se podría crear una máscara adecuada mediante la siguiente sentencia:
También puedes hacer una secuencia de instrucciones dependiendo del estado de tu bit, aquí está:
2. Reinicia tu bit - asigna un cero al bit, mientras que todos los otros bits deben permanecer sin cambios;
usemos la misma propiedad de la conjunción que antes, pero usemos una máscara ligeramente diferente -
exactamente como se muestra a continuación:
Toma en cuenta que la máscara se creó como resultado de la negación de todos los bits de la variable the_mask.
Restablecer el bit es simple, y se ve así (elige el que más te guste):
3. Establece tu bit - asigna un 1 a tu bit, mientras que todos los bits restantes deben permanecer sin cambios;
usa la siguiente propiedad de disyunción:
Ya estás listo para configurar su bit con una de las siguientes instrucciones:
4. Niega tu bit - reemplaza un 1 con un 0 y un 0 con un 1. Puedes utilizar una propiedad interesante del
operador :
Python ofrece otra operación relacionada con los bits individuales: shifting. Esto se aplica solo a los valores de
número entero, y no debe usar flotantes como argumentos para ello.
Ya aplicas esta operación muy a menudo y muy inconscientemente. ¿Cómo multiplicas cualquier número por
diez? Echa un vistazo:
12345 × 10 = 123450
Como puede ver, multiplicar por diez es de hecho un desplazamiento de todos los dígitos a la izquierda y llenar
el vacío resultante con cero.
12340 ÷ 10 = 1234
La computadora realiza el mismo tipo de operación, pero con una diferencia: como dos es la base para los
números binarios (no 10), desplazar un valor un bit a la izquierda corresponde a multiplicarlo por dos;
respectivamente, desplazar un bit a la derecha es como dividir entre dos (observa que se pierde el bit más a la
derecha).
Los operadores de cambio en Python son un par de dígrafos: < < y > >, sugiriendo claramente en qué dirección
actuará el cambio.
El argumento izquierdo de estos operadores es un valor entero cuyos bits se desplazan. El argumento correcto
determina el tamaño del desplazamiento.
La prioridad de estos operadores es muy alta. Los verás en la tabla de prioridades actualizada, que te
mostraremos al final de esta sección.
Nota:
17 >> 1 → 17 // 2 (17 dividido entre 2 a la potencia de 1) → 8 (desplazarse hacia la derecha en un bit
equivale a la división entera entre dos)
17 << 2 → 17 * 4 (17 multiplicado por 2 a la potencia de 2) → 68 (desplazarse hacia la izquierda dos bits
es lo mismo que multiplicar números enteros por cuatro)
Y aquí está la tabla de prioridades actualizada , que contiene todos los operadores presentados hasta ahora:
3.3.7 RESUMEN DE SECCIÓN
R//False
R// 0 5 -5 1 1 16
Si no crees que esta sea una tarea complicada, toma un papel y escribe un programa que:
lea cinco números.
los imprima en orden desde el más pequeño hasta el más grande (Este tipo de procesamiento se
denomina ordenamiento).
Debes percatarte que ni siquiera tienes suficiente papel para completar la tarea.
Hasta ahora, has aprendido como declarar variables que pueden almacenar exactamente un valor dado a la vez.
Tales variables a veces se denominan escalares por analogía con las matemáticas. Todas las variables que has
usado hasta ahora son realmente escalares.
Piensa en lo conveniente que fuera declarar una variable que podría almacenar más de un valor. Por ejemplo,
cien, o mil o incluso diez mil. Todavía sería una y la misma variable, pero muy amplia y espaciosa. ¿Suena
atractivo? Quizás, pero ¿cómo manejarías un contenedor así lleno de valores diferentes? ¿Cómo elegirías solo el
que necesitas?
¿Y si solo pudieras numerarlos? Y luego di: dame el valor número 2; asigna el valor número 15; aumenta el
número del valor 10000.
Te mostraremos como declarar tales variables de múltiples valores. Haremos esto con el ejemplo que acabamos
de sugerir. Escribiremos un programa que ordene una secuencia de números. No seremos particularmente
ambiciosos - asumiremos que hay exactamente cinco números.
Vamos a crear una variable llamada numbers; se le asigna no solo un número, sino que se llena con una lista que
consta de cinco valores (nota: la lista comienza con un corchete abierto y termina con un corchete cerrado; el
espacio entre los corchetes es llenado con cinco números separados por comas).
Digamos lo mismo utilizando una terminología adecuada: numbers es una lista que consta de cinco valores,
todos ellos números. También podemos decir que esta sentencia crea una lista de longitud igual a cinco (ya que
contiene cinco elementos).
Los elementos dentro de una lista pueden tener diferentes tipos. Algunos de ellos pueden ser enteros, otros son
flotantes y otros pueden ser listas.
Python ha adoptado una convención que indica que los elementos de una lista están siempre numerados desde
cero. Esto significa que el elemento almacenado al principio de la lista tendrá el número cero. Como hay cinco
elementos en nuestra lista, al último de ellos se le asigna el número cuatro. No olvides esto.
Pronto te acostumbrarás, y se convertirá en algo natural.
Antes de continuar con nuestra discusión, debemos indicar lo siguiente: nuestra lista es una colección de
elementos, pero cada elemento es un escalar.
Vamos a asignar un nuevo valor de 111 al primer elemento en la lista. Lo hacemos de esta manera:
Y ahora queremos copiar el valor del quinto elemento al segundo elemento - ¿puedes adivinar cómo hacerlo?
El valor dentro de los corchetes que selecciona un elemento de la lista se llama un índice, mientras que la
operación de seleccionar un elemento de la lista se conoce como indexación.
Vamos a utilizar la función print() para imprimir el contenido de la lista cada vez que realicemos los cambios. Esto
nos ayudará a seguir cada paso con más cuidado y ver que sucede después de una modificación de la lista en
particular.
Nota: todos los índices utilizados hasta ahora son literales. Sus valores se fijan en el tiempo de ejecución, pero
cualquier expresión también puede ser un índice. Esto abre muchas posibilidades.
Se puede acceder a cada uno de los elementos de la lista por separado. Por ejemplo, se puede imprimir:
Suponiendo que todas las operaciones anteriores se hayan completado con éxito, el fragmento enviará 111 a la
consola.
Como puedes ver en el editor, la lista también puede imprimirse como un todo - como aquí:
Como probablemente hayas notado antes, Python decora el output de una manera que sugiere que todos los
valores presentados forman una lista. El output del fragmento de ejemplo anterior se ve así:
LA FUNCIÓN LEN()
La longitud de una lista puede variar durante la ejecución. Se pueden agregar nuevos elementos a la lista,
mientras que otros pueden eliminarse de ella. Esto significa que la lista es una entidad muy dinámica.
Si deseas verificar la longitud actual de la lista, puedes usar una función llamada len() (su nombre proviene de
length - longitud).
La función toma el nombre de la lista como un argumento y devuelve el número de elementos almacenados
actualmente dentro de la lista (en otras palabras - la longitud de la lista).
Observa la última línea de código en el editor, ejecuta el programa y verifica que valor imprimirá en la consola.
¿Puedes adivinar?
Cualquier elemento de la lista puede ser eliminado en cualquier momento - esto se hace con una instrucción
llamada del (eliminar). Nota: es una instrucción, no una función.
Tienes que apuntar al elemento que quieres eliminar - desaparecerá de la lista y la longitud de la lista se reducirá
en uno.
Mira el fragmento de abajo. ¿Puedes adivinar qué output producirá? Ejecuta el programa en el editor y
comprueba.
No puedes acceder a un elemento que no existe - no puedes obtener su valor ni asignarle un valor. Ambas
instrucciones causarán ahora errores de tiempo de ejecución:
Agrega el fragmento de código anterior después de la última línea de código en el editor, ejecuta el programa y
verifica que sucede.
Nota: hemos eliminado uno de los elementos de la lista - ahora solo hay cuatro elementos en la lista. Esto
significa que el elemento número cuatro no existe.
Puede parecer extraño, pero los índices negativos son válidos, y pueden ser muy útiles.
Un elemento con un índice igual a -1 es el último en la lista.
ESCENARIO
Había una vez un sombrero. El sombrero no contenía conejo, sino una lista de cinco números: 1, 2, 3, 4, y 5.
Tu tarea es:
escribir una línea de código que solicite al usuario que reemplace el número central en la lista con un
número entero ingresado por el usuario (Paso 1)
escribir una línea de código que elimine el último elemento de la lista (Paso 2)
escribir una línea de código que imprima la longitud de la lista existente (Paso 3).
¿Listo para este desafío?
Un método es un tipo específico de función - se comporta como una función y se parece a una función, pero
difiere en la forma en que actúa y en su estilo de invocación.
Una función no pertenece a ningún dato - obtiene datos, puede crear nuevos datos y (generalmente) produce
un resultado.
Un método hace todas estas cosas, pero también puede cambiar el estado de una entidad seleccionada.
Un método es propiedad de los datos para los que trabaja, mientras que una función es propiedad de todo el
código.
Esto también significa que invocar un método requiere alguna especificación de los datos a partir de los cuales se
invoca el método.
El método se comportará como una función, pero puede hacer algo más - puede cambiar el estado interno de
los datos a partir de los cuales se ha invocado.
Este es un tema esencial en este momento, ya que le mostraremos como agregar nuevos elementos a una lista
existente. Esto se puede hacer con métodos propios de las listas, no por funciones.
Dicha operación se realiza mediante un método llamado append(). Toma el valor de su argumento y lo coloca al
final de la lista que posee el método.
El método insert() es un poco más inteligente - puede agregar un nuevo elemento en cualquier lugar de la lista,
no solo al final.
Observa el código en el editor. Ve como usamos los métodos append() e insert(). Presta atención a lo que sucede
después de usar insert(): el primer elemento anterior ahora es el segundo, el segundo el tercero, y así
sucesivamente.
Agrega el siguiente fragmento después de la última línea de código en el editor:
Imprime el contenido de la lista final en la pantalla y ve que sucede. El fragmento de código sobre el fragmento
de código inserta 333 en la lista, por lo que es el segundo elemento. El segundo elemento anterior se convierte
en el tercero, el tercero en el cuarto, y así sucesivamente.
Puedes iniciar la vida de una lista creándola vacía (esto se hace con un par de corchetes vacíos) y luego agregar
nuevos elementos según sea necesario.
Echa un vistazo al fragmento en el editor. Intenta adivinar su output después de la ejecución del bucle for.
Ejecuta el programa para comprobar si tenías razón.
Será una secuencia de números enteros consecutivos del 1 (luego agrega uno a todos los valores agregados)
hasta 5.
Deberías obtener la misma secuencia, pero en orden inverso (este es el mérito de usar el método insert()).
El bucle for tiene una variante muy especial que puede procesar las listas de manera muy efectiva - echemos un
vistazo a eso.
Supongamos que deseas calcular la suma de todos los valores almacenados en la lista my_list.
Necesitas una variable cuya suma se almacenará y se le asignará inicialmente un valor de 0 - su nombre será
total. (Nota: no la vamos a nombrar sum ya que Python utiliza el mismo nombre para una de sus funciones
integradas: sum(). Utilizar ese nombre sería considerado una mala práctica.) Luego agrega todos los elementos
de la lista usando el bucle for. Echa un vistazo al fragmento en el editor.
Pero el bucle for puede hacer mucho más. Puede ocultar todas las acciones conectadas a la indexación de la lista
y entregar todos los elementos de la lista de manera práctica.
la instrucción for especifica la variable utilizada para navegar por la lista (i) seguida de la palabra clave in
y el nombre de la lista siendo procesado (my_list).
a la variable i se le asignan los valores de todos los elementos de la lista subsiguiente, y el proceso ocurre
tantas veces como hay elementos en la lista;
esto significa que usa la variable i como una copia de los valores de los elementos, y no necesita emplear
índices;
la función len() tampoco es necesaria aquí.
Dejemos de lado las listas por un breve momento y veamos un tema intrigante.
Imagina que necesitas reorganizar los elementos de una lista, es decir, revertir el orden de los elementos: el
primero y el quinto, así como el segundo y cuarto elementos serán intercambiados. El tercero permanecerá
intacto.
Si haces algo como esto, perderás el valor previamente almacenado en variable_2. Cambiar el orden de las
tareas no ayudará. Necesitas una tercera variable que sirva como almacenamiento auxiliar.
Python ofrece una forma más conveniente de hacer el intercambio - echa un vistazo:
¿Seguirá siendo aceptable con una lista que contenga 100 elementos? No, no lo hará.
¿Puedes usar el bucle for para hacer lo mismo automáticamente, independientemente de la longitud de la lista?
Si, si puedes.
Nota:
hemos asignado la variable length a la longitud de la lista actual (esto hace que nuestro código sea un
poco más claro y corto)
hemos preparado el bucle for para que se ejecute su cuerpo length // 2 veces (esto funciona bien para
listas con longitudes pares e impares, porque cuando la lista contiene un número impar de elementos, el
del medio permanece intacto)
hemos intercambiado el elemento i (desde el principio de la lista) por el que tiene un índice igual a
(length - i - 1) (desde el final de la lista); en nuestro ejemplo, for i igual a 0 a la (length - i - 1) da 4; for i
igual a 3, da 3 - esto es exactamente lo que necesitábamos.
ESCENARIO
Los Beatles fueron uno de los grupos de música más populares de la década de 1960 y la banda más vendida en
la historia. Algunas personas los consideran el acto más influyente de la era del rock. De hecho, se incluyeron en
la compilación de la revista Time de las 100 personas más influyentes del siglo XX.
La banda sufrió muchos cambios de formación, que culminaron en 1962 con la formación de John Lennon, Paul
McCartney, George Harrison y Richard Starkey (mejor conocido como Ringo Starr).
Escribe un programa que refleje estos cambios y le permita practicar con el concepto de listas. Tu tarea es:
paso 1: crea una lista vacía llamada beatles;
paso 2: emplea el método append() para agregar los siguientes miembros de la banda a la lista: John
Lennon, Paul McCartney y George Harrison;
paso 3: emplea el bucle for y el append() para pedirle al usuario que agregue los siguientes miembros de
la banda a la lista: Stu Sutcliffe, y Pete Best;
paso 4: usa la instrucción del para eliminar a Stu Sutcliffe y Pete Best de la lista;
paso 5: usa el método insert() para agregar a Ringo Starr al principio de la lista.
Por cierto, ¿eres fan de los Beatles? (Los Beatles son una de las bandas favoritas de Greg. Pero espera...¿Quién es
Greg?)
La lista es un tipo de dato en Python que se utiliza para almacenar múltiples objetos. Es una colección ordenada
y mutable de elementos separados por comas entre corchetes, por ejemplo:
Aprenderás más sobre el anidamiento - por el momento, solo queremos que sepas que algo como esto también
es posible.
Nuevamente, aprenderás más sobre esto - no te preocupes. Por el momento, intenta experimentar con el código
anterior y verifica cómo cambiarlo afecta el output.
Las listas pueden ser iteradas mediante el uso del bucle for, por ejemplo:
La función len() se puede usar para verificar la longitud de la lista, por ejemplo:
Una invocación típica de función tiene el siguiente aspecto: result = function(arg), mientras que una invocación
típica de un método se ve así: result = data.method(arg).
R// [6, 2, 3, 4, 5, 1]
Pregunta 2: ¿Cuál es el resultado del siguiente fragmento de código?
Ahora que puedes hacer malabarismos con los elementos de las listas, es hora de aprender como ordenarlos. Se
han inventado muchos algoritmos de clasificación, que difieren mucho en velocidad, así como en complejidad.
Vamos a mostrar un algoritmo muy simple, fácil de entender, pero desafortunadamente, tampoco es muy
eficiente. Se usa muy raramente, y ciertamente no para listas extensas.
Intentaremos utilizar el siguiente enfoque: tomaremos el primer y el segundo elemento y los compararemos; si
determinamos que están en el orden incorrecto (es decir, el primero es mayor que el segundo), los
intercambiaremos; si su orden es válido, no haremos nada. Un vistazo a nuestra lista confirma lo último - los
elementos 01 y 02 están en el orden correcto, así como 8<10.
Ahora observa el segundo y el tercer elemento. Están en las posiciones equivocadas. Tenemos que
intercambiarlos:
Vamos más allá y observemos los elementos tercero y cuarto. Una vez más, esto no es lo que se supone que es.
Tenemos que intercambiarlos:
Ahora comprobemos los elementos cuarto y quinto. Si, ellos también están en las posiciones equivocadas.
Ocurre otro intercambio:
El primer paso a través de la lista ya está terminado. Todavía estamos lejos de terminar nuestro trabajo, pero
algo curioso ha sucedido mientras tanto. El elemento más grande, 10, ya ha llegado al final de la lista. Ten en
cuenta que este es el lugar deseado para él. Todos los elementos restantes forman un lío pintoresco, pero este
ya está en su lugar.
Ahora, por un momento, intenta imaginar la lista de una manera ligeramente diferente - es decir, de esta
manera:
Observa - El 10 está en la parte superior. Podríamos decir que flotó desde el fondo hasta la superficie, al igual
que las burbujas en una copa de champán. El método de clasificación deriva su nombre de la misma observación
- se denomina ordenamiento burbuja.
Ahora comenzamos con el segundo paso a través de la lista. Miramos el primer y el segundo elemento - es
necesario un intercambio:
3.5.2 ORDENANDO UNA LISTA
Resolvamos este problema de la siguiente manera: introducimos otra variable, su tarea es observar si se ha
realizado algún intercambio durante el pase o no. Si no hay intercambio, entonces la lista ya está ordenada, y no
hay que hacer nada más. Creamos una variable llamada swapped, y le asignamos un valor de False para indicar
que no hay intercambios. De lo contrario, se le asignará True.
En el editor, puedes ver un programa completo, enriquecido por una conversación con el usuario, y que permite
ingresar e imprimir elementos de la lista: El ordenamiento burbuja - versión final interactiva.
Python, sin embargo, tiene sus propios mecanismos de clasificación. Nadie necesita escribir sus propias clases, ya
que hay un número suficiente de herramientas listas-para-usar.
Te explicamos este sistema de clasificación porque es importante aprender como procesar los contenidos de una
lista y mostrarte como puede funcionar la clasificación real.
Como puedes ver, todas las listas tienen un método denominado sort(), que las ordena lo más rápido posible. Ya
has aprendido acerca de algunos de los métodos de lista anteriormente, y pronto aprenderás más sobre otros.
1. Puedes usar el método sort() para ordenar los elementos de una lista, por ejemplo:
2.También hay un método de lista llamado reverse(), que puedes usar para invertir la lista, por ejemplo:
R// [1, 2, 3]
Pregunta 3: ¿Cuál es el resultado del siguiente fragmento de código?
Ahora queremos mostrarte una característica importante y muy sorprendente de las listas, que las distingue de
las variables ordinarias.
Queremos que lo memorices - ya que puede afectar tus programas futuros y causar graves problemas si se olvida
o se pasa por alto.
Echa un vistazo al fragmento en el editor.
El programa:
crea una lista de un elemento llamada list_1;
la asigna a una nueva lista llamada list_2;
cambia el único elemento de list_1;
imprime la list_2;
La parte sorprendente es el hecho de que el programa mostrará como resultado: [2], no [1], que parece ser la
solución obvia.
Las listas (y muchas otras entidades complejas de Python) se almacenan de diferentes maneras que las variables
ordinarias (escalares).
Lee estas dos líneas una vez más - la diferencia es esencial para comprender que vamos a hablar a continuación.
La asignación: list_2 = list_1 copia el nombre del arreglo no su contenido. En efecto, los dos nombres (list_1 y
list_2) identifican la misma ubicación en la memoria de la computadora. Modificar uno de ellos afecta al otro, y
viceversa.
Una rebanada es un elemento de la sintaxis de Python que permite hacer una copia nueva de una lista, o partes
de una lista.
Su output es [1].
Esta parte no visible del código descrito como [:] puede producir una lista completamente nueva.
Como puedes ver, se asemeja a la indexación, pero los dos puntos en el interior hacen una gran diferencia.
Una rebanada de este tipo crea una nueva lista (de destino), tomando elementos de la lista de origen - los
elementos de los índices desde el start hasta el fin fin - 1.
Nota: no hasta el fin sino hasta fin-1. Un elemento con un índice igual a fin es el primer elemento el cual no
participa en la segmentación.
Es posible utilizar valores negativos tanto para el inicio como para el fin(al igual que en la indexación).
La lista new_list contendrá fin - inicio (3 - 1 = 2) elementos ‒ los que tienen índices iguales a 1 y 2 (pero no 3).
Ejecuta el código en el editor para ver cómo Python copia la lista completa y un fragmento de la lista. ¡Siéntete
libre de experimentar!
3.6.3 REBANADAS – ÍNDICES NEGATIVOS
Para confirmar:
start es el índice del primer elemento incluido en la rebanada.
end es el índice del primer elemento no incluido en la rebanada.
Si start especifica un elemento que se encuentra más allá del descrito por end (desde el punto de vista inicial de
la lista), la rebanada estará vacía:
Si omites el start en tu rebanada, se supone que deseas obtener un segmento que comienza en el elemento con
índice 0.
En otras palabras, la rebanada sería de esta forma:
es un equivalente más compacto de:
Del mismo modo, si omites el end en tu rebanada, se supone que deseas que el segmento termine en el
elemento con el índice len(my_list).
La instrucción del descrita anteriormente puede eliminar más de un elemento de la lista a la vez - también
puede eliminar rebanadas:
Echa un vistazo:
Python ofrece dos operadores muy poderosos, capaces de revisar la lista para verificar si un valor específico
está almacenado dentro de la lista o no.
El primero de ellos (in) verifica si un elemento dado (el argumento izquierdo) está actualmente almacenado en
algún lugar dentro de la lista (el argumento derecho) - el operador devuelve True en este caso.
El segundo (not in) comprueba si un elemento dado (el argumento izquierdo) está ausente en una lista - el
operador devuelve True en este caso.
Observa el código en el editor. El fragmento muestra ambos operadores en acción. ¿Puedes adivinar su output?
Ejecuta el programa para comprobar si tenías razón.
El primero de ellos intenta encontrar el valor mayor en la lista. Mira el código en el editor.
El concepto es bastante simple - asumimos temporalmente que el primer elemento es el más grande y
comparamos la hipótesis con todos los elementos restantes de la lista.
El código puede ser reescrito para hacer uso de la forma recién introducida del bucle for:
El programa anterior realiza una comparación innecesaria, cuando el primer elemento se compara consigo
mismo, pero esto no es un problema en absoluto.
La pregunta es: ¿Cuál de estas dos acciones consume más recursos informáticos - solo una comparación o
rebanar casi todos los elementos de una lista?
Nota:
el valor buscado se almacena en la variable to_find;
el estado actual de la búsqueda se almacena en la variable found (True/False).
cuando found se convierte en True, se sale del bucle for.
Supongamos que has elegido los siguientes números en la lotería: 3, 7, 11, 42, 34, 49.
Los números que han salido sorteados son: 5, 11, 9, 42, 3, y 49.
ESCENARIO
Imagina una lista - no muy larga ni muy complicada, solo una lista simple que contiene algunos números enteros.
Algunos de estos números pueden estar repetidos, y esta es la clave. No queremos ninguna repetición.
Queremos que sean eliminados.
Tu tarea es escribir un programa que elimine todas las repeticiones de números de la lista. El objetivo es tener
una lista en la que todos los números aparezcan no más de una vez.
Nota: Asume que la lista original está ya dentro del código - no tienes que ingresarla desde el teclado. Por
supuesto, puedes mejorar el código y agregar una parte que pueda llevar a cabo una conversación con el usuario
y obtener todos los datos.
Sugerencia: Te recomendamos que crees una nueva lista como área de trabajo temporal - no necesitas actualizar
la lista actual.
No hemos proporcionado datos de prueba, ya que sería demasiado fácil. Puedes usar nuestro esqueleto en su
lugar.
Si tienes una lista list_1, y la siguiente asignación: list_2 = list_1 esto no hace una copia de la lista list_1, pero
hace que las variables list_1 y list_2 apunten a la misma lista en la memoria. Por ejemplo:
Si deseas copiar una lista o parte de la lista, puedes hacerlo haciendo uso de rebanadas:
También puede utilizar índices negativos para hacer uso de rebanadas. Por ejemplo:
Los parámetros start y end son opcionales al partir en rebanadas una lista: list[start:end], por ejemplo:
Puedes probar si algunos elementos existen en una lista o no utilizando las palabras clave in y not in, por
ejemplo:
R// ['C']
Pregunta 2: ¿Cuál es el resultado del siguiente fragmento de código?
R// ['B', 'C']
Pregunta 3: ¿Cuál es el resultado del siguiente fragmento de código?
R// []
Pregunta 4: ¿Cuál es el resultado del siguiente fragmento de código?
R//
A menudo encontramos estos arreglos en nuestras vidas. Probablemente el mejor ejemplo de esto sea un
tablero de ajedrez.
Un tablero de ajedrez está compuesto de filas y columnas. Hay ocho filas y ocho columnas. Cada columna está
marcada con las letras de la A a la H. Cada línea está marcada con un número del uno al ocho.
La ubicación de cada campo se identifica por pares de letras y dígitos. Por lo tanto, sabemos que la esquina
inferior derecha del tablero (la que tiene la torre blanca) es A1, mientras que la esquina opuesta es H8.
Supongamos que podemos usar los números seleccionados para representar cualquier pieza de ajedrez. También
podemos asumir que cada fila en el tablero de ajedrez es una lista.
COMPRENSIÓN DE LISTA
El mismo efecto se puede lograr mediante una comprensión de lista, la sintaxis especial utilizada por Python
para completar o llenar listas masivas.
Una comprensión de lista es en realidad una lista, pero se creó sobre la marcha durante la ejecución del
programa, y no se describe de forma estática.
Supongamos también que un símbolo predefinido denominado EMPTY designa un campo vacío en el tablero de
ajedrez.
Entonces, si queremos crear una lista de listas que representan todo el tablero de ajedrez, se puede hacer de la
siguiente manera:
Nota:
la parte interior del bucle crea una fila que consta de ocho elementos (cada uno de ellos es igual a
EMPTY) y lo agrega a la lista del board;
la parte exterior se repite ocho veces;
en total, la lista board consta de 64 elementos (todos iguales a EMPTY).
Este modelo imita perfectamente el tablero de ajedrez real, que en realidad es una lista de elementos de ocho
elementos, todos ellos en filas individuales. Resumamos nuestras observaciones:
los elementos de las filas son campos, ocho de ellos por fila;
los elementos del tablero de ajedrez son filas, ocho de ellos por tablero de ajedrez.
La variable board ahora es un arreglo bidimensional. También se le llama, por analogía a los términos
algebraicos, una matriz.
Como las listas de comprensión puede ser anidadas, podemos acortar la creación del tablero de la siguiente
manera:
La parte interna crea una fila, y la parte externa crea una lista de filas.
El acceso al campo seleccionado del tablero requiere dos índices - el primero selecciona la fila; el segundo - el
número del campo dentro de la fila, el cual es un número de columna.
Echa un vistazo al tablero de ajedrez. Cada campo contiene un par de índices que se deben dar para acceder al
contenido del campo:
Echando un vistazo a la figura que se muestra arriba, coloquemos algunas piezas de ajedrez en el tablero.
Primero, agreguemos todas las torres:
Profundicemos en la naturaleza multidimensional de las listas. Para encontrar cualquier elemento de una lista
bidimensional, debes usar dos coordenadas:
Una vertical (número de fila).
Una horizontal (número de columna).
Imagina que desarrollas una pieza de software para una estación meteorológica automática. El dispositivo
registra la temperatura del aire cada hora y lo hace durante todo el mes. Esto te da un total de 24 × 31 = 744
valores. Intentemos diseñar una lista capaz de almacenar todos estos resultados.
ya que este termómetro puede medir la temperatura con una precisión de 0.1 ℃.
Primero, debes decidir qué tipo de datos sería adecuado para esta aplicación. En este caso, sería mejor un float,
Luego tomarás la decisión arbitraria de que las filas registrarán las lecturas cada hora exactamente (por lo que la
fila tendrá 24 elementos) y cada una de las filas se asignará a un día del mes (supongamos que cada mes tiene 31
días, por lo que necesita 31 filas). Aquí está el par apropiado de comprensiones (h es para las horas, d para el
día)
Toda la matriz está llena de ceros ahora. Puede suponer que se actualiza automáticamente utilizando agentes de
hardware especiales. Lo que tienes que hacer es esperar a que la matriz se llene con las mediciones.
Ahora es el momento de determinar la temperatura promedio mensual del mediodía. Suma las 31 lecturas
registradas al mediodía y divida la suma por 31. Puedes suponer que la temperatura de medianoche se almacena
primero. Aquí está el código:
Nota: La variable day utilizada por el bucle for no es un escalar - cada paso a través de la matriz temps lo asigna a
la siguiente fila de la matriz; Por lo tanto, es una lista. Se debe indexar con 11 para acceder al valor de
temperatura medida al mediodía.
Ahora encuentra la temperatura más alta durante todo el mes - analiza el código:
Note:
la variable day itera en todas las filas de la matriz temps;
la variable temp itera a través de todas las mediciones tomadas en un día.
Python no limita la profundidad de la inclusión lista en lista. Aquí puedes ver un ejemplo de un arreglo
tridimensional:
Imagina un hotel. Es un hotel enorme que consta de tres edificios, de 15 pisos cada uno. Hay 20 habitaciones en
cada piso. Para esto, necesitas un arreglo que pueda recopilar y procesar información sobre las habitaciones
ocupadas/libres.
Primer paso - El tipo de elementos del arreglo. En este caso, sería un valor Booleano (True/False).
Paso dos - análisis de la situación. Resume la información disponible: tres edificios, 15 pisos, 20 habitaciones.
Ahora ya puedes reservar una habitación para dos recién casados: en el segundo edificio, en el décimo piso,
habitación 14
La variable vacancy contiene 0 si todas las habitaciones están ocupadas, o en dado caso el número de
habitaciones disponibles.
¡Felicitaciones! Has llegado al final del módulo. ¡Sigue con el buen trabajo!
1. La comprensión de listas te permite crear nuevas listas a partir de las existentes de una manera concisa y
elegante. La sintaxis de una comprensión de lista es la siguiente: [expresión para el elemento en la lista si es
condicional]
Este es un ejemplo de una comprensión de lista - el código siguiente crea una lista de cinco elementos con
los primeros cinco números naturales elevados a la potencia de 3:
2. Puedes usar listas anidadas en Python para crear matrices (es decir, listas bidimensionales). Por ejemplo:
3. Puedes anidar tantas listas en las listas como desee y, por lo tanto, crear listas n-dimensionales, por ejemplo,
arreglos de tres, cuatro o incluso sesenta y cuatro dimensiones. Por ejemplo:
4.1 SECCIÓN 1 – FUNCIONES
Hasta ahorita has implementado varias veces el uso de funciones, pero solo se han visto algunas de sus ventajas.
Solo se han invocado funciones para utilizarlas como herramientas, con el fin de hacer la vida más fácil, y para
simplificar tareas tediosas y repetitivas.
Cuando se desea mostrar o imprimir algo en consola se utiliza print(). Cuando se desea leer el valor de una
variable se emplea input(), combinados posiblemente con int() o float().
También se ha hecho uso de algunos métodos, los cuales también son funciones, pero declarados de una
manera muy específica.
Ahora aprenderás a escribir tus propias funciones, y como utilizarlas. Escribiremos varias de ellas juntos, desde
muy sencillas hasta algo complejas. Se requerirá de tu concentración y atención.
Muy a menudo ocurre que un cierto fragmento de código se repite muchas veces en un programa. Se repite de
manera literal o, con algunas modificaciones menores, empleando algunas otras variables dentro del programa.
También ocurre que un programador ha comenzado a copiar y pegar ciertas partes del código en más de una
ocasión en el mismo programa.
Puede ser muy frustrante percatarse de repente que existe un error en el código copiado. El programador tendrá
que escarbar bastante para encontrar todos los lugares en el código donde hay que corregir el error. Además,
existe un gran riesgo de que las correcciones produzcan errores adicionales.
Definamos la primera condición por la cual es una buena idea comenzar a escribir funciones propias: si un
fragmento de código comienza a aparecer en más de una ocasión, considera la posibilidad de aislarlo en la
forma de una función invocando la función desde el lugar en el que originalmente se encontraba.
Puede suceder que el algoritmo que se desea implementar sea tan complejo que el código comience a crecer de
manera incontrolada y, de repente, ya no se puede navegar por él tan fácilmente.
Se puede intentar solucionar este problema comentando el código, pero pronto te darás cuenta de que esto
empeorará la situación - demasiados comentarios hacen que el código sea más difícil de leer y entender.
Algunos dicen que una función bien escrita debe ser comprensible con tan solo una mirada.
Un buen desarrollador divide el código (o, mejor dicho: el problema) en piezas aisladas, y codifica cada una de
ellas en la forma de una función.
Esto simplifica considerablemente el trabajo del programa, debido a que cada pieza se codifica por separado, y
consecuentemente se prueba por separado. A este proceso se le llama comúnmente descomposición.
Existe una segunda condición: si un fragmento de código se hace tan extenso que leerlo o entenderlo se hace
complicado, considera dividirlo en pequeños problemas, por separado, e implementa cada uno de ellos como
una función independiente.
Esta descomposición continúa hasta que se obtiene un conjunto de funciones cortas, fáciles de comprender y
probar.
4.1.2 DESCOMPOSICIÓN
Es muy común que un programa sea tan largo y complejo que no puede ser asignado a un solo desarrollador, y
en su lugar un equipo de desarrolladores trabajará en él. El problema, debe ser dividido entre varios
desarrolladores de una manera en que se pueda asegurar su eficiencia y cooperación.
Es inconcebible que más de un programador deba escribir el mismo código al mismo tiempo, por lo tanto, el
trabajo debe de ser dividido entre todos los miembros del equipo.
Este tipo de descomposición tiene diferentes propósitos, no solo se trata de compartir el trabajo, sino también
de compartir la responsabilidad entre varios desarrolladores.
Cada uno debe escribir un conjunto bien definido y claro de funciones, las cuales al ser combinadas dentro de
un módulo (esto se clarificará un poco más adelante) nos dará como resultado el producto final.
Esto nos lleva directamente a la tercera condición: si se va a dividir el trabajo entre varios programadores, se
debe descomponer el problema para permitir que el producto sea implementado como un conjunto de
funciones escritas por separado empacadas juntas en diferentes módulos.
Es bastante sencillo, es un ejemplo de cómo transformar una parte de código que se está repitiendo en una
función.
El mensaje enviado a la consola por la función print() es siempre el mismo. El código es funcional y no contiene
errores, sin embargo, imagina que tendrías que hacer si tu jefe pidiera cambiar el mensaje para que fuese más
cortés, por ejemplo, que comience con la frase "Por favor,".
Tendrías que tomar algo de tiempo para cambiar el mensaje en todos los lugares donde aparece (podrías hacer
uso de copiar y pegar, pero eso no lo haría más sencillo). Es muy probable que cometas errores durante el
proceso de corrección, eso traería frustración a ti y a tu jefe.
¿Es posible separar ese código repetido, darle un nombre y hacerlo reutilizable? Significaría que el cambio hecho
en un solo lugar será propagado a todos los lugares donde se utilice.
Para que esto funcione, dicho código debe ser invocado cada vez que se requiera.
La función es muy sencilla, pero completamente utilizable. Se ha nombrado message, pero eso es opcional, tú
puedes cambiarlo. Hagamos uso de ella.
Esto significa que Python lee la definición de la función y la recuerda, pero no la ejecuta sin tu permiso.
Observa la imagen.
Recuerda - Python lee el código de arriba hacia abajo. No va a adelantarse en el código para determinar si la
función invocada está definida más adelante, (el lugar "correcto" para definirla es "antes de ser invocada".)
Se ha movido la función al final del código. ¿Podrá Python encontrarla cuando la ejecución llegue a la
invocación?
Afortunadamente, es posible combinar o mezclar el código con las funciones - no es forzoso colocar todas las
funciones al inicio del archivo fuente.
El modificar el mensaje de entrada es ahora sencillo - se puede hacer con solo modificar el código una única vez
- dentro del cuerpo de la función.
1. Una función es un bloque de código que realiza una tarea especifica cuando la función es llamada (invocada).
Las funciones son útiles para hacer que el código sea reutilizable, que este mejor organizado, y más legible. Las
funciones contienen parámetros y pueden regresar valores.
funciones integradas las cuales son partes importantes de Python (como lo es la función print()). Puedes
ver una lista completa de las funciones integradas de Python en la siguiente liga
https://docs.python.org/3/library/functions.html.
también están las que se encuentran en módulos pre-instalados (se hablará acerca de ellas en el curso
Fundamentos de Python 2)
funciones definidas por el usuario las cuales son escritas por los programadores para los programadores
- puedes escribir tus propias funciones y utilizarlas libremente en tu código,
las funciones lambda (aprenderás acerca de ellas en el curso Fundamentos de Python 2.)
3. Las funciones propias se pueden definir utilizando la palabra reservada def y con la siguiente sintaxis:
Se puede definir una función sin que haga uso de argumentos, por ejemplo:
También es posible definir funciones con argumentos, como la siguiente que contiene un solo parámetro:
R// Se genera una excepción (la excepción TypeError) ‒ la función hi() no toma argumentos.
Un parámetro es una variable, pero existen dos factores que hacen a un parámetro diferente:
los parámetros solo existen dentro de las funciones en donde han sido definidos, y el único lugar
donde un parámetro puede ser definido es entre los paréntesis después del nombre de la función,
donde se encuentra la palabra clave reservada def;
la asignación de un valor a un parámetro de una función se hace en el momento en que la función se
manda llamar o se invoca, especificando el argumento correspondiente.
Recuerda que:
los parámetros solo existen dentro de las funciones (este es su entorno natural)
los argumentos existen fuera de las funciones, y son los que pasan los valores a los parámetros
correspondientes.
Existe una clara división entre estos dos mundos.
Enriquezcamos la función anterior agregándole un parámetro - se utilizará para mostrar al usuario el valor de un
número que la función pide.
Esta definición especifica que nuestra función opera con un solo parámetro con el nombre de number. Se puede
utilizar como una variable normal, pero solo dentro de la función - no es visible en otro lugar.
Se ha hecho buen uso del parámetro. Nota: No se le ha asignado al parámetro algún valor. ¿Es correcto?
Si, lo es.
¿Puedes ver cómo funciona? El valor del argumento utilizado durante la invocación (1) ha sido pasado a la
función, dándole un valor inicial al parámetro con el nombre de number.
Es posible tener una variable con el mismo nombre del parámetro de la función.
El parámetro llamado number es una entidad completamente diferente de la variable llamada number.
Aquí está:
Ejecuta el código, modifícalo, agrega más parámetros, y ve cómo esto afecta la salida.
La técnica que asigna cada argumento al parámetro correspondiente es llamada paso de parámetros
posicionales, los argumentos pasados de esta manera son llamados argumentos posicionales.
Ya se ha utilizado, pero Python ofrece mucho más. Se abordará este tema a continuación.
Nota: el paso de parámetros posicionales es usado de manera intuitiva por las personas en muchas situaciones.
Por ejemplo, es generalmente aceptado que cuando nos presentamos mencionamos primero nuestro nombre(s)
y después nuestro apellido, por ejemplo, "Me llamo Juan Pérez."
Ahora imaginemos que la función está siendo utilizada en Hungría. En este caso, el código sería de la siguiente
manera:
¿Puedes predecir la salida? Ejecuta el código y verifícalo por ti mismo.
Ahora imaginemos que la función está siendo utilizada en Hungría. En este caso, el código sería de la siguiente
manera:
Python ofrece otra manera de pasar argumentos, donde el significado del argumento está definido por su
nombre, no su posición - a esto se le denomina paso de argumentos con palabra clave.
El concepto es claro - los valores pasados a los parámetros son precedidos por el nombre del parámetro al que se
le va a pasar el valor, seguido por el signo de =.
La posición no es relevante aquí - cada argumento conoce su destino con base en el nombre utilizado.
Es posible combinar ambos tipos si se desea - solo hay una regla inquebrantable: se deben colocar primero los
argumentos posicionales y después los de palabra clave.
También, se puede reemplazar la invocación actual por una con palabras clave, como la siguiente:
Vamos a analizarla:
el argumento (3) para el parámetro a es pasado utilizando la forma posicional;
los argumentos para c y b son especificados con palabras clave.
Observa el siguiente código. Es un código completamente correcto y funcional, pero no tiene mucho sentido:
Todo es correcto, pero el dejar solo un argumento con palabra clave es algo extraño - ¿Qué es lo que opinas?
En ocasiones ocurre que algunos valores de ciertos argumentos son más utilizados que otros. Dichos argumentos
tienen valores predefinidos los cuales pueden ser considerados cuando los argumentos correspondientes han
sido omitidos.
Uno de los apellidos más comunes en Latinoamérica es González. Tomémoslo para el ejemplo.
Solo se tiene que colocar el nombre del parámetro seguido del signo de = y el valor por predeterminada.
¿Y? No parece haber cambiado algo, pero cuando se invoca la función de una manera inusual, como esta:
o así:
no habrá errores, ambas invocaciones funcionarán, la consola mostrará los siguientes resultados:
Puedes hacerlo con más parámetros, si te resulta útil. Ambos parámetros tendrán sus valores por
predeterminada, observa el siguiente código:
Esto hace que la siguiente invocación sea completamente valida:
Si solo se especifica un argumento de palabra clave, el restante tomará el valor por predeterminada:
La salida es:
1. Se puede pasar información a las funciones utilizando parámetros. Las funciones pueden tener tantos
parámetros como sean necesarios.
3. Se puede utilizar la técnica de argumentos con palabras clave para asignar valores predefinidos a los
argumentos:
R//
Todas las funciones presentadas anteriormente tienen algún tipo de efecto - producen un texto y lo envían a la
consola.
Por supuesto, las funciones - al igual que las funciones matemáticas - pueden tener resultados.
Para lograr que las funciones devuelvan un valor (pero no solo para ese propósito) se utiliza la instrucción return
(regresar o retornar).
Esta palabra nos da una idea completa de sus capacidades. Nota: es una palabra clave reservada de Python.
Vamos a investigarlo.
El resultado se puede usar libremente aquí, por ejemplo, para ser asignado a una variable.
Tenga en cuenta que no estamos siendo demasiado educados aquí: la función devuelve un valor y lo ignoramos
(no lo usamos de ninguna manera):
No olvides:
siempre se te permite ignorar el resultado de la función y estar satisfecho con
el efecto de la función (si la función tiene alguno)
si una función intenta devolver un resultado útil, debe contener la segunda variante
de la instrucción return.
Espera un segundo - ¿significa esto que también hay resultados inútiles? Sí, en cierto
sentido.
Permítenos presentarte un valor muy curioso (para ser honestos, un valor que es ninguno) llamado None.
Sus datos no representan valor razonable alguno - en realidad, no es un valor en lo absoluto; por lo tanto, no
debe participar en ninguna expresión.
Solo existen dos tipos de circunstancias en las que None se puede usar de manera segura:
cuando se le asigna a una variable (o se devuelve como el resultado de una función)
cuando se compara con una variable para diagnosticar su estado interno.
No olvides esto: si una función no devuelve un cierto valor utilizando una cláusula de expresión return, se asume
que devuelve implícitamente None.
Vamos a probarlo.
No te sorprendas la próxima vez que veas None como el resultado de la función - puede ser el síntoma de un
error sutil dentro de la función.
La primera es: ¿Se puede enviar una lista a una función como un argumento?
¡Por supuesto que se puede! Cualquier entidad reconocible por Python puede desempeñar el papel de un
argumento de función, aunque debes asegurarte de que la función sea capaz de hacer uso de él.
Entonces, si pasas una lista a una función, la función tiene que manejarla como una lista.
y se invoca así:
retornará 12 como resultado, pero habrá problemas si la invocas de esta manera riesgosa:
Esto se debe al hecho de que el bucle for no puede iterar un solo valor entero.
La segunda pregunta es: ¿Puede una lista ser el resultado de una función?
¡Si, por supuesto! Cualquier entidad reconocible por Python puede ser un resultado de función.
Tu tarea es escribir y probar una función que toma un argumento (un año) y devuelve True si el año es un año
bisiesto, o False si no lo es.
Nota: también hemos preparado un breve código de prueba, que puedes utilizar para probar tu función.
El código utiliza dos listas - una con los datos de prueba y la otra con los resultados esperados. El código te dirá si
alguno de tus resultados no es válido.
Tu tarea es escribir y probar una función que toma dos argumentos (un año y un mes) y devuelve el número de
días del mes/año dado (mientras que solo febrero es sensible al valor year, tu función debería ser universal).
La parte inicial de la función está lista. Ahora, haz que la función devuelva None si los argumentos no tienen
sentido.
Por supuesto, puedes (y debes) utilizar la función previamente escrita y probada (LAB 4.3.1.6). Puede ser muy
útil. Te recomendamos que utilices una lista con los meses. Puedes crearla dentro de la función - este truco
acortará significativamente el código.
Hemos preparado un código de prueba. Amplíalo para incluir más casos de prueba.
4.3.6 LAB DÍA DEL AÑO: ESCRIBIENDO Y USANDO TUS PROPIAS FUNCIONES
Tu tarea es escribir y probar una función que toma tres argumentos (un año, un mes y un día del mes) y devuelve
el día correspondiente del año, o devuelve None si cualquiera de los argumentos no es válido.
Debes utilizar las funciones previamente escritas y probadas. Agrega algunos casos de prueba al código. Esta
prueba es solo el comienzo.
Un número natural es primo si es mayor que 1 y no tiene divisores más que 1 y sí mismo.
¿Complicado? De ninguna manera. Por ejemplo, 8 no es un número primo, ya que puedes dividirlo entre 2 y 4
(no podemos usar divisores iguales a 1 y 8, ya que la definición lo prohíbe).
Por otra parte, 7 es un número primo, ya que no podemos encontrar ningún divisor para él.
La función:
se llama is_prime;
toma un argumento (el valor a verificar)
devuelve True si el argumento es un número primo, y False de lo contrario.
Sugerencia: intenta dividir el argumento por todos los valores posteriores (comenzando desde 2) y verifica el
resto - si es cero, tu número no puede ser un número primo; analiza cuidadosamente cuándo deberías detener
el proceso.
Si necesitas conocer la raíz cuadrada de cualquier valor, puedes utilizar el operador **. Recuerda: la raíz
cuadrada de x es lo mismo que .
SALIDA ESPERADA:
El consumo de combustible de un automóvil se puede expresar de muchas maneras diferentes. Por ejemplo, en
Europa, se muestra como la cantidad de combustible consumido por cada 100 kilómetros.
En los EE. UU., se muestra como la cantidad de millas recorridas por un automóvil con un galón de combustible.
Tu tarea es escribir un par de funciones que conviertan l/100km a mpg (milas por galón), y viceversa.
Las funciones:
se llaman liters_100km_to_miles_gallon y miles_gallon_to_liters_100km respectivamente;
toman un argumento (el valor correspondiente a sus nombres)
Complementa el código en el editor y ejecuta tu código y verifica si tu salida es la misma que la nuestra.
1. Puedes emplear la palabra clave reservada return para decirle a una función que devuelva algún valor. La
instrucción return termina la función, por ejemplo:
2. El resultado de una función se puede asignar fácilmente a una variable, por ejemplo:
Observa la diferencia en la salida en los siguientes dos ejemplos:
3. Puedes usar una lista como argumento de una función, por ejemplo:
R//
El alcance de un nombre (por ejemplo, el nombre de una variable) es la parte del código donde el nombre es
reconocido correctamente.
Por ejemplo, el alcance del parámetro de una función es la función en sí. El parámetro es inaccesible fuera de la
función.
Vamos a revisarlo. Observa el código en el editor. ¿Qué ocurrirá cuando se ejecute?
Vamos a conducir algunos experimentos para mostrar cómo es que Python define los alcances, y como los
puedes utilizar para tu beneficio.
Comencemos revisando si una variable creada fuera de una función es visible dentro de una función. En otras
palabras, ¿El nombre de la variable se propaga dentro del cuerpo de la función?
Observa el código en el editor. Ahí está nuestro conejillo de indias.
La respuesta es: una variable que existe fuera de una función tiene alcance dentro del cuerpo de la función.
Una variable que existe fuera de una función tiene un alcance dentro del cuerpo de la función, excluyendo a
aquellas que tienen el mismo nombre.
También significa que el alcance de una variable existente fuera de una función solo se puede implementar
dentro de una función cuando su valor es leído. El asignar un valor hace que la función cree su propia variable.
Al llegar a este punto, debemos hacernos la siguiente pregunta: ¿Una función es capaz de modificar una variable
que fue definida fuera de ella? Esto sería muy incómodo.
Existe un método especial en Python el cual puede extender el alcance de una variable incluyendo el cuerpo de
las funciones (para poder no solo leer los valores de las variables sino también modificarlos).
El utilizar la palabra reservada dentro de una función con el nombre o nombres de las variables separados
por comas, obliga a Python a abstenerse de crear una nueva variable dentro de la función - se empleará la
que se puede acceder desde el exterior.
En otras palabras, este nombre se convierte en global (tiene un alcance global, y no importa si se está
leyendo o asignando un valor).
Esto debe de ser suficiente evidencia para mostrar lo que la palabra clave reservada global puede hacer.
El código en el editor nos enseña algo. Como puedes observar, la función cambia el valor de su parámetro.
¿Este cambio afecta el argumento?
La conclusión es obvia - al cambiar el valor del parámetro este no se propaga fuera de la función (más
específicamente, no cuando la variable es un valor escalar, como en el ejemplo).
Esto también significa que una función recibe el valor del argumento, no el argumento en sí. Esto es cierto
para los valores escalares.
Vale la pena revisar cómo funciona esto con las listas (¿Recuerdas las peculiaridades de asignar rebanadas de
listas en lugar de asignar la lista entera?)
No se modifica el valor del parámetro my_list_1 (ya se sabe que no afectará el argumento), en lugar de ello
se modificará la lista identificada por él.
Intentémoslo:
si el argumento es una lista, el cambiar el valor del parámetro correspondiente no afecta la lista (recuerda:
las variables que contienen listas son almacenadas de manera diferente que las escalares)
pero si se modifica la lista identificada por el parámetro (nota: ¡la lista, no el parámetro!), la lista reflejará el
cambio.
Es tiempo de escribir algunos ejemplos de funciones. Lo harás en la siguiente sección.
Ejemplo 1:
Ejemplo 2:
Ejemplo 3:
2. Una variable que existe dentro de una función tiene un alcance solo dentro del cuerpo de la función
(Ejemplo 4), por ejemplo:
Ejemplo 4:
4. Se puede emplear la palabra clave reservada global seguida por el nombre de una variable para que el
alcance de la variable sea global, por ejemplo:
4.4.5 PRUEBA DE SECCIÓN
R//
R// 1 2
Pregunta 3: ¿Cuál es la salida del siguiente fragmento de código?
R// 2 3
Pregunta 4: ¿Cuál es la salida del siguiente fragmento de código?
R// 2 2
La nueva función tendrá dos parámetros. Su nombre será bmi, pero si prefieres utilizar otro nombre, adelante.
Codifiquemos la función.
Observa el código en el editor. Hay dos cosas a las cuales hay que prestar atención.
Primero, se asegura que los datos que sean ingresados sean correctos - de lo contrario la salida será: None
Segundo, observa como el símbolo de diagonal invertida (\) es empleado. Si se termina una línea de código con
él, Python entenderá que la línea continua en la siguiente.
Esto puede ser útil cuando se tienen largas líneas de código y se desea que sean más legibles.
Sin embargo, hay algo que omitimos - las medias en sistema inglés. La función no es útil para personas que
utilicen libras, pies y pulgadas.
Escribimos dos funciones sencillas para convertir unidades del sistema inglés al sistema métrico. Comencemos
con las pulgadas.
Es bien conocido que 1 lb = 0.45359237 kg. Esto lo emplearemos en nuestra nueva función.
Esta es la salida:
Es muy posible que en ocasiones se desee utilizar solo pies sin pulgadas. ¿Python nos ayudará? Por supuesto que
sí.
Finalmente, el código es capaz de responder a la pregunta: ¿Cuál es el IMC de una persona que tiene 5'7" de
altura y un peso de 176 lbs?
La respuesta es:
Ahora trabajaremos con triángulos. Comenzaremos con una función que verifique si tres lados de ciertas
longitudes pueden formar un triángulo.
En la escuela aprendimos que la suma arbitraria de dos lados tiene que ser mayor que la longitud del tercer lado.
No será algo difícil. La función tendrá tres parámetros - uno para cada lado.
Regresará True si todos los lados pueden formar un triángulo, y False de lo contrario. En este caso, is_a_triangle
es un buen nombre para dicha función.
Se ha negado la condición (se invirtieron los operadores relacionales y se reemplazaron los con ,
obteniendo una expresión universal para probar triángulos).
Coloquemos la función en un programa más grande. Se le pedirá al usuario los tres valores y se hará uso de la
función.
Observa el código en el editor. Le pide al usuario tres valores. Después hace uso de la función is_a_triangle. El
código está listo para correrse.
También es posible evaluar el área de un triángulo. La Fórmula de Heron será útil aquí:
Lo probaremos con un triángulo rectángulo la mitad de un cuadrado y con un lado igual a 1. Esto significa que su
área debe ser igual a 0.5.
La siguiente función por definir calcula factoriales. ¿Recuerdas cómo se calcula un factorial?Es muy cercano a
0.5, pero no es exactamente 0.5. ¿Qué significa? ¿Es un error?
No, no lo es. Son solo los cálculos de valores punto flotantes. Pronto se discutirá el tema.
Se expresa con un signo de exclamación, y es igual al producto de todos los números naturales previos al
argumento o número dado.
Escribamos el código. Creemos una función con el nombre factorial_function. Aquí está el código:
Observa cómo se sigue el procedimiento matemático, y como se emplea el bucle for para encontrar el producto.
4.5.5 RECURSIVIDAD
Este término puede describir muchos conceptos distintos, pero uno de ellos, hace referencia a la programación
computacional.
Tanto el factorial como la serie Fibonacci, son las mejores opciones para ilustrar este fenómeno.
El número i se refiere al número i-1, y así sucesivamente hasta llegar a los primeros dos.
¿Puede ser empleado en el código? Por supuesto que puede. Puede hacer el código más corto y claro.
La segunda versión de la función fib() hace uso directo de la recursividad:
Si, existe algo de riesgo. Si no se considera una condición que detenga las invocaciones recursivas, el programa
puede entrar en un bucle infinito. Se debe ser cuidadoso.
Es obvio que:
Aquí esta:
Nuestro viaje funcional está por terminar. La siguiente sección abordara dos tipos de datos en Python: tuplas y
diccionarios.
4.5.6 RESUMEN DE SECCIÓN
1. Una función puede invocar otras funciones o incluso a sí misma. Cuando una función se invoca a sí misma, se
le conoce como recursividad, y la función que se invoca a sí misma y contiene una condición de terminación (la
cual le dice a la función que ya no siga invocándose a sí misma) es llamada una función recursiva.
2. Se pueden emplear funciones recursivas en Python para crear funciones limpias, elegantes, y dividir el código
en trozos más pequeños. Sin embargo, se debe tener mucho cuidado ya que es muy fácil cometer un error y
crear una función la cual nunca termine. También se debe considerar que las funciones recursivas consumen
mucha memoria, y por lo tanto pueden ser en ocasiones ineficientes.
Al emplear la recursividad, se deben de tomar en cuenta tanto sus ventajas como desventajas.
Pregunta 1: ¿Qué ocurrirá al intentar ejecutar el siguiente fragmento de código y por qué?
R// La función no tiene una condición de terminación, por lo tanto, Python arrojara una excepción
(RecursionError: maximum recursion depth exceeded)
Pregunta 2: ¿Cuál es la salida del siguiente fragmento de código?
R// 56
Antes de comenzar a hablar acerca de tuplas y diccionarios, se deben introducir dos conceptos importantes:
tipos de secuencia y mutabilidad.
Un tipo de secuencia es un tipo de dato en Python el cual es capaz de almacenar más de un valor (o ninguno si
la secuencia está vacía), los cuales pueden ser secuencialmente (de ahí el nombre) examinados, elemento por
elemento.
Debido a que el bucle for es una herramienta especialmente diseñada para iterar a través de las secuencias,
podemos definirlas de la siguiente manera: una secuencia es un tipo de dato que puede ser escaneado por el
bucle for.
Hasta ahora, has trabajado con una secuencia en Python - la lista. La lista es un clásico ejemplo de una secuencia
de Python. Aunque existen otras secuencias dignas de mencionar, las cuales se presentaran a continuación.
La segunda noción - la mutabilidad - es una propiedad de cualquier tipo de dato en Python que describe su
disponibilidad para poder cambiar libremente durante la ejecución de un programa. Existen dos tipos de datos
en Python: mutables e inmutables.
Los datos mutables pueden ser actualizados libremente en cualquier momento - a esta operación se le
denomina "in situ".
In situ es una expresión en latín que se traduce literalmente como en posición, en el lugar o momento. Por
ejemplo, la siguiente instrucción modifica los datos "in situ":
Imagina que una lista solo puede ser asignada y leída. No podrías adjuntar ni remover un elemento de la lista. Si
se agrega un elemento al final de la lista provocaría que la lista se cree desde cero.
Se tendría que crear una lista completamente nueva, la cual contenga los elementos ya existentes más el nuevo
elemento.
El tipo de datos que se desea tratar ahora se llama tupla. Una tupla es una secuencia inmutable. Se puede
comportar como una lista, pero no puede ser modificada en el momento.
4.6.2 TUPLAS
Lo primero que distingue una lista de una tupla es la sintaxis empleada para crearlas - las tuplas utilizan
paréntesis, mientras que las listas usan corchetes, aunque también es posible crear una tupla tan solo
separando los valores por comas.
Observa el ejemplo:
Nota: cada elemento de una tupla puede ser de distinto tipo (punto flotante, entero, cadena, o cualquier otro
tipo de dato).
¿Es posible crear una tupla vacía? Si, solo se necesitan unos paréntesis:
Si se desea crear una tupla de un solo elemento, se debe de considerar el hecho de que, debido a la sintaxis (una
tupla debe de poder distinguirse de un valor entero ordinario), se debe de colocar una coma al final:
El quitar las comas no arruinará el programa en el sentido sintáctico, pero serán dos variables, no tuplas.
Si deseas leer los elementos de una tupla, lo puedes hacer de la misma manera que se hace con las listas.
Las similitudes pueden ser engañosas - no intentes modificar el contenido de la tupla ¡No es una lista!
Una de las propiedades de las tuplas más útiles es que pueden aparecer en el lado izquierdo del operador de
asignación. Este fenómeno ya se vio con anterioridad, cuando fue necesario encontrar una manera de
intercambiar los valores entre dos variables.
Muestra tres tuplas interactuando - en efecto, los valores almacenados en ellas "circulan" entre ellas - t1 se
convierte en t2, t2 se convierte en t3, y t3 se convierte en t1.
Nota: el ejemplo presenta un importante hecho más: los elementos de una tupla pueden ser variables, no solo
literales. Además, pueden ser expresiones si se encuentran en el lado derecho del operador de asignación.
4.6.3 DICCIONARIOS
El diccionario es otro tipo de estructura de datos de Python. No es una secuencia (pero puede adaptarse
fácilmente a un procesamiento secuencial) y además es mutable.
Para explicar lo que es un diccionario en Python, es importante comprender de manera literal lo que es un
diccionario.
¿CÓMO CREAR UN DICCIONARIO?
En este primer ejemplo, el diccionario emplea claves y valores las cuales ambas son cadenas. En el segundo, las
claves con cadenas, pero los valores son enteros. El orden inverso (claves → números, valores → cadenas)
también es posible, así como la combinación número a número.
La lista de todos los pares es encerrada con llaves, mientras que los pares son separados por comas, y las claves
y valores por dos puntos.
Los diccionarios vacíos son construidos por un par vacío de llaves - nada inusual.
Un diccionario en Python funciona de la misma manera que un diccionario bilingüe. Por ejemplo, se tiene la
palabra en español "gato" y se necesita su equivalente en francés. Lo que se haría es buscar en el diccionario
para encontrar la palabra "gato". Eventualmente la encontrarás, y sabrás que la palabra equivalente en francés
es "chat".
En el mundo de Python, la palabra que se está buscando se denomina key. La palabra que se obtiene del
diccionario es denominada value.
cada clave debe de ser única - no es posible tener una clave duplicada;
una clave puede ser un de dato de cualquier tipo - puede ser un número (entero o flotante), incluso una
cadena, pero no una lista;
un diccionario no es una lista - una lista contiene un conjunto de valores numerados, mientras que un
diccionario almacena pares de valores;
la función len() aplica también para los diccionarios - regresa la cantidad de pares (clave-valor) en el
diccionario;
un diccionario es una herramienta de un solo sentido - si fuese un diccionario español-francés,
podríamos buscar en español para encontrar su contraparte en francés más no viceversa.
A continuación, veamos algunos ejemplos:
El diccionario entero se puede imprimir con una invocación a la función print(). El fragmento de código puede
producir la siguiente salida:
¿Has notado que el orden de los pares impresos es diferente a la asignación inicial? ¿Qué significa esto?
Primeramente, recordemos que los diccionarios no son listas - no guardan el orden de sus datos, el orden no
tiene significado (a diferencia de los diccionarios reales). El orden en que un diccionario almacena sus datos esta
fuera de nuestro control. Esto es normal. (*)
Nota
(*) En Python 3.6x los diccionarios se han convertido en colecciones ordenadas de manera predeterminada. Tu
resultado puede variar dependiendo en la versión de Python que se esté utilizando.
Si deseas obtener cualquiera de los valores, debes de proporcionar una clave válida:
El obtener el valor de un diccionario es semejante a la indexación, gracias a los corchetes alrededor del valor de
la clave.
Nota:
sí una clave es una cadena, se tiene que especificar como una cadena;
las claves son sensibles a las mayúsculas y minúsculas: 'Suzy' sería diferente a 'suzy'.
Afortunadamente, existe una manera simple de evitar dicha situación. El operador in, junto con su
acompañante, not in, pueden salvarnos de esta situación.
Nota
Cuando escribes una expresión grande o larga, puede ser una buena idea mantenerla alineada verticalmente. Así
es como puede hacer que el código sea más legible y amigable para el programador, por ejemplo:
EL MÉTODO KEYS()
¿Pueden los diccionarios ser examinados utilizando el bucle for, como las listas o tuplas?
No y si.
No, porque un diccionario no es un tipo de dato secuencial - el bucle for no es útil aquí.
Si, porque hay herramientas simples y muy efectivas que pueden adaptar cualquier diccionario a los
requerimientos del bucle for (en otras palabras, se construye un enlace intermedio entre el diccionario y una
entidad secuencial temporal).
El primero de ellos es un método denominado keys(), el cual es parte de todo diccionario. El método retorna o
regresa una lista de todas las claves dentro del diccionario. Al tener una lista de claves se puede acceder a todo
el diccionario de una manera fácil y útil.
Otra manera de hacerlo es utilizar el método items(). Este método retorna una lista de tuplas (este es el primer
ejemplo en el que las tuplas son más que un ejemplo de sí mismas) donde cada tupla es un par de cada clave
con su valor.
Nota la manera en que la tupla ha sido utilizada como una variable del bucle for.
El asignar un nuevo valor a una clave existente es sencillo - debido a que los diccionarios son completamente
mutables, no existen obstáculos para modificarlos.
Se va a reemplazar el valor "chat" por "minou", lo cual no es muy adecuado, pero funcionará con nuestro
ejemplo.
Observa:
La salida es:
LA FUNCIÓN SORTED()
¿Deseas que la salida esta ordenada? Solo hay que agregar al bucle for lo siguiente:
También existe un método denominado values(), funciona de manera muy similar al de keys(), pero regresa una
lista de valores.
Como el diccionario no es capaz de automáticamente encontrar la clave de un valor dado, el rol de este método
es algo limitado.
El agregar una nueva clave con su valor a un diccionario es tan simple como cambiar un valor. Solo se tiene que
asignar un valor a una nueva clave que no haya existido antes.
Nota: este es un comportamiento muy diferente comparado a las listas, las cuales no permiten asignar valores a
índices no existentes.
Nota
También es posible insertar un elemento al diccionario utilizando el método update(), por ejemplo:
A continuación, un ejemplo:
EXTRA
Para eliminar el último elemento de la lista, se puede emplear el método popitem():
En versiones anteriores de Python, por ejemplo, antes de la 3.6.7, el método popitem() elimina un elemento al
azar del diccionario.
Se ha preparado un ejemplo sencillo, mostrando como las tuplas y los diccionarios pueden trabajar juntos.
línea 1: crea un diccionario vacío para ingresar los datos; el nombre del alumno es empleado
como clave, mientras que todas las calificaciones asociadas son almacenadas en una tupla (la
tupla puede ser el valor de un diccionario, esto no es un problema)
línea 3: se ingresa a un bucle "infinito" (no te preocupes, saldrémos de el en el momento
indicado)
línea 4: se lee el nombre del alumno aquí;
línea 5-6: si el nombre es una cadena vacía (), salimos del bucle;
línea 8: se pide la calificación del estudiante (un valor entero en el rango del 0-10)
línea 9-10: si la puntuación ingresada no está dentro del rango de 0 a 10, se abandona el bucle;
línea 12-13: si el nombre del estudiante ya se encuentra en el diccionario, se alarga la tupla
asociada con la nueva calificación (observa el operador +=)
línea 14-15: si el estudiante es nuevo (desconocido para el diccionario), se crea una entrada
nueva, su valor es una tupla de un solo elemento la cual contiene la calificación ingresada;
línea 17: se itera a través de los nombres ordenados de los estudiantes;
línea 18-19: inicializa los datos necesarios para calcular el promedio (sum y counter).
línea 20-22: se itera a través de la tupla, tomado todas las calificaciones subsecuentes y
actualizando la suma junto con el contador.
línea 23: se calcula e imprime el promedio del alumno junto con su nombre.
1. Las Tuplas son colecciones de datos ordenadas e inmutables. Se puede pensar en ellas como listas
inmutables. Se definen con paréntesis:
Cada elemento de la tupla puede ser de un tipo de dato diferente (por ejemplo, enteros, cadenas, boleanos,
etc.). Las tuplas pueden contener otras tuplas o listas (y viceversa).
5. Las tuplas son immutable, lo que significa que no se puede agregar, modificar, cambiar o quitar elementos. El
siguiente fragmento de código provocará una excepción:
EXTRA
También se puede crear una tupla utilizando la función integrada de Python tuple(). Esto es particularmente útil
cuando se desea convertir un iterable (por ejemplo, una lista, rango, cadena, etcétera) en una tupla:
De la misma manera, cuando se desea convertir un iterable en una lista, se puede emplear la función integrada
de Python denominada list():
1. Los diccionarios son *colecciones indexadas de datos, mutables y desordenadas. (*En Python 3.6x los
diccionarios están ordenados de manera predeterminada.
Cada diccionario es un par de clave: valor. Se puede crear empleando la siguiente sintaxis:
2. Si se desea acceder a un elemento del diccionario, se puede hacer haciendo referencia a su clave colocándola
dentro de corchetes (Ejemplo 1) o utilizando el método get() (Ejemplo 2):
3. Si se desea cambiar el valor asociado a una clave específica, se puede hacer haciendo referencia a la clave del
elemento, a continuación, se muestra un ejemplo:
4. Para agregar o eliminar una clave (junto con su valor asociado), emplea la siguiente sintaxis:
Además, se puede insertar un elemento a un diccionario utilizando el método update(), y eliminar el último
elemento con el método popitem(), por ejemplo:
5. Se puede emplear el bucle for para iterar a través del diccionario, por ejemplo:
6. Si deseas examinar los elementos (claves y valores) del diccionario, puedes emplear el método items(), por
ejemplo:
7. Para comprobar si una clave existe en un diccionario, se puede emplear la palabra clave reservada in:
8. Se puede emplear la palabra reservada del para eliminar un elemento, o un diccionario entero. Para eliminar
todos los elementos de un diccionario se debe emplear el método clear():
R//
Pregunta 3: Completa el código para emplear correctamente el método count() para encontrar la cantidad de 2
duplicados en la tupla siguiente.
R//
Pregunta 4: Escribe un programa que "una" los dos diccionarios (d1 y d2) para crear uno nuevo (d3).
R//
R//
R//
R//
Parece indiscutible que todos los programadores (incluso tú) quieren escribir código libre de errores y hacen
todo lo posible para lograr este objetivo. Desafortunadamente, nada es perfecto en este mundo y el software no
es una excepción. Presta atención a la palabra excepción, ya que la veremos de nuevo muy pronto en un
significado que no tiene nada que ver con el común.
Errar es humano, es imposible no cometer errores y es imposible escribir código sin errores. No nos
malinterpretes, no queremos convencerte de que escribir programas desordenados y defectuosos es una virtud.
Más bien queremos explicar que incluso el programador más cuidadoso no puede evitar defectos menores o
mayores. Sólo aquellos que no hacen nada no cometen errores.
Paradójicamente, aceptar esta difícil verdad puede convertirte en un mejor programador y mejorar la calidad de
tu código.
Intentaremos mostrártelo.
El lidiar con errores de programación tiene (al menos) dos partes. La primera es cuando te metes en problemas
porque tu código, aparentemente correcto, se alimenta con datos incorrectos. Por ejemplo, esperas que se
ingrese al código un valor entero, pero tu usuario descuidado ingresa algunas letras al azar.
Puede suceder que tu código termine en ese momento y el usuario se quede solo con un mensaje de error
conciso y a la vez ambiguo en la pantalla. El usuario estará insatisfecho y tú también deberías estarlo.
Te mostraremos cómo proteger tu código de este tipo de fallas y cómo no provocar la ira del usuario.
La segunda parte de lidiar con errores de programación se revela cuando ocurre un comportamiento no deseado
del programa debido a errores que se cometieron cuando se estaba escribiendo el código. Este tipo de error se
denomina comúnmente "bug" (bicho en inglés), que es una manifestación de una creencia bien establecida de
que, si un programa funciona mal, esto debe ser causado por bichos maliciosos que viven dentro del hardware
de la computadora y causan cortocircuitos u otras interferencias.
Esta idea no es tan descabellada como puede parecer: incidentes de este tipo eran comunes en tiempos en que
las computadoras ocupaban grandes pasillos, consumían kilovatios de electricidad y producían enormes
cantidades de calor. Afortunadamente, o no, estos tiempos se han ido para siempre y los únicos errores que
pueden estropear tu código son los que tú mismo sembraste en el código. Por lo tanto, intentaremos mostrarte
cómo encontrar y eliminar tus errores, en otras palabras, cómo depurar tu código.
Escribamos un fragmento de código extremadamente trivial - leerá un número natural (un entero no negativo) e
imprimirá su recíproco. De esta forma, 2 se convertirá en 0.5 (1/2) y 4 en 0.25 (1/4). Aquí está el programa:
¿Hay algo que pueda salir mal? El código es tan breve y compacto que no parece que vayamos a encontrar
ningún problema allí.
Parece que ya sabes hacia dónde vamos. Sí, tienes razón - ingresar datos que no sean un número entero (que
también incluye ingresar nada) arruinará completamente la ejecución del programa. Esto es lo que verá el
usuario del código:
Todas las líneas que muestra Python son significativas e importantes, pero la última línea parece ser la más
valiosa. La primera palabra de la línea es el nombre de la excepción la cual provoca que tu código se detenga. Su
nombre aquí es ValueError. El resto de la línea es solo una breve explicación que especifica con mayor precisión
la causa de la excepción ocurrida.
¿Cómo lo afrontas? ¿Cómo proteges tu código de la terminación abrupta, al usuario de la decepción y a ti mismo
de la insatisfacción del usuario?
La primera idea que se te puede ocurrir es verificar si los datos proporcionados por el usuario son válidos y
negarte a cooperar si los datos son incorrectos. En este caso, la verificación puede basarse en el hecho de que
esperamos que la cadena de entrada contenga solo dígitos.
Ya deberías poder implementar esta verificación y escribirla tú mismo, ¿no es así? También es posible comprobar
si la variable value es de tipo int (Python tiene un medio especial para este tipo de comprobaciones - es un
operador llamado is. La revisión en sí puede verse de la siguiente manera:
Su resultado es true si el valor actual de la variable es del tipo int.
Perdónanos si no dedicamos más tiempo a esto ahora - encontrarás explicaciones más detalladas sobre el
operador is en un módulo del curso dedicado a la programación orientada a objetos.
Es posible que te sorprendas al saber que no queremos que realices ninguna validación preliminar de datos. ¿Por
qué? Porque esta no es la forma que Python recomienda.
En el mundo de Python, hay una regla que dice: "Es mejor pedir perdón que pedir permiso".
Detengámonos aquí por un momento. No nos malinterpretes - no queremos que apliques la regla en tu vida
diaria. No tomes el automóvil de nadie sin permiso, con la esperanza de que puedas ser tan convincente que
evites la condena por lo ocurrido. La regla se trata de otra cosa.
En realidad, la regla dice: "es mejor manejar un error cuando ocurre que tratar de evitarlo".
"De acuerdo," puedes decir, "pero ¿cómo debo pedir perdón cuando el programa finaliza y no queda nada que
más por hacer?" Aquí es donde algo llamado excepción entra en escena.
Como puedes ver, este enfoque acepta errores (los trata como una parte normal de la vida del programa) en
lugar de intensificar los esfuerzos para evitarlos por completo.
cualquier fragmento de código colocado entre try y except se ejecuta de una manera muy especial:
cualquier error que ocurra aquí dentro no terminará la ejecución del programa. En cambio, el control
saltará inmediatamente a la primera línea situada después de la palabra clave reservada except, y no se
ejecutará ninguna otra línea del bloque try;
el código en el bloque except se activa solo cuando se ha encontrado una excepción dentro del bloque
try. No hay forma de llegar por ningún otro medio;
cuando el bloque try o except se ejecutan con éxito, el control vuelve al proceso normal de ejecución y
cualquier código ubicado más allá en el archivo fuente se ejecuta como si no hubiera pasado nada.
Ahora queremos hacerte una pregunta: ¿Es ValueError la única forma en que el control podría caer dentro del
bloque except?
La respuesta obvia es "no" - hay más de una forma posible de plantear una excepción. Por ejemplo, un usuario
puede ingresar cero como entrada - ¿puedes predecir lo que sucederá a continuación?
Sí, tienes razón - la división colocada dentro de la invocación de la función print() generará la excepción
ZeroDivisionError. Como es de esperarse, el comportamiento del código será el mismo que en el caso anterior -
el usuario verá el mensaje "No sé qué hacer con...", lo que parece bastante razonable en este contexto, pero
también es posible que desees manejar este tipo de problema de una manera un poco diferente.
¿Es posible? Por supuesto que lo es. Hay al menos dos enfoques que puedes implementar aquí.
El primero de ellos es simple y complicado al mismo tiempo: puedes agregar dos bloques try por separado, uno
que incluya la invocación de la función input() donde se puede generar la excepción ValueError y el segundo
dedicado a manejar posibles problemas inducidos por la división. Ambos bloques try tendrían su propio except y
de esa manera, tendrías un control total sobre dos errores diferentes.
Esta solución es buena, pero es un poco larga - el código se hincha innecesariamente. Además, no es el único
peligro que te espera. Toma en cuenta que dejar el primer bloque try-except deja mucha incertidumbre - tendrás
que agregar código adicional para asegurarte de que el valor que ingresó el usuario sea seguro para usar en la
división. Así es como una solución aparentemente simple se vuelve demasiado complicada.
Afortunadamente, Python ofrece una forma más sencilla de afrontar este tipo de desafíos.
Observa el código en el editor. Como puedes ver, acabamos de agregar un segundo except. Esta no es la única
diferencia - toma en cuenta que ambos except tienen nombres de excepción específicos. En esta variante, cada
una de las excepciones esperadas tiene su propia forma de manejar el error, pero debe enfatizarse en que solo
una de todas puede interceptar el control - si se ejecuta una, todas las demás permanecen inactivas.
Además, la cantidad de except no está limitada - puedes especificar tantas o tan pocas como necesites, pero no
se te olvide que ninguna de las excepciones se puede especificar más de una vez.
Nota
¡el except por defecto debe ser el último except! ¡Siempre!
Analicemos con más detalle algunas excepciones útiles (o más bien, las más comunes) que puedes llegar a
experimentar.
ZERODIVISIONERROR
Esta aparece cuando intentas forzar a Python a realizar cualquier operación que provoque una división en la que
el divisor es cero o no se puede distinguir de cero. Toma en cuenta que hay más de un operador de Python que
puede hacer que se genere esta excepción. ¿Puedes adivinarlos todos?
VALUEERROR
Espera esta excepción cuando estás manejando valores que pueden usarse de manera inapropiada en algún
contexto. En general, esta excepción se genera cuando una función (como int() o float()) recibe un argumento de
un tipo adecuado, pero su valor es inaceptable.
TYPEERROR
Esta excepción aparece cuando intentas aplicar un dato cuyo tipo no se puede aceptar en el contexto actual.
Mira el ejemplo:
No está permitido usar un valor flotante como índice de una lista (la misma regla también se aplica a las tuplas).
TypeError es un nombre adecuado para describir el problema y una excepción adecuada a generar.
ATTRIBUTEERROR
Esta excepción llega - entre otras ocasiones - cuando intentas activar un método que no existe en un elemento
con el que se está tratando. Por ejemplo:
La tercera línea de nuestro ejemplo intenta hacer uso de un método que no está incluido en las listas. Este es el
lugar donde se genera la excepción AttributeError.
SYNTAXERROR
Esta excepción se genera cuando el control llega a una línea de código que viola la gramática de Python. Puede
sonar extraño, pero algunos errores de este tipo no se pueden identificar sin ejecutar primero el código. Este tipo
de comportamiento es típico de los lenguajes interpretados - el intérprete siempre trabaja con prisa y no tiene
tiempo para escanear todo el código fuente. Se conforma con comprobar el código que se está ejecutando en el
momento. Muy pronto se te presentará un ejemplo de esta categoría.
Es una mala idea manejar este tipo de excepciones en tus programas. Deberías producir código sin errores de
sintaxis, en lugar de enmascarar las fallas que has causado.
Aunque vamos a resumir nuestras consideraciones excepcionales aquí, no creas que es todo lo que Python
puede ofrecer para ayudarte a suplicar perdón. La maquinaria de excepciones de Python es mucho más compleja
y sus capacidades te permiten desarrollar estrategias de manejo de errores expandidas. Volveremos a estos
temas - lo prometemos. No dudes en realizar tus experimentos y sumergirte en las excepciones por ti mismo.
Ahora queremos contarte sobre el segundo lado de la lucha interminable contra los errores - el destino
inevitable de la vida de un desarrollador. Como no puedes evitar la creación de errores en tu código, siempre
debes estar listo para buscarlos y destruirlos. No entierres la cabeza en la arena - ignorar los errores no los hará
desaparecer.
Un deber importante para los desarrolladores es probar el código recién creado, pero no debes olvidar que las
pruebas no son una forma de demostrar que el código está libre de errores. Paradójicamente, lo único que las
pruebas determinan, es que tu código contiene errores. No creas que puedes relajarte después de una prueba
exitosa.
El segundo aspecto importante de las pruebas de software es estrictamente psicológico. Es una verdad conocida
desde hace años que los autores - incluso aquellos que son confiables y conscientes de sí mismos - no pueden
evaluar y verificar objetivamente sus trabajos.
Es por eso por lo que cada novelista necesita un editor y cada programador necesita un tester. Algunos dicen -
con un poco de rencor, pero con sinceridad - que los desarrolladores prueban su código para mostrar su
perfección, no para encontrar problemas que puedan frustrarlos. Los testers o probadores están libres de tales
dilemas, y es por eso por lo que su trabajo es más efectivo y rentable.
Por supuesto, esto no te exime de estar atento y cauteloso. Prueba tu código lo mejor que puedas. No facilites
demasiado el trabajo a los probadores.
Su deber principal es asegurarse de haber verificado todas las rutas o caminos de ejecución por las que puede
pasar tu código. ¿Suena misterioso? ¡Por supuesto que no!
Existen tres rutas o caminos de ejecución independientes en el código - ¿puedes verlas? Están determinadas por
las sentencias if-elif-else. Por supuesto, las rutas de ejecución pueden construirse mediante muchas otras
sentencias como bucles, o incluso bloques try-except.
Si vas a probar tu código de manera justa y quieres dormir profundamente y soñar sin pesadillas (las pesadillas
sobre errores pueden ser devastadoras para el rendimiento de un desarrollador), estás obligado a preparar un
conjunto de datos de prueba que obligará a tu código a negociar todos los posibles caminos.
En nuestro ejemplo, el conjunto debe contener al menos tres valores flotantes: uno positivo, uno negativo y
cero.
Tal prueba es crucial. Queremos mostrarte por qué no debes omitirlo. Observa el siguiente código:
Introdujimos intencionalmente un error en el código - esperamos que tus ojos atentos lo noten de inmediato. Sí,
eliminamos solo una letra y, en efecto, la invocación válida de la función print() se convierte en la obviamente
inválida invocación "prin()". No existe tal función como "prin()" en el alcance de nuestro programa, pero ¿es
realmente obvio para Python?
¿Cómo es eso posible? ¿Por qué Python pasa por alto un error de desarrollador tan evidente?
La respuesta es más simple de lo esperado y también un poco decepcionante. Python - como seguramente sabes
- es un lenguaje interpretado. Esto significa que el código fuente se analiza y ejecuta al mismo tiempo. En
consecuencia, es posible que Python no tenga tiempo para analizar las líneas de código que no están sujetas a
ejecución. Como dice un antiguo dicho de los desarrolladores: "es una característica, no un error" (no utilices
esta frase para justificar el comportamiento extraño de tu código).
¿Entiendes ahora por qué el pasar por todos los caminos de ejecución es tan vital e inevitable?
Supongamos que terminas tu código y que las pruebas que has realizado son exitosas. Entregas tu código a los
probadores y - ¡afortunadamente! - encontraron algunos errores en él. Estamos usando la palabra
"afortunadamente" de manera completamente consciente. Debes aceptar que, en primer lugar, los probadores
son los mejores amigos del desarrollador - no debes tratar a los errores que ellos encuentran como una ofensa o
una malignidad; y, en segundo lugar, cada error que encuentran los probadores es un error que no afectará a los
usuarios. Ambos factores son valiosos y merecen tu atención.
Ya sabes que tu código contiene un error o errores (lo segundo es más probable). Ahora, ¿cómo los localizas y
cómo arreglas tu código?
La medida básica que un desarrollador puede utilizar contra los errores es - como era de esperarse - un
depurador, mientras que el proceso durante el cual se eliminan los errores del código se llama depuración.
Según un viejo chiste, la depuración es un complicado juego de misterio en el que eres simultáneamente el
asesino, el detective y - la parte más dolorosa de la intriga - la víctima. ¿Estás listo para interpretar todos estos
roles? Entonces debes armarte con un depurador.
Un depurador es un software especializado que puede controlar cómo se ejecuta tu programa. Con el depurador,
puedes ejecutar tu código línea por línea, inspeccionar todos los estados de las variables y cambiar sus valores
en cualquier momento sin modificar el código fuente, detener la ejecución del programa cuando se cumplen o
no ciertas condiciones, y hacer muchas otras tareas útiles.
Podemos decir que todo IDLE está equipado con un depurador más o menos avanzado. Incluso IDLE tiene uno,
aunque puedes encontrar su manejo un poco complicado y problemático. Si deseas utilizar el depurador
integrado de IDLE, debes activarlo mediante la opción "Debug" en la barra de menú de la ventana principal de
IDLE. Es el punto de partida para la depuración.
Haz clic aquí para ver las capturas de pantalla que muestran el depurador IDLE durante una sesión de depuración
simple. (¡Gracias, Universidad de Kentucky!)
Puedes ver cómo el depurador visualiza las variables y los valores de los parámetros, y observa la pila de
llamadas que muestra la cadena de invocaciones que van desde la función actualmente ejecutada hasta el nivel
del intérprete.
Esta forma de depuración, que se puede aplicar a tu código mediante cualquier tipo de depurador, a veces se
denomina depuración interactiva. El significado del término se explica por sí mismo - el proceso necesita su
interacción (la del desarrollador) para que se lleve a cabo.
Algunas otras técnicas de depuración se pueden utilizar para cazar errores. Es posible que no puedas o no
quieras usar un depurador (las razones pueden variar). ¿Estás entonces indefenso? ¡Absolutamente no!
Puedes utilizar una de las tácticas de depuración más simples y antiguas (pero aún útil) conocida como la
depuración por impresión. El nombre habla por sí mismo - simplemente insertas varias invocaciones print()
adicionales dentro de tu código para generar datos que ilustran la ruta que tu código está negociando
actualmente. Puedes imprimir los valores de las variables que pueden afectar la ejecución.
Estas impresiones pueden generar texto significativo como "Estoy aquí", "Ingresé a la función foo()", "El
resultado es 0", o pueden contener secuencias de caracteres que solo tú puedes leer. Por favor, no uses palabras
obscenas o indecentes para ese propósito, aunque puedas sentir una fuerte tentación - tu reputación puede
arruinarse en un momento si estas payasadas se filtran al público.
Como puedes ver, este tipo de depuración no es realmente interactiva en lo absoluto, o es interactiva solo en
pequeña medida, cuando decides aplicar la función input() para detener o retrasar la ejecución del código.
Una vez que se encuentran y eliminan los errores, las impresiones adicionales pueden comentarse o eliminarse -
tu decides. No permitas que se ejecuten en el código final - pueden confundir tanto a los probadores como a los
usuarios, y traer mal karma sobre ti.
Aquí hay algunos consejos que pueden ayudarte a encontrar y eliminar errores. Ninguno de ellos es definitivo.
Úsalos de manera flexible y confía en tu intuición. No te creas a ti mismo - comprueba todo dos veces.
Intenta decirle a alguien (por ejemplo, a tu amigo o compañero de trabajo) qué es lo que se espera que
haga tu código y cómo se espera que se comporte. Sé concreto y no omitas detalles. Responde todas las
preguntas que te hagan. Es probable que te des cuenta de la causa del problema mientras cuentas tu
historia, ya que el hablar activa esas partes de tu cerebro que permanecen inactivas mientras codificas.
Si ningún humano puede ayudarte con el problema, usa un patito amarillo de goma en su lugar. No
estamos bromeando - consulta el artículo de Wikipedia para obtener más información sobre esta técnica
de uso común: Rubber Duck Debugging.
Intenta aislar el problema. Puedes extraer la parte de tu código que se sospecha que es responsable de
tus problemas y ejecutarla por separado. Puedes comentar partes del código para ocultar el problema.
Asigna valores concretos a las variables en lugar de leerlos desde la consola. Prueba tus funciones
aplicando valores de argumentos predecibles. Analiza el código cuidadosamente. Léelo en voz alta.
Si el error apareció recientemente y no había aparecido antes, analiza todos los cambios que has
introducido en tu código - uno de ellos puede ser la razón.
Tómate un descanso, bebe una taza de café, toma a tu perro y sal a caminar, lee un buen libro, incluso
dos, haz una llamada telefónica a tu mejor amigo - te sorprenderás de la frecuencia con la que esto
ayuda.
Se optimista - eventualmente encontrarás el error; te lo prometemos.
4.7.13 PRUEBAS UNITARIAS - UN MAYOR NIVEL DE CODIFICACIÓN
También existe una técnica de programación importante y ampliamente utilizada que tendrás que adoptar tarde
o temprano durante tu carrera de desarrollador - se llama prueba unitaria. El nombre puede ser un poco
confuso, ya que no se trata solo de probar el software, sino también (y, sobre todo) de cómo se escribe el código.
Para resumir la historia - las pruebas unitarias asumen que las pruebas son partes inseparables del código y la
preparación de los datos de prueba es una parte inseparable de la codificación. Esto significa que cuando
escribes una función o un conjunto de funciones cooperativas, también estás obligado a crear un conjunto de
datos para los cuales el comportamiento de tu código es predecible y conocido.
Además, debes equipar a tu código con una interfaz que pueda ser utilizada por un entorno de pruebas
automatizado. En este enfoque, cualquier enmienda realizada al código (incluso la menos significativa) debe ir
seguida de la ejecución de todas las pruebas unitarias que acompañan al código fuente.
Para estandarizar este enfoque y facilitar su aplicación, Python proporciona un módulo dedicado llamado
unittest. No vamos a discutirlo aquí - es un tema amplio y complejo.
Por lo tanto, hemos preparado un curso y una ruta de certificación independiente para este tema. Se llama
”Testing Essentials with Python, y ahora te invitamos a participar en él.
errores de sintaxis (errores de análisis), que ocurren cuando el analizador encuentra una sentencia de
código que no es correcta. Por ejemplo:
Provocará un error del tipo SyntaxError, y da como resultado el siguiente (o similar) mensaje que se muestra en
la consola:
Presta atención a la flecha - indica el lugar donde el analizador de Python ha tenido problemas. En este caso, la
doble comilla es la que falta. ¿Lo notaste?
excepciones, ocurren incluso cuando una sentencia o expresión es sintácticamente correcta. Estos son
los errores que se detectan durante la ejecución, cuando tu código da como resultado un error que no es
incondicionalmente fatal. Por ejemplo:
Provocará una excepción ZeroDivisionError, y da como resultado el siguiente (o similar) mensaje que se muestra
en la consola:
Presta atención a la última línea del mensaje de error - en realidad, te dice lo que sucedió. Existen muchos
diferentes tipos de excepciones, como ZeroDivisionError, NameError, TypeError, y muchas más; y esta parte del
mensaje te informa qué tipo de excepción se ha generado. Las líneas anteriores muestran el contexto en el que
ha ocurrido la excepción.
2. Puedes "capturar" y manejar excepciones en Python usando el bloque try-except. Por lo tanto, si tienes la
sospecha de que cualquier fragmento de código en particular puede generar una excepción, puedes escribir
el código que la manejará con elegancia y no interrumpirá el programa. Observa el ejemplo:
El código anterior le pide al usuario que ingrese un valor hasta que el valor ingresado sea un número entero
válido. Si el usuario ingresa un valor que no se puede convertir a un int, el programa imprimirá en la consola
Advertencia: el valor ingresado no es un número válido. Intenta de nuevo..., y pide al usuario que ingrese un
número nuevamente. ¿Veamos que sucede en dicho caso?
Si el usuario ingresa un valor correcto y no se genera ninguna excepción, las instrucciones subsiguientes al
bloque try, son ejecutadas. En este caso, los excepts no se ejecutan.
3. Puedes manejar múltiples excepciones en tu bloque de código. Analiza los siguientes ejemplos:
Puedes utilizar varios bloques except dentro de una sentencia try, y especificar nombres de excepciones. Si se
ejecuta alguno de los except, los otros se omitirán. Recuerda: puedes especificar una excepción integrada solo
una vez. Además, no olvides que la excepción por defecto (o genérica), es decir, a la que no se le especifica
nombre, debe ser colocada al final (utiliza las excepciones más específicas primero, y las más generales al
último).
También puedes especificar y manejar múltiples excepciones integradas dentro de un solo bloque except:
4. Algunas de las excepciones integradas más útiles de Python son: ZeroDivisionError, ValueError, TypeError,
AttributeError, y SyntaxError. Una excepción más que, en nuestra opinión, merece tu atención es la excepción
KeyboardInterrupt, que se genera cuando el usuario presiona la tecla de interrupción (CTRL-C o Eliminar).
Ejecuta el código anterior y presiona la combinación de teclas para ver qué sucede.
Para obtener más información sobre las excepciones integradas de Python, consulta la documentación oficial de
Python aquí.
5. Por último, pero no menos importante, debes recordar cómo probar y depurar tu código. Utiliza técnicas de
depuración como depuración de impresión; si es posible - pide a alguien que lea tu código y te ayude a encontrar
errores o mejorarlo; intenta aislar el fragmento de código que es problemático y susceptible a errores: prueba
tus funciones aplicando valores de argumento predecibles, y trata de manejar las situaciones en las que alguien
ingresa valores incorrectos; comenta las partes del código que ocultan el problema. Finalmente, toma descansos
y vuelve a tu código después de un tiempo con un par de ojos nuevos.
R//
R//
PROYECTO Tic-Tac-Toe
Escenario
Tu tarea es escribir un simple programa que simule jugar a tic-tac-toe (nombre en inglés) con el usuario. Para
hacerlo más fácil, hemos decidido simplificar el juego. Aquí están nuestras reglas:
Requerimientos
el tablero debe ser almacenado como una lista de tres elementos, mientras que cada elemento es otra lista de
tres elementos (la lista interna representa las filas) de manera que todos los cuadros puedas ser accedidos
empleado la siguiente sintaxis:
cada uno de los elementos internos de la lista puede contener 'O', 'X', o un digito representando el
número del cuadro (dicho cuadro se considera como libre)
la apariencia de tablero debe de ser igual a la presentada en el ejemplo.
implementa las funciones definidas para ti en el editor.
Para obtener un valor numérico aleatorio se puede emplear una función integrada de Python denominada
randrange(). El siguiente ejemplo muestra cómo utilizarla (El programa imprime 10 números aleatorios del 1 al
8).
Nota: la instrucción from-import provee acceso a la función randrange definida en un módulo externo de Python
denominado random.