Python Institute 1 y 2
Python Institute 1 y 2
1. Módulo 1
Introducción a Python y a la programación de computadora.
2. Módulo 2
Tipos de datos, variables, operaciones básicas de entrada y salida, y operadores
básicos.
3. Módulo 3
Valores booleanos, ejecución condicional, bucles, listas y su procesamiento,
operaciones lógicas y de bit a bit.
4. Módulo 4
Funciones, tuplas, diccionarios y procesamiento de datos.
¿Por qué deberías aprender PYTHON?
Python es omnipresente y muchas personas usan numerosos dispositivos con tecnología
de Python a diario, ya sea que se den cuenta o no. Ha habido millones (bueno, en
realidad miles de millones) de líneas de código escritas en Python, lo que significa
oportunidades casi ilimitadas para la reutilización de código y el aprendizaje de ejemplos
bien elaborados. Además, existe una comunidad de Python grande y muy activa, siempre
feliz de ayudar.
También hay un par de factores que hacen que Python sea excelente para el aprendizaje:
• Es fácil de aprender: el tiempo necesario para aprender Python es más corto que
para muchos otros lenguajes; esto significa que es posible iniciar la programación
real más rápido.
• Es fácil de usar para escribir software nuevo; a menudo es posible escribir código
más rápido cuando se usa Python.
• Es fácil de obtener, instalar e implementar: Python es gratuito, abierto y
multiplataforma; no todos los lenguajes pueden presumir de eso.
Completar este curso puede ser un trampolín para aprender cualquier otro lenguaje de
programación y para explorar tecnologías que usan a Python como base (por ejemplo,
Django). Este curso se distingue por su asequibilidad, amigabilidad y apertura para el
estudiante.
La primera parte comienza desde lo básico, guiándote paso a paso hacia los problemas
complejos que se explican en la parte 2, convirtiéndote en un creador de software
responsable capaz de asumir diferentes desafíos en muchas posiciones en la industria de
TI.
¿Y los principales sitios web y servicios como Dropbox, UBER, Spotify, Pintrest y
BuzzFeed? Si. Todos fueron escritos, en mayor o menor medida, en Python. ¿Otros
ejemplos?
Además, con OpenEDG Python Institute, obtienes acceso a una gran red de profesionales
de la programación en Python, un recurso valioso para resolver problemas relacionados
con Python y para desarrollar soluciones innovadoras.
Fundamentos de Python 1:
Módulo 1
Introducción a Python y a la programación de computadoras.
Un programa hace que una computadora sea utilizable. Sin un programa, una
computadora, incluso la más poderosa, no es más que un objeto. Del mismo modo, sin
un pianista, un piano no es más que una caja de madera.
Imagina que quieres conocer la velocidad promedio que has alcanzado durante un largo
viaje. Sabes la distancia, sabes el tiempo, necesitas la velocidad.
Estas cuatro acciones simples forman un programa. Por supuesto, estos ejemplos no
están formalizados, y están muy lejos de lo que la computadora puede entender, pero
son lo suficientemente buenos como para traducirlos a un lenguaje que la computadora
pueda aceptar.
La palabra clave es el lenguaje.
Otro lenguaje que empleas cada día es tu lengua materna, que utilizas para manifestar tu
voluntad y para pensar en la realidad. Las computadoras también tienen su propio
lenguaje, llamado lenguaje máquina, el cual es muy rudimentario.
Los comandos que reconoce son muy simples. Podemos imaginar que la computadora
responde a órdenes como "Toma este número, divídelo entre otro y guarda el resultado".
Desafortunadamente, esta lengua está muy lejos de ser una lengua materna humana.
Ambos (tanto las computadoras como los humanos) necesitamos algo más, un lenguaje
común para las computadoras y los seres humanos, o un puente entre los dos mundos
diferentes.
Tales lenguajes son a menudo llamados lenguajes de programación de alto nivel. Son
algo similares a los naturales en que usan símbolos, palabras y convenciones legibles
para los humanos. Estos lenguajes permiten a los humanos expresar comandos a las
computadoras que son mucho más complejos que las instrucciones ofrecidas por las IL.
Por supuesto, tal composición tiene que ser correcta en muchos sentidos, tales como:
COMPILACIÓN - el programa fuente se traduce una vez (sin embargo, esta ley debe
repetirse cada vez que se modifique el código fuente) obteniendo un archivo (por
ejemplo, un archivo .exe si el código está diseñado para ejecutarse en MS Windows) que
contiene el código máquina; ahora puedes distribuir el archivo en todo el mundo; el
programa que realiza esta traducción se llama compilador o traductor.
Nota: debe ser texto puro, sin ninguna decoración, como diferentes fuentes, colores,
imágenes incrustadas u otros medios. Ahora tienes que invocar al intérprete y dejar que
lea el archivo fuente.
El intérprete lee el código fuente de una manera que es común en la cultura occidental:
de arriba hacia abajo y de izquierda a derecha. Hay algunas excepciones: se cubrirán más
adelante en el curso.
En primer lugar, el intérprete verifica si todas las líneas subsiguientes son correctas
(utilizando los cuatro aspectos tratados anteriormente).
El intérprete te informará dónde se encuentra el error y qué lo causó. Sin embargo, estos
mensajes pueden ser engañosos, ya que el intérprete no puede seguir tus intenciones
exactas y puede detectar errores a cierta distancia de sus causas reales.
Por ejemplo, si intentas usar una entidad de un nombre desconocido, causará un error,
pero el error se descubrirá en el lugar donde se intenta usar la entidad, no donde se
introdujo el nombre de la nueva entidad.
En otras palabras, la razón real generalmente se ubica un poco antes en el código, por
ejemplo, en el lugar donde se tuvo que informar
al intérprete de que usarías la entidad del
nombre.
INTERPRETACIÓN
Ventajas Desventajas
• Puedes ejecutar el código en cuanto lo • No esperes que la interpretación
completes; no hay fases adicionales de incremente tu código a alta velocidad: tu
traducción. código compartirá la potencia de la
computadora con el intérprete, por lo
que no puede ser realmente rápido.
• El código se almacena utilizando el • Tanto tú como el usuario final deben
lenguaje de programación, no el de la tener el intérprete para ejecutar el
máquina; esto significa que puede código.
ejecutarse en computadoras que utilizan
diferentes lenguajes máquina; no se
compila el código por separado para
cada arquitectura diferente.
Debido a razones históricas, los lenguajes diseñados para ser utilizados en la manera de
interpretación a menudo se llaman lenguajes de scripting, mientras que los programas
fuente codificados que los usan se llaman scripts.
¿Qué es Python?
Python es un lenguaje de programación de alto nivel, interpretado, orientado a objetos y
de uso generalizado con semántica dinámica, que se utiliza para la programación de
propósito general.
Aunque puede que conozcas a la pitón como una gran serpiente, el nombre del lenguaje
de programación Python proviene de una vieja serie de comedia de la BBC
llamada Monty Python's Flying Circus.
Dado que Monty Python es considerado uno de los dos nutrientes fundamentales para
un programador (el otro es la pizza), el creador de Python nombró el lenguaje en honor al
programa de televisión.
Unos 20 años después, está claro que todas estas intenciones se han cumplido. Algunas
fuentes dicen que Python es el lenguaje de programación más popular del mundo,
mientras que otros afirman que es el tercero o el quinto.
De cualquier manera, todavía ocupa un alto
rango en el top ten de PYPL PopularitY of
Programming Language y el TIOBE
Programming Community Index.
• Es fácil de aprender: el tiempo necesario para aprender Python es más corto que
en muchos otros lenguajes; esto significa que es posible comenzar la
programación real más rápido.
• Es fácil de enseñar: la carga de trabajo de enseñanza es menor que la que
necesitan otros lenguajes; esto significa que el profesor puede poner más énfasis
en las técnicas de programación generales (independientes del lenguaje), no
gastando energía en trucos exóticos, extrañas excepciones y reglas
incomprensibles.
• Es fácil de utilizar: para escribir software nuevo; a menudo es posible escribir
código más rápido cuando se emplea Python.
• Es fácil de entender: a menudo, también es más fácil entender el código de otra
persona más rápido si está escrito en Python.
• Es fácil de obtener, instalar y desplegar: Python es gratuito, abierto y
multiplataforma; no todos los lenguajes pueden presumir de eso.
¿Rivales de Python?
Python tiene dos competidores directos, con propiedades y predisposiciones
comparables. Estos son:
El primero es más tradicional, más conservador que Python, y se parece a algunos de los
buenos lenguajes antiguos derivados del lenguaje de programación C clásico.
En contraste, este último es más innovador y está más lleno de ideas nuevas. Python se
encuentra en algún lugar entre estas dos creaciones.
Internet está lleno de foros con discusiones infinitas sobre la superioridad de uno de
estos tres sobre los otros, por si deseas obtener más información sobre cada uno de
ellos.
Python 3 es la versión más nueva (para ser precisos, la actual) del lenguaje. Está
atravesando su propio camino de evolución, creando sus propios estándares y hábitos.
Estas dos versiones de Python no son compatibles entre sí. Las secuencias de comandos
de Python 2 no se ejecutarán en un entorno de Python 3 y viceversa, por lo que si deseas
que un intérprete de Python 3 ejecute el código Python 2 anterior, la única solución
posible es volver a escribirlo, no desde cero, por supuesto. Grandes partes del código
pueden permanecer intactas, pero tienes que revisar todo el código para encontrar todas
las incompatibilidades posibles. Desafortunadamente, este proceso no puede ser
completamente automatizado.
Si estás modificando una solución de Python existente, entonces es muy probable que
esté codificada en Python 2. Esta es la razón por la que Python 2 todavía está en uso. Hay
demasiadas aplicaciones de Python 2 existentes para descartarlo por completo.
NOTA
Guido van Rossum utilizó el lenguaje de programación "C" para implementar la primera
versión de su lenguaje y esta decisión aún está vigente. Todos los Pythons que provienen
del PSF están escritos en el lenguaje "C". Existen muchas razones para este enfoque. Una
de ellas (probablemente la más importante) es que gracias a ello, Python puede ser
portado y migrado fácilmente a todas las plataformas con la capacidad de compilar y
ejecutar programas en lenguaje "C" (virtualmente todas las plataformas tienen esta
característica, lo que abre mucha expansión y oportunidades para Python).
Cython
Otro miembro de la familia Python es Cython.
¿Cómo se reconcilian estas dos contradicciones? Una solución es escribir tus ideas
matemáticas usando Python, y cuando estés absolutamente seguro de que tu código es
correcto y produce resultados válidos, puedes traducirlo a "C". Ciertamente, "C" se
ejecutará mucho más rápido que Python puro.
Jython
Otra versión de Python se llama Jython.
"J" es de "Java". Imagina un Python escrito
en Java en lugar de C. Esto es útil, por
ejemplo, si desarrollas sistemas grandes y
complejos escritos completamente en Java
y deseas agregarles cierta flexibilidad de
Python. El tradicional CPython puede ser
difícil de integrar en un entorno de este
tipo, ya que C y Java viven en mundos
completamente diferentes y no comparten muchas ideas comunes.
Jython puede comunicarse con la infraestructura Java existente de manera más efectiva.
Es por esto que algunos proyectos lo encuentran útil y necesario.
Nota: la implementación actual de Jython sigue los estándares de Python 2. Hasta ahora,
no hay Jython conforme a Python 3.
PyPy y RPython
Echa un vistazo al logo de abajo. ¿Puedes resolverlo?
Esto es útil porque si deseas probar cualquier característica nueva que pueda ser o no
introducida en la implementación de Python, es más fácil verificarla con PyPy que con
CPython. Esta es la razón por la que PyPy es más una herramienta para las personas que
desarrollan Python que para el resto de los usuarios.
Esto no hace que PyPy sea menos importante o menos serio que CPython.
Hay muchos más Pythons diferentes en el mundo. Los encontrarás sí los buscas,
pero este curso se centrará en CPython.
1.2.1.1 Comienza tu viaje con Python
Es probable que los usuarios de Linux tengan Python ya instalado - este es el escenario
más probable, ya que la infraestructura de Python se usa de forma intensiva en muchos
componentes del sistema operativo Linux.
python3
>>>
Si Python 3 está ausente, consulta la documentación de Linux para saber cómo utilizar tu
administrador de paquetes para descargar e instalar un paquete nuevo. El que necesitas
se llama python3 o su nombre comienza con eso.
Todos los usuarios que no sean de Linux pueden descargar una copia
en https://www.python.org/downloads/.
1.2.1.2 Comienza tu viaje con Python | Descargando e instalando
Python
Si eres un usuario de Windows, utiliza el archivo .exe descargado y sigue todos los pasos.
Deja las configuraciones predeterminadas que el instalador sugiere por ahora, con una
excepción: observa la casilla de verificación denominada Agregar Python 3.x a PATH y
selecciónala.
Este será un procedimiento muy simple, pero debería ser suficiente para convencerte de
que el entorno de Python es completo y funcional.
Navega por los menús de tu sistema operativo, encuentra IDLE en algún lugar debajo de
Python 3.x y ejecútalo. Esto es lo que deberías ver:
El primer paso es crear un nuevo archivo fuente y llenarlo con el código. Haz clic
en File en el menú del IDLE y selecciona New File.
Como puedes ver, IDLE abre una nueva ventana para ti. Puedes usarla para escribir y
modificar tu código.
Esta es la ventana del editor. Su único propósito es ser un lugar de trabajo en el que se
trate tu código fuente. No confundas la ventana del editor con la ventana del shell.
Realizan diferentes funciones.
La ventana del editor actualmente no tiene título, pero es una buena práctica comenzar a
trabajar nombrando el archivo fuente.
Haz clic en File (en la nueva ventana), luego haz clic sobre Save as ... , selecciona una
carpeta para el nuevo archivo (el escritorio es un buen lugar para tus primeros intentos
de programación) y elige un nombre para el nuevo archivo.
Nota: no establezcas ninguna extensión para el nombre de archivo que vas a utilizar.
Python necesita que sus archivos tengan la extensión .py, por lo que debes confiar en los
valores predeterminados de la ventana de diálogo. El uso de la extensión .py permite que
el sistema operativo abra estos archivos correctamente.
1.2.1.5 Comienza tu viaje con Python
La línea se ve así:
print("Hisssssss...")
Echa un vistazo más de cerca a las comillas. Estas son la forma más simple de las comillas
(neutrales, rectas, etc.) que se usan comúnmente en los archivos fuente. No intentes
utilizar citas tipográficas (curvadas, rizadas, etc.), utilizadas por los procesadores de texto
avanzados, ya que Python no las acepta.
Si todo sale bien y no hay errores en el código, la ventana de la consola mostrará los
efectos causados por la ejecución del programa.
• Haz clic en File, Open, señala el archivo que guardaste anteriormente y deja que
IDLE lo lea de nuevo.
• Intenta ejecutarlo de nuevo presionando F5 cuando la ventana del editor esté
activa.
Como puedes ver, IDLE puede guardar tu código y recuperarlo cuando lo necesites de
nuevo.
Hisssssss...
Cada vez que coloques el paréntesis de cierre en tu programa, IDLE mostrará la parte del
texto limitada con un par de paréntesis correspondientes. Esto te ayuda a
recordar colocarlos en pares.
Aparece una nueva ventana, dice que el intérprete ha encontrado un EOF (fin-de-archivo)
aunque (en su opinión) el código debería contener algo más de texto.
print("Hisssssss...")
Vamos a arruinar el código una vez más. Elimina una letra de la palabra print. Ejecuta el
código presionando F5. Como puedes ver, Python no puede reconocer la instrucción.
La ventana del editor no proporcionará ninguna información útil sobre el error, pero es
posible que las ventanas de la consola si.
• El rastreo (que es la ruta que el código atraviesa a través de diferentes partes del
programa, puedes ignorarlo por ahora, ya que está vacío en un código tan simple).
• La ubicación del error (el nombre del archivo que contiene el error, el número de
línea y el nombre del módulo); nota: el número puede ser engañoso, ya que
Python generalmente muestra el lugar donde se percata por primera vez de los
efectos del error, no necesariamente del error en sí.
• El contenido de la línea errónea; nota: la ventana del editor de IDLE no muestra
números de línea, pero muestra la ubicación actual del cursor en la esquina
inferior derecha; utilízalo para ubicar la línea errónea en un código fuente largo.
• El nombre del error y una breve explicación.
¡Felicidades!
Has completado el Módulo 1.
¡Bien hecho! Has llegado al final del Módulo 1 y has completado una meta importante en
tu educación de programación en Python. Aquí hay un breve resumen de los objetivos
cubiertos y con los que te has familiarizado en el Módulo 1:
Fundamentos de Python 1:
Módulo 2
Tipos de datos, variables, operaciones básicas de entrada y salida, operadores básicos
¡Hola, Mundo!
Es hora de comenzar a escribir código real y funcional en Python. Por el momento será
muy sencillo.
Como se muestran algunos conceptos y términos fundamentales, estos fragmentos de
código no serán complejos ni difíciles.
Ejecuta el código en la ventana del editor a la derecha. Si todo sale bien, verás la línea de
texto en la ventana de consola.
Como alternativa, inicia IDLE, crea un nuevo archivo fuente de Python, coloca este código,
nombra el archivo y guárdalo. Ahora ejecútalo. Si todo sale bien, verás el texto contenido
entre comillas en la ventana de la consola IDLE. El código que has ejecutado debería
parecerte familiar. Viste algo muy similar cuando te guiamos a través de la configuración
del entorno IDLE.
Ahora dedicaremos un poco de tiempo para mostrarte y explicarte lo que estás viendo y
por que se ve así.
• La palabra print .
• Un paréntesis de apertura.
• Una comilla.
• Una línea de texto: ¡Hola, Mundo! .
• Otra comilla.
• Un paréntesis de cierre.
Cada uno de los elementos anteriores juega un papel muy importante en el código.
print("¡Hola, Mundo!")
La función print()
Observa la línea de código a continuación:
print("¡Hola, Mundo!")
La palabra print que puedes ver aquí es el nombre de una función. Eso no significa que
dondequiera que aparezca esta palabra, será siempre el nombre de una función. El
significado de la palabra proviene del contexto en el cual se haya utilizado la palabra.
Probablemente hayas encontrado el término función muchas veces antes, durante las
clases de matemáticas. Probablemente también puedes recordar varios nombres de
funciones matemáticas, como seno o logaritmo.
Las funciones de Python, sin embargo, son más flexibles y pueden contener más que sus
parientes matemáticos.
Una función (en este contexto) es una parte separada del código de computadora el cual
es capaz de:
• Causar algún efecto (por ejemplo, enviar texto a la terminal, crear un archivo,
dibujar una imagen, reproducir un sonido, etc.); esto es algo completamente
inaudito en el mundo de las matemáticas.
• Evaluar un valor (por ejemplo, la raíz cuadrada de un valor o la longitud de un
texto dado) y devolverlo como el resultado de la función; esto es lo que hace que
las funciones de Python sean parientes de los conceptos matemáticos.
Además, muchas de las funciones de Python pueden hacer las dos cosas anteriores
juntas.
• Pueden venir de Python mismo. La función print es una de este tipo; dicha función
es un valor agregado de Python junto con su entorno (está integrada); no tienes
que hacer nada especial (por ejemplo, pedirle a alguien algo) si quieres usarla.
• Pueden provenir de uno o varios de los módulos de Python llamados
complementos; algunos de los módulos vienen con Python, otros pueden requerir
una instalación por separado, cual sea el caso, todos deben estar conectados
explícitamente con el código (te mostraremos cómo hacer esto pronto).
• Puedes escribirlas tú mismo, colocando tantas funciones como desees y necesites
dentro de su programa para hacerlo más simple, claro y elegante.
El nombre de la función debe ser significativo (el nombre de la función print es evidente),
imprime en la terminal.
Si vas a utilizar alguna función ya existente, no podrás modificar su nombre, pero cuando
comiences a escribir tus propias funciones, debes considerar cuidadosamente la elección
de nombres.
La función print()
Como se dijo anteriormente, una función puede tener:
• Un efecto.
• Un resultado.
Las funciones de Python, por otro lado, son más versátiles. Dependiendo de las
necesidades individuales, pueden aceptar cualquier número de argumentos, tantos como
sea necesario para realizar sus tareas. Nota: algunas funciones de Python no necesitan
ningún argumento.
print("¡Hola, Mundo!")
Si deseas entregar uno o más argumentos a una función, colócalos dentro de los
paréntesis. Si vas a utilizar una función que no tiene ningún argumento, aún tiene que
tener los paréntesis.
Nota: para distinguir las palabras comunes de los nombres de funciones, coloca un par
de paréntesis vacíos después de sus nombres, incluso si la función correspondiente
requiere uno o más argumentos. Esta es una medida estándar.
La función print()
El único argumento entregado a la función print() en este ejemplo es una cadena:
print("¡Hola, Mundo!")
Como puedes ver, la cadena está delimitada por comillas - de hecho, las comillas forman
la cadena, recortan una parte del código y le asignan un significado diferente.
Podemos imaginar que las comillas significan algo así: el texto entre nosotros no es un
código. No está diseñado para ser ejecutado, y se debe tomar tal como está.
Casi cualquier cosa que ponga dentro de las comillas se tomará de manera literal, no
como código, sino como datos. Intenta jugar con esta cadena en particular - puedes
modificarla. Ingresa contenido nuevo o borra parte del contenido existente.
Existe más de una forma de como especificar una cadena dentro del código de Python,
pero por ahora, esta será suficiente.
Hasta ahora, has aprendido acerca de dos partes importantes del código - la función y la
cadena. Hemos hablado de ellos en términos de sintaxis, pero ahora es el momento de
discutirlos en términos de semántica.
La función print()
El nombre de la función (print en este caso) junto con los paréntesis y los argumentos,
forman la invocación de la función.
Discutiremos esto en mayor profundidad más adelante, pero por lo pronto, arrojaremos
un poco más de luz al asunto.
print("¡Hola, Mundo!")
¿Qué sucede cuando Python encuentra una invocación como la que está a continuación?
nombre_función(argumento)
Veamos:
LABORATORIO
Tiempo Estimado
5-10 minutos
Nivel de Dificultad
Muy fácil
Objetivos
• Familiarizarse con la función print() y sus capacidades de formato.
• Experimentar con el código de Python.
Escenario
El comando print() , el cual es una de las directivas más sencillas de Python,
simplemente imprime una línea de texto en la pantalla.
En tu primer laboratorio:
La función print()
Tres preguntas importantes deben ser respondidas antes de continuar:
Cualquiera. Te mostraremos pronto que print() puede operar con prácticamente todos
los tipos de datos ofrecidos por Python. Cadenas, números, caracteres, valores lógicos,
objetos: cualquiera de estos se puede pasar con éxito a print() .
Una línea puede estar vacía (por ejemplo, puede no contener ninguna instrucción) pero
no debe contener dos, tres o más instrucciones. Esto está estrictamente prohibido.
Nota: Python hace una excepción a esta regla: permite que una instrucción se extienda
por más de una línea (lo que puede ser útil cuando el código contiene construcciones
complejas).
Vamos a expandir el código un poco, puedes verlo en el editor. Ejecútalo y observa lo que
aparece en la consola.
salida
• El programa invoca la función print() dos veces, como puedes ver hay dos líneas
separadas en la consola: esto significa que print() comienza su salida desde una
nueva línea cada vez que comienza su ejecución. Puedes cambiar este
comportamiento, pero también puedes usarlo a tu favor.
• Cada invocación de print() contiene una cadena diferente, como su argumento
y el contenido de la consola lo reflejan, esto significa que las instrucciones en el
código se ejecutan en el mismo orden en que se colocaron en el archivo fuente;
no se ejecuta la siguiente instrucción hasta que se complete la anterior (hay
algunas excepciones a esta regla, pero puedes ignorarlas por ahora).
¿Qué ocurre?
salida
Como puedes ver, la invocación de print() vacía no esta tan vacía como se esperaba -
genera una línea vacía (esta interpretación también es correcta) su salida es solo una
nueva línea.
Esta no es la única forma de producir una nueva línea en la consola de salida. Enseguida
mostraremos otra manera.
Hay dos cambios muy sutiles: hemos insertado un par extraño de caracteres dentro del
texto. Se ven así: \n .
La barra invertida ( \ ) tiene un significado muy especial cuando se usa dentro de las
cadenas, es llamado el carácter de escape.
En otras palabras, la barra invertida no significa nada, sino que es solo un tipo de
anuncio, de que el siguiente carácter después de la barra invertida también tiene un
significado diferente.
Vino la lluvia
y se la llevó.
salida
Como se puede observar, aparecen dos nuevas líneas en la canción infantil, en los lugares
donde se ha utilizado \n .
1. Si deseas colocar solo una barra invertida dentro de una cadena, no olvides su
naturaleza de escape: tienes que duplicarla, por ejemplo, la siguiente invocación causará
un error:
print("\")
print("\\")
2. No todos los pares de escape (la diagonal invertida junto con otro carácter) significan
algo.
Hay una invocación de la función print() pero contiene tres argumentos. Todos ellos
son cadenas.
Los argumentos están separados por comas. Se han rodeado de espacios para hacerlos
más visibles, pero no es realmente necesario y no se hará más.
En este caso, las comas que separan los argumentos desempeñan un papel
completamente diferente a la coma dentro de la cadena. El primero es una parte de la
sintaxis de Python, el segundo está destinado a mostrarse en la consola.
Si vuelves a observar el código, verás que no hay espacios dentro de las cadenas.
salida
Los espacios, removidos de las cadenas, han vuelto a aparecer. ¿Puedes explicar porque?
• Una función print() invocada con más de un argumento genera la salida en una
sola línea.
• La función print() coloca un espacio entre los argumentos emitidos por
iniciativa propia.
La función print() tiene dos argumentos de palabra clave que se pueden utilizar para
estos propósitos. El primero de ellos se llama end .
En la ventana del editor se puede ver un ejemplo muy simple de como utilizar un
argumento de palabra clave.
• Un argumento de palabra clave consta de tres elementos: una palabra clave que
identifica el argumento ( end - termina aquí); un signo de igual ( = ); y
un valor asignado a ese argumento.
• Cualquier argumento de palabra clave debe ponerse después del último
argumento posicional (esto es muy importante).
Como puedes ver, el argumento de palabra clave end determina los caracteres que la
función print() envía a la salida una vez que llega al final de sus argumentos posicionales.
salida
El argumento de palabra clave que puede hacer esto se denomina sep (separador).
Mi-nombre-es-Monty-Python.
salida
La función print() ahora utiliza un guion, en lugar de un espacio, para separar los
argumentos generados.
Nota: el valor del argumento sep también puede ser una cadena vacía. Pruébalo tu
mismo.
Ahora que comprendes la función print() , estás listo para aprender cómo almacenar y
procesar datos en Python.
LABORATORIO
Tiempo Estimado
5-10 minutos
Nivel de Dificultad
Muy fácil
Objetivos
• Familiarizarse con la función de print() y sus capacidades de formato.
• Experimentar con el código de Python.
Escenario
Modifica la primera línea de código en el editor, utilizando las palabras clave sep y end ,
para que coincida con el resultado esperado. Recuerda, utilizar dos funciones print() .
Salida Esperada
Fundamentos***Programación***en...Python
salida
print("Fundamentos","Programación","en")
print("Python")
LABORATORIO
Tiempo Estimado
5-15 minutos
Nivel de Dificultad
Fácil
Objetivos
• Experimentar con el código Python existente.
• Descubrir y solucionar errores básicos de sintaxis.
• Familiarizarse con la función print() y sus capacidades de formato.
Escenario
Recomendamos que juegues con el código que hemos escrito para ti y que realices
algunas correcciones (quizás incluso destructivas). Siéntete libre de modificar cualquier
parte del código, pero hay una condición: aprende de tus errores y saca tus propias
conclusiones.
Intenta:
print(" *")
print(" * *")
print(" * *")
print(" * *")
print("*** ***")
print(" * *")
print(" * *")
print(" *****")
Puntos Clave
1. La función print() es una función integrada imprime/envía un mensaje específico a la
pantalla/ventana de consola.
2. Las funciones integradas, al contrario de las funciones definidas por el usuario, están
siempre disponibles y no tienen que ser importadas. Python 3.7.1 viene con 69 funciones
incorporadas. Puedes encontrar su lista completa en orden alfabético en Python
Standard Library.
7. Los argumentos posicionales son aquellos cuyo significado viene dictado por su
posición, por ejemplo, el segundo argumento se emite después del primero, el tercero se
emite después del segundo, etc.
8. Los argumentos de palabra clave son aquellos cuyo significado no está dictado por su
ubicación, sino por una palabra especial (palabra clave) que se utiliza para identificarlos.
9. Los parámetros end y sep se pueden usar para dar formato la salida de la
función print() . El parámetro sep especifica el separador entre los argumentos
emitidos (por ejemplo, print("H", "E", "L", "L", "O", sep="-") , mientras que el
parámetro end especifica que imprimir al final de la declaración de impresión.
Un literal se refiere a datos cuyos valores están determinados por el literal mismo.
Debido a que es un concepto un poco difícil de entender, un buen ejemplo puede ser
muy útil.
123
¿Puedes adivinar qué valor representa? Claro que puedes - es ciento veintitrés.
c
¿Representa algún valor? Tal vez. Puede ser el símbolo de la velocidad de la luz, por
ejemplo. También puede representar la constante de integración. Incluso la longitud de
una hipotenusa en el Teorema de Pitágoras. Existen muchas posibilidades.
Se utilizan literales para codificar datos y ponerlos dentro del código. Ahora mostraremos
algunas convenciones que se deben seguir al utilizar Python.
La primera línea luce familiar. La segunda parece ser errónea debido a la falta visible de
comillas.
Intenta ejecutarlo.
Vamos a tomar algo de tiempo para discutir literales numéricas y su vida interna.
print("2")
print(2)
2.2.1.3 Literales de Python
Enteros
Quizá ya sepas un poco acerca de como las computadoras hacen cálculos con números.
Tal vez has escuchado del sistema binario, y como es que ese es el sistema que las
computadoras utilizan para almacenar números y como es que pueden realizar cualquier
tipo de operaciones con ellos.
Esta definición no es tan precisa, pero es suficiente por ahora. La distinción es muy
importante, y la frontera entre estos dos tipos de números es muy estricta. Ambos tipos
difieren significativamente en como son almacenados en una computadora y en el rango
de valores que aceptan.
Si se codifica un literal y se coloca dentro del código de Python, la forma del literal
determina la representación (tipo) que Python utilizará para almacenarlo en la memoria.
Por ahora, dejemos los números flotantes a un lado (regresaremos a ellos pronto) y
analicemos como es que Python reconoce un número entero.
El proceso es casi como usar lápiz y papel, es simplemente una cadena de dígitos que
conforman el número, pero hay una condición, no se deben insertar caracteres que no
sean dígitos dentro del número.
Tomemos por ejemplo, el número once millones ciento once mil ciento once. Si tomaras
ahorita un lápiz en tu mano, escribirías el siguiente número: 11,111,111 , o
así: 11.111.111 , incluso de esta manera: 11 111 111 .
Es claro que la separación hace que sea más fácil de leer, especialmente cuando el
número tiene demasiados dígitos. Sin embargo, Python no acepta estas cosas.
Está prohibido. ¿Qué es lo que Python permite? El uso de guion bajo en los literales
numéricos.*
print(0o123)
0x123 es un número hexadecimal con un valor (decimal) igual a 291 . La función print()
puede manejar estos valores también. Intenta esto:
print(0x123)
Flotantes
Ahora es tiempo de hablar acerca de otro tipo, el cual esta designado para representar y
almacenar los números que (como lo diría un matemático) tienen una parte decimal no
vacía.
Son números que tienen (o pueden tener) una parte fraccionaria después del punto
decimal, y aunque esta definición es muy pobre, es suficiente para lo que se desea
discutir.
Cuando se usan términos como dos y medio o menos cero punto cuatro, pensamos en
números que la computadora considera como números punto-flotante:
2.5
-0.4
Nota: dos punto cinco se ve normal cuando se escribe en un programa, sin embargo si tu
idioma nativo prefiere el uso de una coma en lugar de un punto, se debe asegurar que el
número no contenga comas.
Si se quiere utilizar solo el valor de dos punto cinco, se debe escribir como se mostró
anteriormente. Nota que hay un punto entre el 2 y el 5, no una coma.
Como puedes imaginar, el valor de cero punto cuatro puede ser escrito en Python como:
0.4
Pero no hay que olvidar esta sencilla regla, se puede omitir el cero cuando es el único
dígito antes del punto decimal.
.4
4.
Se puede pensar que son idénticos, pero Python los ve de una manera completamente
distinta.
Por otro lado, no solo el punto hace que un número sea flotante. Se puede utilizar la
letra e .
Cuando se desea utilizar números que son muy pequeños o muy grandes, se puede
implementar la notación científica.
Para evitar escribir tantos ceros, los libros de texto emplean la forma abreviada, la cual
probablemente hayas visto: 3 x 108 .
En Python, el mismo efecto puede ser logrado de una manera similar, observa lo
siguiente:
3E8
Nota:
Codificando Flotantes
Veamos ahora como almacenar números que son muy pequeños (en el sentido de que
están muy cerca del cero).
Una constante de física denominada "La Constante de Planck" (denotada como h), de
acuerdo con los libros de texto, tiene un valor de: 6.62607 x 10-34.
Si se quisiera utilizar en un programa, se debería escribir de la siguiente manera:
6.62607E-34
Nota: el hecho de que se haya escogido una de las posibles formas de codificación de un
valor flotante no significa que Python lo presentará de la misma manera.
Este es el resultado:
1e-22
salida
Python siempre elige la presentación más corta del número, y esto se debe de tomar en
consideración al crear literales.
Cadenas
Las cadenas se emplean cuando se requiere procesar texto (como nombres de cualquier
tipo, direcciones, novelas, etc.), no números.
Ya conoces un poco acerca de ellos, por ejemplo, que las cadenas requieren comillas así
como los flotantes necesitan punto decimal.
Sin embargo, hay una cuestión. ¿Cómo se puede codificar una comilla dentro de una
cadena que ya está delimitada por comillas?
¿Cómo se puede hacer esto sin generar un error? Existen dos posibles soluciones.
La primera se basa en el concepto ya conocido del carácter de escape, el cual recordarás
se utiliza empleando la diagonal invertida. La diagonal invertida puede también escapar
de la comilla. Una comilla precedida por una diagonal invertida cambia su significado, no
es un limitador, simplemente es una comilla. Lo siguiente funcionará como se desea:
Nota: ¿Existen dos comillas con escape en la cadena, puedes observar ambas?
La segunda solución puede ser un poco sorprendente. Python puede utilizar una
apóstrofe en lugar de una comilla. Cualquiera de estos dos caracteres puede delimitar
una cadena, pero para ello se debe ser consistente.
Si se delimita una cadena con una comilla, se debe cerrar con una comilla.
Codificando Cadenas
Ahora, la siguiente pregunta es: ¿Cómo se puede insertar un apóstrofe en una cadena la
cual está limitada por dos apóstrofes?
¿Sabes cómo hacerlo? Haz clic en Revisar para saber si estas en lo cierto:
Revisar
Como se puede observar, la diagonal invertida es una herramienta muy poderosa, puede
escapar no solo comillas, sino también apóstrofes.
Ya se ha mostrado, pero se desea hacer énfasis en este fenómeno una vez mas - una
cadena puede estar vacía - puede no contener carácter alguno.
''
""
Valores Booleanos
Para concluir con los literales de Python, existen dos más.
No son tan obvios como los anteriores y se emplean para representar un valor muy
abstracto - la veracidad.
Cada vez que se le pregunta a Python si un número es más grande que otro, el resultado
es la creación de un tipo de dato muy específico - un valor booleano.
El nombre proviene de George Boole (1815-1864), el autor de Las Leyes del Pensamiento,
las cuales definen el Álgebra Booleana - una parte del álgebra que hace uso de dos
valores: Verdadero y Falso , denotados como 1 y 0 .
Nunca habrá una respuesta como: No lo sé o probablemente si, pero no estoy seguro.
True
False
No se pueden cambiar, se deben tomar estos símbolos como son, incluso respetando
las mayúsculas y minúsculas.
LABORATORIO
Tiempo Estimado
5-10 minutos
Nivel de Dificultad
Fácil
Objetivos
• Familiarizarse con la función print() y sus capacidades de formato.
• Practicar el codificar cadenas.
• Experimentar con el código de Python.
Escenario
Escribe una sola línea de código, utilizando la función print() , así como los caracteres
de nueva línea y escape, para obtener la salida esperada de tres líneas.
Salida Esperada
"Estoy"
""aprendiendo""
"""Python"""
salida
Puntos Clave
1. Literales son notaciones para representar valores fijos en el código. Python tiene varios
tipos de literales, es decir, un literal puede ser un número por ejemplo, 123 ), o una
cadena (por ejemplo, "Yo soy un literal.").
2. El Sistema Binario es un sistema numérico que emplea 2 como su base. Por lo tanto,
un número binario está compuesto por 0s y 1s únicamente, por ejemplo, 1010 es 10 en
decimal.
3. Los Enteros (o simplemente int) son uno de los tipos numéricos que soporta Python.
Son números que no tienen una parte fraccionaria, por ejemplo, 256 , o -1 (enteros
negativos).
4. Los números Punto-Flotante (o simplemente flotantes) son otro tipo numérico que
soporta Python. Son números que contienen (o son capaces de contener) una parte
fraccionaria, por ejemplo, 1.27 .
5. Para codificar un apóstrofe o una comilla dentro de una cadena se puede utilizar el
carácter de escape, por ejemplo, 'I\'m happy.' , o abrir y cerrar la cadena utilizando un
conjunto de símbolos distintos al símbolo que se desea codificar, por ejemplo, "I'm
happy." para codificar un apóstrofe, y 'Él dijo "Python", no "typhoon"' para
codificar comillas.
6. Los Valores Booleanos son dos objetos constantes Verdadero y Falso empleados
para representar valores de verdad (en contextos numéricos 1 es True , mientras
que 0 es False ).
EXTRA
Existe un literal especial más utilizado en Python: el literal None . Este literal es llamado un
objeto de NonType (ningún tipo), y puede ser utilizado para representar la ausencia de un
valor. Pronto se hablará más acerca de ello.
Ejercicio 1
Revisar
Ejercicio 2
Revisar
El primero es una cadena, el segundo es numérico (flotante), el tercero es numérico
(entero) y el cuarto es booleano.
Ejercicio 3
1011
Revisar
print(2+2)
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.
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:
+ , - , * , / , // , % , **
Las matemáticas clásicas prefieren una notación con superíndices, como el siguiente: 23.
Los editores de texto puros no aceptan esa notación, por lo tanto Python utiliza ** en
lugar de la notación matemática, por ejemplo, 2 ** 3 .
Nota: En los ejemplos, los dobles asteriscos están rodeados de espacios, no es obligatorio
hacerlo pero hace que el código sea mas legible.
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:
print(2 ** 3)
print(2 ** 3.)
print(2. ** 3)
print(2. ** 3.)
2.3.1.3 Operadores: herramientas para la manipulación de datos
print(2 * 3)
print(2 * 3.)
print(2. * 3)
print(2. * 3.)
print(6 / 3)
print(6 / 3.)
print(6. / 3)
print(6. / 3.)
¿Esto ocasiona un problema? Sí, en ocasiones se podrá necesitar que el resultado de una
división sea entero, no flotante.
print(6 // 3)
print(6 // 3.)
print(6. // 3)
print(6. // 3.)
Como se puede observar, una división de entero entre entero da un resultado entero.
Todos los demás casos producen flotantes.
print(6 // 4)
print(6. // 4)
print(-6 // 4)
print(6. // -4)
Nota: Algunos de los valores son negativos. Esto obviamente afectara el resultado. ¿Pero
cómo?
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 .
NOTA
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.
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.
print(14 % 4)
print(12 % 4.5)
¿Cuál es el resultado?
Revisar
3.0 - no 3 pero 3.0 (la regla aun funciona: 12 // 4.5 da 2.0; 2.0 * 4.5 da 9.0; 12
- 9.0 da 3.0)
No intentes:
Operadores: suma
El símbolo del operador de suma es el + (signo de más), el cual esta completamente
alineado a los estándares matemáticos.
print(-4 + 4)
print(-4. + 8)
Esta es una gran oportunidad para mencionar una distinción muy importante entre
operadores unarios y binarios.
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 ultima
línea de código del siguiente fragmento:
print(-4 - 4)
print(4. - 8)
print(-1.1)
Por cierto: también hay un operador + unario. Se puede utilizar de la siguiente manera:
print(+2)
Observa el fragmento de código que está arriba - ¿Puedes adivinar el resultado o salida?
2 + 3 * 5
El fenómeno que causa que algunos operadores actúen antes que otros es 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.
Operadores y sus enlaces
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.
print(9 % 6 % 2)
El resultado debe ser 1 . El operador tiene un enlazado del lado izquierdo. Pero hay una
excepción interesante.
print(2 ** 2 ** 3)
• 2 ** 2 → 4 ; 4 ** 3 → 64
• 2 ** 3 → 8 ; 2 ** 8 → 256
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.
Prioridad Operador
1 +, - unario
2 **
3 *, /, //, %
4 +, - binario
Nota: se han enumerado los operadores en orden de la más alta (1) a la más baja (4)
prioridad.
print(2 * 3 % 5)
Revisar
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 sub-expresiones 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.
Revisar
10.0
Puntos Clave
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 .
Ejercicio 1
Revisar
16 8.0 8
Ejercicio 2
Revisar
-0.5 0.5 0 -1
Ejercicio 3
Revisar
-2 2 512
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 como es que se pueden almacenar los resultados de estas
operaciones, para poder emplearlos en otras operaciones, y así sucesivamente.
Python ayudará con ello. Python ofrece "cajas" (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).
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:
Además, Python permite utilizar no solo las letras latinas, sino caracteres específicos de
otros idiomas que utilizan otros alfabetos.
10t (no comienza con una letra), Tasa Cambio (contiene un espacio)
NOTA
• Los nombres de las variables deben estar en minúsculas, con palabras separadas
por guiones bajos para mejorar la legibilidad (por ejemplo: var , mi_variable ).
• Los nombres de las funciones siguen la misma convención que los nombres de las
variables (por ejemplo: fun , mi_función ).
• También es posible usar letras mixtas (por ejemplo: miVariable ), 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 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.
import
No se puede tener una variable con ese nombre, esta prohibido, pero se puede hacer lo
siguiente:
Import
Estas palabras podrían parecer un misterio ahorita, pero pronto se aprenderá acerca de
su significado.
Creando variables
¿Qué se puede poner dentro de una variable?
Cualquier cosa.
Se puede utilizar una variable para almacenar cualquier tipo de los valores que ya se han
mencionado, y muchos mas de los cuales aun 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.
• 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.
Nota: print() tiene una función más – puede manejar variables también. ¿Puedes
predecir cuál será la salida (resultado) del código?
Revisar
Utilizando variables
Se tiene permitido utilizar cuantas declaraciones de variables sean necesarias para lograr
el objetivo del programa, por ejemplo:
var = 1
account_balance = 1000.0
client_name = 'John Doe'
print(var, account_balance, client_name)
print(var)
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).
var = 1
print(Var)
RECUERDA
var = "3.8.5"
print("Versión de Python: " + var)
Revisar
1
2
salida
La primer línea del código crea una nueva variable llamada var y le asigna el valor de 1 .
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.
var = 100
var = 200 + 300
print(var)
Revisar
500 - ¿Porque? Bueno, primero, la variable var es creada y se le asigna el valor de 100.
Después, a la misma variable se le asigna un nuevo valor: el resultado de sumarle 200 a
300, lo cual es 500.
2.4.1.6 Variables: cajas con forma de datos
El siguiente código evalúa la longitud de la hipotenusa (es decir, el lado más largo de un
triangulo rectángulo, el opuesto al ángulo recto) utilizando el Teorema de Pitágoras:
a = 3.0
b = 4.0
c = (a ** 2 + b ** 2) ** 0.5
print("c =", c)
Nota: se necesita hacer uso del operador ** para evaluar la raíz cuadrada:
√ (x) = x(½)
y
c = √ a2 + b2
¿Puedes predecir la salida del código?
Revisar
c = 5.0
a = 3.0
b = 4.0
c = (a ** 2 + b ** 2) ** 0.5
print("c =", c)
Tiempo Estimado
10 minutos
Nivel de Dificultad
Fácil
Objetivos
• Familiarizarse con el concepto de almacenar y trabajar con diferentes tipos de
datos en Python.
• Experimentar con el código en Python.
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:
Operadores Abreviados
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 = .
x = x * 2
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:
sheep = sheep + 1
Python ofrece una manera más corta de escribir operaciones como estas, lo cual se
puede codificar de la siguiente manera:
x *= 2
sheep += 1
i = i + 2 * j ⇒ i += 2 * j
var = var / 2 ⇒ var /= 2
rem = rem % 10 ⇒ rem %= 10
j = j - (i + var + rem) ⇒ j -= (i + var + rem)
x = x ** 2 ⇒ x **= 2
Tiempo Estimado
10 minutos
Nivel de Dificultad
Fácil
Objetivos
• Familiarizarse con el concepto de variables y trabajar con ellas.
• Realizar operaciones básicas y conversiones.
• Experimentar con el código de Python.
Escenario
Millas y kilómetros son unidades de longitud o distancia.
• Millas a kilómetros.
• Kilómetros a millas.
Pon mucha atención a lo que esta ocurriendo dentro de la función print() . Analiza
como 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 ).
TIP
Hay una cosa interesante más que esta 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.
Resultado Esperado
7.38 millas son 11.88 kilómetros
12.25 kilómetros son 7.61 millas
salida
kilometers = 12.25
miles = 7.38
miles_to_kilometers = ###
kilometers_to_miles = ###
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
• Familiarizarse con los conceptos de números, operadores y operaciones
aritméticas en Python.
• Realizar cálculos básicos.
Escenario
Observa el código en el editor: lee un valor flotante , 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:
3x3 - 2x2 + 3x - 1
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.
Datos de Prueba
Entrada de Muestra
x = 0
x = 1
x = -1
Salida Esperada
y = -1.0
y = 3.0
y = -9.0
salida
Puntos Clave
var = 2
print(var)
var = 3
print(var)
var += 1
print(var)
Ejercicio 1
var = 2
var = 3
print(var)
Revisar
Ejercicio 2
my_var
averylongvariablename
m101
Del
Ejercicio 3
a = '1'
b = "1"
print(a + b)
Revisar
11
Ejercicio 4
a = 6
b = 3
a /= 2 * b
print(a)
Revisar
1.0
2*b=6
a = 6 → 6 / 6 = 1.0
2.5.1.1 Comentarios
¿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.
Si se desea colocar un comentario que abarca varias líneas, se debe colocar este símbolo
en cada línea.
Por ejemplo, si una variable determinada está diseñada para almacenar el área de un
cuadrado, el nombre area_cuadrado será muchísimo mejor que tia_juana .
El nombre dado a la variable se puede definir como auto-comentable.
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 descomenta la línea resaltada, esto afectara la salida o resultado
del código:
TIP
Tiempo Estimado
5 minutos
Nivel de Dificultad
Muy Fácil
Objetivos
• Familiarizarse con el concepto de comentarios en Python.
• Utilizar y no utilizar los comentarios.
• Reemplazar los comentarios con código.
• Experimentar con el código de Python.
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 mas legible), además, 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.
Una cosa mas: puede ocurrir que un comentario contenga una pieza de información
incorrecta o errónea, nunca se debe de hacer eso a propósito.
a = 2 # número de horas
seconds = 3600 # número de segundos en una hora
Puntos Clave
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.
# un saludo en pantalla
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 altura y longitud son una mejor elección que mivar1 y mivar2 .
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).
Ejercicio 1
# print("Cadena #1")
print("Cadena #2")
Revisar
Cadena #2
Ejercicio 2
# Esto es
un comentario
en varias líneas #
print("¡Hola!")
Revisar
La función input()
Ahora se introducirá una nueva función, la cual pareciese ser un reflejo de la
función print() .
¿Por qué? Bueno, print() envía datos a la consola.
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:
print("Dime algo...")
anything = input()
print("Mmm...", anything, "...¿en serio?")
Nota:
Intenta ejecutar el código y permite que la función te muestre lo que puede hacer.
2.6.1.2 Cómo hablar con una computadora
Nota:
• La función input() al ser invocada con un argumento, contiene una cadena con
un mensaje.
• El mensaje será mostrado en consola antes de que el usuario tenga oportunidad
de escribir algo.
• Después de esto input() hará su trabajo.
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.
La última línea lo explica todo, se intentó aplicar el operador ** a 'str' (una cadena)
acompañado por un 'float' (valor flotante).
Esto debe de ser obvio. ¿Puedes predecir el valor de "ser o no ser" elevado a
la 2 potencia?
¿Habremos llegado a un punto muerto? ¿Existirá alguna solución? Claro que la hay.
Esto es muy simple y muy 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.
Prueba con diferentes valores, pequeños, grandes, negativos y positivos. El cero también
es un buen valor a 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.
Este programa le preguntó al usuario los dos catetos, calcula la hipotenusa e imprime el
resultado.
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).
Ahora veremos que son capaces también de manejar o manipular cadenas, aunque, en
una manera muy específica.
Concatenación
El signo de + (más), al ser aplicado a dos cadenas, se convierte en un operador de
concatenación:
string + string
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.
Este es un programa sencillo que muestra como funciona el signo + como concatenador:
Nota: El utilizar + para concatenar cadenas te permite construir la salida de una manera
más precisa, en comparación de utilizar únicamente la función print() , aún cuando se
enriquezca con los argumentos end= y sep= .
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.
string * number
number * string
Por ejemplo:
RECUERDA
Este sencillo programa "dibuja" un rectángulo, haciendo uso del operador ( + ), pero en un
nuevo rol:
str(number)
Sinceramente, puede hacer mucho más que transformar números en cadenas, eso lo
veremos después.
Se ha modificado un poco para mostrar cómo es que la función str() trabaja. Gracias a
esto, podemos pasar el resultado entero a la función print() como una sola cadena, sin
utilizar las comas.
LABORATORIO
Tiempo Estimado
5-10 minutos
Nivel de Dificultad
Fácil
Objetivos
• Familiarizarse con la entrada y salida de datos en Python.
• Evaluar expresiones simples.
Escenario
La tarea es completar el código para evaluar y mostrar el resultado de cuatro operaciones
aritméticas básicas.
Quizá no podrás proteger el código de un usuario que intente dividir entre cero. Por
ahora, no hay que preocuparse por ello.
LABORATORIO
Tiempo Estimado
20 minutos
Nivel de Dificultad
Intermedio
Objetivos
• Familiarizarse con los conceptos de números, operadores y expresiones
aritméticas en Python.
• Comprender la precedencia y asociatividad de los operadores de Python, así como
el correcto uso de los paréntesis.
Escenario
La tarea es completar el código para poder evaluar la siguiente expresión:
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
Entrada de muestra: 10
Salida esperada:
y = 0.09901951266867294
Salida esperada:
y = 0.009999000199950014
Entrada de muestra: -5
Salida esperada:
y = -0.19258202567760344
print("y =", y)
LABORATORIO
Tiempo Estimado
15-20 minutos
Nivel de Dificultad
Fácil
Objetivos
• Mejorar la habilidad de implementar números, operadores y operaciones
aritméticas en Python.
• Utilizar la función print() y sus capacidades de formato.
• Aprender a expresar fenómenos del día a día en términos de un lenguaje de
programación.
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. Las horas van de 0 a 23 y los
minutos de 0 a 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
Entrada de muestra:23
58
642
Entrada de muestra:0
1
2939
Puntos Clave
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 inicial: un mensaje de tipo cadena para el
usuario. Permite escribir un mensaje antes de la entrada del usuario, por ejemplo:
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 y 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?
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:
Ejercicio 1
Revisar
55
Ejercicio 2
<class 'str'>
• Los métodos básicos de formato y salida de datos ofrecidos por Python, junto con
los tipos principales de datos y operadores numéricos, sus relaciones mutuas y
enlaces.
• El concepto de variables y la manera correcta de darles nombre.
• El operador de asignación, las reglas que rigen la construcción de expresiones.
• La entrada y conversión de datos.
Ahora estás listo para tomar el cuestionario del módulo e intentar el desafío final: La
Prueba del Módulo 2, que te ayudará a evaluar lo que has aprendido hasta ahora.
Fundamentos de Python 1:
Módulo 3
En este módulo, aprenderás sobre:
Preguntas y respuestas
Un programador escribe un programa y el programa hace preguntas.
• Si, es cierto.
• No, esto es falso.
Nunca obtendrás una respuesta como Déjame pensar..., no lo sé, o probablemente sí,
pero no lo sé con seguridad.
Es un operador binario con enlazado del lado izquierdo. Necesita dos argumentos
y verifica si son iguales.
Ejercicios
Ahora vamos a hacer algunas preguntas. Intenta adivinar las respuestas.
2 == 2 Revisar
True - por supuesto, 2 es igual a 2. Python responderá True (recuerda este par de
literales predefinidos, True y False - también son palabras clave reservadas de Python).
Pregunta #2: ¿Cuál es el resultado de la siguiente comparación?
2 == 2 Revisar
Esta pregunta no es tan fácil como la primera. Por suerte, Python es capaz de convertir el
valor entero en su equivalente real, y en consecuencia, la respuesta es True .
1 == 2 Revisar
Esto debería ser fácil. La respuesta será (o mejor dicho, siempre es) False .
var == 0
Toma en cuenta que no podemos encontrar la respuesta si no sabemos qué valor está
almacenado actualmente en la variable var .
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.
black_sheep == 2 * white_sheep
Debido a la baja prioridad del operador == , la pregunta será tratada como la siguiente:
black_sheep == (2 * white_sheep)
3.1.1.3 Tomando decisiones en Python
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 enlace 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).
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:
Prioridad Operador
1 +, - unario
2 **
3 *, /, //, %
4 +, - binario
LABORATORIO
Tiempo Estimado
5 minutos
Nivel de Dificultad
Muy Fácil
Objetivos
• Familiarizarse con la función input() .
• Familiarizarse con los operadores de comparación en Python.
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
Ejemplo de entrada: 55
Ejemplo de entrada: 99
Ejemplo de entrada: -5
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).
La primera forma de una sentencia condicional, que puede ver a continuación, está
escrita de manera muy informal pero figurada:
if true_or_not:
do_this_if_true
después, almorzaremos
Como puedes ver, almorzar no es una actividad condicional y no depende del clima.
if the_weather_is_good:
go_for_a_walk()
have_lunch()
3.1.1.6 Tomando decisiones en Python
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.
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.
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.
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:
if true_or_false_condition:
perform_if_condition_true
else:
perform_if_condition_false
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).
if the_weather_is_good:
go_for_a_walk()
else:
go_to_a_theater()
have_lunch()
Todo lo que hemos dicho sobre la sangría funciona de la misma manera dentro de la
rama else :
if the_weather_is_good:
go_for_a_walk()
have_fun()
else:
go_to_a_theater()
enjoy_the_movie()
have_lunch()
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.
if the_weather_is_good:
if nice_restaurant_is_found:
have_lunch()
else:
eat_a_sandwich()
else:
if tickets_are_available:
go_to_the_theater()
else:
go_shopping()
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 todo falla,
regresaremos a casa y jugaremos ajedrez.
¿Has notado cuantas veces hemos usado la palabra de lo contrario? Esta es la etapa en la
que la palabra clave reservada elif desempeña su función.
if the_weather_is_good:
go_for_a_walk()
elif tickets_are_available:
go_to_the_theater()
elif table_is_available:
go_for_lunch()
else:
play_chess_at_home()
Esto puede sonar un poco desconcertante, pero ojalá que algunos ejemplos simples
ayuden a comprenderlo mejor.
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?
#Se leen dos números
number1 = int(input("Ingresa el primer número: "))
number2 = int(input("Ingresa el segundo número: "))
# Imprime el resultado
print("El número más grande es:", larger_number)
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:
# Imprime el resultado
print("El número más grande es:", larger_number)
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.
# Imprime el resultado.
print("El número más grande es:", largest_number)
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.
¿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.
largest_number = -999999999
number = int(input())
if number == -1:
print(largest_number)
exit()
if number > largest_number:
largest_number = number
# Ir a la línea 02
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 a 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:
# Imprime el resultado.
print("El número más grande es:", largest_number)
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 codigo. Entonces, por ahora, no estamos tomando
atajos.
Tiempo Estimado
5-10 minutos
Nivel de Dificultad
Fácil
Objetivos
• Familiarizarse con la función input().
• Familiarizarse con los operadores de comparación en Python.
• Familiarizarse con el concepto de ejecución condicional.
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 , grita 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:
Datos de Prueba
Entrada de muestra: espatifilo
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
Familiarizar al estudiante con:
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.
Nota: Este país feliz nunca devuelve dinero a sus ciudadanos. Si el impuesto calculado es
menor que cero, solo significa que no hay impuesto (el impuesto es igual a cero). Ten esto
en cuenta durante tus cálculos.
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
Resultado esperado: El impuesto es: 1244.0 pesos
#
# Escribe tu código aquí.
#
tax = round(tax, 0)
print("El impuesto es:", tax, "pesos")
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
Familiarizar al estudiante con:
Escenario
Como seguramente sabrás, debido a algunas razones astronómicas, el año pueden
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:
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
Resultado esperado: Año Bisiesto
#
# Escribe tu código aquí.
#
Puntos Clave
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 :
x != y # True
Devuelve True si los valores de los operandos no
!= son iguales, y False de lo contrario.
x != z # False
2. Cuando deseas ejecutar algún código solo si se cumple una determinada condición,
puedes usar una sentencia condicional:
• Una única sentencia if , por ejemplo:
x = 10
if x == 10: # condición
print("x es igual a 10") # Ejecutado si la condición es
Verdadera.
x = 10
x = 10
else:
print("x es mayor o igual a 10") # Ejecutado si la
condición es Falsa.
x = 10
if x > 5: # True
print("x > 5")
if x > 8: # True
print("x > 8")
x = 10
if x == 10: # True
print("x == 10")
else:
print("else no será ejecutado")
x = 10
if x > 5: # True
if x == 6: # False
print("anidado: x == 6")
elif x == 10: # True
print("anidado: x == 10")
else:
print("anidado: else")
else:
print("else")
Ejercicio 1
print(x > y)
print(y > z)
Revisar
False
True
salida
Ejercicio 2
¿Cuál es la salida del siguiente fragmento de código?
x, y, z = 5, 10, 8
print(x > z)
print((y - 5) == x)
Revisar
False
True
salida
Ejercicio 3
¿Cuál es la salida del siguiente fragmento de código?
x, y, z = 5, 10, 8
x, y, z = z, y, x
print(x > z)
print((y - 5) == x)
Revisar
True
False
salida
Ejercicio 4
¿Cuál es la salida del siguiente fragmento de código?
x = 10
if x == 10:
print(x == 10)
if x > 5:
print(x > 5)
if x < 10:
print(x < 10)
else:
print("else")
Revisar
True
True
else
salida
Toma en cuenta que este registro también declara que, si no hay nada que hacer, nada
ocurrirá.
while conditional_expression:
instruction
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 .
Nota: todas las reglas relacionadas con sangría también se aplican aquí. Te mostraremos
esto pronto.
while conditional_expression:
instruction_one
instruction_two
instruction_three
:
:
instruction_n
Ahora, es importante recordar que:
Un bucle infinito
Un bucle infinito, también denominado bucle sin fin, es una secuencia de instrucciones
en un programa que se repite indefinidamente (bucle sin fin).
while True:
print("Estoy atrapado dentro de un bucle.")
NOTA
odd_numbers = 0
even_numbers = 0
# 0 termina la ejecución.
while number != 0:
# Verificar si el número es impar.
if number % 2 == 1:
# Incrementar el contador de números impares odd_numbers.
odd_numbers += 1
else:
# Incrementar el contador de números pares even_numbers.
even_numbers += 1
# Leer el siguiente número.
number = int(input("Introduce un número o escribe 0 para detener:
"))
# Imprimir resultados.
print("Cuenta de números impares:", odd_numbers)
print("Cuenta de números pares:", even_numbers)
Ciertas expresiones se pueden simplificar sin cambiar el comportamiento del programa.
Intenta recordar cómo Python interpreta la verdad de una condición y ten en cuenta que
estas dos formas son equivalentes:
if number % 2 == 1: y if number % 2:
counter = 5
while counter != 0:
print("Dentro del bucle.", counter)
counter -= 1
print("Fuera del bucle.", counter)
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 tambien 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 .
counter = 5
while counter:
print("Dentro del bucle.", counter)
counter -= 1
print("Fuera del bucle.", counter)
¿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. Manten tu
código listo para un nuevo programador.
secret_number = 777
print(
"""
+==================================+
| ¡Bienvenido a mi juego, muggle! |
| Introduce un número entero |
| y adivina qué número he |
| elegido para ti. |
| Entonces, |
| ¿Cuál es el número secreto? |
+==================================+
""")
Imagina que el cuerpo de un bucle debe ejecutarse exactamente cien veces. Si deseas
utilizar el bucle while para hacerlo, puede tener este aspecto:
i = 0
while i < 100:
# do_something()
i += 1
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.
for i in range(100):
# do_something()
pass
for i in range(10):
print("El valor de i es actualmente", i)
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:
Nota: la función range() solo acepta enteros como argumentos y genera secuencias de
enteros.
¿Puedes adivinar la salida del programa? Ejecútalo para comprobar si ahora también
estabas en lo cierto.
El valor de i es actualmente 2
El valor de i es actualmente 5
salida
¿Sabes por qué? El primer argumento pasado a la función range() nos dice cual es el
número de inicio de la secuencia (por lo tanto, 2 en la salida). 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.
Echemos un vistazo a un programa corto cuya tarea es escribir algunas de las primeras
potencias de dos:
power = 1
for expo in range(16):
print("2 a la potencia de", expo, "es", power)
power *= 2
La variable expo se utiliza como una variable de control para el bucle e indica el valor
actual del exponente. La propia exponenciación se sustituye multiplicando por dos. Dado
que 2 0 es igual a 1, después 2 × 1 es igual a 21, 2 × 21 es igual a 22, y así sucesivamente.
¿Cuál es el máximo exponente para el cual nuestro programa aún imprime el resultado?
LABORATORIO
Tiempo Estimado
5 minutos
Nivel de dificultad
Muy fácil
Objetivos
Familiarizar al estudiante con:
• Utilizar el bucle for.
• Reflejar situaciones de la vida real en código de computadora.
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!
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
1 Mississippi
2 Mississippi
3 Mississippi
4 Mississippi
5 Mississippi
import time
Ahora te mostraremos dos ejemplos simples para ilustrar como funcionan las dos
instrucciones. Mira el código en el editor. Ejecuta el programa y analiza la salida. Modifica
el código y experimenta.
# break - ejemplo
# continue - ejemplo
largest_number = -99999999
counter = 0
while True:
number = int(input("Ingresa un número o escribe -1 para finalizar el programa: "))
if number == -1:
break
counter += 1
if number > largest_number:
largest_number = number
if counter != 0:
print("El número más grande es", largest_number)
else:
print("No has ingresado ningún número.")
if counter:
print("El número más grande es", largest_number)
else:
print("No has ingresado ningún número.")
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.
De nuevo: ejecútalo, pruébalo y experimenta con él.
LABORATORIO
Tiempo Estimado
10 minutos
Nivel de Dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
Escenario
La instrucción break se implementa para salir/terminar un bucle.
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 salida
secreta, en cuyo caso el mensaje "¡Has dejado el bucle con éxito". Debe
imprimirse en la pantalla y el bucle debe terminar.
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objectives
Familiarizar al estudiante con:
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.
• 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
Salida esperada:
B
S
T
M
S
Salida esperada:
(vacio)
Tiempo Estimado
5-10 minutos
Nivel de Dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
Escenario
Tu tarea aquí es aún más especial que antes: ¡Debes rediseñar el devorador de vocales
(feo) del laboratorio anterior (3.1.2.10) y crear un mejor devorador de vocales (bonito)
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:
Salida esperada:
GRGRY
Salida esperada:
BSTMS
Salida esperada:
(vacio)
word_without_vowels = ""
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.
i = 5
while i < 5:
print(i)
i += 1
else:
print("else:", i)
i = 1
while i < 5:
print(i)
i += 1
else:
print("else:", i)
i = 111
for i in range(2, 1):
print(i)
else:
print("else:", i)
¿Puedes adivinar la salida?
Cuando el cuerpo del bucle no se ejecuta, la variable de control conserva el valor que
tenía antes del bucle.
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.
for i in range(5):
print(i)
else:
print("else:", i)
LABORATORIO
Tiempo Estimado
20-30 minutos
Nivel de Dificultad
Medio
Objetivos
Familiarizar al estudiante con:
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.
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 es: 5
Entrada de muestra: 2
Salida esperada: La altura de la pirámide es: 1
Tiempo Estimado
20 minutos
Nivel de Dificultad
Media
Objetivos
Familiarizar al estudiante con:
• Utilizar el bucle while .
• Convertir bucles definidos verbalmente en código real de Python.
Escenario
En 1937, un matemático alemán llamado Lothar Collatz formuló una hipótesis intrigante
(aún no se ha comprobado) que se puede describir de la siguiente manera:
1. Toma cualquier número entero que no sea negativo y que no sea cero y asígnale
el nombre c0 .
2. Si es par, evalúa un nuevo c0 como c0 ÷ 2 .
3. De lo contrario, si es impar, evalúe un nuevo c0 como 3 × c0 + 1 .
4. Si c0 ≠ 1 , salta al punto 2.
La hipótesis dice que, independientemente del valor inicial de c0 , el valor siempre tiende
a 1.
Por supuesto, es una tarea extremadamente compleja usar una computadora para
probar la hipótesis de cualquier número natural (incluso puede requerir inteligencia
artificial), pero puede usar Python para verificar algunos números individuales. Tal vez
incluso encuentres el que refutaría la hipótesis.
Escribe un programa que lea un número natural y ejecute los pasos anteriores siempre
que c0 sea diferente de 1. También queremos que cuente los pasos necesarios para
lograr el objetivo. Tu código también debe mostrar todos los valores intermedios de c0 .
Sugerencia: la parte más importante del problema es como transformar la idea de Collatz
en un bucle while - esta es la clave del éxito.
Test Data
Entrada de muestra: 15
Salida esperada:
46
23
70
35
106
53
160
80
40
20
10
5
16
8
4
2
1
pasos = 17
Entrada de muestra: 16
Salida esperada:
8
4
2
1
pasos = 4
Puntos Clave
# Ejemplo 1
while True:
print("Atascado en un bucle infinito.")
# Ejemplo 2
counter = 5
while counter > 2:
print(counter)
counter -= 1
• El bucle for ejecuta un conjunto de sentencias muchas veces; se usa para iterar
sobre una secuencia (por ejemplo, una lista, un diccionario, una tupla o un
conjunto; pronto aprenderás sobre ellos) u otros objetos que son iterables (por
ejemplo, cadenas). Puedes usar el bucle for para iterar sobre una secuencia de
números usando la función incorporada range . Mira los ejemplos a continuación:
# Ejemplo 1
word = "Python"
for letter in word:
print(letter, end="*")
# Ejemplo 2
for i in range(1, 10):
if i % 2 == 0:
print(i)
2. Puedes usar las sentencias break y continue para cambiar el flujo de un bucle:
text = "pyxpyxpyx"
for letter in text:
if letter == "x":
continue
print(letter, end="")
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:
n = 0
while n != 3:
print(n)
n += 1
else:
print(n, "else")
print()
Código de ejemplo:
for i in range(3):
print(i, end=" ") # Salidas: 0 1 2
Revisar
Solución de muestra:
for i in range(0, 11):
if i % 2 != 0:
print(i)
Ejercicio 2
Crea un bucle while que cuente de 0 a 10, e imprima números impares en la pantalla.
Usa el esqueleto de abajo:
x = 1
while x < 11:
# Línea de código.
# Línea de código.
# Línea de código.
Revisar
Solución de muestra:
x = 1
while x < 11:
if x % 2 != 0:
print(x)
x += 1
Ejercicio 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:
for ch in "[email protected]":
if ch == "@":
# Línea de código.
# Línea de código.
Revisar
Solución de muestra:
for ch in "[email protected]":
if ch == "@":
break
print(ch, end="")
Ejercicio 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:
for digit in "0165031806510":
if digit == "0":
# Línea de código.
# Línea de código.
# Línea de código.
Revisar
Solución de muestra:
for digit in "0165031806510":
if digit == "0":
print("x", end="")
continue
print(digit, end="")
Ejercicio 5
¿Cuál es la salida del siguiente código?
n = 3
while n > 0:
print(n + 1)
n -= 1
else:
print(n)
Revisar
4
3
2
0
Ejercicio 5
¿Cuál es la salida del siguiente código?
n = range(4)
for num in n:
print(num - 1)
else:
print(num)
Revisar
-1
0
1
2
3
Ejercicio 7
¿Cuál es la salida del siguiente código?
for i in range(0, 6, 3):
print(i)
Revisar
0
3
Lógica de computadora
¿Te has dado cuenta de que las condiciones que hemos usado hasta ahora han sido muy
simples, por no decir, bastante primitivas? Las condiciones que utilizamos en la vida real
son mucho más complejas. Veamos este enunciado:
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:
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.
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:
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:
Argumento A Argumento B A or B
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:
False True
True False
Expresiones lógicas
Creemos una variable llamada var y asignémosle 1 . Las siguientes condiciones
son equivalentes a pares:
# Ejemplo 1:
print(var > 0)
print(not (var <= 0))
# Ejemplo 2:
print(var != 0)
print(not (var == 0))
Observa como 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.
El resultado de sus operaciones es uno de estos valores: False o True . Esto significa que
este fragmento de código asignará el valor True a la variable j si i no es cero; de lo
contrario, será False .
i = 1
j = not not i
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0
Operaciones bit a bit ( ~)
Argumento ~ Argumento
0 1
1 0
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).
i = 15
j = 22
Si asumimos que los enteros se almacenan con 32 bits, la imagen a nivel de bits de las
dos variables será la siguiente:
i: 00000000000000000000000000001111
j: 00000000000000000000000000010110
Se ejecuta la asignación:
log = i and j
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.
log: True
bit = i & j
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:
i 00000000000000000000000000001111
j 00000000000000000000000000010110
logneg = not i
bitneg = ~i
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.
i 00000000000000000000000000001111
bitneg = ~i 11111111111111111111111111110000
Cada uno de estos operadores de dos argumentos se puede utilizar en forma abreviada.
Estos son los ejemplos de sus notaciones equivalentes:
x = x & y x &= y
x = x | y x |= y
x = x ^ y x ^= y
flag_register = 0x1234
flag_register = 0000000000000000000000000000x000
x & 1 = x
x & 0 = 0
00000000000000000000000000001000
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 23=8 . Se podría crear una máscara adecuada
mediante la siguiente sentencia:
the_mask = 8
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:
11111111111111111111111111110111
Tenga 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):
flag_register = flag_register & ~the_mask
flag_register &= ~the_mask
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:
x | 1 = 1
x | 0 = x
Ya estás listo para configurar su bit con una de las siguientes instrucciones:
x ^ 1 = ~x
x ^ 0 = x
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 (observe 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.
17 68 8
salida
Nota:
Y aquí está la tabla de prioridades actualizada , que contiene todos los operadores
presentados hasta ahora:
Prioridad Operador
1 ~, +, - unario
2 **
3 *, /, //, %
4 +, - binario
5 <<, >>
7 ==, !=
8 &
9 |
=, +=, -
10
=, *=, /=, %=, &=, ^=, |=, >>=, <<=
var = 17
var_right = var >> 1
var_left = var << 2
print(var, var_left, var_right)
Puntos Clave
1. Python es compatible con los siguientes operadores lógicos:
2. 2. Puedes utilizar operadores bit a bit para manipular bits de datos individuales. Los
siguientes datos de muestra:
Se utilizarán para ilustrar el significado de operadores bit a bit en Python. Analiza los
ejemplos a continuación::
• & hace un bit a bit and (y), por ejemplo, x & y = 0 , el cual es 0000 0000 en
binario.
• | hace un bit a bit or (o), por ejemplo, x | y = 31 , el cual es 0001 1111 en
binario.
• ˜ hace un bit a bit not (no), por ejemplo, ˜ x = 240 , el cual es 1111 0000 en
binario.
• ^ hace un bit a bit xor, por ejemplo, x ^ y = 31 , el cual es 0001 1111 en binario.
• >> hace un desplazamiento bit a bit a la derecha, por ejemplo, y >> 1 = 8 , el
cual es 0000 1000 en binario.
• << hace un desplazamiento bit a bit a la izquierda, por ejemplo, y << 3 = , el
cual es 1000 0000 en binario.
Ejercicio 1
Revisar
False
Ejercicio 2
x = 4
y = 1
a = x & y
b = x | y
c = ~x # !difícil!
d = x ^ 5
e = x >> 2
f = x << 2
print(a, b, c, d, e, f)
Revisar
0 5 -5 1 1 16
var1 = int(input())
var2 = int(input())
var3 = int(input())
var4 = int(input())
var5 = int(input())
var6 = int(input())
:
:
Si no crees que esta sea una tarea complicada, toma un papel y escribe un programa que:
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 sería 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 numeros ; 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).
numbers = [10, 5, 7, 2, 1]
Digamos lo mismo utilizando una terminología adecuada: numeros 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.
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
3.4.1.2 Listas - colecciones de datos | Indexación
Indexando Listas
¿Cómo cambias el valor de un elemento elegido en la lista?
numbers = [10, 5, 7, 2, 1]
numbers[0] = 111
Y ahora queremos copiar el valor del quinto elemento al segundo elemento. ¿Puedes
adivinar cómo hacerlo?
numbers = [10, 5, 7, 2, 1]
numbers[0] = 111
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.
numbers = [10, 5, 7, 2, 1]
print("Contenido de la lista:", numbers) # Imprimiendo contenido
# de la lista original.
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 la salida de una manera que
sugiere que todos los valores presentados forman una lista. La salida del fragmento de
ejemplo anterior se ve así:
[111, 1, 7, 2, 1]
output
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.
Observa la última línea de código en el editor, ejecuta el programa y verifica que valor
imprimirá en la consola. ¿Puedes adivinar?
numbers = [10, 5, 7, 2, 1]
print("Contenido de la lista original:", numbers) # Imprimiendo el contenido
# de la lista original.
numbers[0] = 111
Mira el fragmento de abajo. ¿Puedes adivinar qué salida producirá? Ejecuta el programa
en el editor y comprueba.
del numbers[1]
print(len(numbers))
print(numbers)
print(numbers[4])
numbers[4] = 1
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.
numbers = [10, 5, 7, 2, 1]
numbers[0] = 111
print(numbers[-1])
Del mismo modo, el elemento con un índice igual a -2 es el anterior al último en la lista.
print(numbers[-2])
El último elemento accesible en nuestra lista es numeros[-4] (el primero). ¡No intentes ir
más lejos!
numbers = [111, 7, 2, 1]
print(numbers[-1])
print(numbers[-2])
Tiempo Estimado
5 minutos
Nivel de Dificultad
Muy fácil
Objetivos
Familiarizar al estudiante con:
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).
print(hat_list)
3.4.1.7 Listas - colecciones de datos | Funciones y métodos
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.
result = function(arg)
result = data.method(arg)
Nota: el nombre del método está precedido por el nombre de los datos que posee el
método. A continuación, se agrega un punto, seguido del nombre del método y un par
de paréntesis que encierran los argumentos.
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.
3.4.1.8 Listas - colecciones de datos | Métodos de list
list.append(value)
list.insert(location, value)
• El primero muestra la ubicación requerida del elemento a insertar. Nota: todos los
elementos existentes que ocupan ubicaciones a la derecha del nuevo elemento
(incluido el que está en la posición indicada) se desplazan a la derecha, para hacer
espacio para el nuevo elemento.
• El segundo es el elemento a insertar.
numbers.insert(1, 333)
numbers = [111, 7, 2, 1]
print(len(numbers))
print(numbers)
###
numbers.append(4)
print(len(numbers))
print(numbers)
###
numbers.insert(0, 222)
print(len(numbers))
print(numbers)
Será una secuencia de números enteros consecutivos del 1 (luego agrega uno a todos los
valores agregados) hasta 5 .
for i in range(5):
my_list.insert(0, i + 1)
print(my_list)
¿Qué pasará ahora? Ejecuta el programa y comprueba si esta vez también tenías razón.
Deberías obtener la misma secuencia, pero en orden inverso (este es el mérito de usar el
método insert() ).
for i in range(5):
my_list.append(i + 1)
print(my_list)
my_list = [10, 1, 8, 3, 5]
total = 0
for i in my_list:
total += i
print(total)
for i in range(len(my_list)):
total += my_list[i]
print(total)
variable_1 = 1
variable_2 = 2
variable_2 = variable_1
variable_1 = variable_2
variable_1 = 1
variable_2 = 2
auxiliary = variable_1
variable_1 = variable_2
variable_2 = auxiliary
Python ofrece una forma más conveniente de hacer el intercambio, echa un vistazo:
variable_1 = 1
variable_2 = 2
Listas en acción
Ahora puedes intercambiar fácilmente los elementos de la lista para revertir su orden:
my_list = [10, 1, 8, 3, 5]
print(my_list)
[5, 3, 8, 1, 10]
salida
¿Seguirá siendo aceptable con una lista que contenga 100 elementos? No, no lo hará.
my_list = [10, 1, 8, 3, 5]
length = len(my_list)
print(my_list)
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 más 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.
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
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.
a 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:
Por cierto, ¿eres fan de los Beatles? (Los Beatles son una de las bandas favoritas de Greg.
Pero espera...¿Quién es Greg?)
# paso 1
print("Paso 1:", Beatles)
# paso 2
print("Paso 2:", Beatles)
# paso 3
print("Paso 3:", Beatles)
# paso 4
print("Paso 4:", Beatles)
# paso 5
print("Paso 5:", Beatles)
1. 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:
my_list[1] = '?'
print(my_list) # salida: [1, '?', True, 'Soy una cadena', 256, 0]
my_list.insert(0, "primero")
my_list.append("último")
print(my_list) # outputs: ['primero', 1, '?', True, 'Soy una
cadena', 256, 0, 'último']
Aprenderás más sobre el anidamiento en el módulo 3.7; por el momento, solo queremos
que sepas que algo como esto también es posible.
my_list = [1, 2, 3, 4]
del my_list[2]
print(my_list) # salida: [1, 2, 4]
del my_list # borra la lista entera
5.Las listas pueden ser iteradas mediante el uso del bucle for , por ejemplo:
my_list = ["blanco", "purpura", "azul", "amarillo", "verde"]
6. La función len() se puede usar para verificar la longitud de la lista, por ejemplo:
del my_list[2]
print(len(my_list)) # salida 4
Ejercicio 1
¿Cuál es la salida del siguiente fragmento de código?
lst = [1, 2, 3, 4, 5]
lst.insert(1, 6)
del lst[0]
lst.append(1)
print(lst)
Revisar
[6, 2, 3, 4, 5, 1]
Ejercicio 2
¿Cuál es la salida del siguiente fragmento de código?
lst = [1, 2, 3, 4, 5]
lst_2 = []
add = 0
print(lst_2)
Revisar
Ejercicio 3
¿Cuál es la salida del siguiente fragmento de código?
lst = []
del lst
print(lst)
Revisar
Ejercicio 4
¿Cuál es la salida del siguiente fragmento de código?
Revisar
[2, 3]
3
Ordenamiento Burbuja
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.
En las siguientes secciones, ordenaremos la lista en orden ascendente, de modo que los
números se ordenen de menor a mayor.
8 6 10 2 4
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:
8 6 2 10 4
Ahora comprobemos los elementos cuarto y quinto. Si, ellos también están en las
posiciones equivocadas. Ocurre otro intercambio:
8 6 2 4 10
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 el. 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:
10
4
2
6
8
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 de
burbuja.
Ahora comenzamos con el segundo paso a través de la lista. Miramos el primer y el
segundo elemento, es necesario un intercambio:
6 8 2 4 10
La lista ya está ordenada. No tenemos nada más que hacer. Esto es exactamente lo que
queremos.
Como puedes ver, la esencia de este algoritmo es simple: comparamos los elementos
adyacentes y, al intercambiar algunos de ellos, logramos nuestro objetivo.
Codifiquemos en Python todas las acciones realizadas durante un solo paso a través de la
lista, y luego consideraremos cuántos pases necesitamos para realizarlo. No hemos
explicado esto hasta ahora, pero lo haremos pronto.
while swapped:
swapped = False # no hay intercambios hasta ahora
for i in range(len(my_list) - 1):
if my_list[i] > my_list[i + 1]:
swapped = True # ¡ocurrió el intercambio!
my_list[i], my_list[i + 1] = my_list[i + 1], my_list[i]
print(my_list)
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.
[2, 4, 6, 8, 10]
salida
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.
my_list = []
swapped = True
num = int(input("¿Cuántos elementos deseas ordenar?: "))
for i in range(num):
val = float(input("Ingresa un elemento de la lista: "))
my_list.append(val)
while swapped:
swapped = False
for i in range(len(my_list) - 1):
if my_list[i] > my_list[i + 1]:
swapped = True
my_list[i], my_list[i + 1] = my_list[i + 1],
my_list[i]
print("\nOrdenada:")
print(my_list)
Puntos Clave
1. Puedes usar el método sort() para ordenar los elementos de una lista, por ejemplo:
lst = [5, 3, 1, 2, 4]
print(lst)
lst.sort()
print(lst) # outputs: [1, 2, 3, 4, 5]
2.También hay un método de lista llamado reverse() , que puedes usar para invertir la
lista, por ejemplo:
lst = [5, 3, 1, 2, 4]
print(lst)
lst.reverse()
print(lst) # salida: [4, 2, 1, 3, 5]
Ejercicio 1
¿Cuál es la salida del siguiente fragmento de código?
lst = ["D", "F", "A", "Z"]
lst.sort()
print(lst)
Revisar
Ejercicio 2
¿Cuál es la salida del siguiente fragmento de código?
a = 3
b = 1
c = 2
lst = [a, c, b]
lst.sort()
print(lst)
Revisar
[1, 2, 3]
Ejercicio 3
¿Cuál es la salida del siguiente fragmento de código?
a = "A"
b = "B"
c = "C"
d = " "
lst = [a, b, c, d]
lst.reverse()
print(lst)
Revisar
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:
Lee estas dos líneas una vez más, la diferencia es esencial para comprender de que
vamos a hablar a continuación.
list_1 = [1]
list_2 = list_1
list_1[0] = 2
print(list_2)
Rebanadas Poderosas
Afortunadamente, la solución está al alcance de tu mano: su nombre es rebanada.
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 salida es [1] .
Esta parte no visible del código descrito como [:] puede producir una lista
completamente nueva.
my_list[start:end]
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 principio hasta el 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).
my_list = [10, 8, 6, 4, 2]
new_list = my_list[1:3]
print(new_list)
La lista new_list contendrá fin - inicio (3 - 1 = 2) elementos, los que tienen índices
iguales a 1 y 2 (pero no 3 ).
my_list[start:end]
Para confirmar:
my_list = [10, 8, 6, 4, 2]
new_list = my_list[1:-1]
print(new_list)
[8, 6, 4]
salida
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:
my_list = [10, 8, 6, 4, 2]
new_list = my_list[-1:1]
print(new_list)
[]
salida
Rebanadas: continuación
Si omites el start en tu rebanada, se supone que deseas obtener un segmento que
comienza en el elemento con índice 0 .
my_list[:end]
es un equivalente más compacto de:
my_list[0:end]
my_list = [10, 8, 6, 4, 2]
new_list = my_list[:3]
print(new_list)
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) .
my_list[start:]
my_list[start:len(my_list)]
my_list = [10, 8, 6, 4, 2]
new_list = my_list[3:]
print(new_list)
Rebanadas: continuación
Como hemos dicho anteriormente, el omitir el inicio y fin crea una copia de toda la
lista:
my_list = [10, 8, 6, 4, 2]
new_list = my_list[:]
print(new_list)
El resultado del fragmento es: [10, 8, 6, 4, 2] .
my_list = [10, 8, 6, 4, 2]
del my_list[1:3]
print(my_list)
my_list = [10, 8, 6, 4, 2]
del my_list[:]
print(my_list)
Echa un vistazo:
my_list = [10, 8, 6, 4, 2]
del my_list
print(my_list)
elem in my_list
elem not in my_list
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.
print(5 in my_list)
print(5 not in my_list)
print(12 in my_list)
El primero de ellos intenta encontrar el valor mayor en la lista. Mira el código en el editor.
El código puede ser reescrito para hacer uso de la forma recién introducida del
bucle for :
for i in my_list:
if i > largest:
largest = i
print(largest)
El programa anterior realiza una comparación innecesaria, cuando el primer elemento se
compara consigo mismo, pero esto no es un problema en absoluto.
for i in my_list[1:]:
if i > largest:
largest = i
print(largest)
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?
print(largest)
for i in range(len(my_list)):
found = my_list[i] == to_find
if found:
break
if found:
print("Elemento encontrado en el índice", i)
else:
print("ausente")
Nota:
print(hits)
Nota:
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
• Indexación de listas.
• Utilizar operadores in y not in .
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.
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.
my_list = [1, 2, 4, 4, 1, 4, 2, 6, 2, 9]
#
# Escribe tu código aquí.
#
print("La lista con elementos únicos:")
print(my_list)
Puntos Clave
1. 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:
vehicles_two = vehicles_one
del vehicles_one[0] # elimina 'carro'
print(vehicles_two) # salida: ['bicicleta', 'motor']
2. Si deseas copiar una lista o parte de la lista, puedes hacerlo haciendo uso
de rebanadas:
3. También puede utilizar índices negativos para hacer uso de rebanadas. Por ejemplo:
my_list = [1, 2, 3, 4, 5]
slice_one = my_list[2: ]
slice_two = my_list[ :2]
slice_three = my_list[-2: ]
my_list = [1, 2, 3, 4, 5]
del my_list[0:2]
print(my_list) # salida: [3, 4, 5]
del my_list[:]
print(my_list) # delimina el contenido de la lista, genera: []
6. Puedes probar si algunos elementos existen en una lista o no utilizando las palabras
clave in y not in , por ejemplo:
del list_1[0]
del list_2[0]
print(list_3)
Revisar
['C']
Ejercicio 2
del list_1[0]
del list_2
print(list_3)
Revisar
['B', 'C']
Ejercicio 3
del list_1[0]
del list_2[:]
print(list_3)
Revisar
[]
Ejercicio 4
del list_1[0]
del list_2[0]
print(list_3)
Revisar
Ejercicio 5
Inserta in o not in en lugar de ??? para que el código genere el resultado esperado.
Revisar
my_list = [1, 2, "in", True, "ABC"]
print(1 in my_list) # salida True
print("A" not in my_list) # salida True
print(3 not in my_list) # salida True
print(False in my_list) # salida False
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.
row = []
for i in range(8):
row.append(WHITE_PAWN)
Crea una lista que contiene ocho elementos que representan la segunda fila del tablero
de ajedrez: la que está llena de peones (supon que WHITE_PAWN es un símbolo
predefinido que representa un peón blanco).
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.
Ejemplo #1:
Ejemplo #2:
El fragmento crea un arreglo de ocho elementos que contiene las primeras ocho
potencias del numero dos (1, 2, 4, 8, 16, 32, 64, 128)
Ejemplo #3:
El fragmento crea una lista con solo los elementos impares de la lista squares .
Entonces, si queremos crear una lista de listas que representan todo el tablero de
ajedrez, se puede hacer de la siguiente manera:
board = []
for i in range(8):
row = [EMPTY for i in range(8)]
board.append(row)
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.
Echa un vistazo al tablero de ajedrez. Cada campo contiene un par de índices que se
deben dar para acceder al contenido del campo:
EMPTY = "-"
PAWN = "PEON"
ROOK = "TORRE"
KNIGHT = "CABALLO"
board = []
for i in range(8):
row = [EMPTY for i in range(8)]
board.append(row)
board[0][0] = ROOK
board[0][7] = ROOK
board[7][0] = ROOK
board[7][7] = ROOK
print(board)
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.
Primero, debes decidir qué tipo de datos sería adecuado para esta aplicación. En este
caso, sería mejor un float , ya que este termómetro puede medir la temperatura con
una precisión de 0.1 ℃.
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):
total = 0.0
average = total / 31
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:
#
# La matriz se actualiza aquí.
#
highest = -100.0
Nota:
hot_days = 0
Arreglos tridimensionales
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 ).
Ahora ya puedes reservar una habitación para dos recién casados: en el segundo edificio,
en el décimo piso, habitación 14:
rooms[1][9][13] = True
y desocupar el segundo cuarto en el quinto piso ubicado en el primer edificio:
rooms[0][4][1] = False
vacancy = 0
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!
Puntos Clave
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:
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:
# Una tabla de cuatro columnas y cuatro filas: un arreglo bidimensional (4x4)
print(table)
print(table[0][0]) # outputs: ':('
print(table[0][3]) # outputs: ':)'
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:
# Cubo - un arreglo tridimensional (3x3x3)
print(cube)
print(cube[0][0][0]) # outputs: ':('
print(cube[2][2][0]) # outputs: ':)'
Ahora estás listo para tomar la prueba del módulo e intentar el desafío final: la Prueba
del Módulo 3, que te ayudará a evaluar lo que has aprendido hasta ahora.
Fundamentos de Python 1
Módulo 4
Funciones, Tuplas, Diccionarios, Exceptiones y Procesamiento de Datos
En este módulo, se cubrirán los siguientes temas:
4.1.1.1 Funciones
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 primer 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 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.
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 pequeños problemas por separado e
implementa cada uno de ellos como una función independiente.
4.1.1.2 Funciones
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án en el. 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.
Cada uno debe escribir un conjunto bien definido y claro de funciones, las cuales al
ser combinadas dentro de un módulo (esto se clarificara 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.
• De Python mismo: varias funciones (como print() ) son una parte integral de
Python, y siempre están disponibles sin algún esfuerzo adicional del programador;
se les llama a estas funciones integradas.
• De los módulos preinstalados de Python: muchas de las funciones, las cuales
comúnmente son menos utilizadas que las integradas, están disponibles en
módulos instalados juntamente con Python; para poder utilizar estas funciones el
programador debe realizar algunos pasos adicionales (se explicará acerca de esto
en un momento).
• Directamente del código: tu puedes escribir tus propias funciones, colocarlas
dentro del código, y usarlas libremente.
• Existe una posibilidad más, pero se relaciona con clases, se omitirá por ahora.
4.1.1.3 Escribiendo funciones
Tu primer función
Observa el fragmento de código en el editor.
Es bastante sencillo, es un ejemplo de como transformar una parte de código que se está
repitiendo en una función.
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.
Tu primer función
¿Cómo es que se crea dicha función?
def function_name():
function_body
def message():
print("Ingresa un valor: ")
def message():
print("Ingresa un valor: ")
Se comienza aquí.
Se termina aquí.
salida
Esto significa que Python lee la definición de la función y la recuerda, pero no la ejecuta
sin tu permiso.
def message():
print("Ingresa un valor: ")
def my_function():
# cuerpo de la función
• Cuando se invoca una función, Python recuerda el lugar donde esto ocurre
y salta hacia dentro de la función invocada.
• El cuerpo de la función es entonces ejecutado.
• Al llegar al final de la función, Python regresa al lugar inmediato después de
donde ocurrió la invocación.
def message():
print("Ingresa un valor: ")
salida
def message():
print("Ingresa un valor: ")
message = 1
El asignar un valor al nombre "message" causa que Python olvide su rol anterior. La
función con el nombre de message ya no estará disponible.
Afortunadamente, es posible combinar o mezclar el código con las funciones - no es
forzoso colocar todas las funciones al inicio del archivo fuente.
def message():
print("Ingresa un valor: ")
message()
message()
a = int(input())
message()
b = int(input())
message()
c = int(input())
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.
Puntos Clave
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.
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:
Ejercicio 1
Revisar
¿Qué es lo que ocurre cuando se invoca una función antes de ser definida? Ejemplo:
hi()
def hi():
print("¡Hola!")
Revisar
Ejercicio 3
def hi():
print("hola")
hi(5)
Revisar
Se genera una excepción (la excepción TypeError ) ‒ la función hi() no toma
argumentos
Funciones parametrizadas
El potencial completo de una función se revela cuando puede ser equipada con una
interface que es capaz de aceptar datos provenientes de la invocación. Dichos datos
pueden modificar el comportamiento de la función, haciéndola más flexible y adaptable a
condiciones cambiantes.
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 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.
def function(parameter):
###
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.
Funciones parametrizadas
El potencial completo de una función se revela cuando puede ser equipada con una
interface que es capaz de aceptar datos provenientes de la invocación. Dichos datos
pueden modificar el comportamiento de la función, haciéndola más flexible y adaptable a
condiciones cambiantes.
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 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.
def function(parameter):
###
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.
def message(number):
###
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.
def message(number):
print("Ingresa un número:", number)
Si, lo es.
def message(number):
print("Ingresa un número:", number)
message(1)
Ingresa un número: 1
salida
¿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.
def message(number):
print("Ingresa un número:", number)
number = 1234
message(1)
print(number)
Ingresa un número: 1
1234
salida
def message(number):
print("Ingresa un número:", number)
message()
Aquí está:
message("teléfono", 11)
message("precio", 5)
message("número", "número")
Ejecuta el código, modifícalo, agrega más parámetros y ve cómo esto afecta la salida.
Ya se ha utilizado, pero Python ofrece mucho más. Se abordará este tema a continuación.
my_function(1, 2, 3)
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."
introduction("Luke", "Skywalker")
introduction("Jesse", "Quick")
introduction("Clark", "Kent")
Ahora imaginemos que la función esta siendo utilizada en Hungría. En este caso, el código
sería de la siguiente manera:
introduction("Skywalker", "Luke")
introduction("Quick", "Jesse")
introduction("Kent", "Clark")
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 = .
introduction(surname="Skywalker", first_name="Luke")
salida
Inténtalo tu mismo.
4.2.1.6 Cómo las funciones se comunican con su entorno
adding(1, 2, 3)
1 + 2 + 3 = 6
salida
También, se puede reemplazar la invocación actual por una con palabras clave, como la
siguiente:
adding(c = 1, a = 2, b = 3)
2 + 3 + 1 = 6
salida
adding(3, c = 1, b = 2)
Vamos a analizarla:
3 + 2 + 1 = 6
salida
adding(3, a = 1, b = 2)
adding(4, 3, c = 2)
Todo es correcto, pero el dejar solo un argumento con palabra clave es algo extraño -
¿Qué es lo que opinas?
Solo se tiene que colocar el nombre del parámetro seguido del signo de = y el valor por
default.
introduction("Jorge", "Pérez")
¿Y? No parece haber cambiado algo, pero cuando se invoca la función de una manera
inusual, como esta:
introduction("Enrique")
o así:
introduction(first_name="Guillermo")
Pruébalo.
Puedes hacerlo con más parámetros, si te resulta útil. Ambos parámetros tendrán sus
valores por default, observa el siguiente código:
introduction()
Y esta es la salida esperada:
Hola, mi nombre es Juan González
salida
introduction(last_name="Rodríguez")
La salida es:
Pruébalo.
Puntos Clave
1. Se puede pasar información a las funciones utilizando parámetros. Las funciones
pueden tener tantos parámetros como sean necesarios.
def hi(name):
print("Hola,", name)
hi("Greg")
hi_all("Sebastián", "Konrad")
address(s, c, p_c)
#Ejemplo 1
def subtra(a, b):
print(a - b)
subtra(5, 2) # salida: 3
subtra(2, 5) # salida: -3
#Ejemplo 2
def subtra(a, b):
print(a - b)
#Ejemplo 3
def subtra(a, b):
print(a - b)
Ejercicio 1
intro()
Revisar
Ejercicio 2
intro(b="Sergio López")
Revisar
Ejercicio 3
intro("Susan")
Revisar
add_numbers(a=1, c=3)
Revisar
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.
De cualquier manera, se puede emplear para terminar las actividades de una función,
antes de que el control llegue a la última línea de la función.
Consideremos la siguiente función:
happy_new_year()
Tres...
Dos...
Uno...
¡Feliz año nuevo!
salida
Tres...
Dos...
Uno...
salida
def function():
return expression
x = boring_function()
Vamos a investigarlo.
La instrucción return , enriquecida con la expresión (la expresión es muy simple aquí),
"transporta" el valor de la expresión al lugar donde se ha invocado la función.
El resultado se puede usar libremente aquí, por ejemplo, para ser asignado a una
variable.
Ten en cuenta que no estamos siendo muy educados aquí: la función devuelve un valor y
lo ignoramos (no lo usamos de ninguna manera):
def boring_function():
print("'Modo aburrimiento' ON.")
return 123
No olvides:
Espera un segundo, ¿Significa esto que también hay resultados inútiles? Sí, en cierto
sentido.
print(None + 2)
salida
Solo existen dos tipos de circunstancias en las que None se puede usar de manera
segura:
value = None
if value is None:
print("Lo siento, no contienes ningún valor")
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.
print(strange_function(2))
print(strange_function(1))
True
None
salida
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.
def strange_function(n):
if(n % 2 == 0):
return True
¡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.
def list_sum(lst):
s = 0
return s
y se invoca así:
print(list_sum([5, 4, 3]))
Retorna 12 como resultado, pero habrá problemas si la invocas de esta manera riesgosa:
print(list_sum(5))
Esto se debe al hecho de que el bucle for no puede iterar un solo valor entero.
def list_sum(lst):
s = 0
return s
[4, 3, 2, 1, 0]
salida
Vamos a profundizar un poco más en los problemas relacionados con las variables en las
funciones. Esto es esencial para crear funciones efectivas y seguras.
def strange_list_fun(n):
strange_list = []
return strange_list
print(strange_list_fun(5))
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
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.
def is_year_leap(year):
#
# Escribe tu código aquí.
#
Tiempo Estimado
15-20 minutos
Nivel de Dificultad
Medio
Requisitos Previos
LABORATORIO 4.1.3.6
Objetivos
Familiarizar al estudiante con:
Escenario
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.
Hemos preparado un código de prueba. Amplíalo para incluir más casos de prueba.
def is_year_leap(year):
#
# Tu código del LABORATORIO 4.3.6.
#
LABORATORIO
Tiempo Estimado
20-30 minutos
Nivel de Dificultad
Medio
Requisitos Previos
LABORATORIO 4.1.3.6
LABORATORIO 4.1.3.7
Objetivos
Familiarizar al estudiante con:
Escenario
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.
def is_year_leap(year):
#
# Tu código del LABORATORIO 4.3.1.6.
#
def days_in_month(year, month):
#
# Tu código del LABORATORIO 4.3.1.7.
#
Tiempo Estimado
15-20 minutos
Nivel de Dificultad
Medio
Objetivos
• Familiarizar al estudiante con nociones y algoritmos clásicos.
• Mejorar las habilidades del estudiante para definir y emplear funciones.
Escenario
Un número natural es primo si es mayor que 1 y no tiene divisores más que 1 y si mismo.
Por otra parte, 7 es un número primo, ya que no podemos encontrar ningún divisor para
el.
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.
Datos de prueba
Salida esperada:
2 3 5 7 11 13 17 19
def is_prime(num):
#
# Escribe tu código aquí.
#
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
• Mejorar las habilidades del estudiante para definir, utilizar y probar funciones.
Escenario
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 re
spectivamente.
• Toman un argumento (el valor correspondiente a sus nombres).
Salida esperada:
60.31143162393162
31.36194444444444
23.52145833333333
3.9007393587617467
7.490910297239916
10.009131205673757
def liters_100km_to_miles_gallon(liters):
#
# Escribe tu código aquí.
#
def miles_gallon_to_liters_100km(miles):
#
# Escribe tu código aquí.
#
print(liters_100km_to_miles_gallon(3.9))
print(liters_100km_to_miles_gallon(7.5))
print(liters_100km_to_miles_gallon(10.))
print(miles_gallon_to_liters_100km(60.3))
print(miles_gallon_to_liters_100km(31.4))
print(miles_gallon_to_liters_100km(23.5))
Puntos Clave
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:
def wishes():
return "¡Felíz Cumpleaños!"
w = wishes()
# Ejemplo 1
def wishes():
print("Mis deseos")
return "Felíz Cumpleaños"
# Ejemplo 2
def wishes():
print("Mis deseos")
return "Felíz Cumpleaños"
print(wishes())
3. Puedes usar una lista como argumento de una función, por ejemplo:
def hi_everybody(my_list):
for name in my_list:
print("Hola,", name)
def create_list(n):
my_list = []
for i in range(n):
my_list.append(i)
return my_list
print(create_list(5))
Ejercicio 1
¿Cuál es la salida del siguiente fragmento de código?
def hi():
return
print("¡Hola!")
hi()
Revisar
Ejercicio 2
¿Cuál es la salida del siguiente fragmento de código?
def is_int(data):
if type(data) == int:
return True
elif type(data) == float:
return False
print(is_int(5))
print(is_int(5.0))
print(is_int("5"))
Revisar
True
False
None
Ejercicio 3
¿Cuál es la salida del siguiente fragmento de código?
def even_num_lst(ran):
lst = []
for num in range(ran):
if num % 2 == 0:
lst.append(num)
return lst
print(even_num_lst(11))
Revisar
[0, 2, 4, 6, 8, 10]
Ejercicio 4
¿Cuál es la salida del siguiente fragmento de código?
def list_updater(lst):
upd_list = []
for elem in lst:
elem **= 2
upd_list.append(elem)
return upd_list
foo = [1, 2, 3, 4, 5]
print(list_updater(foo))
Revisar
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 como es que Python define los
alcances y como los puedes utilizar para tu beneficio.
def scope_test():
x = 123
scope_test()
print(x)
¿Conozco a la variable? 1
1
salida
La respuesta es: una variable que existe fuera de una función tiene alcance dentro del
cuerpo de la función.
def my_function():
var = 2
print("¿Conozco a la variable?", var)
var = 1
my_function()
print(var)
El resultado ha cambiado también, el código arroja una salida con una ligera diferencia:
¿Conozco a la variable? 2
1
salida
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.
def my_function():
print("¿Conozco a la variable?", var)
var = 1
my_function()
print(var)
global name
global name1, name2, ...
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.
Esto debe de ser suficiente evidencia para mostrar lo que la palabra clave
reservada global puede hacer.
def my_function():
global var
var = 2
print("¿Conozco a aquella variable?", var)
var = 1
my_function()
print(var)
Yo recibí 1
Ahora tengo 2
1
salida
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?)
def my_function(my_list_1):
print("Print #1:", my_list_1)
print("Print #2:", my_list_2)
my_list_1 = [0, 1]
print("Print #3:", my_list_1)
print("Print #4:", my_list_2)
my_list_2 = [2, 3]
my_function(my_list_2)
print("Print #5:", my_list_2)
def my_function(my_list_1):
print("Print #1:", my_list_1)
print("Print #2:", my_list_2)
del my_list_1[0] # Presta atención a esta línea.
print("Print #3:", my_list_1)
print("Print #4:", my_list_2)
my_list_2 = [2, 3]
my_function(my_list_2)
print("Print #5:", my_list_2)
Intentémoslo:
def my_function(n):
print("Yo recibí", n)
n += 1
print("Ahora tengo", n)
var = 1
my_function(var)
print(var)
4.4.1.5 RESUMEN DE SECCIÓN
Puntos Clave
1. Una variable que existe fuera de una función tiene alcance dentro del cuerpo de la
función. (Ejemplo 1) al menos que la función defina una variable con el mismo nombre.
(Ejemplo 2, y Ejemplo 3), por ejemplo:
Ejemplo 1:
var = 2
def mult_by_var(x):
return x * var
print(mult_by_var(7)) # salida: 14
Ejemplo 2:
def mult(x):
var = 5
return x * var
print(mult(7)) # salida: 35
Ejemplo 3:
def mult(x):
var = 7
return x * var
var = 3
print(mult(7)) # salida: 49
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:
def adding(x):
var = 7
return x + var
print(adding(4)) # salida: 11
print(var) # NameError
3. 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:
var = 2
print(var) # salida: 2
def return_var():
global var
var = 5
return var
print(return_var()) # salida: 5
print(var) # salida: 5
Ejercicio 1
def message():
alt = 1
print("¡Hola, mundo!")
print(alt)
Revisar
Ejercicio 2
a = 1
def fun():
a = 2
print(a)
fun()
print(a)
Revisar
2
1
Ejercicio 3
a = 1
def fun():
global a
a = 2
print(a)
fun()
a = 3
print(a)
Revisar
2
3
Ejercicio 4
a = 1
def fun():
global a
a = 2
print(a)
a = 3
fun()
print(a)
Revisar
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.
print(bmi(52.5, 1.65))
19.283746556473833
salida
La función hace lo que deseamos, pero es un poco sencilla - asume que los valores de
ambos parámetros son significativos. Se debe comprobar que son confiables.
print(bmi(52.5, 1.65))
None
salida
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.
def lb_to_kg(lb):
return lb * 0.45359237
print(lb_to_kg(1))
0.45359237
salida
print(ft_and_inch_to_m(1, 1))
0.3302
salida
Resulta como esperado.
in es una palabra clave reservada de Python ‒ no se puede usar como nombre.
print(ft_and_inch_to_m(6, 0))
Esta es la salida:
1.8288000000000002
salida
Es muy posible que en ocasiones se desee utilizar solo pies sin pulgadas. ¿Python nos
ayudará? Por supuesto que si.
print(ft_and_inch_to_m(6))
1.8288000000000002
salida
def lb_to_kg(lb):
return lb * 0.45359237
La respuesta es:
27.565214082533313
salida
print(bmi(352.5, 1.65))
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.
True
False
salida
print(is_a_triangle(1, 1, 1))
print(is_a_triangle(1, 1, 3))
print(is_a_triangle(1, 1, 1))
print(is_a_triangle(1, 1, 3))
print(is_a_triangle(1, 1, 1))
print(is_a_triangle(1, 1, 3))
c2 = a 2 + b 2
print(is_a_right_triangle(5, 3, 4))
print(is_a_right_triangle(1, 3, 4))
Observa como se establece la relación entre la hipotenusa y los dos catetos. Se eligió el
lado más largo y se aplico el Teorema de Pitágoras para verificar que todo estuviese en
orden. Esto requiere tres revisiones en total.
if is_a_triangle(a, b, c):
print('Si, si puede ser un triángulo.')
else:
print('No, no puede ser un triángulo.')
0.49999999999999983
salida
No, no lo es. Son solo los cálculos de valores punto flotantes. Pronto se discutirá el tema.
if is_a_triangle(a, b, c):
print('Si, si puede ser un triángulo.')
else:
print('No, no puede ser un triángulo.')
0! = 1 (¡Si!, es verdad.)
1! = 1
2! = 1 * 2
3! = 1 * 2 * 3
4! = 1 * 2 * 3 * 4
:
:
n! = 1 * 2 ** 3 * 4 * ... * n-1 * n
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.
def factorial_function(n):
if n < 0:
return None
if n < 2:
return 1
product = 1
for i in range(2, n + 1):
product *= i
return product
1 1
2 2
3 6
4 24
5 120
salida
Son una secuencia de números enteros los cuales siguen una regla sencilla:
def fib(n):
if n < 1:
return None
if n < 3:
return 1
elem_1 = elem_2 = 1
the_sum = 0
for i in range(3, n + 1):
the_sum = elem_1 + elem_2
elem_1, elem_2 = elem_2, the_sum
return the_sum
Analiza el codigo del bucle for cuidadosamente, descifra como se mueven las
variables elem_1 y elem_2 a través de los números subsecuentes de la serie Fibonacci.
1 -> 1
2 -> 1
3 -> 2
4 -> 3
5 -> 5
6 -> 8
7 -> 13
8 -> 21
9 -> 34
salida
Este termino 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.
def fib(n):
if n < 1:
return None
if n < 3:
return 1
return fib(n - 1) + fib(n - 2)
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.
n! = 1 × 2 × 3 × ... × n-1 × n
Es obvio que:
n! = (n-1)! × n
Esto se empleará en nuestra nueva solución.
Aquí esta:
def factorial_function(n):
if n < 0:
return None
if n < 2:
return 1
return n * factorial_function(n - 1)
Nuestro viaje funcional esta por terminar. La siguiente sección abordara dos tipos de
datos en Python: tuplas y diccionarios.
def fib(n):
if n < 1:
return None
if n < 3:
return 1
elem_1 = elem_2 = 1
the_sum = 0
for i in range(3, n + 1):
the_sum = elem_1 + elem_2
elem_1, elem_2 = elem_2, the_sum
return the_sum
Puntos Clave
1. Una función puede invocar otras funciones o incluso a sí misma. Cuando una función
se invoca a si misma, se le conoce como recursividad, y la función que se invoca a si
misma y contiene una condición de terminación (la cual le dice a la función que ya no siga
invocándose a si misma) es llamada una función recursiva.
def factorial(n):
if n == 1: # El caso base (condición de terminación).
return 1
else:
return n * factorial(n - 1)
print(factorial(4)) # 4 * 3 * 2 * 1 = 24
Ejercicio 1
def factorial(n):
return n * factorial(n - 1)
print(factorial(4))
Revisar
La función no tiene una condición de terminación, por lo tanto Python arrojara una
excepción ( RecursionError: maximum recursion depth exceeded )
Ejercicio 2
def fun(a):
if a > 30:
return 3
else:
return a + fun(a + 3)
print(fun(25))
Revisar
56
4.6.1.1 Tuplas y diccionarios
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.
Los datos mutables pueden ser actualizados libremente en cualquier momento, a esta
operación se le denomina "in situ".
list.append(1)
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.
¿Qué es una tupla?
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:
tuple_1 = (1, 2, 4, 8)
tuple_2 = 1., .5, .25, .125
tuple_1 = (1, 2, 4, 8)
tuple_2 = 1., .5, .25, .125
print(tuple_1)
print(tuple_2)
(1, 2, 4, 8)
(1.0, 0.5, 0.25, 0.125)
salida
Nota: cada elemento de una tupla puede ser de distinto tipo (punto flotante, entero,
cadena, o cualquier otro tipo de dato).
empty_tuple = ()
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:
one_element_tuple_1 = (1, )
one_element_tuple_2 = 1.,
El quitar las comas no arruinará el programa en el sentido sintáctico, pero serán dos
variables, no tuplas.
4.6.1.2 Tuplas y diccionarios
1
1000
(10, 100, 1000)
(1, 10)
1
10
100
1000
salida
Las similitudes pueden ser engañosas - no intentes modificar el contenido de la tupla ¡No
es una lista!
my_tuple.append(10000)
del my_tuple[0]
my_tuple[1] = -10
salida
print(my_tuple[0])
print(my_tuple[-1])
print(my_tuple[1:])
print(my_tuple[:-2])
La salida es la siguiente:
9
(1, 10, 100, 1000, 10000)
(1, 10, 100, 1, 10, 100, 1, 10, 100)
True
True
salida
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.
var = 123
t1 = (1, )
t2 = (2, )
t3 = (3, var)
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 mas: 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.
print(len(t2))
print(t1)
print(t2)
print(10 in my_tuple)
print(-10 not in my_tuple)
¿Qué es un diccionario?
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.
• Cada clave debe de ser única. No es posible tener una clave duplicada.
• Una clave puede ser un tipo de dato de cualquier tipo: puede ser un número
(entero o flotante), o incluso una cadena.
• 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.
print(dictionary)
print(phone_numbers)
print(empty_dictionary)
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.
¿Has notado que el orden de los pares impresos es diferente a la asignación inicial?, ¿Qué
significa esto?
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 este utilizando.
print(dictionary['gato'])
print(phone_numbers['Suzy'])
Nota:
• Si 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' .
chat
5557654321
salida
Ahora algo muy importante: No se puede utilizar una clave que no exista. Hacer algo
como lo siguiente:
print(phone_numbers['presidente'])
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 más
amigable para el programador, por ejemplo:
# Ejemplo 1:
dictionary = {
"gato": "chat",
"perro": "chien",
"caballo": "cheval"
}
# Ejemplo 2:
phone_numbers = {'jefe': 5551234567,
'Suzy': 22657854310
}
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).
La función sorted()
¿Deseas que la salida este ordenada? Solo hay que agregar al bucle for lo siguiente:
Nota la manera en que la tupla ha sido utilizada como una variable del bucle for .
chat
chien
cheval
salida
dictionary = {"gato" : "chat", "perro" : "chien", "caballo" :
"cheval"}
Observa:
dictionary['gato'] = 'minou'
print(dictionary)
La salida es:
Nota: este es un comportamiento muy diferente comparado a las listas, las cuales no
permiten asignar valores a índices no existentes.
dictionary['cisne'] = 'cygne'
print(dictionary)
El ejemplo muestra como salida:
{'gato': 'chat', 'perro': 'chien', 'caballo': 'cheval', 'cisne':
'cygne'}
salida
EXTRA
dictionary.update({"pato": "canard"})
print(dictionary)
Nota: al eliminar la clave también se removerá el valor asociado. Los valores no pueden
existir sin sus claves.
A continuación un ejemplo:
del dictionary['perro']
print(dictionary)
EXTRA
dictionary['gato'] = 'minou'
print(dictionary)
• 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 1-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.
school_class = {}
while True:
name = input("Ingresa el nombre del estudiante: ")
if name == '':
break
if name in school_class:
school_class[name] += (score,)
else:
school_class[name] = (score,)
1. Las Tuplas son colecciones de datos ordenadas e inmutables. Se puede pensar en ellas
como listas inmutables. Se definen con paréntesis:
my_tuple = (1, 2, True, "una cadena", (3, 4), [5, 6], None)
print(my_tuple)
my_list = [1, 2, True, "una cadena", (3, 4), [5, 6], None]
print(my_list)
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).
empty_tuple = ()
print(type(empty_tuple)) # salida: <class 'tuple'>
my_tuple = 1, 2, 3,
del my_tuple
print(my_tuple) # NameError: name 'my_tuple' is not defined
6. Puedes iterar a través de los elementos de una tupla con un bucle (Ejemplo 1), verificar
si un elemento o no esta presente en la tupla (Ejemplo 2), emplear la función len() para
verificar cuantos elementos existen en la tupla (Ejemplo 3), o incluso unir o multiplicar
tuplas (Ejemplo 4):
# Ejemplo 1
tuple_1 = (1, 2, 3)
for elem in tuple_1:
print(elem)
# Ejemplo 2
tuple_2 = (1, 2, 3, 4)
print(5 in tuple_2)
print(5 not in tuple_2)
# Ejemplo 3
tuple_3 = (1, 2, 3, 5)
print(len(tuple_3))
# Ejemplo 4
tuple_4 = tuple_1 + tuple_2
tuple_5 = tuple_3 * 2
print(tuple_4)
print(tuple_5)
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:
my_list = [2, 4, 6]
print(my_list) # salida: [2, 4, 6]
print(type(my_list)) # salida: <class 'list'>
tup = tuple(my_list)
print(tup) # salida: (2, 4, 6)
print(type(tup)) # salida: <class 'tuple'>
tup = 1, 2, 3,
my_list = list(tup)
print(type(my_list)) # salida: <class 'list'>
Cada diccionario es un par de clave : valor. Se puede crear empleado la siguiente sintaxis:
my_dictionary = {
key1: value1,
key2: value2,
key3: value3,
}
pol_esp_dictionary = {
"kwiat": "flor",
"woda": "agua",
"gleba": "tierra"
}
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:
pol_esp_dictionary = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
}
pol_esp_dictionary["zamek"] = "cerradura"
item = pol_esp_dictionary["zamek"]
print(item) # salida: cerradura
4. Para agregar o eliminar una clave (junto con su valor asociado), emplea la siguiente
sintaxis:
del phonebook["Adán"]
print(phonebook) # salida: {}
pol_esp_dictionary.update({"gleba": "tierra"})
print(pol_esp_dictionary) # salida: {'kwiat': 'flor', 'gleba': 'tierra'}
pol_esp_dictionary.popitem()
print(pol_esp_dictionary) # salida: {'kwiat': 'flor'}
5. Se puede emplear el bucle for para iterar a través del diccionario, por ejemplo:
pol_esp_dictionary = {
"zamek": "castillo",
"woda": "agua",
"gleba": "tierra"
}
# salida: zamek
# woda
# gleba
6. Si deseas examinar los elementos (claves y valores) del diccionario, puedes emplear el
método items() , por ejemplo:
pol_esp_dictionary = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
}
pol_esp_dictionary = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
}
if "zamek" in pol_esp_dictionary:
print("Si")
else:
print("No")
pol_esp_dictionary = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
}
print(len(pol_esp_dictionary)) # salida: 3
del pol_esp_dictionary["zamek"] # eliminar un elemento
print(len(pol_esp_dictionary)) # salida: 2
pol_esp_dictionary = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
}
copy_dictionary = pol_esp_dictionary.copy()
4.6.1.12 RESUMEN DE SECCIÓN (3/3)
Puntos Claves: Tuplas y diccionarios
Ejercicio 1
¿Qué ocurrirá cuando se intente ejecutar el siguiente código?
my_tup = (1, 2, 3)
print(my_tup[2])
Revisar
Ejercicio 2
¿Cuál es la salida del siguiente fragmento de código?
tup = 1, 2, 3
a, b, c = tup
print(a * b * c)
Revisar
Ejercicio 3
Completa el código para emplear correctamente el método count() para encontrar la
cantidad de 2 duplicados en la tupla siguiente.
tup = 1, 2, 3, 2, 4, 5, 6, 2, 7, 2, 8, 9
duplicates = # Escribe tu código aquí.
print(duplicates) # salida: 4
Revisar
tup = 1, 2, 3, 2, 4, 5, 6, 2, 7, 2, 8, 9
duplicates = tup.count(2)
print(duplicates) # salida: 4
Ejercicio 4
Escribe un programa que "una" los dos diccionarios ( d1 y d2 ) para crear uno nuevo ( d3 ).
d1 = {'Adam Smith': 'A', 'Judy Paxton': 'B+'}
d2 = {'Mary Louis': 'A', 'Patrick White': 'C'}
d3 = {}
print(d3)
Revisar
Solución muestra:
print(d3)
Ejercicio 5
Escribe un programa que convierta la lista my_list en una tupla.
Revisar
Solución muestra:
my_list = ["car", "Ford", "flower", "Tulip"]
t = tuple(my_list)
print(t)
Ejercicio 6
Escribe un programa que convierta la tupla colors en un diccionario.
print(colors_dictionary)
Revisar
Solución muestra:
colors_dictionary = dict(colors)
print(colors_dictionary)
Ejercicio 7
¿Que ocurrirá cuando se ejecute el siguiente código?
my_dictionary = {"A": 1, "B": 2}
copy_my_dictionary = my_dictionary.copy()
my_dictionary.clear()
print(copy_my_dictionary)
Revisar
Ejercicio 8
¿Cuál es la salida del siguiente programa?
colors = {
"blanco": (255, 255, 255),
"gris": (128, 128, 128),
"rojo": (255, 0, 0),
"verde": (0, 128, 0)
}
Revisar
4.7.1.1 Excepciones
Intentaremos mostrártelo.
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 tu 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.
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.
¿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.
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.
type(value) is int
4.7.1.3 Excepciones
El Código Python
En el mundo de Python, hay una regla que dice: "Es mejor pedir perdón que pedir
permiso".
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.
• El primero, comienza con la palabra clave reservada try: este es el lugar donde
se coloca el código que se sospecha que es riesgoso y puede terminar en caso de
un error; nota: este tipo de error lleva por nombre excepción, mientras que la
ocurrencia de la excepción se le denomina generar; podemos decir que se genera
(o se generó) una excepción.
• • El segundo, la parte del código que comienza con la palabra clave
reservada except: esta parte fue diseñada para manejar la excepción; depende
de ti lo que quieras hacer aquí: puedes limpiar el desorden o simplemente puede
barrer el problema debajo de la alfombra (aunque se prefiere la primera
solución).
• La palabra clave reservada try marca el lugar donde intentas hacer algo sin
permiso.
• La palabra clave reservada except comienza un lugar donde puedes mostrar tu
talento para disculparte o pedir perdón.
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.
try:
# Es un lugar donde
# tu puedes hacer algo
# sin pedir permiso.
except:
# Es un espacio dedicado
# exclusivamente para pedir perdón.
4.7.1.4 Excepciones
Ahora queremos hacerte una pregunta: ¿Es ValueError la única forma en que el control
podría caer dentro del bloque except ?
try:
value = input('Ingresa un número natural: ')
print('El recíproco de', value, 'es', 1/int(value))
except:
print('No se que hacer con', value)
4.7.1.5 Excepciones
¿Es posible? Por supuesto que lo es. Hay al menos dos enfoques que puedes
implementar aquí.
Afortunadamente, Python ofrece una forma más sencilla de afrontar este tipo de
desafíos.
4.7.1.6 Excepciones
Nota:
try:
value = input('Ingresa un número natural: ')
print('El recíproco de', value, 'es', 1/int(value))
except ValueError:
print('No se que hacer con', value)
except ZeroDivisionError:
print('La división entre cero no está permitida en nuestro Universo.')
except:
print('Ha sucedido algo extraño, ¡lo siento!')
4.7.1.7 Excepciones
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?
Si, estos son: /, //, y %.
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:
short_list = [1]
one_value = short_list[0.5]
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:
short_list = [1]
short_list.append(2)
short_list.depend(3)
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.
4.7.1.8 Excepciones
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.
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.
En nuestro ejemplo, el conjunto debe contener al menos tres valores flotantes: uno
positivo, uno negativo y cero.
if temperature > 0:
print("Por encima de cero")
elif temperature < 0:
print("Por debajo de cero")
else:
print("Cero")
4.7.1.9 Excepciones
¿Cómo es eso posible? ¿Por qué Python pasa por alto un error de desarrollador tan
evidente?
if temperature > 0:
print("Por encima de cero")
elif temperature < 0:
prin("Por debajo de cero")
else:
print("Cero")
4.7.1.10 Excepciones
Pruebas y probadores
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?
Las capturas de pantalla que ves al lado muestran el depurador IDLE durante una simple
sesión de depuración.
Puedes ver cómo el depurador visualiza las variables y los valores de los parámetros.
Observa la pila de llamadas que muestra la cadena de invocaciones que van desde la
función actualmente ejecutada hacia el intérprete.
4.7.1.11 Excepciones
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
tu 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.
4.7.1.12 Excepciones
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.
print("Hola, ¡Mundo!)
Provocará un error del tipo SyntaxError, y da como resultado el siguiente (o
similar) mensaje que se muestra en la consola:
print("Hola, ¡Mundo!)
^
SyntaxError: EOL while scanning string literal
salida
print(1/0)
print(1/0)
salida
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 mas; 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.
while True:
try:
number = int(input("Ingresa un número entero: "))
print(number/2)
break
except:
print("Advertencia: el valor ingresado no es un número válido. Intenta de nuevo...")
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.
while True:
try:
number = int(input("Ingresa un número entero: "))
print(5/number)
break
except ValueError:
print("Valor incorrecto.")
except ZeroDivisionError:
print("Lo siento. No puedo dividir entre cero.")
except:
print("No se que hacer...")
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).
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.
Ejercicio
try:
value = int(input("Ingresa un número entero: "))
print(value/value)
except ValueError:
print("Entrada incorrecta...")
except ZeroDivisionError:
print("Entrada errónea...")
except:
print("¡Buuuu!")
Revisar
PROYECTO
Tiempo Estimado
30-60 minutos
Nivel de Dificultad
Medio/Difícil
Objetivos
• Perfeccionar las habilidades del estudiante al emplear Python para resolver
problemas complejos.
• La integración de técnicas de programación en un solo programa consistente de
varias partes.
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
Implementa las siguientes características:
• 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:
board[row][column]
• 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.
for i in range(10):
print(randrange(8))
def DisplayBoard(board):
# La función acepta un parámetro el cual contiene el estado actual del tablero
# y lo muestra en la consola.
def EnterMove(board):
# La función acepta el estado actual del tablero y pregunta al usuario acerca de su
movimiento,
# verifica la entrada y actualiza el tablero acorde a la decisión del usuario.
def MakeListOfFreeFields(board):
# La función examina el tablero y construye una lista de todos los cuadros vacíos.
# La lista esta compuesta por tuplas, cada tupla es un par de números que indican la
fila y columna.
def DrawMove(board):
# La función dibuja el movimiento de la máquina y actualiza el tablero.
4.7.2.2 Terminación del Módulo
Ahora estás listo para tomar el cuestionario del módulo e intentar el Desafío Final:
Examen del Módulo 4, el cual te ayudará a determinar que tanto has aprendido hasta
ahora.
¡Felicidades!
Has completado Fundamentos de Python 1
¡Bien hecho! Has llegado al final del curso Fundamentos de Python 1, y has completado
un paso importante en tu educación de programación en Python.
Ahora estás preparado para tomar el desafío final, el Examen Global, que te ayudará a
revisar la información más importante que has leído y probar las habilidades y
conocimientos que has adquirido a lo largo del curso.
Habiendo completado el curso, también estás preparado para presentar el examen de la
certificación PCEP - Certified Entry-Level Python Programmer, el cual es un paso
intermedio para la certificación PCAP - Certified Associate in Python Programming, así
como el punto de partida para iniciar una carrera en desarrollo de software,
programación en Python y tecnologías relacionadas.
¿Listo?
Fundamentos de Python 2 - Módulo 1
Fundamentos de Python 2:
Módulo 1
Módulos, Paquetes y PIP
1.1.1.1 Módulos
¿Qué es un módulo?
El código de computadora tiene una tendencia a crecer. Podemos decir que el código que
no crece probablemente sea completamente inutilizable o esté abandonado. Un código
real, deseado y ampliamente utilizado se desarrolla continuamente, ya que tanto las
demandas de los usuarios como sus expectativas se desarrollan de manera diferente.
El código creciente es, de hecho, un problema creciente. Un código más grande siempre
significa un mantenimiento más difícil. La búsqueda de errores siempre es más fácil
cuando el código es más pequeño (al igual que encontrar una rotura mecánica es más
simple cuando la maquinaria es más simple y pequeña).
Además, cuando se espera que el código que se está creando sea realmente grande
(puedes usar el número total de líneas de código como una medida útil, pero no muy
precisa, del tamaño del código) entonces, se deseará, o más bien, habrá la necesidad de
dividirlo en muchas partes, implementado en paralelo por unos cuantos, una docena,
varias docenas o incluso varios cientos de desarrolladores.
Por supuesto, esto no se puede hacer usando un archivo fuente grande, el cual esta
siendo editado por todos los programadores al mismo tiempo. Esto seguramente
conducirá a un desastre.
Si se desea que dicho proyecto de software se complete con éxito, se deben tener los
medios que permitan:
• La interfaz de usuario (la parte que se comunica con el usuario mediante widgets
y una pantalla gráfica).
• La lógica (la parte que procesa los datos y produce resultados).
Cada una de estas partes se puede (muy probablemente) dividir en otras más pequeñas,
y así sucesivamente. Tal proceso a menudo se denomina descomposición.
Por ejemplo, si te pidieran organizar una boda, no harías todo tu mismo: encontrarías
una serie de profesionales y dividirías la tarea entre todos.
¿Cómo se divide una pieza de software en partes separadas pero cooperantes? Esta es la
pregunta. Los módulos son la respuesta.
Todos estos módulos, junto con las funciones integradas, forman la Biblioteca Estándar
de Python - un tipo especial de biblioteca donde los módulos desempeñan el papel de
libros (incluso podemos decir que las carpetas desempeñan el papel de estanterías). Si
deseas ver la lista completa de todos los "volúmenes" recopilados en esa biblioteca, se
puede encontrar aquí: https://docs.python.org/3/library/index.html.
Cada módulo consta de entidades (como un libro consta de capítulos). Estas entidades
pueden ser funciones, variables, constantes, clases y objetos. Si se sabe como acceder a
un módulo en particular, se puede utilizar cualquiera de las entidades que almacena.
Comencemos la discusión con uno de los módulos más utilizados, el que lleva por
nombre math . Su nombre habla por sí mismo: el módulo contiene una rica colección de
entidades (no solo funciones) que permiten a un programador implementar
efectivamente cálculos que exigen el uso de funciones matemáticas, como sen() o log().
Importando un módulo
Para que un módulo sea utilizable, hay que importarlo (piensa en ello como sacar un libro
del estante). La importación de un módulo se realiza mediante una instrucción
llamada import . Nota: import es también una palabra clave reservada (con todas sus
implicaciones).
Supongamos que deseas utilizar dos entidades proporcionadas por el módulo math :
• Un símbolo (constante) que representa un valor preciso (tan preciso como sea
posible usando aritmética de punto flotante doble) de π (aunque usar una letra
griega para nombrar una variable es totalmente posible en Python, el símbolo se
llama pi: es una solución más conveniente, especialmente para esa parte del
mundo que ni tiene ni va a usar un Teclado Griego).
• Una función llamada sin() (el equivalente informático de la función
matemática seno).
Ambas entidades están disponibles a través del módulo math , pero la forma en que se
pueden usar depende en gran medida de como se haya realizado la importación.
import math
La cláusula contiene:
La instrucción puede colocarse en cualquier parte del código, pero debe colocarse antes
del primer uso de cualquiera de las entidades del módulo.
import math
import sys
o enumerando los módulos después de la palabra clave reservada import , como aquí:
La instrucción importa dos módulos, primero uno llamado math y luego un segundo
llamado sys .
Esta singularidad se puede lograr de muchas maneras, por ejemplo, mediante el uso de
apodos junto con los nombres (funcionará dentro de un grupo pequeño como una clase
en una escuela) o asignando identificadores especiales a todos los miembros del grupo
(el número de Seguro Social de EE. UU. es un buen ejemplo de tal práctica).
Esto significa que puedes tener tus propias entidades llamadas sin o pi y no serán
afectadas en alguna manera por la importación.
En este punto, es posible que te estes preguntando como acceder al pi el cual viene del
módulo math .
Para hacer esto, se debe de mandar llamar el pi con el nombre del módulo original.
math.pi
math.sin
Es sencillo, se pone:
Este primer ejemplo no será muy avanzado: solo se desea imprimir el valor de sin((½π).
Nota: el eliminar cualquiera de las dos indicaciones del nombre del módulo hará que el
código sea erróneo. No hay otra forma de entrar al namespace de math si se hizo lo
siguiente:
import math
import math
print(math.sin(math.pi/2))
0.99999999
1.0
salida
import math
def sin(x):
if 2 * x == pi:
return 0.99999999
else:
return None
pi = 3.14
print(sin(pi/2))
print(math.sin(math.pi/2))
• Las entidades listadas son las únicas que son importadas del módulo indicado.
• Los nombres de las entidades importadas pueden ser accedidas dentro del código
sin especificar el nombre del módulo de origen.
print(math.e)
Aquí está:
print(sin(pi/2))
El resultado debe de ser el mismo que el anterior, se han empleado las mismas
entidades: 1.0 . Copia y pega el código en el editor, y ejecuta el programa.
¿El código parece más simple? Quizás, pero el aspecto no es el único efecto de este tipo
de importación. Veamos más a detalle esto.
1 pi = 3.14
2
3
4 def sin(x):
5 if 2 * x == pi:
6 return 0.99999999
7 else:
8 return None
9
10
11 print(sin(pi / 2))
12
13 from math import sin, pi
14
15 print(sin(pi / 2))
print(sin(pi / 2))
pi = 3.14
def sin(x):
if 2 * x == pi:
return 0.99999999
else:
return None
print(sin(pi / 2))
1.1.1.9 Importando un módulo | * y as
Importando un módulo: *
En el tercer método, la sintaxis del import es una forma más agresiva que la presentada
anteriormente:
¿Es conveniente? Sí, lo es, ya que libera del deber de enumerar todos los nombres que se
necesiten.
¿Es inseguro? Sí, a menos que conozcas todos los nombres proporcionados por el
módulo, es posible que no puedas evitar conflictos de nombres. Trata esto como una
solución temporal e intenta no usarlo en un código regular.
La creación de un alias se realiza junto con la importación del módulo, y exige la siguiente
forma de la instrucción import:
El "module" identifica el nombre del módulo original mientras que el "alias" es el nombre
que se desea usar en lugar del original.
import math as m
print(m.sin(m.pi/2))
Nota: después de la ejecución exitosa de una importación con alias, el nombre original
del módulo se vuelve inaccesible y no debe ser utilizado.
A su vez, cuando usa la variante from module import name y se necesita cambiar el
nombre de la entidad, se crea un alias para la entidad. Esto hará que el nombre sea
reemplazado por el alias que se elija.
La frase name as alias puede repetirse: puedes emplear comas para separar las frases,
como a continuación:
Ahora estás familiarizado con los conceptos básicos del uso de módulos. Permítenos
mostrarte algunos módulos y algunas de sus entidades útiles.
import math as m
print(m.sin(m.pi/2))
1.1.1.11 RESUMEN DE SECCIÓN
Puntos Claves
1. Si deseas importar un módulo como un todo, puedes hacerlo usando la
sentencia import nombre_del_módulo . Puedes importar más de un módulo a la vez
utilizando una lista separada por comas. Por ejemplo:
import mod1
import mod2, mod3, mod4
import mod2
import mod3
import mod4
import my_module
result = my_module.my_function(my_module.my_data)
El fragmento de código utiliza dos entidades que provienen del módulo my_module : una
función llamada my_function() y una variable con el nombre my_data . Ambos
nombres deben tener el prefijo my_module. Ninguno de los nombres de entidad
importados entra en conflicto con los nombres idénticos existentes en el namespace de
tu código.
3. Se te permite no solo importar un módulo como un todo, sino también importar solo
entidades individuales de él. En este caso, las entidades importadas no deben
especificar el prefijo cuando son empleadas. Por ejemplo:
result = my_function(my_data)
Nota: la variante de esta importación no se recomienda debido a las mismas razones que
antes (la amenaza de un conflicto de nombres es aún más peligrosa aquí).
result = fun(dat)
Ejercicio 1
import mint
Revisar
mint.make_money()
Ejercicio 2
Revisasr
make_money()
Ejercicio 3
Has escrito una función llamada make_money por tu cuenta. Necesitas importar una
función con el mismo nombre del módulo mint y no deseas cambiar el nombre de
ninguno de tus nombres previamente definidos. ¿Qué variante de la
sentencia import puede ayudarte con el problema?
Revisar
# solución de muestra
from mint import make_money as make_more_money
Ejercicio 4
Revisar
make_money()
Existe una condición: el módulo debe haberse importado previamente como un todo (es
decir, utilizar la instrucción import module - from module no es suficiente).
La función devuelve una lista ordenada alfabéticamente la cual contiene todos los
nombres de las entidades disponibles en el módulo:
dir(module)
Nota: Si el nombre del módulo tiene un alias, debes usar el alias, no el nombre original.
Usar la función dentro de un script normal no tiene mucho sentido, pero aún así, es
posible.
Por ejemplo, se puede ejecutar el siguiente código para imprimir los nombres de todas
las entidades dentro del módulo math :
import math
salida
¿Has notado los nombres extraños que comienzan con __ al inicio de la lista? Se hablará
más sobre ellos cuando hablemos sobre los problemas relacionados con la escritura de
módulos propios.
El emplear la función dir() dentro de un código puede no parecer muy útil; por lo
general, se desea conocer el contenido de un módulo en particular antes de escribir y
ejecutar el código.
import math
dir(math)
Se han elegido algunas arbitrariamente, pero esto no significa que las funciones no
mencionadas aquí sean menos significativas. Tómate el tiempo para revisar las demás
por ti mismo: no tenemos el espacio ni el tiempo para hablar de todas a detalle.
• sin(x) → el seno de x.
• cos(x) → el coseno de x.
• tan(x) → la tangente de x.
• asin(x) → el arcoseno de x.
• acos(x) → el arcocoseno de x.
• atan(x) → el arcotangente de x.
Estas funciones toman un argumento (verifican que sea correcto) y devuelven una
medida de un ángulo en radianes.
Para trabajar eficazmente con mediciones de ángulos, el módulo math proporciona las
siguientes entidades:
from math import pi, radians, degrees, sin, cos, tan, asin
ad = 90
ar = radians(ad)
ad = degrees(ar)
print(ad == 90.)
print(ar == pi / 2.)
print(sin(ar) / cos(ar) == tan(ar))
print(asin(sin(ar)) == ar)
• e → una constante con un valor que es una aproximación del número de Euler (e).
• exp(x) → encontrar el valor de ex.
• log(x) → el logaritmo natural de x.
• log(x, b) → el logaritmo de x con base b.
• log10(x) → el logaritmo decimal de x (más preciso que log(x, 10) ).
• log2(x) → el logaritmo binario de x (más preciso que log(x, 2) ).
print(pow(e, 1) == exp(log(e)))
print(pow(2, 2) == exp(2 * log(2)))
print(log(e, e) == exp(0))
1.2.1.4 Módulos Útiles | math
x = 1.4
y = 2.6
print(floor(x), floor(y))
print(floor(-x), floor(-y))
print(ceil(x), ceil(y))
print(ceil(-x), ceil(-y))
print(trunc(x), trunc(y))
print(trunc(-x), trunc(-y))
Los algoritmos no son aleatorios, son deterministas y predecibles. Solo aquellos procesos
físicos que se salgan completamente de nuestro control (como la intensidad de la
radiación cósmica) pueden usarse como fuente de datos aleatorios reales. Los datos
producidos por computadoras deterministas no pueden ser aleatorios de ninguna
manera.
La duración de un ciclo en el que todos los valores semilla son únicos puede ser muy
largo, pero no es infinito: tarde o temprano los valores iniciales comenzarán a repetirse y
los valores generadores también se repetirán. Esto es normal. Es una característica, no un
error.
El factor aleatorio del proceso puede ser aumentado al establecer la semilla tomando un
número de la hora actual - esto puede garantizar que cada ejecución del programa
comience desde un valor semilla diferente (por lo tanto, usará diferentes números
aleatorios).
for i in range(5):
print(random())
0.9535768927411208
0.5312710096244534
0.8737691983477731
0.5896799172452125
0.02116716297022092
salida de muestra
La función seed
seed(0)
for i in range(5):
print(random())
Debido al hecho de que la semilla siempre se establece con el mismo valor, la secuencia
de valores generados siempre se ve igual.
0.844421851525
0.75795440294
0.420571580831
0.258916750293
0.511274721369
salida de muestra
¿Y tú?
Nota: tus valores pueden ser ligeramente diferentes si tu sistema utiliza aritmética de
punto flotante más precisa o menos precisa, pero la diferencia se verá bastante lejos del
punto decimal.
Si deseas valores aleatorios enteros, una de las siguientes funciones encajaría mejor:
• randrange(fin)
• randrange(inico, fin)
• randrange(inicio, fin, incremento)
• randint(izquierda, derecha)
• range(fin)
• range(inicio, fin)
• range(inicio, fin, incremento)
Observa el código en el editor. Este programa generará una línea que consta de tres
ceros y un cero o un uno en el cuarto lugar.
for i in range(10):
print(randint(1, 10), end=',')
9,4,5,4,5,8,9,4,8,4,
salida de muestra
Como puedes ver, esta no es una buena herramienta para generar números para la
lotería. Afortunadamente, existe una mejor solución que escribir tu propio código para
verificar la singularidad de los números "sorteados".
• choice(secuencia)
• sample(secuencia, elementos_a_elegir=1)
En otras palabras, la función elige algunos de los elementos de entrada, devolviendo una
lista con la elección. Los elementos de la muestra se colocan en orden aleatorio. Nota
que elementos_a_elegir no debe ser mayor que la longitud de la secuencia de entrada.
print(choice(my_list))
print(sample(my_list, 5))
print(sample(my_list, 10))
4
[3, 1, 8, 9, 10]
[10, 8, 5, 1, 6, 4, 3, 9, 7, 2]
salida
Imagina el entorno de tu programa como una pirámide que consta de varias capas o
plataformas.
Esto significa que algunas de las acciones del programa tienen que recorrer un largo
camino para ejecutarse con éxito, imagina que:
• Tu código quiere crear un archivo, por lo que invoca una de las funciones de
Python.
• Python acepta la orden, la reorganiza para cumplir con los requisitos del sistema
operativo local, es como poner el sello "aprobado" en una solicitud y lo envía (esto
puede recordarte una cadena de mando).
• El SO comprueba si la solicitud es razonable y válida (por ejemplo, si el nombre del
archivo se ajusta a algunas reglas de sintaxis) e intenta crear el archivo. Tal
operación, aparentemente es muy simple, no es atómica: consiste de muchos
pasos menores tomados por:
• El hardware, el cual es responsable de activar los dispositivos de almacenamiento
(disco duro, dispositivos de estado sólido, etc.) para satisfacer las necesidades del
sistema operativo.
Por lo general, no eres consciente de todo ese alboroto: quieres que se cree el archivo y
eso es todo.
Pero a veces quieres saber más, por ejemplo, el nombre del sistema operativo que aloja
Python y algunas características que describen el hardware que aloja el sistema
operativo.
Hay un módulo que proporciona algunos medios para permitir saber dónde se encuentra
y qué componentes funcionan. El módulo se llama platform. Veamos algunas de las
funciones que brinda para ti.
Existe también una función que puede mostrar todas las capas subyacentes en un solo
vistazo, llamada platform . Simplemente devuelve una cadena que describe el entorno;
por lo tanto, su salida está más dirigida a los humanos que al procesamiento
automatizado (lo verás pronto).
Windows-Vista-6.0.6002-SP2
Windows-Vista-6.0.6002-SP2
Windows-Vista
salida
Linux-3.18.62-g6-x86_64-Intel-R-_Core-TM-_i3-2330M_CPU_@_2.20GHz-
with-gentoo-2.3
Linux-3.18.62-g6-x86_64-Intel-R-_Core-TM-_i3-2330M_CPU_@_2.20GHz-
with-gentoo-2.3
Linux-3.18.62-g6-x86_64-Intel-R-_Core-TM-_i3-2330M_CPU_@_2.20GHz-
with-glibc2.3.4
salida
Linux-4.4.0-1-rpi2-armv7l-with-debian-9.0
Linux-4.4.0-1-rpi2-armv7l-with-debian-9.0
Linux-4.4.0-1-rpi2-armv7l-with-glibc2.9
salida
También puedes ejecutar el programa en el IDLE de tu máquina local para verificar que
salida tendrá.
print(platform())
print(platform(1))
print(platform(0, 1))
1.2.1.11 Módulos Útiles | platform
En ocasiones, es posible que solo se desee conocer el nombre genérico del procesador
que ejecuta el sistema operativo junto con Python y el código, una función
llamada machine() te lo dirá. Como anteriormente, la función devuelve una cadena.
x86
salida
x86_64
salida
armv7l
salida
print(machine())
La función processor() devuelve una cadena con el nombre real del procesador (si lo
fuese posible).
x86
salida
armv7l
salida
Una función llamada system() devuelve el nombre genérico del sistema operativo en
una cadena.
Windows
salida
Linux
salida
Linux
salida
6.0.6002
salida
print(version())
Si necesitas saber que versión de Python está ejecutando tu código, puedes verificarlo
utilizando una serie de funciones dedicadas, aquí hay dos de ellas:
• python_implementation() → devuelve una cadena que denota la
implementación de Python (espera CPython aquí, a menos que decidas utilizar
cualquier rama de Python no canónica).
• python_version_tuple() → devuelve una tupla de tres elementos la cual
contiene:
o La parte mayor de la versión de Python.
o La parte menor.
o El número del nivel de parche.
CPython
3
7
7
salida de muestra
print(python_implementation())
Estos módulos no están (y no serán) distribuidos junto con Python, o a través de canales
oficiales, lo que hace que el universo de Python sea más amplio, casi infinito.
Puntos Clave
1. Una función llamada dir() puede mostrarte una lista de las entidades contenidas
dentro de un módulo importado. Por ejemplo:
import os
dir(os)
Imprime una lista de todo el contenido del módulo os el cual, puedes usar en tu código.
Ejercicio 1
¿Cuál es el valor esperado de la variable result después de que se ejecuta el siguiente
código?
import math
result = math.e == math.exp(1)
Revisar
True
Ejercicio 2
(Completa el enunciado) Establecer la semilla del generador con el mismo valor cada vez
que se ejecuta tu programa garantiza que ...
Revisar
... los valores pseudoaleatorios emitidos desde el módulo random serán exactamente los
mismos.
Ejercicio 3
¿Cuál de las funciones del módulo platform utilizarías para determinar el nombre del
CPU que corre dentro de tu computadora?
Revisar
La función processor()
Ejercicio 4
¿Cuál es el resultado esperado del siguiente fragmento de código?
import platform
print(len(platform.python_version_tuple()))
Revisar
¿Qué es un paquete?
Escribir tus propios módulos no difiere mucho de escribir scripts comunes.
Existen algunos aspectos específicos que se deben tomar en cuenta, pero definitivamente
no es algo complicado. Lo verás pronto.
1
2
module.py
Se necesitan dos archivos para realizar estos experimentos. Uno de ellos será
el módulo en sí. Está vacío ahora. No te preocupes, lo vas a llenar con código pronto.
El archivo lleva por nombre module.py. No muy creativo, pero es simple y claro.
1 import module
2
main.py
Nota: ambos archivos deben estar ubicados en la misma carpeta. Te recomendamos
crear una carpeta nueva y vacía para ambos archivos. Esto hará que las cosas sean más
fáciles.
Inicia el IDLE (o cualquier otro que prefieras) y ejecuta el archivo main.py. ¿Qué es lo que
ves?
No deberías ver nada. Esto significa que Python ha importado con éxito el contenido del
archivo module.py.
No importa que el módulo esté vacío por ahora. El primer paso ya está hecho, pero antes
de dar el siguiente paso, queremos que eches un vistazo a la carpeta en la que se
encuentran ambos archivos.
Puedes mirar dentro del archivo: el contenido es completamente ilegible para los
humanos. Tiene que ser así, ya que el archivo está destinado solo para uso el uso de
Python.
Cuando Python importa un módulo por primera vez, traduce el contenido a una forma
algo compilada.
Gracias a eso, cada importación posterior será más rápida que interpretar el código
fuente desde cero.
Python puede verificar si el archivo fuente del módulo ha sido modificado (en este caso,
el archivo pyc será reconstruido) o no (cuando el archivo pyc pueda ser ejecutado al
instante). Este proceso es completamente automático y transparente, no tiene que ser
tomando en cuenta.
1.3.1.3 Módulos y Paquetes
module.py
¿Puedes notar alguna diferencia entre un módulo y un script ordinario? No hay ninguna
hasta ahora.
Es posible ejecutar este archivo como cualquier otro script. Pruébalo por ti mismo.
main.py
Ejecuta el archivo. ¿Qué ves? Con suerte, verás algo como esto:
Nota: la inicialización se realiza sólo una vez, cuando se produce la primera importación,
por lo que las asignaciones realizadas por el módulo no se repiten innecesariamente.
A primera vista, se puede pensar que mod1 será importado dos veces -
afortunadamente, solo se produce la primera importación. Python recuerda los módulos
importados y omite silenciosamente todas las importaciones posteriores.
module.py
__main__
salida
module
salida
if __name__ == "__main__":
print("Yo prefiero ser un módulo")
else:
print("Me gusta ser un módulo")
module.py
Sin embargo, existe una forma más inteligente de utilizar la variable. Si escribes un
módulo lleno de varias funciones complejas, puedes usarla para colocar una serie de
pruebas para verificar si las funciones trabajan correctamente.
Cada vez que modifiques alguna de estas funciones, simplemente puedes ejecutar el
módulo para asegurarte de que sus enmiendas no estropeen el código. Estas pruebas se
omitirán cuando el código se importe como un módulo.
counter = 0
if __name__ == "__main__":
print("Yo prefiero ser un módulo")
else:
print("Me gusta ser un módulo")
module.py
main.py
Como puedes ver, el archivo principal intenta acceder a la variable de contador del
módulo. ¿Es esto legal? Sí lo es. ¿Es utilizable? Claro. ¿Es seguro?
Eso depende: si confías en los usuarios de tu módulo, no hay problema; sin embargo, es
posible que no desees que el resto del mundo vea tu variable personal o privada.
Solo puedes informar a tus usuarios que esta es tu variable, que pueden leerla, pero que
no deben modificarla bajo ninguna circunstancia.
Esto se hace anteponiendo al nombre de la variable _ (un guión bajo) o __ (dos guiones
bajos), pero recuerda, es solo un acuerdo. Los usuarios de tu módulo pueden obedecerlo
o no.
#!/usr/bin/env python3
__counter = 0
def suml(the_list):
global __counter
__counter += 1
the_sum = 0
for element in the_list:
the_sum += element
return the_sum
def prodl(the_list):
global __counter
__counter += 1
prod = 1
for element in the_list:
prod *= element
return prod
if __name__ == "__main__":
print("Yo prefiero ser un módulo, pero puedo realizar algunas
pruebas por ti")
my_list = [i+1 for i in range(5)]
print(suml(my_list) == 15)
print(prodl(my_list) == 120)
module.py
main.py
Para responder a esta pregunta, tenemos que hablar sobre como Python busca los
módulos. Hay una variable especial (en realidad una lista) que almacena todas las
ubicaciones (carpetas o directorios) que se buscan para encontrar un módulo que ha sido
solicitado por la instrucción import.
La variable se llama path (ruta), y es accesible a través del módulo llamado sys . Así es
como puedes verificar su valor:
import sys
for p in sys.path:
print(p)
C:\Users\user
C:\Users\user\AppData\Local\Programs\Python\Python36-32\python36.zip
C:\Users\user\AppData\Local\Programs\Python\Python36-32\DLLs
C:\Users\user\AppData\Local\Programs\Python\Python36-32\lib
C:\Users\user\AppData\Local\Programs\Python\Python36-32
C:\Users\user\AppData\Local\Programs\Python\Python36-32\lib\site-
packages
salida de muestra
Nota: la carpeta en la que comienza la ejecución aparece en el primer elemento de la
ruta.
Ten en cuenta también que: hay un archivo zip listado como uno de los elementos de la
ruta, esto no es un error. Python puede tratar los archivos zip como carpetas ordinarias,
esto puede ahorrar mucho almacenamiento.
¿Puedes predecir cómo resolver este problema? Puedes resolverlo agregando una
carpeta que contenga el módulo a la variable de ruta (la variable path), es completamente
modificable.
path.append('..\\modules')
import module
main.py
Nota:
Revisar
Debido a que una diagonal invertida se usa para escapar de otros caracteres, si
deseas obtener solo una diagonal invertida, debes escapar.
• Hemos utilizado el nombre relativo de la carpeta: esto funcionará si inicia el
archivo main.py directamente desde la carpeta de inicio, y no funcionará si el
directorio actual no se ajusta a la ruta relativa; siempre puedes usar una ruta
absoluta, como esta:
path.append('C:\\Users\\user\\py\\modules')
def funA():
return "Alpha"
if __name__ == "__main__":
print("Yo prefiero ser un módulo")
alpha.py
Nota: hemos presentado todo el contenido solo para el módulo alpha.py, supongamos
que todos los módulos tienen un aspecto similar (contienen una función
denominada funX , donde X es la primera letra del nombre del módulo).
Construyamos un árbol que refleje las dependencias proyectadas entre los módulos.
Tal estructura es casi un paquete (en el sentido de Python). Carece del detalle fino para
ser funcional y operativo. Lo completaremos en un momento.
Por ejemplo:
• La ubicación de una función llamada funT() del paquete tau puede describirse
como:
extra.good.best.tau.funT()
• Una función marcada como:
extra.ugly.psi.funP()
Proviene del módulo psi el cual esta almacenado en el subpaquete ugly del
paquete extra.
La primer pregunta tiene una respuesta sorprendente: los paquetes, como los módulos,
pueden requerir inicialización.
En su lugar, debes usar un truco diferente: Python espera que haya un archivo con un
nombre muy exclusivo dentro de la carpeta del paquete: __init__.py.
El contenido del archivo se ejecuta cuando se importa cualquiera de los módulos del
paquete. Si no deseas ninguna inicialización especial, puedes dejar el archivo vacío, pero
no debes omitirlo.
Nota: no solo la carpeta raiz puede contener el archivo __init.py__, también puedes
ponerlo dentro de cualquiera de sus subcarpetas (subpaquetes). Puede ser útil si algunos
de los subpaquetes requieren tratamiento individual o un tipo especial de inicialización.
import extra.iota
print(extra.iota.funI())
main2.py
Nota:
main2.py
path.append('..\\packages')
import extra.good.best.sigma
from extra.good.best.tau import funT
print(extra.good.best.sigma.funS())
print(funT())
main2.py
path.append('..\\packages')
print(sig.funS())
print(alp.funA())
main2.py
path.append('..\\packages\\extrapack.zip')
print(sig.funS())
print(alp.funA())
print(funI())
print(funB())
main2.py
Si deseas realizar tus propios experimentos con el paquete que hemos creado, puedes
descargarlo a continuación. Te alentamos a que lo hagas.
Puntos Clave
1. Mientras que un módulo está diseñado para acoplar algunas entidades relacionadas
como funciones, variables o constantes, un paquete es un contenedor que permite el
acoplamiento de varios módulos relacionados bajo un mismo nombre. Dicho contenedor
se puede distribuir tal cual (como un lote de archivos implementados en un subárbol de
directorio) o se puede empaquetar dentro de un archivo zip.
3. Si deseas decirle al usuario del módulo que una entidad en particular debe tratarse
como privada (es decir, no debe usarse explícitamente fuera del módulo), puedes marcar
su nombre con el prefijo _ o __ . No olvides que esto es solo una recomendación, no una
orden.
Ejercicio 1
Deseas evitar que el usuario de tu módulo ejecute tu código como un script ordinario.
¿Cómo lograrías tal efecto?
Revisar
import sys
if __name__ == "__main__":
print "¡No hagas eso!"
sys.exit()
Ejercicio 2
Algunos paquetes adicionales y necesarios se almacenan dentro del
directorio D:\Python\Project\Modules . Escribe un código asegurándote de que Python
recorra el directorio para encontrar todos los módulos solicitados.
Revisar
import sys
Ejercicio 3
El directorio mencionado en el ejercicio anterior contiene un subárbol con la siguiente
estructura:
abc
|__ def
|__ mymodule.py
Revisar
import abc.def.mymodule
Por supuesto, no tiene ningún sentido hacer que todos los usuarios de Python escriban
su código desde cero, manteniéndolos perfectamente aislados del mundo exterior y de
los logros de otros programadores. Esto sería antinatural y contraproducente.
Como sabes, Python se creó como software de código abierto, y esto también funciona
como una invitación para que todos los programadores mantengan todo el ecosistema
de Python como un entorno abierto, amigable y libre. Para que el modelo funcione y
evolucione, se deben proporcionar algunas herramientas adicionales, herramientas que
ayuden a los creadores a publicar, mantener y cuidar su código.
Estas mismas herramientas deberían ayudar a los usuarios a hacer uso del código, tanto
el código ya existente como el código nuevo que aparece todos los días. Gracias a eso,
escribir código nuevo para nuevos desafíos no es como construir una casa nueva,
comenzando por los cimientos.
Para hacer girar este mundo, se deben establecer y mantener en movimiento dos
entidades básicas: un repositorio centralizado de todos los paquetes de software
disponibles; y una herramienta que permite a los usuarios acceder al repositorio . Ambas
entidades ya existen y se pueden utilizar en cualquier momento.
1.4.1.2 Instalador de Paquetes de Python (PIP)
En Julio de 2021 fuimos al sitio mencionado, y descubrimos que PyPI albergaba 315,000
proyectos, que constan de más de 4,500,000 archivos administrados por 520,000
usuarios.
Nos referimos al repositorio como una tienda, porque vas allí por las mismas razones por
las que vas a otras tiendas: para satisfacer tus necesidades. Si quieres un poco de queso,
ve a la quesería. Si deseas una pieza de software, ve a la tienda de software.
Afortunadamente, la analogía termina aquí: no necesitas dinero para sacar algún
software de la tienda de repositorios.
OK, se comprende lo de la tienda, pero ¿qué tiene que ver el queso con Python?
The Cheese Shop (La Tienda de Quesos) es uno de los sketches más famosos de Monty
Python. Representa la aventura surrealista de un inglés que intenta comprar queso.
Desafortunadamente, la tienda que visita (llamada inmodestamente Ye National Cheese
Emporium) no tiene queso en existencia.
Por supuesto, está destinado a ser irónico. Como ya sabes, PyPI tiene una gran cantidad
de software en stock y está disponible las 24 horas del día, los 7 días de la semana. Tiene
todo el derecho a identificarse como Ye International Python Software Emporium.
1.4.1.4 Instalador de Paquetes de Python (PIP)
No, no has escuchado mal. Solo pip. Es otro acrónimo, claro, pero su naturaleza es más
compleja que el PyPI mencionado anteriormente, ya que es un ejemplo de acrónimo
recursivo, lo que significa que el acrónimo se refiere a sí mismo, lo que significa que
explicarlo es un proceso infinito.
¿Por qué? Porque pip significa "pip instala paquetes", y el pip dentro de "pip instala
paquetes" significa "pip instala paquetes" y ...
Por cierto, hay algunos otros acrónimos recursivos muy famosos. Uno de ellos es Linux,
que se puede interpretar como "Linux no es Unix".
1.4.1.5 Instalador de Paquetes de Python (PIP)
Algunas instalaciones de Python vienen con pip, otras no. Además, no solo depende del
sistema operativo que utilices, aunque este es un factor muy importante.
pip en MS Windows
El instalador de Python para MS Windows ya contiene pip, por lo que no es necesario
seguir ningún otro paso para instalarlo. Desafortunadamente, si la variable PATH está
mal configurada, es posible que pip no esté disponible.
• pip --version
•
• En el escenario más optimista (y realmente queremos que eso suceda) verás algo
como esto:
pip en Linux
Diferentes distribuciones de Linux pueden comportarse de manera diferente cuando se
trata de usar pip. Algunas de ellas (como Gentoo), que están estrechamente vinculadas a
Python y que lo usan internamente, pueden tener pip preinstalado y están
instantáneamente listas para funcionar.
No olvides que algunas distribuciones de Linux pueden utilizar más de una versión de
Python al mismo tiempo, por ejemplo, un Python 2 y un Python 3 coexistiendo uno al
lado del otro. Estos sistemas pueden iniciar Python 2 como la versión predeterminada y
puede ser necesario especificar explícitamente el nombre del programa como python3.
En este caso, puede haber dos pip diferentes identificados como pip (o pip2) y pip3.
Compruébalo cuidadosamente.
pip --version
Una respuesta similar a la que se muestra en la imagen anterior determina que has
iniciado pip desde Python 2, por lo que el siguiente intento debería verse de la siguiente
manera:
pip3 --version
Como puedes ver, ahora estamos seguros de que estamos utilizando la versión adecuada
de pip.
El primero es definitivamente mejor. Aunque hay algunos scripts inteligentes que pueden
descargar e instalar pip ignorando el sistema operativo, te recomendamos que no los
utilices. Este método puede causarte problemas.
Observa, intentamos iniciar pip3 y fallamos. Nuestro sistema operativo (esta vez
usamos Ubuntu Budgie) sugirió usar apt para instalar el paquete llamado python3-pip:
Ese es un buen consejo y lo seguiremos, pero hay que decir que necesitaremos derechos
administrativos para hacerlo. No olvides que diferentes distribuciones de Linux pueden
usar diferentes administradores de paquetes (por ejemplo, podría ser pacman si usas
Arch Linux, o yum usado por distribuciones derivadas de Red Hat).
De cualquier manera, todos estos métodos deberían ayudarte en tener pip (o pip3)
instalado y funcionando.
pip3 --version
y espera la respuesta.
1.4.1.10 Dependencias
Dependencias
Ahora que estamos seguros de que pip está listo para usarse, vamos a limitar nuestro
enfoque a MS Windows solamente, ya que su comportamiento es (debería ser) el mismo
en todos los sistemas operativos, pero antes de comenzar, debemos explicar un asunto
importante e informarte sobre las dependencias.
Imagina que has creado una brillante aplicación de Python llamada redsuspenders, capaz
de predecir los tipos de cambio de la bolsa de valores con un 99% de precisión (por
cierto, si realmente lo haces, contáctanos de inmediato).
Por supuesto, has utilizado algún código existente para lograr este objetivo, por ejemplo,
tu aplicación importa un paquete llamado nyse que contiene algunas funciones y clases
cruciales. Además, el paquete nyse importa otro paquete llamado wallstreet, mientras
que el paquete wallstreet importa otros dos paquetes esenciales llamados bull y bear.
Como probablemente ya habrás adivinado, las conexiones entre estos paquetes son
cruciales, y si alguien decide usar tu código (pero recuerda, ya lo hemos reclamado
primero) también tendrás que asegurarte de que todos los paquetes requeridos están en
su lugar.
Para abreviar, podemos decir que la dependencia es un fenómeno que aparece cada vez
que vas a utilizar un software que depende de otro software. Ten en cuenta que la
dependencia puede incluir (y generalmente incluye) más de un nivel de desarrollo de
software.
¿Significa esto que un usuario potencial del paquete nyse está obligado a rastrear todas
las dependencias e instalar manualmente todos los paquetes necesarios? Eso sería
horrible, ¿no?
¿Cómo nos ocupamos de eso? ¿Todos los usuarios están condenados a visitar el infierno
para ejecutar el código por primera vez?
Afortunadamente no, pip puede hacer todo esto por ti. Puede descubrir, identificar y
resolver todas las dependencias. Además, puede hacerlo de la manera más inteligente,
evitando descargas y reinstalaciones innecesarias.
1.4.1.11 Cómo usar pip
pip help
No olvides que puedes necesitar reemplazar pip por pip3 si tu entorno lo requiere.
La lista producida por pip resume todas las operaciones disponibles, y la última de ellas
es help , la cual acabamos de usar.
Si deseas saber más sobre cualquiera de las operaciones enumeradas, puedes utilizar la
siguiente forma de invocación de pip:
Si deseas saber qué paquetes de Python se han instalado hasta ahora, puedes usar la
operación list , justo como aquí:
pip list
El resultado que verás es bastante impredecible. No te sorprendas si el contenido de tu
pantalla termina siendo completamente diferente. El nuestro es el siguiente:
Como puedes ver, hay dos columnas en la lista, una muestra el nombre del paquete
instalado y la otra muestra la versión del paquete. No podemos predecir el estado de tu
instalación de Python.
Lo único que sabemos con certeza es que tu lista contiene las dos líneas que vemos en
nuestra lista: pip y setuptools. Esto sucede porque el sistema operativo está convencido
de que un usuario que desee pip probablemente necesitará las setuptools (herramientas
de configuración). No está mal.
• Qué paquetes son necesarios para utilizar con éxito el paquete ( Requires: ).
• Qué paquetes necesitan que el paquete se utilice con éxito ( Required-by: ).
Como puedes ver, ambas propiedades están vacías. No dudes en intentar utilizar el
comando show en relación con cualquier otro paquete instalado.
El poder de pip proviene del hecho de que en realidad es una puerta de entrada al
universo del software Python. Gracias a eso, puedes navegar e instalar cualquiera de los
cientos de paquetes listos para usar reunidos en los repositorios de PyPI. No olvides
que pip no puede almacenar todo el contenido de PyPI localmente (es innecesario y no
sería económico).
De hecho, pip usa Internet para consultar PyPI y descargar los datos requeridos. Esto
significa que debes tener una conexión de red en funcionamiento siempre que vayas a
solicitar a pip cualquier cosa que pueda implicar interacciones directas con la
infraestructura de PyPI.
Uno de estos casos ocurre cuando deseas buscar en PyPI para encontrar el paquete
deseado. Este tipo de búsqueda se inicia con el siguiente comando:
Ten en cuenta que algunas búsquedas pueden generar una avalancha real de datos, así
que trata de ser lo más específico posible. Por ejemplo, una consulta de apariencia
inocente como esta:
pip search pip
• Deseas instalar un nuevo paquete solo para ti; no estará disponible para ningún
otro usuario (cuenta) existente en tu computadora; este procedimiento es el único
disponible si no puedes elevar tus permisos y actuar como administrador del
sistema.
• Has decidido instalar un nuevo paquete para todo el sistema; tienes privilegios de
administrador y no tienes miedo de utilizarlos.
Para distinguir entre estas dos acciones, pip emplea una opción dedicada llamada --
user (observa el guión doble). La presencia de esta opción indica a pip que actúe
localmente en nombre de tu usuario sin privilegios de administrador.
Si no agregas esto, pip asume que eres un administrador del sistema y no hará nada para
corregirlo si no lo eres.
El proyecto ha estado en desarrollo desde el año 2000, por lo que es un código maduro y
confiable. Si quieres saber más sobre el proyecto y sobre la comunidad que lo lidera,
visita https://www.pygame.org.
Si eres administrador del sistema, puedes instalar pygame usando el siguiente comando:
Te alentamos a usar:
pip list
import pygame
run = True
width = 400
height = 100
pygame.init()
screen = pygame.display.set_mode((width, height))
font = pygame.font.SysFont(None, 48)
text = font.render("Bienvenido a pygame", True, (255, 255, 255))
screen.blit(text, ((width - text.get_width()) // 2,
(height - text.get_height()) // 2))
pygame.display.flip()
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT\
or event.type == pygame.MOUSEBUTTONUP\
or event.type == pygame.KEYUP:
run = False
Donde -U significa actualizar. Nota: esta forma del comando hace uso de la opción --
user por el mismo propósito que se presentó anteriormente.
Pip querrá saber si estás seguro de la elección que estás tomando; debes estar
preparado para dar la respuesta correcta.
El proceso se ve así:
1.4.1.17 Cómo usar pip
¡Utiliza pip!
Las capacidades de Pip no terminan aquí, pero el conjunto de comandos que te
presentamos es suficiente para comenzar a administrar con éxito los paquetes que no
forman parte de la instalación regular de Python.
Esperamos haberte animado a realizar tus propios experimentos con pip y el universo de
paquetes de Python. PyPI te invita a sumergirte en sus amplios recursos.
Algunos dicen que una de las virtudes más importantes de la programación es la pereza.
No nos malinterpretes, no queremos que pases todo el día durmiendo una siesta en el
sofá y soñando con código de Python.
Puntos Claves
1. Un repositorio (o repo para abreviar) diseñado para recopilar y compartir código
Python gratuito lleva por nombre Python Package Index (PyPI) aunque también es
probable que te encuentres con el nombre de The Cheese Shop (La Tienda de Queso). Su
sitio web está disponible en https://pypi.org/.
2. Para hacer uso de The Cheese Shop, se ha creado una herramienta especializada y su
nombre es pip (pip instala paquetes mientras que pip significa ... ok, no importa). Como
es posible que pip no se implemente como parte de la instalación estándar de Python, es
posible que debas instalarlo manualmente. Pip es una herramienta de consola.
pip --version
pip3 --version
Ejercicio 1
¿De donde proviene el nombre The Cheese Shop?
Revisar
Es una referencia a un viejo sketch de Monty Python que lleva el mismo nombre.
Ejercicio 2
¿Por qué deberías asegurarte de cuál pip o pip3 es el correcto para ti?
Revisar
Cuando Python 2 y Python 3 coexisten en el sistema operativo, es probable
que pip identifique la instancia de pip que trabaja solo con paquetes de Python 2.
Ejercicio 3
¿Cómo puedes determinar si tu pip funciona con Python 2 o Python 3?
Revisar
Ejercicio 4
Desafortunadamente, no tienes privilegios de administrador. ¿Qué debes hacer para
instalar un paquete en todo el sistema?
Revisar
Tienes que consultar a tu administrador del sistema – ¡no intentes hackear tu sistema
operativo!
Ahora estás listo para realizar el cuestionario del módulo e intentar el desafío final: El
Examen del Módulo 1, que te ayudará a evaluar lo que has aprendido hasta ahora.
Fundamentos de Python 2:
Módulo 2
Cadenas, Métodos de Listas y Excepciones
¿Cómo puedes hacerlo en Python? Esto es lo que discutiremos ahora. Comencemos con
como las computadoras entienden los caracteres individuales.
Las computadoras almacenan los caracteres como números. Cada carácter utilizado por
una computadora corresponde a un número único, y viceversa. Esta asignación debe
incluir más caracteres de los que podrías esperar. Muchos de ellos son invisibles para los
humanos, pero esenciales para las computadoras.
Las personas no ven este signo (o estos signos), pero pueden observar el efecto de su
aplicación donde ven un salto de línea.
El denominado ASCII (por sus siglas en inglés American Standard Code for Information
Interchange). El Código Estándar Americano para Intercambio de Información es el más
utilizado, y es posible suponer que casi todos los dispositivos modernos (como
computadoras, impresoras, teléfonos móviles, tabletas, etc.) usan este código.
El código proporciona espacio para 256 caracteres diferentes, pero solo nos interesan los
primeros 128. Si deseas ver como se construye el código, mira la tabla a continuación.
Haz clic en la tabla para ampliarla. Mírala cuidadosamente: hay algunos datos
interesantes. Observa el código del carácter más común: el espacio. El cual es el 32.
Ahora verifica el código de la letra minúscula a. El cual es 97. Ahora encuentra
la A mayúscula. Su código es 65. Ahora calcula la diferencia entre el código de la a y la A.
Es igual a 32. Ese es el código del espacio. Interesante, ¿no es así?
También ten en cuenta que las letras están ordenadas en el mismo orden que en el
Alfabeto Latino.
I18N
Ahora, el alfabeto latino no es suficiente para toda la humanidad. Los usuarios de ese
alfabeto son minoría. Era necesario idear algo más flexible y capaz que ASCII, algo capaz
de hacer que todo el software del mundo sea susceptible de internacionalización, porque
diferentes idiomas usan alfabetos completamente diferentes, y a veces estos alfabetos no
son tan simples como el latino.
¿Por qué? Observa con cuidado, hay una I al inicio de la palabra, a continuación
hay 18 letras diferentes, y una N al final.
El software I18N es un estándar en los tiempos actuales. Cada programa tiene que ser
escrito de una manera que permita su uso en todo el mundo, entre diferentes culturas,
idiomas y alfabetos.
El código ASCII emplea ocho bits para cada signo. Ocho bits significan 256 caracteres
diferentes. Los primeros 128 se usan para el alfabeto latino estándar (tanto en
mayúsculas como en minúsculas). ¿Es posible colocar todos los otros caracteres utilizados
en todo el mundo a los 128 lugares restantes?
No, no lo es.
Puntos de código y páginas de códigos
Necesitamos un nuevo término: un punto de código.
Como el ASCII estándar ocupa 128 de 256 puntos de código posibles, solo puedes hacer
uso de los 128 restantes.
No es suficiente para todos los idiomas posibles, pero puede ser suficiente para un
idioma o para un pequeño grupo de idiomas similares.
¿Se puede establecer la mitad superior de los puntos de código de manera diferente para
diferentes idiomas? Si, por supuesto. A tal concepto se le denomina una página de
códigos.
Una página de códigos es un estándar para usar los 128 puntos de código superiores
para almacenar caracteres específicos. Por ejemplo, hay diferentes páginas de códigos
para Europa Occidental y Europa del Este, alfabetos cirílicos y griegos, idiomas árabe y
hebreo, etc.
Esto significa que el mismo punto de código puede formar diferentes caracteres cuando
se usa en diferentes páginas de códigos.
Por ejemplo, el punto de código 200 forma una Č (una letra usada por algunas lenguas
eslavas) cuando lo utiliza la página de códigos ISO/IEC 8859-2, pero forma un Ш (una letra
cirílica) cuando es usado por la página de códigos ISO/IEC 8859-5.
En otras palabras, los puntos de código derivados del código de páginas son ambiguos.
Unicode
Las páginas de códigos ayudaron a la industria informática a resolver problemas de I18N
durante algún tiempo, pero pronto resultó que no serían una solución permanente.
UCS-4
El estándar Unicode no dice nada sobre como codificar y almacenar los caracteres en la
memoria y los archivos. Solo nombra todos los caracteres disponibles y los asigna a
planos (un grupo de caracteres de origen, aplicación o naturaleza similares).
Existe más de un estándar que describe las técnicas utilizadas para implementar Unicode
en computadoras y sistemas de almacenamiento informáticos reales. El más general de
ellos es UCS-4.
UCS-4 emplea 32 bits (cuatro bytes) para almacenar cada carácter, y el código es solo el
número único de los puntos de código Unicode. Un archivo que contiene texto codificado
UCS-4 puede comenzar con un BOM (byte order mark - marca de orden de bytes), una
combinación no imprimible de bits que anuncia la naturaleza del contenido del archivo.
Algunas utilidades pueden requerirlo.
UTF-8
Uno de los más utilizados es UTF-8.
El concepto es muy inteligente. UTF-8 emplea tantos bits para cada uno de los puntos de
código como realmente necesita para representarlos.
Por ejemplo:
• Todos los caracteres latinos (y todos los caracteres ASCII estándar) ocupan ocho
bits.
• Los caracteres no latinos ocupan 16 bits.
• Los ideógrafos CJK (China-Japón-Corea) ocupan 24 bits.
Debido a las características del método utilizado por UTF-8 para almacenar los puntos de
código, no es necesario usar el BOM, pero algunas de las herramientas lo buscan al leer
el archivo, y muchos editores lo configuran durante el guardado.
Puntos Clave
1. Las computadoras almacenan caracteres como números. Hay más de una forma
posible de codificar caracteres, pero solo algunas de ellas ganaron popularidad en todo el
mundo y se usan comúnmente en TI: estas son ASCII (se emplea principalmente para
codificar el alfabeto latino y algunos de sus derivados) y UNICODE (capaz de codificar
prácticamente todos los alfabetos que utilizan los seres humanos).
jercico 1
¿Qué es BOM?
Revisar
BOM (Byte Order Mark), Una Marca de Orden de Bytes es una combinación especial de
bits que anuncia la codificación utilizada por el contenido de un archivo (por ejemplo,
UCS-4 o UTF-B).
Ejercico 2
Revisar
Es muy importante tener en cuenta esto, porque significa que debes esperar un
comportamiento familiar.
word = 'by'
print(len(word))
# Ejemplo 2
empty = ''
print(len(empty))
# Ejemplo 3
i_am = 'I\'m'
print(len(i_am))
Cadenas multilínea
Ahora es un muy buen momento para mostrarte otra forma de especificar cadenas
dentro del código fuente de Python. Ten en cuenta que la sintaxis que ya conoces no te
permitirá usar una cadena que ocupe más de una línea de texto.
multiline = 'Línea #1
Línea #2'
print(len(multiline))
Afortunadamente, para este tipo de cadenas, Python ofrece una sintaxis simple,
conveniente y separada.
Como puedes ver, la cadena comienza con tres apóstrofes, no uno. El mismo apóstrofe
triplicado se usa para terminar la cadena.
Cuenta los caracteres con cuidado. ¿Es este resultado correcto o no? Se ve bien a primera
vista, pero cuando cuentas los caracteres, no lo es.
Línea #1 contiene ocho caracteres. Las dos líneas juntas contienen 16 caracteres.
¿Perdimos un carácter? ¿Dónde? ¿Cómo?
No, no lo hicimos.
Se denota como: \n .
¿Lo recuerdas? Es un carácter especial (de control) utilizado para forzar un avance de
línea. No puedes verlo, pero cuenta.
Las cadenas multilínea pueden ser delimitadas también por comillas triples, como aqui:
multiline = """Línea #1
Línea #2"""
print(len(multiline))
multiline = '''Línea #1
Línea #2'''
print(len(multiline))
• Concatenadas (unidas).
• Replicadas.
ab
ba
aaaaa
bbbb
salida
Nota: Los atajos de los operadores anteriores también son aplicables para las cadenas
( += y *= ).
str1 = 'a'
str2 = 'b'
print(str1 + str2)
print(str2 + str1)
print(5 * 'a')
print('b' * 4)
La función necesita una cadena de un carácter como argumento - incumplir este requisito
provoca una excepción TypeError, y devuelve un número que representa el punto de
código del argumento.
Observa el código en el editor y ejecútalo. Las salida del fragmento de código es:
97
32
salida
Ahora asigna diferentes valores a ch1 y ch2 , por ejemplo, α (letra griega alfa), y ę (una
letra en el alfabeto polaco); luego ejecuta el código y ve qué resultado produce. Realiza
tus propios experimentos.
char_1 = 'a'
char_2 = ' ' # space
print(ord(char_1))
print(ord(char_2))
a
α
salida
Nota:
• chr(ord(x)) == x
• ord(chr(x)) == x
Las cadenas no son listas, pero pueden ser tratadas como tal en muchos casos.
Por ejemplo, si deseas acceder a cualquiera de los caracteres de una cadena, puedes
hacerlo usando indexación. Ejecuta el programa:
# Indexando cadenas.
for ix in range(len(the_string)):
print(the_string[ix], end=' ')
print()
Ten cuidado, no intentes pasar los límites de la cadena, ya que provocará una excepción.
s i l l y w a l k s
salida
Por cierto, los índices negativos también se comportan como se espera. Comprueba esto
tú mismo.
print()
Rebanadas
Todo lo que sabes sobre rebanadas es utilizable.
Hemos reunido algunos ejemplos que muestran cómo funcionan las rebanadas en el
mundo de las cadenas. Observa el código en el editor, analízalo y ejecútalo.
No verás nada nuevo en el ejemplo, pero queremos que estés seguro de entender todas
las líneas del código.
bd
efg
abd
e
e
adf
beg
salida
# Rebanadas
alpha = "abdefg"
print(alpha[1:3])
print(alpha[3:])
print(alpha[:3])
print(alpha[3:-2])
print(alpha[-3:4])
print(alpha[::2])
print(alpha[1::2])
alphabet = "abcdefghijklmnopqrstuvwxyz"
print("f" in alphabet)
print("F" in alphabet)
print("1" in alphabet)
print("ghi" in alphabet)
print("Xyz" in alphabet)
salida
El operador not in
alphabet = "abcdefghijklmnopqrstuvwxyz"
False
True
True
False
True
salida
2.2.1.9 La naturaleza de las cadenas en Python
alphabet = "abcdefghijklmnopqrstuvwxyz"
del alphabet[0]
Lo único que puedes hacer con del y una cadena es eliminar la cadena como un todo.
Intenta hacerlo.
alphabet = "abcdefghijklmnopqrstuvwxyz"
alphabet.append("A")
alphabet = "abcdefghijklmnopqrstuvwxyz"
alphabet.insert(0, "A")
alphabet = "abcdefghijklmnopqrstuvwxyz"
Esta forma de código es totalmente aceptable, funcionará sin doblar las reglas de Python
y traerá el alfabeto latino completo a tu pantalla:
abcdefghijklmnopqrstuvwxyz
salida
Es posible que desees preguntar si el crear una nueva copia de una cadena cada vez que
se modifica su contenido empeora la efectividad del código.
alphabet = "bcdefghijklmnopqrstuvwxy"
print(alphabet)
A
salida
Nota: Es una A mayúscula. ¿Por qué? Recuerda la tabla ASCII, ¿qué letras ocupan las
primeras posiciones, mayúsculas o minúsculas?
[ ]
0
salida
Nota: hemos utilizado corchetes para evitar que el espacio se pase por alto en tu pantalla.
t = [0, 1, 2]
print(min(t))
z
salida
Ahora veamos la función max() a los mismos datos del ejemplo anterior. Observa
los Ejemplos 2 y 3 en el editor.
[¡]
2
salida
t = [0, 1, 2]
print(max(t))
El método devuelve el índice de la primera aparición del argumento (lo que significa que
el resultado más bajo posible es 0, mientras que el más alto es la longitud del argumento
decrementado en 1).
2
7
1
salida
# Demonstrando el método index():
print("aAbByYzZaA".index("b"))
print("aAbByYzZaA".index("Z"))
print("aAbByYzZaA".index("A")
Nota: no es estrictamente una función de cadenas - list() es capaz de crear una nueva
lista de muchas otras entidades (por ejemplo, de tuplas y diccionarios).
Observa el código de ejemplo en el editor.
La salida es:
Es:
2
0
salida
Puntos Claves
1. Las cadenas de Python son secuencias inmutables y se pueden indexar, dividir en
rebanadas e iterar como cualquier otra secuencia, además de estar sujetas a los
operadores in y not in . Existen dos tipos de cadenas en Python:
• Cadenas de una línea, las cuales no pueden cruzar los límites de una línea, las
denotamos usando apóstrofes ( 'cadena' ) o comillas ( "cadena" ).
• Cadenas multilínea, que ocupan más de una línea de código fuente, delimitadas
por apóstrofes triples:
'''
cadena
'''
"""
cadena
"""
print(len("\n\n"))
Su salida es 2 .
asterisk = '*'
plus = "+"
decoration = (asterisk + plus) * 4 + asterisk
print(decoration)
salida *+*+*+*+* .
4. El par de funciones chr() y ord() se pueden utilizar para crear un carácter utilizando
su punto de código y para determinar un punto de código correspondiente a un carácter.
Las dos expresiones siguientes son siempre verdaderas:
chr(ord(character)) == character
ord(chr(codepoint)) == codepoint
• list() – crea una lista que consta de todos los caracteres de la cadena.
• max() – encuentra el carácter con el punto de código máximo.
• min() – encuentra el carácter con el punto de código mínimo.
Ejercicio 1
"""
"""
Revisar
Ejercicio 2
s = 'yesteryears'
the_list = list(s)
print(the_list[3:6])
Revisar
Ejercicio 3
for ch in "abc":
print(chr(ord(ch) + 1), end='')
Revisar
bcd
El método capitalize()
Veamos algunos métodos estándar de cadenas en Python. Vamos a analizarlos en orden
alfabético, cualquier orden tiene tanto desventajas como ventajas, por lo que la elección
puede ser aleatoria.
El método capitalize() hace exactamente lo que dice - crea una nueva cadena con los
caracteres tomados de la cadena fuente, pero intenta modificarlos de la siguiente
manera:
No olvides que:
• La cadena original desde la cual se invoca el método no se cambia de ninguna
manera, la inmutabilidad de una cadena debe obedecerse sin reservas.
• La cadena modificada (en mayúscula en este caso) se devuelve como resultado; si
no se usa de alguna manera (asígnala a una variable o pásala a una función /
método) desaparecerá sin dejar rastro.
Nota: los métodos no tienen que invocarse solo dentro de las variables. Se pueden
invocar directamente desde dentro de literales de cadena. Usaremos esa convención
regularmente: simplificará los ejemplos, ya que los aspectos más importantes no
desaparecerán entre asignaciones innecesarias.
Abcd
salida
print("Alpha".capitalize())
print('ALPHA'.capitalize())
print(' Alpha'.capitalize())
print('123'.capitalize())
print("αβγδ".capitalize())
El método center()
La variante de un parámetro del método center() genera una copia de la cadena
original, tratando de centrarla dentro de un campo de un ancho especificado.
El ejemplo en el editor usa corchetes para mostrar claramente donde comienza y termina
realmente la cadena centrada.
La variante de dos parámetros de center() hace uso del carácter del segundo
argumento, en lugar de un espacio. Analiza el siguiente ejemplo:
[*******gamma********]
salida
El método endswith()
El método endswith() comprueba si la cadena dada termina con el argumento
especificado y devuelve True(verdadero) o False(falso) , dependiendo del resultado.
si
salida
El método find()
El método find() es similar al método index() , el cual ya conoces - busca una
subcadena y devuelve el índice de la primera aparición de esta subcadena, pero:
El ejemplo imprime:
1
-1
salida
t = 'theta'
print(t.find('eta'))
print(t.find('et'))
print(t.find('the'))
print(t.find('ha'))
print('kappa'.find('a', 2))
El segundo argumento especifica el índice en el que se iniciará la búsqueda (no tiene que
estar dentro de la cadena).
Se puede emplear el método find() para buscar todas las ocurrencias de la subcadena,
como aquí:
fnd = the_text.find('the')
while fnd != -1:
print(fnd)
fnd = the_text.find('the', fnd + 1)
El código imprime los índices de todas las ocurrencias del artículo the, y su salida se ve
así:
15
80
198
221
238
salida
Existe también una mutación de tres parámetros del método find() - el tercer
argumento apunta al primer índice que no se tendrá en cuenta durante la búsqueda (en
realidad es el límite superior de la búsqueda).
print('kappa'.find('a', 1, 4))
print('kappa'.find('a', 2, 4))
El segundo argumento especifica el índice en el que se iniciará la búsqueda (no tiene que
estar dentro de la cadena).
1
-1
salida
El método isalnum()
El método sin parámetros llamado isalnum() comprueba si la cadena contiene solo
dígitos o caracteres alfabéticos (letras) y devuelve True(verdadero) o False(falso) de
acuerdo al resultado.
Nota: cualquier elemento de cadena que no sea un dígito o una letra hace que el método
regrese False(falso) . Una cadena vacía también lo hace.
True
True
True
False
False
False
salida
t = 'Six lambdas'
print(t.isalnum())
t = 'ΑβΓδ'
print(t.isalnum())
t = '20E1'
print(t.isalnum())
El método isalpha()
El método isalpha() es más especializado, se interesa en letras solamente.
True
False
salida
El método isdigit()
Al contrario, el método isdigit() busca solo dígitos - cualquier otra cosa
produce False(falso) como resultado.
True
False
salida
El método islower()
El método islower() es una variante de isalpha() - solo acepta letras minúsculas.
False
True
salida
El método isspace()
El método isspace() identifica espacios en blanco solamente - no tiene en cuenta
ningún otro carácter (el resultado es entonces False ).
True
True
False
salida
El método isupper()
El método isupper() es la versión en mayúscula de islower() - se concentra solo en
letras mayúsculas.
False
False
True
salida
# Ejemplo 1: Demostración del método islower():
print("Moooo".islower())
print('moooo'.islower())
El método join()
El método join() es algo complicado, así que déjanos guiarte paso a paso:
• El método join() se invoca desde una cadena que contiene una coma (la cadena
puede ser larga o puede estar vacía).
• El argumento del join es una lista que contiene tres cadenas.
• El método devuelve una nueva cadena.
Aquí está:
omicron,pi,rh
salida
El método lower()
El método lower() genera una copia de una cadena, reemplaza todas las letras
mayúsculas con sus equivalentes en minúsculas, y devuelve la cadena como resultado.
Nuevamente, la cadena original permanece intacta.
sigma=60
salida
Como ya sabes, realiza tus propios experimentos.
El método lstrip()
El método sin parámetros lstrip() devuelve una cadena recién creada formada a partir
de la original eliminando todos los espacios en blanco iniciales.
Los corchetes no son parte del resultado, solo muestran los límites del resultado.
[tau ]
salida
El método con un parámetro lstrip() hace lo mismo que su versión sin parámetros,
pero elimina todos los caracteres incluidos en el argumento (una cadena), no solo
espacios en blanco:
print("www.cisco.com".lstrip("w."))
cisco.com
salida
print("pythoninstitute.org".lstrip(".org"))
El método replace()
El método replace() con dos parámetros devuelve una copia de la cadena original en la
que todas las apariciones del primer argumento han sido reemplazadas por el segundo
argumento.
www.pythoninstitute.org
Thare are it!
Apple
salida
La variante del método replace() con tres parámetros emplea un tercer argumento (un
número) para limitar el número de reemplazos.
El método rfind()
Los métodos de uno, dos y tres parámetros denominados rfind() hacen casi lo mismo
que sus contrapartes (las que carecen del prefijo r), pero comienzan sus búsquedas
desde el final de la cadena, no el principio (de ahí el prefijo r, de reversa).
Echa un vistazo al código en el editor e intenta predecir su salida. Ejecuta el código para
verificar si tenías razón.
# Demostración del método rfind():
print("tau tau tau".rfind("ta"))
print("tau tau tau".rfind("ta", 9))
print("tau tau tau".rfind("ta", 3, 9))
El método rstrip()
Dos variantes del método rstrip() hacen casi lo mismo que el método lstrip ,
pero afecta el lado opuesto de la cadena.
El método split()
El método split() divide la cadena y crea una lista de todas las subcadenas detectadas.
El método asume que las subcadenas están delimitadas por espacios en blanco - los
espacios no participan en la operación y no se copian en la lista resultante.
El método startswith()
El método startswith() es un espejo del método endswith() - comprueba si una
cadena dada comienza con la subcadena especificada.
False
True
salida
El método strip()
El método strip() combina los efectos causados por rstrip() y lstrip() - crea una
nueva cadena que carece de todos los espacios en blanco iniciales y finales.
[aleph]
salida
print()
El método swapcase()
El método swapcase() crea una nueva cadena intercambiando todas las letras por
mayúsculas o minúsculas dentro de la cadena original: los caracteres en mayúscula se
convierten en minúsculas y viceversa.
Observa el primer ejemplo en el editor. ¿Puedes adivinar la salida? No se verá nada bien,
pero debes observarla:
yO SÉ QUE NO SÉ NADA.
salida
El método title()
El método title() realiza una función algo similar cambia la primera letra de cada
palabra a mayúsculas, convirtiendo todas las demás a minúsculas.
El método upper()
Por último, pero no menos importante, el método upper() hace una copia de la cadena
de origen, reemplaza todas las letras minúsculas con sus equivalentes en mayúsculas, y
devuelve la cadena como resultado.
¡Hurra! Hemos llegado al final de esta sección. ¿Te sorprende alguno de los métodos de
cadena que hemos discutido hasta ahora? Toma un par de minutos para revisarlos y
pasemos a la siguiente parte del curso, donde te mostraremos que cosas podemos hacer
con las cadenas.
print()
print()
Puntos Clave
1. Algunos de los métodos que ofrecen las cadenas son:
Ejercicio 1
for ch in "abc123XYX":
if ch.isupper():
print(ch.lower(), end='')
elif ch.islower():
print(ch.upper(), end='')
else:
print(ch, end='')
Revisar
ABC123xyz
Ejercicio 2
Revisar
de
Ejercicio 3
Revisar
¿Dónde*están*las*nevadas?
Ejercicio 4
Revisar
Es difícil o posible
LABORATORIO
Tiempo Estimado
20-25 minutos
Nivel de dificultad
Medio
Objetivos
• Mejorar las habilidades del alumno al trabajar con cadenas.
• Utilizar los métodos incorporados de Python para las cadenas.
Escenario
Ya sabes como funiona el método split() . Ahora queremos que lo pruebes.
Salida esperada
['Ser', 'o', 'no', 'ser', 'esa', 'es,', 'la', 'pregunta']
['Ser', 'o', 'no', 'ser,esa', 'es', 'la', 'pregunta']
[]
['abc']
[]
def mysplit(strng):
#
# coloca tu código aquí
#
Comparando cadenas
Las cadenas en Python pueden ser comparadas usando el mismo conjunto de
operadores que se emplean con los números.
• ==
• !=
• >
• >=
• <
• <=
Existe un "pero": los resultados de tales comparaciones a veces pueden ser un poco
sorprendentes. No olvides que Python no es consciente (no puede serlo de ninguna
manera) de problemas lingüísticos sutiles, simplemente compara valores de puntos de
código, carácter por carácter.
Los resultados que se obtienen de una operación de este tipo a veces son sorprendentes.
Comencemos con los casos más simples.
Dos cadenas son iguales cuando consisten de los mismos caracteres en el mismo orden.
Del mismo modo, dos cadenas no son iguales cuando no consisten de los mismos
caracteres en el mismo orden.
'alpha' == 'alpha'
'alpha' != 'Alpha'
'10' == '010'
'10' > '010'
'10' > '8'
'20' < '8'
'20' < '80'
False
True
False
True
True
salida
Las únicas comparaciones que puede realizar con impunidad son aquellas simbolizadas
por los operadores == y != . El primero siempre devuelve False (falso), mientras que el
segundo siempre devuelve True (verdadero).
Vamos a verlo:
'10' == 10
'10' != 10
'10' == 1
'10' != 1
'10' > 10
Los resultados en este caso son:
False
True
False
True
TypeError exception
salida
Ordenamiento
La comparación está estrechamente relacionada con el ordenamiento (o más bien, el
ordenamiento es, de hecho, un caso muy sofisticado de comparación).
Esta es una buena oportunidad para mostrar dos formas posibles de ordenar listas que
contienen cadenas. Dicha operación es muy común en el mundo real: cada vez que ves
una lista de nombres, productos, títulos o ciudades, esperas que este ordenada.
La función toma un argumento (una lista) y retorna una nueva lista, con los elementos
ordenados del argumento. (Nota: esta descripción está un poco simplificada en
comparación con la implementación real; lo discutiremos más adelante).
El segundo método afecta a la lista misma - no se crea una nueva lista. El ordenamiento
se realiza por el método denominado sort() .
La salida no ha cambiado:
print(first_greek)
print(first_greek_2)
print()
second_greek.sort()
print(second_greek)
itg = 13
flt = 1.3
si = str(itg)
sf = str(flt)
13 1.3
salida
si = '13'
sf = '1.3'
itg = int(si)
flt = float(sf)
print(itg + flt)
14.3
salida
Puntos Claves
1. Las cadenas se pueden comparar con otras cadenas utilizando operadores de
comparación generales, pero compararlas con números no da un resultado razonable,
porque ninguna cadena puede ser igual a ningún otro número. Por ejemplo:
Ejercicio 1
Revisar
1, 3 y 4
Ejercicio 2
Revisar
de
Ejercicio 3
s1 = '12.8'
i = int(s1)
s2 = str(i)
f = float(s2)
print(s1 == s2)
Revisar
LABORATORIO
Tiempo Estimado
30 minutos
Nivel de dificultad
Medio
Objetivos
• Mejorar las habilidades del alumno al trabajar con cadenas.
• Usar cadenas para representar datos que no son texto.
Escenario
Seguramente has visto un display de siete segmentos.
Cada dígito es construido con 13 LEDs (algunos iluminados, otros apagados, por
supuesto), así es como lo imaginamos:
Tu código debe mostrar cualquier número entero no negativo ingresado por el usuario.
Consejo: puede ser muy útil usar una lista que contenga patrones de los diez dígitos.
Datos de prueba
Entrada de muestra:
123
Salida de muestra:
# ### ###
# # #
# ### ###
# # #
# ### ###
Entrada de muestra:
9081726354
Salida de muestra:
El primer problema que queremos mostrarte se llama Cifrado César - más detalles
aquí: https://en.wikipedia.org/wiki/Caesar_cipher.
Este cifrado fue (probablemente) inventado y utilizado por Cayo Julio César y sus tropas
durante las Guerras Galas. La idea es bastante simple: cada letra del mensaje se
reemplaza por su consecuente más cercano (A se convierte en B, B se convierte en C, y así
sucesivamente). La única excepción es la Z, la cual se convierte en A.
• Solo acepta letras latinas (nota: los Romanos no usaban espacios en blanco ni
dígitos).
• Todas las letras del mensaje están en mayúsculas (nota: los Romanos solo
conocían las mayúsculas).
Veamos el código:
• La línea 02: pide al usuario que ingrese un mensaje (sin cifrar) de una línea.
• La línea 03: prepara una cadena para el mensaje cifrado (esta vacía por ahora).
• La línea 04: inicia la iteración a través del mensaje.
• La línea 05: si el carácter actual no es alfabético...
• La línea 06: ...ignoralo.
• La línea 07: convierta la letra a mayúsculas (es preferible hacerlo a ciegas, en lugar
de verificar si es necesario o no).
• La línea 08: obtén el código de la letra e increméntalo en uno.
• La línea 09: si el código resultante ha "dejado" el alfabeto latino (si es mayor que el
código de la Z)...
• La línea 10: ... cámbialo al código de la A.
• La línea 11: agrega el carácter recibido al final del mensaje cifrado.
• La línea 13: imprime el cifrado.
AVE CAESAR
Da como salida:
BWFDBFTBS
salida
# Cifrado César.
text = input("Ingresa tu mensaje: ")
cipher = ''
for char in text:
if not char.isalpha():
continue
char = char.upper()
code = ord(char) + 1
if code > ord('Z'):
code = ord('A')
cipher += chr(code)
print(cipher)
print(text)
El Procesador de Números
El tercer programa muestra un método simple que permite ingresar una línea llena de
números y sumarlos fácilmente. Nota: la función input() , combinada junto con las
funciones int() o float() , no es lo adecuado para este propósito.
Emplear listas puede hacer que el código sea más pequeño. Puedes hacerlo si quieres.
• La línea 03: pide al usuario que ingrese una línea llena de cualquier cantidad de
números (los números pueden ser flotantes).
• La línea 04: divide la línea en una lista con subcadenas.
• La línea 05: se inicializa la suma total a cero.
• La línea 06: como la conversión de cadena a flotante puede generar una
excepción, es mejor continuar con la protección del bloque try-except.
• La línea 07: itera a través de la lista...
• La línea 08: ... e intenta convertir todos sus elementos en números flotantes; si
funciona, aumenta la suma.
• La línea 09: todo está bien hasta ahora, así que imprime la suma.
• La línea 10: el programa termina aquí en caso de error.
• La línea 11: imprime un mensaje de diagnóstico que muestra al usuario el motivo
de la falla.
El código tiene una debilidad importante: muestra un resultado falso cuando el usuario
ingresa una línea vacía. ¿Puedes arreglarlo?
#Procesador de Números.
El Validador IBAN
El cuarto programa implementa (en una forma ligeramente simplificada) un algoritmo
utilizado por los bancos Europeos para especificar los números de cuenta. El estándar
llamado IBAN (Número de cuenta bancaria internacional) proporciona un método simple
y bastante confiable para validar los números de cuenta contra errores tipográficos
simples que pueden ocurrir durante la reescritura del número, por ejemplo, de
documentos en papel, como facturas o facturas en las computadoras.
• Un código de país de dos letras tomado del estándar ISO 3166-1 (por
ejemplo, FR para Francia, GB para Gran Bretaña DE para Alemania, y así
sucesivamente).
• Dos dígitos de verificación utilizados para realizar las verificaciones de validez:
pruebas rápidas y simples, pero no totalmente confiables, que muestran si un
número es inválido (distorsionado por un error tipográfico) o válido.
• El número de cuenta real (hasta 30 caracteres alfanuméricos; la longitud de esa
parte depende del país).
El estándar dice que la validación requiere los siguientes pasos (según Wikipedia):
• (Paso 1) Verificar que la longitud total del IBAN sea correcta según el país (este
programa no lo hará, pero puedes modificar el código para cumplir con este
requisito si lo deseas; nota: pero debes enseñar al código a conocer todas las
longitudes utilizadas en Europa).
• (Paso 2) Mueve los cuatro caracteres iniciales al final de la cadena (es decir, el
código del país y los dígitos de verificación).
• (Paso 3) Reemplaza cada letra en la cadena con dos dígitos, expandiendo así la
cadena, donde A = 10, B = 11 ... Z = 35.
• (Paso 4) Interpreta la cadena como un entero decimal y calcula el residuo de ese
número dividiéndolo entre 97. Si el residuo es 1, pasa la prueba de verificación de
dígitos y el IBAN puede ser válido.
• Línea 03: pide al usuario que ingrese el IBAN (el número puede contener espacios,
ya que mejoran significativamente la legibilidad del número...
• Línea 04: ... pero remueve los espacios de inmediato).
• Línea 05: el IBAN ingresado debe constar solo de dígitos y letras, de lo contrario...
• Línea 06: ... muestra un mensaje.
• Línea 07: el IBAN no debe tener menos de 15 caracteres (esta es la variante más
corta, utilizada en Noruega).
• Línea 08: si es más corto, se informa al usuario.
• Línea 09: además, el IBAN no puede tener más de 31 caracteres (esta es la
variante más larga, utilizada en Malta).
• Línea 10: si es más largo, se le informa al usuario.
• Línea 11: se comienza con el procesamiento.
• Línea 12: se mueven los cuatro caracteres iniciales al final del número y se
convierten todas las letras a mayúsculas (paso 02 del algoritmo).
• Línea 13: esta es la variable utilizada para completar el número, creada al
reemplazar las letras con dígitos (de acuerdo con el paso 03 del algoritmo).
• Línea 14: iterar a través del IBAN.
• Línea 15: si el carácter es un dígito...
• Línea 16: ... se copia.
• Línea 17: de lo contrario...
• Línea 18: ... conviértelo en dos dígitos (observa cómo se hace aquí).
• Línea 19: la forma convertida del IBAN está lista: ahora se convierte en un número
entero.
• Línea 20: ¿el residuo de la división de iban2 entre 97 es igual a 1 ?
• Línea 21: si es así, entonces el número es correcto.
• Línea 22: de lo contrario...
• Línea 23: ... el número no es válido.
Agreguemos algunos datos de prueba (todos estos números son válidos; puedes
invalidarlos cambiando cualquier carácter).
# Validador IBAN.
if not iban.isalnum():
print("Has introducido caracteres no válidos.")
elif len(iban) < 15:
print("El IBAN ingresado es demasiado corto.")
elif len(iban) > 31:
print("El IBAN ingresado es demasiado largo.")
else:
iban = (iban[4:] + iban[0:4]).upper()
iban2 = ''
for ch in iban:
if ch.isdigit():
iban2 += ch
else:
iban2 += str(10 + ord(ch) - ord('A'))
iban = int(iban2)
if iban % 97 == 1:
print("El IBAN ingresado es válido.")
else:
print("El IBAN ingresado no es válido.")
Puntos Claves
2. El comparar cadenas de forma estricta (como lo hace Python) puede ser muy
insatisfactorio cuando se trata de búsquedas avanzadas (por ejemplo, durante consultas
extensas a bases de datos). En respuesta a esta demanda, se han creado e implementado
una serie de algoritmos de comparación de cadenas difusos. Estos algoritmos pueden
encontrar cadenas que no son iguales en el sentido de Python, pero que son similares.
Un algoritmo utilizado para realizar una comparación de este tipo para el idioma Inglés se
llama Soundex y se inventó, no lo creerás, en 1918. Puedes encontrar más información al
respecto aquí: https://en.wikipedia.org/wiki/Soundex.
Esta es la ley de Murphy, y funciona en todo y siempre. Si la ejecución del código puede
salir mal, lo hará.
Observa el código en el editor. Hay al menos dos formas posibles de que "salga mal" la
ejecución. ¿Puedes verlas?
Ingresa x: Abracadabra
x = float(input("Ingresa x: "))
y = math.sqrt(x)
¿Puedes protegerte de tales sorpresas? Por supuesto. Además, tienes que hacerlo para
ser considerado un buen programador.
import math
x = float(input("Ingresa x: "))
y = math.sqrt(x)
Excepciones
Cada vez que tu código intenta hacer algo erróneo, irresponsable o inaplicable, Python
hace dos cosas:
• Detiene tu programa.
• Crea un tipo especial de dato, llamado excepción.
Ambas actividades llevan por nombre generar una excepción. Podemos decir que Python
siempre genera una excepción (o que una excepción ha sido generada) cuando no tiene
idea de qué hacer con el código.
• La excepción generada espera que alguien o algo lo note y haga algo al respecto.
• Si la excepción no es resuelta, el programa será terminado abruptamente, y verás
un mensaje de error enviado a la consola por Python.
• De otra manera, si se atiende la excepción y es manejada apropiadamente, el
programa puede reanudarse y su ejecución puede continuar.
Excepciones: continuación
Observa el código en el editor. Ejecuta el (obviamente incorrecto) programa.
value = 1
value /= 0
my_list = []
x = my_list[0]
Excepciones: continuación
¿Cómo se manejan las excepciones? La palabra try es clave para la solución.
Pero, ¿no sería mejor verificar primero todas las circunstancias y luego hacer algo solo si
es seguro?
Es cierto que esta forma puede parecer la mas natural y comprensible, pero en realidad,
este método no facilita la programación. Todas estas revisiones pueden hacer al código
demasiado grande e ilegible.
if second_number != 0:
print(first_number / second_number)
else:
print("Esta operación no puede ser realizada.")
print("FIN.")
Excepciones: continuación
Observa el código en el editor. Este es el enfoque favorito de Python.
Nota:
Resumamos esto:
try:
:
:
except:
:
:
• En el primer paso, Python intenta realizar todas las instrucciones colocadas entre
las instrucciones try: y except: .
• Si no hay ningún problema con la ejecución y todas las instrucciones se realizan
con éxito, la ejecución salta al punto después de la última línea del
bloque except: , y la ejecución del bloque se considera completa.
• Si algo sale mal dentro del bloque try: o except: , la ejecución salta
inmediatamente fuera del bloque y entra en la primera instrucción ubicada
después de la palabra clave reservada except: , esto significa que algunas de las
instrucciones del bloque pueden ser silenciosamente omitidas.
first_number = int(input("Ingresa el primer numero: "))
second_number = int(input("Ingresa el segundo numero: "))
try:
print(first_number / second_number)
except:
print("Esta operación no puede ser realizada.")
print("FIN.")
Excepciones: continuación
Observa el código en el editor. Te ayudará a comprender este mecanismo.
1
Oh cielos, algo salió mal...
3
salida
try:
print("1")
x = 1 / 0
print("2")
except:
print("Oh cielos, algo salió mal...")
print("3")
Excepciones: continuación
Este enfoque tiene una desventaja importante: si existe la posibilidad de que más de una
excepción se salte a un apartado except: , puedes tener problemas para descubrir lo
que realmente sucedió.
• Construir dos bloques consecutivos try-except, uno por cada posible motivo de
excepción (fácil, pero provocará un crecimiento desfavorable del código).
• Emplear una variante más avanzada de la instrucción.
Se ve de la siguiente manera:
try:
:
except exc1:
:
except exc2:
:
except:
:
• Si el try genera la excepción exc1 , esta será manejada por el bloque except
exc1: .
• De la misma manera, si el try genera la excepción exc2 , esta será manejada por
el bloque except exc2: .
• Si el try genera cualquier otra excepción, será manejado por el bloque sin
nombre except .
try:
x = int(input("Ingresa un numero: "))
y = 1 / x
except:
print("Oh cielos, algo salió mal...")
print("FIN.")
Excepciones: continuación
Observa el código en el editor. Nuestra solución esta ahí.
El código, cuando se ejecute, producirá una de las siguientes cuatro variantes de salida:
0.2
FIN.
salida
• Si se ingresa 0 , dirá:
try:
x = int(input("Ingresa un numero: "))
y = 1 / x
print(y)
except ZeroDivisionError:
print("No puedes dividir entre cero, lo siento.")
except ValueError:
print("Debes ingresar un valor entero.")
except:
print("Oh cielos, algo salió mal...")
print("FIN.")
Excepciones: continuación
No olvides que:
• Los bloques except son analizados en el mismo orden en que aparecen en el
código.
• No debes usar más de un bloque de excepción con el mismo nombre.
• El número de diferentes bloques except es arbitrario, la única condición es que si
se emplea el try , debes poner al menos un except (nombrado o no) después de
el.
• La palabra clave reservada except no debe ser empleada sin que le preceda
un try .
• Si uno de los bloques except es ejecutado, ningún otro lo será.
• Si ninguno de los bloques except especificados coincide con la excepción
planteada, la excepción permanece sin manejar (lo discutiremos pronto).
• Si un except sin nombre existe, tiene que especificarse como el último.
try:
:
except exc1:
:
except exc2:
:
except:
:
Como no existe un bloque declarado para la división entre cero, la excepción cae dentro
del bloque general (sin nombre): esto significa que en este caso, el programa dirá:
try:
x = int(input("Ingresa un numero: "))
y = 1 / x
print(y)
except ValueError:
print("Debes ingresar un valor entero.")
except:
print("Oh cielos, algo salió mal...")
print("FIN.")
2.6.1.11 Errores: el pan diario del programador | try-
except
Excepciones: continuación
Echemos a perder el código una vez más.
Observa el programa en el editor. Esta vez, hemos eliminado el bloque sin nombre.
• La excepción no será manejada por ValueError : no tiene nada que ver con ello.
• Como no hay otro bloque, deberías ver este mensaje:
salida
try:
x = int(input("Ingresa un número: "))
y = 1 / x
print(y)
except ValueError:
print("Debes ingresar un valor entero.")
print("FIN.")
Puntos Clave
1. Una excepción es un evento durante la ejecución del programa causado por una
situación anormal. La excepción debe manejarse para evitar la terminación del programa.
La parte del código que se sospecha que es la fuente de la excepción debe colocarse
dentro del bloque try .
Cuando ocurre la excepción, la ejecución del código no se termina, sino que salta al
bloque except . Este es el lugar donde debe llevarse a cabo el manejo de la excepción. El
esquema general para tal construcción es el siguiente:
:
# El código que siempre corre suavemente.
:
try:
:
# Código arriesgado.
:
except:
:
# La gestión de la crisis se lleva a cabo aquí.
:
:
# De vuelta a la normalidad.
:
2. Si necesitas manejar más de una excepción proveniente del mismo bloque try ,
puedes agregar más de un bloque except , pero debes etiquetarlos con diferentes
nombres, así:
:
# El código que siempre corre suavemente.
:
try:
:
# Código arriesgado.
:
except Except_1:
# La gestión de la crisis se lleva a cabo aquí.
except Except_2:
# Salvamos el mundo aqui.
:
# De vuelta a la normalidad.
:
En el mejor caso, se ejecuta uno de los bloques except ; ninguno de los bloques se
ejecuta cuando la excepción generada no coincide con ninguna de las excepciones
especificadas.
:
# El código que siempre corre suavemente.
:
try:
:
# Código arriesgado.
:
except Except_1:
# La gestión de la crisis se lleva a cabo aquí.
except Except_2:
# Salvamos el mundo aqui.
except:
# Todos los demás problemas caen aquí.
:
# De vuelta a la normalidad.
:
Ejercicio 1
try:
print("Tratemos de hacer esto")
print("#"[2])
print("¡Tuvimos éxito!")
except:
print("Hemos fallado")
print("Hemos terminado")
Revisar
Ejercicio 2
try:
print("alpha"[1/0])
except ZeroDivisionError:
print("cero")
except IndexingError:
print("índice")
except:
print("algo")
Revisar
cero
2.7.1.1 La anatomía de las excepciones
Excepciones
Python 3 define 63 excepciones integradas, y todas ellas forman una jerarquía en forma
de árbol, aunque el árbol es un poco extraño ya que su raíz se encuentra en la parte
superior.
Algunas de las excepciones integradas son más generales (incluyen otras excepciones)
mientras que otras son completamente concretas (solo se representan a sí mismas).
Podemos decir que cuanto más cerca de la raíz se encuentra una excepción, más general
(abstracta) es. A su vez, las excepciones ubicadas en los extremos del árbol (podemos
llamarlas hojas) son concretas.
Observa la figura:
Nota:
BaseException
↑
Exception
↑
ArithmeticError
↑
ZeroDivisionError
Excepciones: continuación
Observa el código en el editor. Es un ejemplo simple para comenzar. Ejecútalo.
Uuuppsss...
FIN.
salida
try:
y = 1 / 0
except ArithmeticError:
print("Uuuppsss...")
print("FIN.")
Ya se sabe que ArithmeticError es una clase general que incluye (entre otras) la
excepción ZeroDivisionError .
Vamos a resumir:
try:
y = 1 / 0
except ZeroDivisionError:
print("Uuupsss...")
print("FIN.")
Excepciones: continuación
Observa el código en el editor. ¿Qué pasará aquí?
¿Cambiará algo si intercambiamos los dos bloques except ? Justo como aquí abajo:
try:
y = 1 / 0
except ArithmeticError:
print("¡Problema Aritmético!")
except ZeroDivisionError:
print("¡División entre Cero!")
print("FIN.")
¡Problema Aritmético!
FIN.
salida
Recuerda:
print("FIN.")
Excepciones: continuación
Si deseas manejar dos o más excepciones de la misma manera, puedes usar la siguiente
sintaxis:
try:
:
except (exc1, exc2):
:
Simplemente tienes que poner todos los nombres de las excepciones empleadas en una
lista separada por comas y no olvidar los paréntesis.
• Dentro de la función.
• Fuera de la función.
¡Problema Aritmético!
FIN.
salida
def bad_fun(n):
return 1 / n
try:
bad_fun(0)
except ArithmeticError:
print("¿Que pasó? ¡Se generó una excepción!")
print("FIN.")
El problema tiene que ser resuelto por el invocador (o por el invocador del invocador, y
así sucesivamente).
Nota: la excepción generada puede cruzar la función y los límites del módulo, y viajar a
través de la cadena de invocación buscando una cláusula except capaz de manejarla.
Ahora vamos a suspender esta discusión, ya que queremos presentarte una nueva
instrucción de Python.
def bad_fun(n):
try:
return 1 / n
except ArithmeticError:
print("¡Problema Aritmético!")
return None
bad_fun(0)
print("FIN.")
Excepciones: continuación
La instrucción raise genera la excepción especificada denominada exc como si fuese
generada de manera natural:
raise exc
Nota: raise es una palabra clave reservada.
La instrucción te permite:
De esta manera, puedes probar tu rutina de manejo de excepciones sin forzar al código a
hacer cosas incorrectas.
def bad_fun(n):
raise ZeroDivisionError
try:
bad_fun(0)
except ArithmeticError:
print("¿Que pasó? ¿Un error?")
print("FIN.")
Excepciones: continuación
La instrucción raise también se puede utilizar de la siguiente manera (toma en cuenta la
ausencia del nombre de la excepción):
raise
Existe una seria restricción: esta variante de la instrucción raise puede ser
utilizada solamente dentro del bloque except ; usarla en cualquier otro contexto causa
un error.
• Primero, dentro del try debido a que se intentó realizar una división entre cero.
• Segundo, dentro de la parte except por la instrucción raise .
try:
bad_fun(0)
except ArithmeticError:
print("¡Ya veo!")
print("FIN.")
Excepciones: continuación
Ahora es un buen momento para mostrarte otra instrucción de Python,
llamada assert (afirmar). Esta es una palabra clave reservada.
assert expression
¿Cómo funciona?
• Se evalúa la expresión.
• Si la expresión se evalúa como True (Verdadera), o un valor numérico distinto de
cero, o una cadena no vacía, o cualquier otro valor diferente de None , no hará
nada más.
• De lo contrario, automáticamente e inmediatamente se genera una excepción
llamada AssertionError (en este caso, decimos que la afirmación ha fallado).
• Puedes ponerlo en la parte del código donde quieras estar absolutamente a salvo
de datos incorrectos, y donde no estés absolutamente seguro de que los datos
hayan sido examinados cuidadosamente antes (por ejemplo, dentro de una
función utilizada por otra persona).
• El generar una excepción AssertionError asegura que tu código no produzca
resultados no válidos y muestra claramente la naturaleza de la falla.
• Las aserciones no reemplazan las excepciones ni validan los datos, son
suplementos.
Si las excepciones y la validación de datos son como conducir con cuidado, la aserción
puede desempeñar el papel de una bolsa de aire.
x = math.sqrt(x)
print(x)
Puntos Clave
1. No se puede agregar más de un bloque except sin nombre después de los bloques
con nombre.
:
# El código que siempre corre suavemente.
:
try:
:
# Código arriesgado.
:
except Except_1:
# La gestión de la crisis se lleva a cabo aquí.
except Except_2:
# Salvamos el mundo aqui.
except:
# Todos los demás problemas caen aquí.
:
# De vuelta a la normalidad.
:
2. Todas las excepciones de Python predefinidas forman una jerarquía, es decir, algunas
de ellas son más generales (la llamada BaseException es la más general) mientras que
otras son más o menos concretas (por ejemplo, IndexError es más concreta
que LookupError ).
No debes poner excepciones más concretas antes de las más generales dentro de la
misma secuencia de bloques except . Por ejemplo, puedes hacer esto:
try:
# Código arriesgado.
except IndexError:
# Solucionando problemas con listas.
except LookupError:
# Lidiando con búsquedas erróneas.
Pero no hagas esto (a menos de que estés absolutamente seguro de que quieres que
alguna parte de tu código sea inaccesible).
try:
# Código arriesgado.
except LookupError:
# Lidiando con búsquedas erróneas.
except IndexError:
# Nunca llegarás aquí.
Ejercicio 1
Revisar
cero
Ejercicio 2
try:
print(1/0)
except ArithmeticError:
print("arit")
except ZeroDivisionError:
print("cero")
except:
print("algo")
Revisar
arit
Ejercicio 3
def foo(x):
assert x
return 1/x
try:
print(foo(0))
except ZeroDivisionError:
print("cero")
except:
print("algo")
Revisar
algo
2.8.1.1 Excepciones útiles
Excepciones integradas
Te mostraremos una breve lista de las excepciones más útiles. Si bien puede sonar
extraño llamar "útil" a una cosa o un fenómeno que es un signo visible de una falla o
retroceso, como sabes, errar es humano y si algo puede salir mal, saldrá mal.
Las excepciones son tan rutinarias y normales como cualquier otro aspecto de la vida de
un programador.
• Su nombre.
• Su ubicación en el árbol de excepciones.
• Una breve descripción.
• Un fragmento de código conciso que muestre las circunstancias en las que se
puede generar la excepción.
Hay muchas otras excepciones para explorar: simplemente no tenemos el espacio para
revisarlas todas aquí.
ArithmeticError
Ubicación: BaseException ← Exception ← ArithmeticError
Descripción: una excepción abstracta que incluye todas las excepciones causadas por
operaciones aritméticas como división cero o dominio inválido de un argumento.
AssertionError
Ubicación: BaseException ← Exception ← AssertionError
Código:
IndexError
Ubicación: BaseException ← Exception ← LookupError ← IndexError
Descripción: una excepción concreta que surge cuando se intenta acceder al elemento de
una secuencia inexistente (por ejemplo, el elemento de una lista).
Código:
the_list = [1, 2, 3, 4, 5]
ix = 0
do_it = True
while do_it:
try:
print(the_list[ix])
ix += 1
except IndexError:
do_it = False
print('Listo')
Descripción: una excepción concreta que surge cuando el usuario usa un atajo de teclado
diseñado para terminar la ejecución de un programa (Ctrl-C en la mayoría de los Sistemas
Operativos); si manejar esta excepción no conduce a la terminación del programa, el
programa continúa su ejecución.
Código:
# Este código no puede ser terminado
# presionando Ctrl-C.
seconds = 0
while True:
try:
print(seconds)
seconds += 1
sleep(1)
except KeyboardInterrupt:
print("¡No hagas eso!")
LookupError
Ubicación: BaseException ← Exception ← LookupError
Descripción: una excepción abstracta que incluye todas las excepciones causadas por
errores resultantes de referencias no válidas a diferentes colecciones (listas, diccionarios,
tuplas, etc.).
MemoryError
Ubicación: BaseException ← Exception ← MemoryError
Código:
string = 'x'
try:
while True:
string = string + string
print(len(string))
except MemoryError:
print('¡Esto no es gracioso!')
OverflowError
Ubicación: BaseException ← Exception ← ArithmeticError ← OverflowError
Descripción: una excepción concreta que surge cuando una operación produce un
número demasiado grande para ser almacenado con éxito.
Código:
ex = 1
try:
while True:
print(exp(ex))
ex *= 2
except OverflowError:
print('El número es demasiado grande.')
Código:
try:
import math
import time
import abracadabra
except:
print('Una de tus importaciones ha fallado.')
KeyError
Ubicación: BaseException ← Exception ← LookupError ← KeyError
Descripción: una excepción concreta que se genera cuando intentas acceder al elemento
inexistente de una colección (por ejemplo, el elemento de un diccionario).
Código:
# ¿Cómo abusar del diccionario
# y cómo lidiar con ello?
try:
while True:
ch = dictionary[ch]
print(ch)
except KeyError:
print('No existe tal clave:', ch)
Hemos terminado con excepciones por ahora, pero volverán cuando discutamos la
programación orientada a objetos en Python. Puedes usarlas para proteger tu código de
accidentes graves, pero también tienes que aprender a sumergirte en ellas, explorando la
información que llevan.
De hecho, las excepciones son objetos; sin embargo, no podemos decirle nada sobre este
aspecto hasta que te presentemos clases, objetos y similares.
Por el momento, si deseas obtener más información sobre las excepciones por tu cuenta,
consulta la Biblioteca Estándar de Python
en https://docs.python.org/3.6/library/exceptions.html.
Nivel de dificultad
Medio
Objetivos
• Mejorar las habilidades del alumno al definir funciones.
• Utilizar excepciones para proporcionar un entorno de entrada más seguro.
Escenario
Tu tarea es escribir una función capaz de ingresar valores enteros y verificar si están
dentro de un rango especificado.
La función deberá:
• Aceptar tres argumentos: una entrada, un límite inferior aceptable y un límite
superior aceptable.
• Si el usuario ingresa una cadena que no es un valor entero, la función debe emitir
el mensaje Error: entrada incorrecta , y solicitará al usuario que ingrese el
valor nuevamente.
• Si el usuario ingresa un número que está fuera del rango especificado, la función
debe emitir el mensaje Error: el valor no está dentro del rango
permitido (min..max) y solicitará al usuario que ingrese el valor nuevamente.
• Si el valor de entrada es válido, será regresado como resultado.
Datos de Prueba
Prueba tu código cuidadosamente.
Puntos Clave
1. Algunas excepciones integradas abstractas de Python son:
• ArithmeticError .
• BaseException .
• LookupError .
• AssertionError .
• ImportError .
• IndexError .
• KeyboardInterrupt .
• KeyError .
• MemoryError .
• OverflowError .
Ejercicio 1
¿Cuál de las excepciones se utilizará para proteger al código de ser interrumpido por el
uso del teclado?
Revisar
KeyboardInterrupt
Ejercicio 2
Revisar
BaseException
Ejercicio 3
huge_value = 1E250 ** 2
Revisar
OverflowError
Fundamentos de Python 2:
Módulo 3
Programación Orientada a Objetos
Casi todos los programas y técnicas que has utilizado hasta ahora pertenecen al estilo de
programación procedimental. Es cierto que has utilizado algunos objetos incorporados,
pero cuando nos referimos a ellos, se mencionan lo mínimo posible.
El enfoque orientado a objetos es bastante joven (mucho más joven que el enfoque
procedimental) y es particularmente útil cuando se aplica a proyectos grandes y
complejos llevados a cabo por grandes equipos formados por muchos desarrolladores.
Este tipo de programación en un proyecto facilita muchas tareas importantes, por
ejemplo, dividir el proyecto en partes pequeñas e independientes y el desarrollo
independiente de diferentes elementos del proyecto.
Además, puedes crear muchas aplicaciones útiles, incluso si no se sabe nada sobre clases
y objetos, pero debes tener en cuenta que algunos de los problemas (por ejemplo, el
manejo de la interfaz gráfica de usuario) puede requerir un enfoque estricto de objetos.
Las funciones pueden usar datos, pero no al revés. Además, las funciones pueden abusar
de los datos, es decir, usar el valor de manera no autorizada (por ejemplo, cuando la
función seno recibe el saldo de una cuenta bancaria como parámetro).
Los datos no pueden usar funciones. ¿Pero es esto completamente cierto? ¿Hay algunos
tipos especiales de datos que puedan usar funciones?
Sí, los hay, los llamados métodos. Estas son funciones que se invocan desde dentro de los
datos, no junto con ellos. Si puedes ver esta distinción, has dado el primer paso en la
programación de objetos.
Las recetas pueden modificarse si son inadecuadas para fines específicos y, en efecto,
pueden crearse nuevas clases. Estas nuevas clases heredan propiedades y métodos de
los originales, y generalmente agregan algunos nuevos, creando nuevas herramientas
más específicas.
Los objetos son encarnaciones de las ideas expresadas en clases, como un pastel de
queso en tu plato, es una encarnación de la idea expresada en una receta impresa en un
viejo libro de cocina.
Los objetos interactúan entre sí, intercambian datos o activan sus métodos. Una clase
construida adecuadamente (y, por lo tanto, sus objetos) puede proteger los datos
sensibles y ocultarlos de modificaciones no autorizadas.
No existe un límite claro entre los datos y el código: viven como uno solo dentro de los
objetos.
Todos estos conceptos no son tan abstractos como pudieras pensar al principio. Por el
contrario, todos están tomados de experiencias de la vida real y, por lo tanto, son
extremadamente útiles en la programación de computadoras: no crean vida
artificial reflejan hechos reales, relaciones y circunstancias.
Jerarquías de clase
La palabra clases tiene muchos significados, pero no todos son compatibles con las ideas
que queremos discutir aquí. La clase que nos concierne es como una categoría, como
resultado de similitudes definidas con precisión.
Intentaremos señalar algunas clases que son buenos ejemplos de este concepto.
Veamos por un momento los vehículos. Todos los vehículos existentes (y los que aún no
existen) están relacionados por una sola característica importante: la capacidad de
moverse. Puedes argumentar que un perro también se mueve; ¿Es un perro un vehículo?
No lo es. Tenemos que mejorar la definición, es decir, enriquecerla con otros criterios,
distinguir los vehículos de otros seres y crear una conexión más fuerte. Consideremos las
siguientes circunstancias: los vehículos son entidades creadas artificialmente que se
utilizan para el transporte, movidos por fuerzas de la naturaleza y dirigidos (conducidos)
por humanos.
La clase Vehículos es muy amplia. Tenemos que definir clases especializadas. Las clases
especializadas son las subclases. La clase Vehículos será una superclase para todas ellas.
Nota: la jerarquía crece de arriba hacia abajo, como raíces de árboles, no ramas. La clase
más general y más amplia siempre está en la parte superior (la superclase) mientras que
sus descendientes se encuentran abajo (las subclases).
• Vehículos Terrestres.
• Vehículos Acuáticos.
• Vehículos Aéreos.
• Vehículos Espaciales.
Los vehículos terrestres pueden dividirse aún más, según el método con el que impactan
el suelo. Entonces, podemos enumerar:
Podemos decir que todos los Animales (nuestra clase de nivel superior) se puede dividir
en cinco subclases:
• Mamíferos.
• Reptiles.
• Aves.
• Peces.
• Anfibios.
• Mamíferos Salvajes.
• Mamíferos Domesticados.
Intenta extender la jerarquía de la forma que quieras y encuentra el lugar adecuado para
los humanos.
¿Qué es un objeto?
Una clase (entre otras definiciones) es un conjunto de objetos. Un objeto es un ser
perteneciente a una clase.
Un objeto es una encarnación de los requisitos, rasgos y cualidades asignados a una clase
específica. Esto puede sonar simple, pero ten en cuenta las siguientes circunstancias
importantes. Las clases forman una jerarquía.
Esto puede significar que un objeto que pertenece a una clase específica pertenece a
todas las superclases al mismo tiempo. También puede significar que cualquier objeto
perteneciente a una superclase puede no pertenecer a ninguna de sus subclases.
Cada subclase es más especializada (o más específica) que su superclase. Por el contrario,
cada superclase es más general (más abstracta) que cualquiera de sus subclases.
Ten en cuenta que hemos supuesto que una clase solo puede tener una superclase; esto
no siempre es cierto, pero discutiremos este tema más adelante.
Herencia
Definamos uno de los conceptos fundamentales de la programación de objetos,
llamado herencia. Cualquier objeto vinculado a un nivel específico de una jerarquía de
clases hereda todos los rasgos (así como los requisitos y cualidades) definidos dentro de
cualquiera de las superclases.
La clase de inicio del objeto puede definir nuevos rasgos (así como requisitos y
cualidades) que serán heredados por cualquiera de sus superclases.
No deberías tener ningún problema para hacer coincidir esta regla con ejemplos
específicos, ya sea que se aplique a animales o vehículos.
3.1.1.6 Los fundamentos de la POO
Existe una pista (aunque esto no siempre funciona) que te puede ayudar a identificar
cualquiera de las tres esferas anteriores. Cada vez que se describe un objeto y se usa:
Tu primera clase
La programación orientada a objetos es el arte de definir y expandir clases. Una clase es
un modelo de una parte muy específica de la realidad, que refleja las propiedades y
actividades que se encuentran en el mundo real.
Las clases definidas al principio son demasiado generales e imprecisas para cubrir el
mayor número posible de casos reales.
No hay obstáculo para definir nuevas subclases más precisas. Heredarán todo de su
superclase, por lo que el trabajo que se utilizó para su creación no se desperdicia.
La nueva clase puede agregar nuevas propiedades y nuevas actividades y, por lo tanto,
puede ser más útil en aplicaciones específicas. Obviamente, se puede usar como una
superclase para cualquier número de subclases recién creadas.
El proceso no necesita tener un final. Puedes crear tantas clases como necesites.
La clase que se define no tiene nada que ver con el objeto: la existencia de una clase no
significa que ninguno de los objetos compatibles se creará automáticamente. La clase en
sí misma no puede crear un objeto: debes crearlo tu mismo y Python te permite hacerlo.
Es hora de definir la clase más simple y crear un objeto. Analiza el siguiente ejemplo:
class TheSimplestClass:
pass
La definición comienza con la palabra clave reservada class . La palabra clave reservada
es seguida por un identificador que le dará nombre a la clase (nota: no lo confundas con
el nombre del objeto: estas son dos cosas diferentes).
A continuación, se agregan dos puntos ( : ), como clases, como funciones, forman su
propio bloque anidado. El contenido dentro del bloque define todas las propiedades y
actividades de la clase.
La palabra clave reservada pass llena la clase con nada. No contiene ningún método ni
propiedades.
Tu primer objeto
La clase recién definida se convierte en una herramienta que puede crear nuevos objetos.
La herramienta debe usarse explícitamente, bajo demanda.
Para hacer esto, debes asignar una variable para almacenar el objeto recién creado de
esa clase y crear un objeto al mismo tiempo.
my_first_object = TheSimplestClass()
Nota:
• El nombre de la clase intenta fingir que es una función, ¿puedes ver esto? Lo
discutiremos pronto.
• El objeto recién creado está equipado con todo lo que trae la clase. Como esta
clase está completamente vacía, el objeto también está vacío.
El acto de crear un objeto de la clase seleccionada también se llama instanciación (ya que
el objeto se convierte en una instancia de la clase).
Dejemos las clases en paz por un breve momento, ya que ahora diremos algunas
palabras sobre pilas. Sabemos que el concepto de clases y objetos puede no estar
completamente claro todavía. No te preocupes, te explicaremos todo muy pronto.
Puntos Clave
1. Una clase es una idea (más o menos abstracta) que se puede utilizar para crear varias
encarnaciones; una encarnación de este tipo se denomina objeto.
2. Cuando una clase se deriva de otra clase, su relación se denomina herencia. La clase
que deriva de la otra clase se denomina subclase. El segundo lado de esta relación se
denomina superclase. Una forma de presentar dicha relación es en un diagrama de
herencia, donde:
4. Para definir una clase de Python,se necesita usar la palabra clave reservada class . Por
ejemplo:
class This_Is_A_Class:
pass
5. Para crear un objeto de la clase previamente definida, se necesita usar la clase como si
fuera una función. Por ejemplo:
this_is_an_object = This_Is_A_Class()
Ejercicio 1
Si asumimos que pitones, víboras y cobras son subclases de la misma superclase, ¿cómo
la llamarías?
Revisar
Serpiente, reptil, vertebrado, animal: todas estas respuestas son aceptables.
Ejercicio 2
Revisar
Pitón india, Pitón de Roca Sfricana, Pitón Bola, Pitón Birmana: la lista es larga.
Ejercicio 3
¿Puedes usar la palabra "class" para darle nombre a alguna de tus clases?
Revisar
¡No, no puedes, class es una palabra clave reservada!
3.2.1.1 Un corto viaje desde el enfoque procedimental hacia el
orientado a objetos
Del mismo modo, no puedes sacar una moneda de la pila desde ningún lugar que no sea
la parte superior de la pila. Si deseas obtener la moneda que se encuentra en la parte
inferior, debes eliminar todas las monedas de los niveles superiores.
El nombre alternativo para una pila (pero solo en la terminología de TI) es UEPS (LIFO son
sus siglas en inglés).
Es una abreviatura para una descripción muy clara del comportamiento de la pila: Último
en Entrar - Primero en Salir (Last In - First Out). La moneda que quedó en último lugar en
la pila saldrá primero.
Las pilas se usan muy a menudo en muchos algoritmos clásicos, y es difícil imaginar la
implementación de muchas herramientas ampliamente utilizadas sin el uso de pilas.
Implementemos una pila en Python. Esta será una pila muy simple, y te mostraremos
como hacerlo en dos enfoques independientes: de manera procedimental y orientado a
objetos.
stack = []
Estamos listos para definir una función que coloca un valor en la pila. Aquí están las
presuposiciones para ello:
def push(val):
stack.append(val)
Ahora es tiempo de que una función quite un valor de la pila. Así es como puedes
hacerlo:
def pop():
val = stack[-1]
del stack[-1]
return val
Armemos todas las piezas juntas para poner la pila en movimiento. El programa
completo empuja (push) tres números a la pila, los saca e imprime sus valores en
pantalla. Puedes verlo en la ventana del editor.
El programa muestra el siguiente texto en pantalla:
1
2
3
salida
Pruébalo.
stack = []
def push(val):
stack.append(val)
def pop():
val = stack[-1]
del stack[-1]
return val
push(3)
push(2)
push(1)
print(pop())
print(pop())
print(pop())
Pero cuanto más la uses, más desventajas encontrarás. Éstas son algunas de ellas:
stack[0] = 0
• También puede suceder que un día necesites más de una pila; tendrás que crear
otra lista para el almacenamiento de la pila, y probablemente otras
funciones push y pop .
• También puede suceder que no solo necesites funciones push y pop , pero
también algunas otras funciones; ciertamente podrías implementarlas, pero
intenta imaginar qué sucedería si tuvieras docenas de pilas implementadas por
separado.
El enfoque orientado a objetos ofrece soluciones para cada uno de los problemas
anteriores. Vamos a nombrarlos primero:
• Cuando tienes una clase que implementa todos los comportamientos de pila
necesarios, puedes producir tantas pilas como desees; no necesitas copiar ni
replicar ninguna parte del código.
Ahora escribamos una nueva implementación de pila desde cero. Esta vez, utilizaremos el
enfoque orientado a objetos, que te guiará paso a paso en el mundo de la programación
de objetos.
3.2.1.4 Un corto viaje desde el enfoque procedimental hacia el
orientado a objetos
class Stack:
En su lugar, debes agregar una instrucción específica. Las propiedades deben agregarse a
la clase manualmente.
¿Cómo garantizar que dicha actividad tiene lugar cada vez que se crea una nueva pila?
Existe una manera simple de hacerlo, tienes que equipar a la clase con una función
específica:
class Stack:
def __init__(self):
print("¡Hola!")
stack_object = Stack()
Expliquemos más a detalle:
¡Hola!
salida
Nota: no hay rastro de la invocación del constructor dentro del código. Ha sido invocado
implícita y automáticamente. Hagamos uso de eso ahora.
Ahora agreguemos solo una propiedad al nuevo objeto, una lista para la pila. La
nombraremos stack_list .
class Stack:
def __init__(self):
self.stack_list = []
stack_object = Stack()
print(len(stack_object.stack_list))
Nota:
• Hemos usado la notación punteada, al igual que cuando se invocan métodos. Esta
es la manera general para acceder a las propiedades de un objeto: debes
nombrar el objeto, poner un punto ( . ) después de el, y especificar el nombre de la
propiedad deseada, ¡no uses paréntesis! No deseas invocar un método,
deseas acceder a una propiedad.
• Si estableces el valor de una propiedad por primera vez (como en el constructor),
lo estás creando; a partir de ese momento, el objeto tiene la propiedad y está listo
para usar su valor.
• Hemos hecho algo más en el código: hemos intentado acceder a la
propiedad stack_list desde fuera de la clase inmediatamente después de que
se haya creado el objeto; queremos verificar la longitud actual de la pila, ¿lo
hemos logrado?
0
salida
class Stack:
def __init__(self):
self.stack_list = []
stack_object = Stack()
print(len(stack_object.stack_list))
stack_object = Stack()
print(len(stack_object.__stack_list))
¿Por qué?
Cuando cualquier componente de la clase tiene un nombre que comienza con dos
guiones bajos ( __ ), se vuelve privado, esto significa que solo se puede acceder desde
dentro de la clase.
No puedes verlo desde el mundo exterior. Así es como Python implementa el concepto
de encapsulación.
class Stack:
def __init__(self):
self.__stack_list = []
stack_object = Stack()
print(len(stack_object.__stack_list))
Tal componente es llamado público, por ello no puede comenzar su nombre con dos (o
más) guiones bajos. Hay un requisito más el nombre no debe tener más de un guión
bajo.
Las funciones en sí son simples. Echa un vistazo:
class Stack:
def __init__(self):
self.__stack_list = []
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
stack_object = Stack()
stack_object.push(3)
stack_object.push(2)
stack_object.push(1)
print(stack_object.pop())
print(stack_object.pop())
print(stack_object.pop())
Sin embargo, hay algo realmente extraño en el código. Las funciones parecen familiares,
pero tienen más parámetros que sus contrapartes procedimentales.
Todos los métodos deben tener este parámetro. Desempeña el mismo papel que el
primer parámetro constructor.
Esto significa que el método está obligado a tener al menos un parámetro, que Python
mismo utiliza, no tienes ninguna influencia sobre el.
Hay una cosa más que requiere explicación: la forma en que se invocan los métodos
desde la variable __stack_list .
class Stack:
def __init__(self):
self.__stack_list = []
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
stack_object = Stack()
stack_object.push(3)
stack_object.push(2)
stack_object.push(1)
print(stack_object.pop())
print(stack_object.pop())
print(stack_object.pop())
Analiza el código:
class Stack:
def __init__(self):
self.__stack_list = []
def push(self, val):
self.__stack_list.append(val)
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
stack_object_1 = Stack()
stack_object_2 = Stack()
stack_object_1.push(3)
stack_object_2.push(stack_object_1.pop())
print(stack_object_2.pop())
Existen dos pilas creadas a partir de la misma clase base. Trabajan independientemente.
Puedes crear más si quieres.
Ejecuta el código en el editor y observa que sucede. Realiza tus propios experimentos.
class Stack:
def __init__(self):
self.__stack_list = []
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
stack_object_1 = Stack()
stack_object_2 = Stack()
stack_object_1.push(3)
stack_object_2.push(stack_object_1.pop())
print(stack_object_2.pop())
class Stack:
def __init__(self):
self.__stack_list = []
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
little_stack = Stack()
another_stack = Stack()
funny_stack = Stack()
little_stack.push(1)
another_stack.push(little_stack.pop() + 1)
funny_stack.push(another_stack.pop() - 2)
print(funny_stack.pop())
class Stack:
def __init__(self):
self.__stack_list = []
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
La nueva clase debería poder evaluar la suma de todos los elementos almacenados
actualmente en la pila.
El primer paso es fácil: solo define una nueva subclase que apunte a la clase que se usará
como superclase.
class AddingStack(Stack):
pass
La clase aún no define ningún componente nuevo, pero eso no significa que esté
vacía. Obtiene (hereda) todos los componentes definidos por su superclase, el nombre de
la superclase se escribe después de los dos puntos, después del nombre de la nueva
clase.
• Queremos que el método push no solo inserte el valor en la pila, sino que
también sume el valor a la variable sum .
• Queremos que la función pop no solo extraiga el valor de la pila, sino que también
reste el valor de la variable sum .
En primer lugar, agreguemos una nueva variable a la clase. Será una variable privada, al
igual que la lista de pila. No queremos que nadie manipule el valor de la variable sum .
Como ya sabes, el constructor agrega una nueva propiedad a la clase. Ya sabes como
hacerlo, pero hay algo realmente intrigante dentro del constructor. Echa un vistazo:
class AddingStack(Stack):
def __init__(self):
Stack.__init__(self)
self.__sum = 0
La segunda línea del cuerpo del constructor crea una propiedad llamada __sum ,
almacenará el total de todos los valores de la pila.
Pero la línea anterior se ve diferente. ¿Qué hace? ¿Es realmente necesaria? Sí lo es.
Al contrario de muchos otros lenguajes, Python te obliga a invocar explícitamente el
constructor de una superclase. Omitir este punto tendrá efectos nocivos: el objeto se
verá privado de la lista __stack_list . Tal pila no funcionará correctamente.
Esta es la única vez que puedes invocar a cualquiera de los constructores disponibles
explícitamente; se puede hacer dentro del constructor de la superclase.
class Stack:
def __init__(self):
self.__stack_list = []
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
class AddingStack(Stack):
def __init__(self):
Stack.__init__(self)
self.__sum = 0
Se dice que el método push ha sido anulado, el mismo nombre que en la superclase
ahora representa una funcionalidad diferente.
class Stack:
def __init__(self):
self.__stackList = []
def pop(self):
val = self.__stackList[-1]
del self.__stackList[-1]
return val
class AddingStack(Stack):
def __init__(self):
Stack.__init__(self)
self.__sum = 0
def pop(self):
val = Stack.pop(self)
self.__sum -= val
return val
Aquí está:
def get_sum(self):
return self.__sum
Como puedes ver, agregamos cinco valores subsiguientes en la pila, imprimimos su suma
y los sacamos todos de la pila.
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
class AddingStack(Stack):
def __init__(self):
Stack.__init__(self)
self.__sum = 0
def get_sum(self):
return self.__sum
def pop(self):
val = Stack.pop(self)
self.__sum -= val
return val
stack_object = AddingStack()
for i in range(5):
stack_object.push(i)
print(stack_object.get_sum())
for i in range(5):
print(stack_object.pop())
6. Si queremos ocultar alguno de los componentes de una clase del mundo exterior,
debemos comenzar su nombre con __ . Estos componentes se denominan privados.
Ejercicio 1
Suponiendo que hay una clase llamada Snakes , escribe la primera línea de la declaración
de clase Python , expresando el hecho de que la nueva clase es en realidad una subclase
de Snake.
Revisar
class Python(Snakes):
Ejercicio 2
class Snakes
def __init__():
self.sound = 'Sssssss'
Revisar
Ejercicio 3
class Snakes
def __init__(self):
self.venomous = True
Revisar
El código debería verse como sigue:
class Snakes
def __init__(self):
self.__venomous = True
Tiempo Estimado
20-45 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
• Mejorar las habilidades del estudiante para definir clases.
• Emplear clases existentes para crear nuevas clases equipadas con nuevas
funcionalidades.
Escenario
Recientemente te mostramos cómo extender las posibilidades de Stack definiendo una
nueva clase (es decir, una subclase) que retiene todos los rasgos heredados y agrega
algunos nuevos.
• Introduce una propiedad diseñada para contar las operaciones pop y nombrarla
de una manera que garantice que esté oculta.
• Inicializala a cero dentro del constructor.
• Proporciona un método que devuelva el valor asignado actualmente al contador
(nómbralo get_counter() ).
Completa el código en el editor. Ejecútalo para comprobar si tu código da como salida
100.
class Stack:
def __init__(self):
self.__stk = []
def pop(self):
val = self.__stk[-1]
del self.__stk[-1]
return val
class CountingStack(Stack):
def __init__(self):
#
# Llena el constructor con acciones apropiadas.
#
def get_counter(self):
#
# Presenta el valor actual del contador al mundo.
#
def pop(self):
#
# Haz un pop y actualiza el contador.
#
stk = CountingStack()
for i in range(100):
stk.push(i)
stk.pop()
print(stk.get_counter())
Tiempo Estimado
20-45 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
• Mejorar las habilidades del estudiante para definir clases desde cero.
• Implementar estructuras de datos estándar como clases.
Escenario
Como ya sabes, una pila es una estructura de datos que realiza el modelo LIFO (último en
entrar, primero en salir). Es fácil y ya te has acostumbrado a ello perfectamente.
Probemos algo nuevo ahora. Una cola (queue) es un modelo de datos caracterizado por
el término FIFO: primero en entrar, primero en salir. Nota: una cola (fila) regular que
conozcas de las tiendas u oficinas de correos funciona exactamente de la misma manera:
un cliente que llegó primero también es el primero en ser atendido.
Salida Esperada
1
perro
False
Error de Cola
def get(self):
#
# Escribe código aquí.
#
que = Queue()
que.put(1)
que.put("perro")
que.put(False)
try:
for i in range(4):
print(que.get())
except:
print("Error de Cola")
Nivel de Dificultad
Fácil/Medio
Objetivos
• Mejorar las habilidades del estudiante para definir subclases.
• Agregar nueva funcionalidad a una clase existente.
Escenario
Tu tarea es extender ligeramente las capacidades de la clase Queue . Queremos que tenga
un método sin parámetros que devuelva True si la cola está vacía y False de lo
contrario.
Revisar
class QueueError(IndexError):
pass
class Queue:
def __init__(self):
self.queue = []
def put(self,elem):
self.queue.insert(0,elem)
def get(self):
if len(self.queue) > 0:
elem = self.queue[-1]
del self.queue[-1]
return elem
else:
raise QueueError
Saluda Esperada
1
perro
False
Cola vacía
class QueueError(???):
pass
class Queue:
#
# Código del laboratorio anterior.
#
class SuperQueue(Queue):
#
# Escribe código nuevo aquí.
#
que = SuperQueue()
que.put(1)
que.put("perro")
que.put(False)
for i in range(4):
if not que.isempty():
print(que.get())
else:
print("Cola vacía")
Variables de instancia
En general, una clase puede equiparse con dos tipos diferentes de datos para formar las
propiedades de una clase. Ya viste uno de ellos cuando estábamos estudiando pilas.
Este tipo de propiedad existe solo cuando se crea explícitamente y se agrega a un objeto.
Como ya sabes, esto se puede hacer durante la inicialización del objeto, realizada por el
constructor.
La palabra instancia sugiere que están estrechamente conectadas a los objetos (que son
instancias de clase), no a las clases mismas. Echemos un vistazo más de cerca.
class ExampleClass:
def __init__(self, val = 1):
self.first = val
def set_second(self, val):
self.second = val
example_object_1 = ExampleClass()
example_object_2 = ExampleClass(2)
example_object_2.set_second(3)
example_object_3 = ExampleClass(4)
example_object_3.third = 5
print(example_object_1.__dict__)
print(example_object_2.__dict__)
print(example_object_3.__dict__)
Se necesita una explicación adicional antes de entrar en más detalles. Echa un vistazo a
las últimas tres líneas del código.
La variable contiene los nombres y valores de todas las propiedades (variables) que el
objeto contiene actualmente. Vamos a usarla para presentar de forma segura el
contenido de un objeto.
• Hemos creado tres objetos de la clase ExampleClass , pero todas estas instancias
difieren:
La salida del programa muestra claramente que nuestras suposiciones son correctas:
aquí están:
{'first': 1}
{'second': 3, 'first': 2}
{'third': 5, 'first': 4}
salida
Hay una conclusión adicional que debería mencionarse aquí: el modificar una variable de
instancia de cualquier objeto no tiene impacto en todos los objetos restantes. Las
variables de instancia están perfectamente aisladas unas de otras.
Es casi lo mismo que el anterior. La única diferencia está en los nombres de las
propiedades. Hemos antepuesto dos guiones bajos ( __ ).
Como sabes, tal adición hace que la variable de instancia sea privada, se vuelve
inaccesible desde el mundo exterior.
{'_ExampleClass__first': 1}
{'_ExampleClass__first': 2, '_ExampleClass__second': 3}
{'_ExampleClass__first': 4, '__third': 5}
salida
¿Puedes ver estos nombres extraños llenos de guiones bajos? ¿De dónde provienen?
Cuando Python ve que deseas agregar una variable de instancia a un objeto y lo vas a
hacer dentro de cualquiera de los métodos del objeto, maneja la operación de la
siguiente manera:
print(example_object_1._ExampleClass__first)
Como puedes ver, hacer que una propiedad sea privada es limitado.
No funcionará si agregas una variable de instancia fuera del código de la clase. En este
caso, se comportará como cualquier otra propiedad ordinaria.
class ExampleClass:
def __init__(self, val = 1):
self.__first = val
example_object_1 = ExampleClass()
example_object_2 = ExampleClass(2)
example_object_2.set_second(3)
example_object_3 = ExampleClass(4)
example_object_3.__third = 5
print(example_object_1.__dict__)
print(example_object_2.__dict__)
print(example_object_3.__dict__)
Variables de clase
Una variable de clase es una propiedad que existe en una sola copia y se almacena fuera
de cualquier objeto.
Nota: no existe una variable de instancia si no hay ningún objeto de la clase; solo existe
una variable de clase en una copia, incluso si no hay objetos en la clase.
class ExampleClass:
counter = 0
def __init__(self, val = 1):
self.__first = val
ExampleClass.counter += 1
example_object_1 = ExampleClass()
example_object_2 = ExampleClass(2)
example_object_3 = ExampleClass(4)
print(example_object_1.__dict__, example_object_1.counter)
print(example_object_2.__dict__, example_object_2.counter)
print(example_object_3.__dict__, example_object_3.counter)
Observa:
{'_ExampleClass__first': 1} 3
{'_ExampleClass__first': 2} 3
{'_ExampleClass__first': 4} 3
salida
class ExampleClass:
__counter = 0
def __init__(self, val = 1):
self.__first = val
ExampleClass.__counter += 1
example_object_1 = ExampleClass()
example_object_2 = ExampleClass(2)
example_object_3 = ExampleClass(4)
print(example_object_1.__dict__, example_object_1._ExampleClass__counter)
print(example_object_2.__dict__, example_object_2._ExampleClass__counter)
print(example_object_3.__dict__, example_object_3._ExampleClass__counter)
Como puedes ver __dict__ contiene muchos más datos que la contraparte de su objeto.
La mayoría de ellos son inútiles ahora, el que queremos que verifiques cuidadosamente
muestra el valor actual de varia .
Nota que el __dict__ del objeto está vacío, el objeto no tiene variables de instancia.
class ExampleClass:
varia = 1
def __init__(self, val):
ExampleClass.varia = val
print(ExampleClass.__dict__)
example_object = ExampleClass(2)
print(ExampleClass.__dict__)
print(example_object.__dict__)
El objeto creado por el constructor solo puede tener uno de los dos atributos
posibles: a o b .
1
Traceback (most recent call last):
File ".main.py", line 11, in
print(example_object.b)
AttributeError: 'ExampleClass' object has no attribute 'b'
salida
Como puedes ver, acceder a un atributo de objeto (clase) no existente genera una
excepción AttributeError.
class ExampleClass:
def __init__(self, val):
if val % 2 != 0:
self.a = 1
else:
self.b = 1
example_object = ExampleClass(1)
print(example_object.a)
print(example_object.b)
Como puedes ver, esta acción no es muy sofisticada. Esencialmente, acabamos de barrer
el tema debajo de la alfombra.
Python proporciona una función que puede verificar con seguridad si algún objeto / clase
contiene una propiedad específica. La función se llama hasattr , y espera que le pasen
dos argumentos:
class ExampleClass:
def __init__(self, val):
if val % 2 != 0:
self.a = 1
else:
self.b = 1
example_object = ExampleClass(1)
print(example_object.a)
if hasattr(example_object, 'b'):
print(example_object.b)
class ExampleClass:
def __init__(self, val):
if val % 2 != 0:
self.a = 1
else:
self.b = 1
example_object = ExampleClass(1)
print(example_object.a)
try:
print(example_object.b)
except AttributeError:
pass
¿Puedes adivinar la salida del código? Ejecútalo para verificar tus conjeturas.
class ExampleClass:
a = 1
def __init__(self):
self.b = 2
example_object = ExampleClass()
print(hasattr(example_object, 'b'))
print(hasattr(example_object, 'a'))
print(hasattr(ExampleClass, 'b'))
print(hasattr(ExampleClass, 'a'))
Bien, hemos llegado al final de esta sección. En la siguiente sección vamos a hablar sobre
los métodos, ya que los métodos dirigen los objetos y los activan.
class ExampleClass:
attr = 1
print(hasattr(ExampleClass, 'attr'))
print(hasattr(ExampleClass, 'prop'))
Puntos Clave
Además, se pueden agregar y quitar libremente de los objetos durante su vida útil. Todas
las variables de instancia de objeto se almacenan dentro de un diccionario dedicado
llamado __dict__ , contenido en cada objeto por separado.
2. Una variable de instancia puede ser privada cuando su nombre comienza con __ , pero
no olvides que dicha propiedad aún es accesible desde fuera de la clase usando
un nombre modificado construido como < codel>_ClassName__PrivatePropertyName.
3. Una variable de clase es una propiedad que existe exactamente en una copia y no
necesita ningún objeto creado para ser accesible. Estas variables no se muestran como
contenido de __dict__ .
Todas las variables de clase de una clase se almacenan dentro de un diccionario dedicado
llamado __dict__ , contenido en cada clase por separado.
4. Una función llamada hasattr() se puede utilizar para determinar si algún objeto o
clase contiene cierta propiedad especificada.
Por ejemplo:
class Sample:
gamma = 0 # Class variable.
def __init__(self):
self.alpha = 1 # Variable de instancia.
self.__delta = 3 # Variable de instancia privada.
obj = Sample()
obj.beta = 2 # Otra variable de instancia (que existe solo dentro de
la instancia "obj").
print(obj.__dict__)
Ejercicio 1
¿Cuáles de las propiedades de la clase Python son variables de instancia y cuáles son
variables de clase? ¿Cuáles de ellos son privados?
class Python:
population = 1
victims = 0
def __init__(self):
self.length_ft = 3
self.__venomous = False
Revisar
population y victims son variables de clase, mientras que length y __venomous son
variables de instancia (esta última también es privada).
Ejercicio 2
Vas a negar la propiedad __venomous del objeto version_2 , ignorando el hecho de que
la propiedad es privada. ¿Cómo vas a hacer esto?
version_2 = Python()
Revisar
Ejercicio 3
Escribe una expresión que compruebe si el objeto version_2 contiene una propiedad de
instancia denominada constrictor (¡si, constrictor!).
Revisar
hasattr(version_2, 'constrictor')
Métodos a detalle
Resumamos todos los hechos relacionados con el uso de métodos en las clases de
Python.
Como ya sabes, un método es una función que está dentro de una clase.
El nombre self sugiere el propósito del parámetro: identifica el objeto para el cual se
invoca el método.
método
salida
Toma en cuenta la forma en que hemos creado el objeto, hemos tratado el nombre de la
clase como una función, y devuelve un objeto recién instanciado de la clase.
class Classy:
def method(self, par):
print("método:", par)
obj = Classy()
obj.method(1)
obj.method(2)
obj.method(3)
método: 1
método: 2
método: 3
salida
class Classy:
def method(self):
print("método")
obj = Classy()
obj.method()
3.4.1.2 POO: Métodos
class Classy:
varia = 2
def method(self):
print(self.varia, self.var)
obj = Classy()
obj.var = 3
obj.method()
2 3
salida
El parámetro self también se usa para invocar otros métodos desde dentro de la clase.
class Classy:
def other(self):
print("otro")
def method(self):
print("método")
self.other()
obj = Classy()
obj.method()
método
otro
salida
# Probar ejemplos aquí.
El constructor:
objeto
salida
• No puede retornar un valor, ya que está diseñado para devolver un objeto recién
creado y nada más.
• No se puede invocar directamente desde el objeto o desde dentro de la
clase (puedes invocar un constructor desde cualquiera de las superclases del
objeto, pero discutiremos esto más adelante).
class Classy:
def __init__(self, value):
self.var = value
obj_1 = Classy("objeto")
print(obj_1.var)
objeto
None
salida
Todo lo que hemos dicho sobre el manejo de los nombres también se aplica a los
nombres de métodos, un método cuyo nombre comienza con __ está (parcialmente)
oculto.
class Classy:
def visible(self):
print("visible")
def __hidden(self):
print("oculto")
obj = Classy()
obj.visible()
try:
obj.__hidden()
except:
print("fallido")
obj._Classy__hidden()
visible
fallido
oculto
salida
class Classy:
def __init__(self, value = None):
self.var = value
obj_1 = Classy("objeto")
obj_2 = Classy()
print(obj_1.var)
print(obj_2.var)
Observemos como esta propiedad trata con los métodos: mira el código en el editor.
Encuentra todos los métodos y atributos definidos. Localiza el contexto en el que existen:
dentro del objeto o dentro de la clase.
class Classy:
varia = 1
def __init__(self):
self.var = 2
def method(self):
pass
def __hidden(self):
pass
obj = Classy()
print(obj.__dict__)
print(Classy.__dict__)
Nota: el atributo __name__ está ausente del objeto, existe solo dentro de las clases.
Classy
Classy
salida
print(obj.__name__)
causará un error.
class Classy:
pass
print(Classy.__name__)
obj = Classy()
print(type(obj).__name__)
__main__
__main__
salida
print(Classy.__module__)
obj = Classy()
print(obj.__module__)
Te mostraremos solo un ejemplo muy básico, ya que queremos resaltar cómo funciona la
herencia.
Además, te mostraremos cómo usar este atributo cuando discutamos los aspectos
orientados a objetos de las excepciones.
Nota: solo las clases tienen este atributo, los objetos no.
( object )
( object )
( SuperOne SuperTwo )
salida
Nota: una clase sin superclases explícitas apunta a object (una clase de Python
predefinida) como su antecesor directo.
class SuperOne:
pass
class SuperTwo:
pass
for x in cls.__bases__:
print(x.__name__, end=' ')
print(')')
printBases(SuperOne)
printBases(SuperTwo)
printBases(Sub)
Reflexión e introspección
Todo esto permite que el programador de Python realice dos actividades importantes
específicas para muchos lenguajes objetivos. Las cuales son:
Investigando Clases
¿Qué puedes descubrir acerca de las clases en Python? La respuesta es simple: todo.
Tanto la reflexión como la introspección permiten al programador hacer cualquier cosa
con cada objeto, sin importar de dónde provenga.
¡Eso es todo!
class MyClass:
pass
obj = MyClass()
obj.a = 1
obj.b = 2
obj.i = 3
obj.ireal = 3.5
obj.integer = 4
obj.z = 5
def incIntsI(obj):
for name in obj.__dict__.keys():
if name.startswith('i'):
val = getattr(obj, name)
if isinstance(val, int):
setattr(obj, name, val + 1)
print(obj.__dict__)
incIntsI(obj)
print(obj.__dict__)
Puntos Clave
1. Un método es una función dentro de una clase. El primer (o único) parámetro de cada
método se suele llamar self , que está diseñado para identificar al objeto para el que se
invoca el método con el fin de acceder a las propiedades del objeto o invocar sus
métodos.
2. Si una clase contiene un constructor (un método llamado __init__ ), este no puede
devolver ningún valor y no se puede invocar directamente.
3. Todas las clases (pero no los objetos) contienen una propiedad llamada __name__ , que
almacena el nombre de la clase. Además, una propiedad llamada __module__ almacena
el nombre del módulo en el que se ha declarado la clase, mientras que la propiedad
llamada __bases__ es una tupla que contiene las superclases de una clase.
Por ejemplo:
class Sample:
def __init__(self):
self.name = Sample.__name__
def myself(self):
print("Mi nombre es " + self.name + " y vivo en " +
Sample.__module__)
obj = Sample()
obj.myself()
salida
Ejercicio 1
class Snake:
def __init__(self):
self.victims = 0
Revisar
class Snake:
def __init__(self):
self.victims = 0
def increment(self):
self.victims += 1
Ejercicio 2
Redefine el constructur de la clase Snake para que tenga un parámetro que inicialice el
campo victims con un valor pasado al objeto durante la construcción.
Revisar
class Snake:
def __init__(self, victims):
self.victims = victims
Ejercicio 3
¿Puedes predecir el resultado del siguiente código?
class Snake:
pass
class Python(Snake):
pass
Revisar
LABORATORIO
Tiempo Estimado
30-60 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
• Mejorar las habilidades del estudiante para definir clases desde cero.
• Definir y usar variables de instancia.
• Definir y usar métodos.
Escenario
Necesitamos una clase capaz de contar segundos. ¿Fácil? No es tan fácil como podrías
pensar, ya que tendremos algunos requisitos específicos.
Léelos con atención, ya que la clase sobre la que escribes se utilizará para lanzar cohetes
en misiones internacionales a Marte. Es una gran responsabilidad. ¡Contamos contigo!
• Los objetos de la clase deben ser "imprimibles", es decir, deben poder convertirse
implícitamente en cadenas de la siguiente forma: "hh:mm:ss", con ceros a la
izquierda agregados cuando cualquiera de los valores es menor que 10.
• La clase debe estar equipada con métodos sin parámetros
llamados next_second() y previous_second () , incrementando el tiempo
almacenado dentro de los objetos en +1/-1 segundos respectivamente.
class Timer:
def __init__( ??? ):
#
# Escribir código aquí.
#
def __str__(self):
#
# Escribir código aquí.
#
def next_second(self):
#
# Escribir código aquí.
#
def prev_second(self):
#
# Escribir código aquí.
#
Tiempo Estimado
30-60 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
• Mejorar las habilidades del estudiante para definir clases desde cero.
• Definir y usar variables de instancia.
• Definir y usar métodos.
Escenario
Tu tarea es implementar una clase llamada Weeker. Sí, tus ojos no te engañan, este
nombre proviene del hecho de que los objetos de esta clase podrán almacenar y
manipular los días de la semana.
Invocar al constructor con un argumento desde fuera de este conjunto debería generar la
excepción WeekDayError (defínela tu mismo; no te preocupes, pronto hablaremos sobre
la naturaleza objetiva de las excepciones). La clase debe proporcionar las siguientes
facilidades:
• Los objetos de la clase deben ser "imprimibles", es decir, deben poder convertirse
implícitamente en cadenas de la misma forma que los argumentos del
constructor.
• La clase debe estar equipada con métodos de un parámetro
llamados add_days(n) y subtract_days(n) , siendo n un número entero que
actualiza el día de la semana almacenado dentro del objeto mediante el número
de días indicado, hacia adelante o hacia atrás.
• Todas las propiedades del objeto deben ser privadas.
Salida Esperada
Lun
Mar
Dom
Lo siento, no puedo atender tu solicitud.
class WeekDayError(Exception):
pass
class Weeker:
#
# Escribir código aquí.
#
def __init__(self, day):
#
# Escribir código aquí.
#
def __str__(self):
#
# Escribir código aquí.
#
try:
weekday = Weeker('Lun')
print(weekday)
weekday.add_days(15)
print(weekday)
weekday.subtract_days(23)
print(weekday)
weekday = Weeker('Lun')
except WeekDayError:
print("Lo siento, no puedo atender tu solicitud.")
LABORATORIO
Tiempo Estimado
30-60 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
• Mejorar las habilidades del estudiante para definir clases desde cero.
• Definir y usar variables de instancia.
• Definir y usar métodos.
Escenario
Visitemos un lugar muy especial: un plano con el sistema de coordenadas cartesianas
(puedes obtener más información sobre este concepto
aquí: https://en.wikipedia.org/wiki/Cartesian_coordinate_system).
• Se llama Point .
• Su constructor acepta dos argumentos (x y y respectivamente), ambos por defecto
se igualan a cero.
• Todas las propiedades deben ser privadas.
• La clase contiene dos métodos sin parámetros llamados getx() y gety() , que
devuelven cada una de las dos coordenadas (las coordenadas se almacenan de
forma privada, por lo que no se puede acceder a ellas directamente desde el
objeto).
• La clase proporciona un método llamado distance_from_xy(x,y) , que calcula y
devuelve la distancia entre el punto almacenado dentro del objeto y el otro punto
dado en un par de números flotantes.
• La clase proporciona un método llamado distance_from_point(point) , que
calcula la distancia (como el método anterior), pero la ubicación del otro punto se
da como otro objeto de clase Point.
Salida esperada
1.4142135623730951
1.4142135623730951
import math
class Point:
def __init__(self, x=0.0, y=0.0):
#
# Escribir el código aquí.
#
def getx(self):
#
# Escribir el código aquí.
#
def gety(self):
#
# Escribir el código aquí.
#
point1 = Point(0, 0)
point2 = Point(1, 1)
print(point1.distance_from_point(point2))
print(point2.distance_from_xy(2, 0))
3.4.1.15 Triángulo
LABORATORIO
Tiempo Estimado
30-60 minutos
Nivel de Dificultad
Fácil/Medio
Objetivos
• Mejorar las habilidades del estudiante para definir clases desde cero.
• Emplear composición.
Escenario
Ahora vamos a colocar la clase Point (ver Lab 3.4.1.14) dentro de otra clase. Además,
vamos a poner tres puntos en una clase, lo que nos permitirá definir un triángulo.¿Cómo
podemos hacerlo?
• El constructor acepta tres argumentos - todos ellos son objetos de la clase Point .
• Los puntos se almacenan dentro del objeto como una lista privada
• La clase proporciona un método sin parámetros llamado perimeter() , que
calcula el perímetro del triángulo descrito por los tres puntos; el perímetro es la
suma de todas las longitudes de los lados (lo mencionamos para que conste,
aunque estamos seguros de que tú mismo lo conoces perfectamente).
Revisar
class Point:
def __init__(self, x=0.0, y=0.0):
self.__x = x
self.__y = y
Salida esperada
3.414213562373095
import math
class Point:
#
# El código copiado del laboratorio anterior.
#
class Triangle:
def __init__(self, vertice1, vertice2, vertice3):
#
# Escribir el código aquí.
#
def perimeter(self):
#
# Escribir el código aquí.
#
El programa imprime solo una línea de texto, que en nuestro caso es:
Como puedes ver, la impresión aquí no es realmente útil, y algo más específico, es
preferible.
class Star:
def __init__(self, name, galaxy):
self.name = name
self.galaxy = galaxy
El método por default __str__() devuelve la cadena anterior: fea y poco informativa.
Puedes cambiarlo definiendo tu propio método.
El método nuevo __str__() genera una cadena que consiste en los nombres de la
estrella y la galaxia, nada especial, pero los resultados de impresión se ven mejor ahora,
¿no?
class Star:
def __init__(self, name, galaxy):
self.name = name
self.galaxy = galaxy
def __str__(self):
return self.name + ' en ' + self.galaxy
En otras palabras, la herencia es una forma de construir una nueva clase, no desde cero,
sino utilizando un repertorio de rasgos ya definido. La nueva clase hereda (y esta es la
clave) todo el equipamiento ya existente, pero puedes agregar algo nuevo si es necesario.
Gracias a eso, es posible construir clases más especializadas (más concretas) utilizando
algunos conjuntos de reglas y comportamientos generales predefinidos.
El factor más importante del proceso es la relación entre la superclase y todas sus
subclases (nota: si B es una subclase de A y C es una subclase de B, esto también significa
que C es una subclase de A, ya que la relación es totalmente transitiva).
class Vehicle:
pass
class LandVehicle(Vehicle):
pass
class TrackedVehicle(LandVehicle):
pass
Todas las clases presentadas están vacías por ahora, ya que te mostraremos cómo
funcionan las relaciones mutuas entre las superclases y las subclases. Las llenaremos con
contenido pronto.
El conocimiento anterior proviene de la lectura del código (en otras palabras, lo sabemos
porque podemos verlo).
issubclass(ClassOne, ClassTwo)
Hay dos bucles anidados. Su propósito es verificar todos los pares de clases ordenadas
posibles y que imprima los resultados de la verificación para determinar si el par coincide
con la relación subclase-superclase.
Existe una observación importante que hacer: cada clase se considera una subclase de sí
misma.
class Vehicle:
pass
class LandVehicle(Vehicle):
pass
class TrackedVehicle(LandVehicle):
pass
Herencia: isinstance()
Como ya sabes, un objeto es la encarnación de una clase. Esto significa que el objeto es
como un pastel horneado usando una receta que se incluye dentro de la clase.
Del mismo modo, puede ser crucial si el objeto tiene (o no tiene) ciertas características.
En otras palabras, si es un objeto de cierta clase o no.
isinstance(objectName, ClassName)
Ser una instancia de una clase significa que el objeto (el pastel) se ha preparado
utilizando una receta contenida en la clase o en una de sus superclases.
Hemos creado tres objetos, uno para cada una de las clases. Luego, usando dos bucles
anidados, verificamos todos los pares posibles de clase de objeto para averiguar si los
objetos son instancias de las clases.
Ejecuta el código.
Esto es lo que obtenemos:
class Vehicle:
pass
class LandVehicle(Vehicle):
pass
class TrackedVehicle(LandVehicle):
pass
my_vehicle = Vehicle()
my_land_vehicle = LandVehicle()
my_tracked_vehicle = TrackedVehicle()
Herencia: el operador is
También existe un operador de Python que vale la pena mencionar, ya que se refiere
directamente a los objetos: aquí está:
object_one is object_two
El operador is verifica si dos variables, en este caso ( object_one y object_two ) se
refieren al mismo objeto.
No olvides que las variables no almacenan los objetos en sí, sino solo los identificadores
que apuntan a la memoria interna de Python.
Asignar un valor de una variable de objeto a otra variable no copia el objeto, sino solo su
identificador. Es por ello que un operador como is puede ser muy útil en ciertas
circunstancias.
• Existe una clase muy simple equipada con un constructor simple, que crea una
sola propiedad. La clase se usa para instanciar dos objetos. El primero se asigna a
otra variable, y su propiedad val se incrementa en uno.
• Luego, el operador is se aplica tres veces para verificar todos los pares de
objetos posibles, y todos los valores de la propiedad val son mostrados en
pantalla.
• La última parte del código lleva a cabo otro experimento. Después de tres tareas,
ambas cadenas contienen los mismos textos, pero estos textos se almacenan en
diferentes objetos.
El código imprime:
False
False
True
1 2 1
True False
salida
Los resultados prueban que object_1 y object_3 son en realidad los mismos objetos,
mientras que string_1 y string_2 no lo son, a pesar de que su contenido sea el mismo.
class SampleClass:
def __init__(self, val):
self.val = val
object_1 = SampleClass(0)
object_2 = SampleClass(2)
object_3 = object_1
object_3.val += 1
print(object_1 is object_2)
print(object_2 is object_3)
print(object_3 is object_1)
print(object_1.val, object_2.val, object_3.val)
• Existe una clase llamada Super , que define su propio constructor utilizado para
asignar la propiedad del objeto, llamada name .
• La clase también define el método __str__() , lo que permite que la clase pueda
presentar su identidad en forma de texto.
• La clase se usa luego como base para crear una subclase llamada Sub . La
clase Sub define su propio constructor, que invoca el de la superclase. Toma nota
de como lo hemos hecho: Super.__init__(self, name) .
• Hemos nombrado explícitamente la superclase y hemos apuntado al método para
invocar a __init__() , proporcionando todos los argumentos necesarios.
• Hemos instanciado un objeto de la clase Sub y lo hemos impreso.
Mi nombre es Andy.
salida
Nota: Como no existe el método __str__() dentro de la clase Sub , la cadena a imprimir
se producirá dentro de la clase Super . Esto significa que el método __str__() ha sido
heredado por la clase Sub .
class Super:
def __init__(self, name):
self.name = name
def __str__(self):
return "Mi nombre es " + self.name + "."
class Sub(Super):
def __init__(self, name):
Super.__init__(self, name)
obj = Sub("Andy")
print(obj)
super().__init__(name)
La función super() crea un contexto en el que no tiene que (además, no debe) pasar el
argumento propio al método que se invoca; es por eso que es posible activar el
constructor de la superclase utilizando solo un argumento.
Nota: puedes usar este mecanismo no solo para invocar al constructor de la superclase,
pero también para obtener acceso a cualquiera de los recursos disponibles dentro de la
superclase.
class Super:
def __init__(self, name):
self.name = name
def __str__(self):
return "Mi nombre es " + self.name + "."
class Sub(Super):
def __init__(self, name):
super().__init__(name)
obj = Sub("Andy")
print(obj)
Como puedes observar, la clase Super define una variable de clase llamada supVar , y la
clase Sub define una variable llamada subVar .
Ambas variables son visibles dentro del objeto de clase Sub , es por ello que el código da
como salida:
2
1
salida
class Sub(Super):
subVar = 2
obj = Sub()
print(obj.subVar)
print(obj.supVar)
El constructor de la clase Sub crea una variable de instancia llamada subVar , mientras
que el constructor de Super hace lo mismo con una variable de nombre supVar . Al igual
que el ejemplo anterior, ambas variables son accesibles desde el objeto de clase Sub .
class Sub(Super):
def __init__(self):
super().__init__()
self.subVar = 12
obj = Sub()
print(obj.subVar)
print(obj.supVar)
Cuando intentes acceder a una entidad de cualquier objeto, Python intentará (en este
orden):
La primera condición puede necesitar atención adicional. Como sabes, todos los objetos
derivados de una clase en particular pueden tener diferentes conjuntos de atributos, y
algunos de los atributos pueden agregarse al objeto mucho tiempo después de la
creación del objeto.
El ejemplo en el editor resume esto en una línea de herencia de tres niveles. Analízalo
cuidadosamente.
Todos los comentarios que hemos hecho hasta ahora están relacionados con casos de
herencia única, cuando una subclase tiene exactamente una superclase. Esta es la
situación más común (y también la recomendada).
Python, sin embargo, ofrece mucho más aquí. En las próximas lecciones te mostraremos
algunos ejemplos de herencia múltiple.
class Level1:
variable_1 = 100
def __init__(self):
self.var_1 = 101
def fun_1(self):
return 102
class Level2(Level1):
variable_2 = 200
def __init__(self):
super().__init__()
self.var_2 = 201
def fun_2(self):
return 202
class Level3(Level2):
variable_3 = 300
def __init__(self):
super().__init__()
self.var_3 = 301
def fun_3(self):
return 302
obj = Level3()
Sintácticamente, dicha herencia se presenta como una lista de superclases separadas por
comas entre paréntesis después del nombre de la nueva clase, al igual que aquí:
class SuperA:
var_a = 10
def fun_a(self):
return 11
class SuperB:
var_b = 20
def fun_b(self):
return 21
obj = Sub()
print(obj.var_a, obj.fun_a())
print(obj.var_b, obj.fun_b())
La clase Sub tiene dos superclases: SuperA y SuperB . Esto significa que la
clase Sub hereda todos los bienes ofrecidos por ambas clases SuperA y SuperB .
El código imprime:
10 11
20 21
salida
¿Qué crees que sucederá si más de una de las superclases define una entidad con un
nombre en particular?
class SuperA:
var_a = 10
def fun_a(self):
return 11
class SuperB:
var_b = 20
def fun_b(self):
return 21
obj = Sub()
print(obj.var_a, obj.fun_a())
print(obj.var_b, obj.fun_b())
Tanto la clase, Level1 y Level2 definen un método llamado fun() y una propiedad
llamada var . ¿Significará esto el objeto de la clase Level3 podrá acceder a dos copias de
cada entidad? De ningún modo.
La entidad definida después (en el sentido de herencia) anula la misma entidad definida
anteriormente. Es por eso que el código produce el siguiente resultado:
200 201
salida
Como puedes ver, la variable de clase var y el método fun() de la clase Level2 anula
las entidades de los mismos nombres derivados de la clase Level1 .
¿Qué ocurre cuando una clase tiene dos ancestros que ofrecen la misma entidad y se
encuentran en el mismo nivel? En otras palabras, ¿Qué se debe esperar cuando surge
una clase usando herencia múltiple? Miremos lo siguiente.
class Level1:
var = 100
def fun(self):
return 101
class Level2(Level1):
var = 200
def fun(self):
return 201
class Level3(Level2):
pass
obj = Level3()
print(obj.var, obj.fun())
La clase Sub hereda todos los bienes de dos superclases Left y Right ((estos nombres
están destinados a ser significativos).
Esto es claro. Pero, ¿De donde proviene la variable var ? ¿Es posible adivinarlo? El mismo
problema se encuentra con el método fun() - ¿Será invocada desde Left o
desde Right ? Ejecutemos el programa: la salida será:
L LL RR Left
salida
Esto prueba que ambos casos poco claros tienen una solución dentro de la clase Left .
¿Es esta una premisa suficiente para formular una regla general? Sí lo es.
R LL RR Right
salida
class Left:
var = "L"
var_left = "LL"
def fun(self):
return "Left"
class Right:
var = "R"
var_right = "RR"
def fun(self):
return "Right"
obj = Sub()
Si divides un problema entre las clases y decides cual de ellas debe ubicarse en la parte
superior y cual debe ubicarse en la parte inferior de la jerarquía, debes analizar
cuidadosamente el problema, pero antes de mostrarte como hacerlo (y como no hacerlo),
queremos resaltar un efecto interesante. No es nada extraordinario (es solo una
consecuencia de las reglas generales presentadas anteriormente), pero recordarlo puede
ser clave para comprender como funcionan algunos códigos y cómo se puede usar este
efecto para construir un conjunto flexible de clases.
• Existen dos clases llamadas One y Two , se entiende que Two es derivada de One .
Nada especial. Sin embargo, algo es notable: el método do_it() .
• El método do_it() está definido dos veces: originalmente dentro
de One posteriormente dentro de Two . La esencia del ejemplo radica en el hecho
de que es invocado solo una vez dentro de One .
La pregunta es: ¿cuál de los dos métodos será invocado por las dos últimas líneas del
código?
La primera invocación parece ser simple, el invocar el método doanything() del objeto
llamado one obviamente activará el primero de los métodos.
class One:
def do_it(self):
print("do_it de One")
def doanything(self):
self.do_it()
class Two(One):
def do_it(self):
print("do_it de Two")
one = One()
two = Two()
one.doanything()
two.doanything()
¿Se parece a algo? Sí, por supuesto que lo hace. Se refiere al ejemplo que se muestra al
comienzo del módulo cuando hablamos de los conceptos generales de la programación
orientada a objetos.
Puede parecer extraño, pero no utilizamos herencia en este ejemplo, solo queríamos
mostrarte que no nos limita.
Definimos dos clases separadas capaces de producir dos tipos diferentes de vehículos
terrestres. La principal diferencia entre ellos está en cómo giran. Un vehículo con ruedas
solo gira las ruedas delanteras (generalmente). Un vehículo oruga tiene que detener una
de las pistas.
Los métodos turn() son muy similares como para dejarlos en esta forma.
Vamos a reconstruir el código: vamos a presentar una superclase para reunir todos los
aspectos similares de los vehículos, trasladando todos los detalles a las subclases.
import time
class TrackedVehicle:
def control_track(left, stop):
pass
def turn(left):
control_track(left, True)
time.sleep(0.25)
control_track(left, False)
class WheeledVehicle:
def turn_front_wheels(left, on):
pass
def turn(left):
turn_front_wheels(left, True)
time.sleep(0.25)
turn_front_wheels(left, False)
• Definimos una superclase llamada Vehicle , la cual utiliza el método turn() para
implementar un esquema para poder girar, mientras que el giro en si es realizado
por change_direction() ; nota: dicho método está vacío, ya que vamos a poner
todos los detalles en la subclase (dicho método a menudo se denomina método
abstracto, ya que solo demuestra alguna posibilidad que será instanciada más
tarde).
• Definimos una subclase llamada TrackedVehicle (nota: es derivada de la
clase Vehicle ) la cual instancia el método change_direction() utilizando el
método denominado control_track() .
• Respectivamente, la subclase llamada WheeledVehicle hace lo mismo, pero usa
el método turn_front_wheels() para obligar al vehículo a girar.
La ventaja más importante (omitiendo los problemas de legibilidad) es que esta forma de
código te permite implementar un nuevo algoritmo de giro simplemente modificando el
método turn() , lo cual se puede hacer en un solo lugar, ya que todos los vehículos lo
obedecerán.
import time
class Vehicle:
def change_direction(left, on):
pass
def turn(left):
change_direction(left, True)
time.sleep(0.25)
change_direction(left, False)
class TrackedVehicle(Vehicle):
def control_track(left, stop):
pass
class WheeledVehicle(Vehicle):
def turn_front_wheels(left, on):
pass
Existen dos clases llamadas Tracks y Wheels , ellas saben como controlar la dirección del
vehículo. También hay una clase llamada Vehicle que puede usar cualquiera de los
controladores disponibles (los dos ya definidos o cualquier otro definido en el futuro):
el controlador se pasa a la clase durante la inicialización.
import time
class Tracks:
def change_direction(self, left, on):
print("pistas: ", left, on)
class Wheels:
def change_direction(self, left, on):
print("ruedas: ", left, on)
class Vehicle:
def __init__(self, controller):
self.controller = controller
wheeled = Vehicle(Wheels())
tracked = Vehicle(Tracks())
wheeled.turn(True)
tracked.turn(False)
3.5.1.19 Fundamentos de POO: Herencia
Solo hay un "pero". El hecho de que puedas hacerlo no significa que tengas que hacerlo.
No olvides que:
• Una sola clase de herencia siempre es más simple, segura y fácil de entender y
mantener.
• La herencia múltiple siempre es arriesgada, ya que tienes muchas más
oportunidades de cometer un error al identificar estas partes de las superclases
que influirán efectivamente en la nueva clase.
• La herencia múltiple puede hacer que la anulación sea extremadamente difícil;
además, el emplear la función super() se vuelve ambiguo.
• La herencia múltiple viola el principio de responsabilidad única (mas detalles
aquí: https://en.wikipedia.org/wiki/Single_responsibility_principle) ya que forma
una nueva clase de dos (o más) clases que no saben nada una de la otra.
• Sugerimos encarecidamente la herencia múltiple como la última de todas las
posibles soluciones: si realmente necesitas las diferentes funcionalidades que
ofrecen las diferentes clases, la composición puede ser una mejor alternativa.
Te mostraremos cómo funciona el MRO de Python en dos casos peculiares que son
ejemplos claros de problemas que pueden ocurrir cuando intentas usar la herencia
múltiple de manera demasiado imprudente. Comencemos con un fragmento que
inicialmente puede parecer simple. Mira lo que te hemos preparado en el editor.
bottom
middle
top
salida
Sin sorpresas hasta ahora. Hagamos un pequeño cambio en este código. Echa un vistazo:
class Top:
def m_top(self):
print("top")
class Middle(Top):
def m_middle(self):
print("middle")
object = Bottom()
object.m_bottom()
object.m_middle()
object.m_top()
De esta manera exótica, hemos convertido un código muy simple con una clara ruta de
herencia única en un misterioso acertijo de herencia múltiple. "¿Es válido?" Te puedes
preguntar. Sí lo es. "¿Cómo es eso posible?" te preguntas, esperamos que realmente
sientas la necesidad de hacer esta pregunta.
Como puedes ver, el orden en el que se enumeran las dos superclases entre paréntesis
cumple con la estructura del código: la clase Middle precede a la clase Top , justo como
en la ruta de herencia real.
class Top:
def m_top(self):
print("top")
class Middle(Top):
def m_middle(self):
print("middle")
object = Bottom()
object.m_bottom()
object.m_middle()
object.m_top()
Creemos que el mensaje habla por sí solo. El MRO de Python no se puede doblar ni violar,
no solo porque esa es la forma en que funciona Python, sino también porque es una
regla que debes obedecer.
class Top:
def m_top(self):
print("top")
class Middle(Top):
def m_middle(self):
print("middle")
class Bottom(Middle):
def m_bottom(self):
print("bottom")
object = Bottom()
object.m_bottom()
object.m_middle()
object.m_top()
3.5.1.21 Fundamentos de POO: MRO
Python, sin embargo, ha elegido una ruta diferente: permite la herencia múltiple y no le
importa si escribe y ejecuta código como el del editor. Pero no te olvides del MRO:
siempre está a cargo.
class Top:
def m_top(self):
print("top")
class Middle_Left(Top):
def m_middle(self):
print("middle_left")
class Middle_Right(Top):
def m_middle(self):
print("middle_right")
object = Bottom()
object.m_bottom()
object.m_middle()
object.m_top()
Nota: ambas clases Middle definen un método con el mismo nombre: m_middle() .
Object.m_middle()
¿Estás listo?
Como puedes ver, los diamantes pueden traer algunos problemas a tu vida, tanto los
reales como los que ofrece Python.
class A:
pass
class B(A):
pass
class C(A):
pass
d = D()
Puntos Clave
1. Un método llamado __str__() es responsable de convertir el contenido de un objeto
en una cadena (más o menos) legible. Puedes redefinirlo si deseas que tu objeto pueda
presentarse de una forma más elegante. Por ejemplo:
class Mouse:
def __init__(self, name):
self.my_name = name
def __str__(self):
return self.my_name
the_mouse = Mouse('mickey')
print(the_mouse) # Imprime "mickey".
2. Una función llamada issubclass(Class_1, Class_2) es capaz de determinar
si Class_1 es una subclase de Class_2 . Por ejemplo:
class Mouse:
pass
class LabMouse(Mouse):
pass
class Mouse:
pass
class LabMouse(Mouse):
pass
mickey = Mouse()
print(isinstance(mickey, Mouse), isinstance(mickey, LabMouse)) #
Imprime "True False".
class Mouse:
pass
mickey = Mouse()
minnie = Mouse()
cloned_mickey = mickey
5. Una función sin parámetros llamada super() retorna la referencia a la superclase más
cercana de la clase. Por ejemplo:
class Mouse:
def __str__(self):
return "Mouse"
class LabMouse(Mouse):
def __str__(self):
return "Laboratory " + super().__str__()
doctor_mouse = LabMouse();
print(doctor_mouse) # Imprime "Laboratory Mouse".
6. Los métodos, así como las variables de instancia y de clase definidas en una superclase
son heredados automáticamente por sus subclases. Por ejemplo:
class Mouse:
Population = 0
def __init__(self, name):
Mouse.Population += 1
self.name = name
def __str__(self):
return "Hola, mi nombre es " + self.name
class LabMouse(Mouse):
pass
class Mouse:
def __init__(self, name):
self.name = name
def __str__(self):
return "Mi nombre es " + self.name
class AncientMouse(Mouse):
def __str__(self):
return "Meum nomen est " + self.name
Ejercicios
Escenario
class Dog:
kennel = 0
def __init__(self, breed):
self.breed = breed
Dog.kennel += 1
def __str__(self):
return self.breed + " dice: ¡Guau!"
class SheepDog(Dog):
def __str__(self):
return super().__str__() + " ¡No huyas, corderito!"
class GuardDog(Dog):
def __str__(self):
return super().__str__() + " ¡Quédese donde está, intruso!"
rocky = SheepDog("Collie")
luna = GuardDog("Dobermann")
Ejercicio 1
print(rocky)
print(luna)
Revisar
Collie dice: ¡Guau! ¡No huyas, corderito!
Dobermann dice: ¡Guau! ¡Quédese donde está, intruso!
Ejercicio 2
Revisar
True False
False True
Ejercicio 3
Revisar
True False
2
Ejercicio 4
Revisar
class LowlandDog(SheepDog):
def __str__(self):
return Dog.__str__(self) + " ¡No me gustan las montañas"
Nota: el bloque else: debe ubicarse después del último bloque except .
def reciprocal(n):
try:
n = 1 / n
except ZeroDivisionError:
print("División fallida")
return None
else:
print("Todo salió bien")
return n
print(reciprocal(2))
print(reciprocal(0))
3.6.1.2 Excepciones una vez más
Nota: estas dos variantes ( else y finally ) no son dependientes entre si, y pueden
coexistir u ocurrir de manera independiente.
El bloque finally siempre se ejecuta (finaliza la ejecución del bloque try-except, de ahí
su nombre), sin importar lo que sucedió antes, incluso cuando se genera una excepción,
sin importar si esta se ha manejado o no.
def reciprocal(n):
try:
n = 1 / n
except ZeroDivisionError:
print("División fallida")
n = None
else:
print("Todo salió bien")
finally:
print("Es momento de decir adiós")
return n
print(reciprocal(2))
print(reciprocal(0))
Probablemente no te sorprenderá saber que las excepciones son clases. Además, cuando
se genera una excepción, se crea una instancia de un objeto de la clase y pasa por todos
los niveles de ejecución del programa, buscando el bloque "except" que está preparado
para tratar con la excepción.
Tal objeto lleva información útil que puede ayudarte a identificar con precisión todos los
aspectos de la situación pendiente. Para lograr ese objetivo, Python ofrece una variante
especial de la cláusula de excepción: puedes encontrarla en el editor.
Como puedes ver, la sentencia except se extendió y contiene una frase adicional que
comienza con la palabra clave reservada as , seguida por un identificador. El identificador
está diseñado para capturar la excepción con el fin de analizar su naturaleza y sacar
conclusiones adecuadas.
Nota: el alcance del identificador solo es dentro del except , y no va más allá.
El ejemplo presenta una forma muy simple de utilizar el objeto recibido: simplemente
imprímelo (como puedes ver, la salida es producida por el método del objeto __str__() )
y contiene un breve mensaje que describe la razón.
try:
i = int("¡Hola!")
except Exception as e:
print(e)
print(e.__str__())
Todas las excepciones integradas de Python forman una jerarquía de clases. Si lo deseas,
puedes extenderlo sin problema.
Como un árbol es un ejemplo perfecto de una estructura de datos recursiva, la recursión
parece ser la mejor manera de recorrerlo. La función print_exception_tree() toma
dos argumentos:
Comencemos desde la raíz del árbol: la raíz de las clases de excepciones de Python es la
clase BaseException (es una superclase de todas las demás excepciones).
Para cada una de las clases encontradas, se realiza el mismo conjunto de operaciones:
Toma en cuenta como hemos dibujado las ramas. La impresión no está ordenada de
alguna manera: si deseas un desafío, puedes intentar ordenarla tú mismo. Además, hay
algunas imprecisiones sutiles en la forma en que se presentan algunas ramas. Eso también
se puede arreglar, si lo deseas.
BaseException
+---Exception
| +---TypeError
| +---StopAsyncIteration
| +---StopIteration
| +---ImportError
| | +---ModuleNotFoundError
| | +---ZipImportError
| +---OSError
| | +---ConnectionError
| | | +---BrokenPipeError
| | | +---ConnectionAbortedError
| | | +---ConnectionRefusedError
| | | +---ConnectionResetError
| | +---BlockingIOError
| | +---ChildProcessError
| | +---FileExistsError
| | +---FileNotFoundError
| | +---IsADirectoryError
| | +---NotADirectoryError
| | +---InterruptedError
| | +---PermissionError
| | +---ProcessLookupError
| | +---TimeoutError
| | +---UnsupportedOperation
| | +---herror
| | +---gaierror
| | +---timeout
| | +---Error
| | | +---SameFileError
| | +---SpecialFileError
| | +---ExecError
| | +---ReadError
| +---EOFError
| +---RuntimeError
| | +---RecursionError
| | +---NotImplementedError
| | +---_DeadlockError
| | +---BrokenBarrierError
| +---NameError
| | +---UnboundLocalError
| +---AttributeError
| +---SyntaxError
| | +---IndentationError
| | | +---TabError
| +---LookupError
| | +---IndexError
| | +---KeyError
| | +---CodecRegistryError
| +---ValueError
| | +---UnicodeError
| | | +---UnicodeEncodeError
| | | +---UnicodeDecodeError
| | | +---UnicodeTranslateError
| | +---UnsupportedOperation
| +---AssertionError
| +---ArithmeticError
| | +---FloatingPointError
| | +---OverflowError
| | +---ZeroDivisionError
| +---SystemError
| | +---CodecRegistryError
| +---ReferenceError
| +---BufferError
| +---MemoryError
| +---Warning
| | +---UserWarning
| | +---DeprecationWarning
| | +---PendingDeprecationWarning
| | +---SyntaxWarning
| | +---RuntimeWarning
| | +---FutureWarning
| | +---ImportWarning
| | +---UnicodeWarning
| | +---BytesWarning
| | +---ResourceWarning
| +---error
| +---Verbose
| +---Error
| +---TokenError
| +---StopTokenizing
| +---Empty
| +---Full
| +---_OptionError
| +---TclError
| +---SubprocessError
| | +---CalledProcessError
| | +---TimeoutExpired
| +---Error
| | +---NoSectionError
| | +---DuplicateSectionError
| | +---DuplicateOptionError
| | +---NoOptionError
| | +---InterpolationError
| | | +---InterpolationMissingOptionError
| | | +---InterpolationSyntaxError
| | | +---InterpolationDepthError
| | +---ParsingError
| | | +---MissingSectionHeaderError
| +---InvalidConfigType
| +---InvalidConfigSet
| +---InvalidFgBg
| +---InvalidTheme
| +---EndOfBlock
| +---BdbQuit
| +---error
| +---_Stop
| +---PickleError
| | +---PicklingError
| | +---UnpicklingError
| +---_GiveupOnSendfile
| +---error
| +---LZMAError
| +---RegistryError
| +---ErrorDuringImport
+---GeneratorExit
+---SystemExit
+---KeyboardInterrupt
salida
print(thisclass.__name__)
print_exception_tree(BaseException)
La clase BaseException introduce una propiedad llamada args . Es una tupla diseñada
para reunir todos los argumentos pasados al constructor de la clase. Está vacío si la
construcción se ha invocado sin ningún argumento, o solo contiene un elemento cuando
el constructor recibe un argumento (no se considera el argumento self aquí), y así
sucesivamente.
Hemos preparado una función simple para imprimir la propiedad args de una manera
elegante, puedes ver la función en el editor.
Hemos utilizado la función para imprimir el contenido de la propiedad args en tres casos
diferentes, donde la excepción de la clase Exception es generada de tres maneras
distintas. Para hacerlo más espectacular, también hemos impreso el objeto en sí, junto
con el resultado de la invocación __str__() .
El primer caso parece de rutina, solo hay el nombre Exception después de la palabra
clave reservada raise . Esto significa que el objeto de esta clase se ha creado de la
manera más rutinaria.
El segundo y el tercer caso pueden parecer un poco extraños a primera vista, pero no hay
nada extraño, son solo las invocaciones del constructor. En la segunda sentencia raise ,
el constructor se invoca con un argumento, y en el tercero, con dos.
Como puedes ver, la salida del programa refleja esto, mostrando los contenidos
apropiados de la propiedad args :
: :
mi excepción : mi excepción : mi excepciín
('mi', 'excepción') : ('mi', 'excepción') : ('mi', 'excepción')
salida
def print_args(args):
lng = len(args)
if lng == 0:
print("")
elif lng == 1:
print(args[0])
else:
print(str(args))
try:
raise Exception
except Exception as e:
print(e, e.__str__(), sep=' : ' ,end=' : ')
print_args(e.args)
try:
raise Exception("mi excepción")
except Exception as e:
print(e, e.__str__(), sep=' : ', end=' : ')
print_args(e.args)
try:
raise Exception("mi", "excepción")
except Exception as e:
print(e, e.__str__(), sep=' : ', end=' : ')
print_args(e.args)
Puede ser útil cuando se crea un módulo complejo que detecta errores y genera
excepciones, y deseas que las excepciones se distingan fácilmente de cualquier otra de
Python.
Esto se puede hacer al definir tus propias excepciones como subclases derivadas de las
predefinidas.
Nota: si deseas crear una excepción que se utilizará como un caso especializado de
cualquier excepción incorporada, derivala solo de esta. Si deseas construir tu propia
jerarquía, y no quieres que esté estrechamente conectada al árbol de excepciones de
Python, derivala de cualquiera de las clases de excepción principales, tal como: Exception.
Imagina que has creado una aritmética completamente nueva, regida por sus propias
leyes y teoremas. Está claro que la división también se ha redefinido, y tiene que
comportarse de una manera diferente a la división de rutina. También está claro que esta
nueva división debería plantear su propia excepción, diferente de la
incorporada ZeroDivisionError, pero es razonable suponer que, en algunas
circunstancias, tu (o el usuario de tu aritmética) pueden tratar todas las divisiones entre
cero de la misma manera.
En efecto, una excepción de esta clase puede ser, dependiendo del punto de vista
deseado, tratada como una simple excepción ZeroDivisionError, o puede ser
considerada por separado.
La función se invoca cuatro veces en total, mientras que las dos primeras
invocaciones se manejan utilizando solo un bloque except (la más general), las
dos últimas invocan dos bloques diferentes, capaces de distinguir las excepciones
(no lo olvides: el orden de los bloques hace una diferencia fundamental).
class MyZeroDivisionError(ZeroDivisionError):
pass
def do_the_division(mine):
if mine:
raise MyZeroDivisionError("peores noticias")
else:
raise ZeroDivisionError("malas noticias")
Puedes comenzar a construirla definiendo una excepción general como una nueva clase
base para cualquier otra excepción especializada. Lo hemos hecho de la siguiente
manera:
class PizzaError(Exception):
def __init__(self, pizza, message):
Exception.__init__(self, message)
self.pizza = pizza
Un problema más específico (como un exceso de queso) puede requerir una excepción
más específica. Es posible derivar la nueva clase de la ya definida PizzaError , como
hemos hecho aquí:
class TooMuchCheeseError(PizzaError):
def __init__(self, pizza, cheese, message):
PizzaError._init__(self, pizza, message)
self.cheese = cheese
class PizzaError(Exception):
def __init__(self, pizza, message):
Exception.__init__(self, message)
self.pizza = pizza
class TooMuchCheeseError(PizzaError):
def __init__(self, pizza, cheese, message):
PizzaError._init__(self, pizza, message)
self.cheese = cheese
Nota:
La solución anterior, aunque elegante y eficiente, tiene una debilidad importante. Debido
a la manera algo fácil de declarar los constructores, las nuevas excepciones no se pueden
usar tal cual, sin una lista completa de los argumentos requeridos.
class PizzaError(Exception):
def __init__(self, pizza='desconocida', message=''):
Exception.__init__(self, message)
self.pizza = pizza
class TooMuchCheeseError(PizzaError):
def __init__(self, pizza='desconocida', cheese='>100', message=''):
PizzaError.__init__(self, pizza, message)
self.cheese = cheese
Ahora, si las circunstancias lo permiten, es posible usar únicamente los nombres de clase.
class PizzaError(Exception):
def __init__(self, pizza, message):
Exception.__init__(self, message)
self.pizza = pizza
class TooMuchCheeseError(PizzaError):
def __init__(self, pizza, cheese, message):
PizzaError.__init__(self, pizza, message)
self.cheese = cheese
Puntos Clave
1. El bloque else: de la sentencia try se ejecuta cuando no ha habido ninguna
excepción durante la ejecución del try: .
Por ejemplo:
try:
assert __name__ == "__main__"
except:
print("fallido", end=' ')
else:
print("éxito", end=' ')
finally:
print("terminado")
Ejercicio 1
import math
try:
print(math.sqrt(9))
except ValueError:
print("inf")
else:
print("ok")
Revisar
3.0
ok
Ejercicio 2
import math
try:
print(math.sqrt(-9))
except ValueError:
print("inf")
else:
print("ok")
finally:
print("fin")
Revisar
inf
fin
Ejercicio 3
import math
class NewValueError(ValueError):
def __init__(self, name, color, state):
self.data = (name, color, state)
try:
raise NewValueError("Advertencia enemiga", "Alerta roja", "Alta
disponibilidad")
except NewValueError as nve:
for arg in nve.args:
print(arg, end='! ')
Revisar
Fundamentos de Python 2:
Módulo 4
Misceláneo
Puede que no te hayas dado cuenta, pero te has topado con generadores muchas,
muchas veces antes. Echa un vistazo al fragmento de código:
for i in range(5):
print(i)
¿Cuál es la diferencia?
Una función devuelve un valor bien definido, el cual, puede ser el resultado de una
evaluación compleja, por ejemplo, de un polinomio, y se invoca una vez, solo una vez.
El proceso anterior es completamente transparente. Vamos a arrojar algo de luz sobre el.
Vamos a mostrarte el protocolo iterador.
for i in range(5):
print(i)
• __iter__() el cual debe devolver el objeto en sí y que se invoca una vez (es
necesario para que Python inicie con éxito la iteración).
• __next__() el cual debe devolver el siguiente valor (primero, segundo, etc.) de la
serie deseada: será invocado por las sentencias for / in para pasar a la siguiente
iteración; si no hay más valores a proporcionar, el método deberá generar la
excepción StopIteration .
Hemos creado una clase capaz de iterar a través de los primeros n valores (donde n es
un parámetro del constructor) de los números de Fibonacci.
Fib1 = 1
Fib2 = 1
Fibi = Fibi-1 + Fibi-2
En otras palabras:
__init__
__iter__
__next__
1
__next__
1
__next__
2
__next__
3
__next__
5
__next__
8
__next__
13
__next__
21
__next__
34
__next__
55
__next__
salida
Observa:
class Fib:
def __init__(self, nn):
print("__init__")
self.__n = nn
self.__i = 0
self.__p1 = self.__p2 = 1
def __iter__(self):
print("__iter__")
return self
def __next__(self):
print("__next__")
self.__i += 1
if self.__i > self.__n:
raise StopIteration
if self.__i in [1, 2]:
return 1
ret = self.__p1 + self.__p2
self.__p1, self.__p2 = self.__p2, ret
return ret
for i in Fib(10):
print(i)
Hemos colocado el iterador Fib dentro de otra clase (podemos decir que lo hemos
compuesto dentro de la clase Class ). Se instancia junto con el objeto de Class .
El objeto de la clase se puede usar como un iterador cuando (y solo cuando) responde
positivamente a la invocación __iter__ - esta clase puede hacerlo, y si se invoca de esta
manera, proporciona un objeto capaz de obedecer el protocolo de iteración.
Es por eso que la salida del código es la misma que anteriormente, aunque el objeto de la
clase Fib no se usa explícitamente dentro del contexto del bucle for .
class Fib:
def __init__(self, nn):
self.__n = nn
self.__i = 0
self.__p1 = self.__p2 = 1
def __iter__(self):
print("Fib iter")
return self
def __next__(self):
self.__i += 1
if self.__i > self.__n:
raise StopIteration
if self.__i in [1, 2]:
return 1
ret = self.__p1 + self.__p2
self.__p1, self.__p2 = self.__p2, ret
return ret
class Class:
def __init__(self, n):
self.__iter = Fib(n)
def __iter__(self):
print("Class iter")
return self.__iter
object = Class(8)
for i in object:
print(i)
La sentencia yield
El protocolo iterador no es difícil de entender y usar, pero también es indiscutible que el
protocolo es bastante inconveniente.
La principal molestia que tiene es que necesita guardar el estado de la iteración en las
invocaciones subsecuentes de __iter__ .
Por ejemplo, el iterador Fib se ve obligado a almacenar con precisión el lugar en el que
se detuvo la última invocación (es decir, el número evaluado y los valores de los dos
elementos anteriores). Esto hace que el código sea más grande y menos comprensible.
Es por eso que Python ofrece una forma mucho más efectiva, conveniente y elegante de
escribir iteradores.
Se puede ver a la palabra clave reservada yield como un hermano más inteligente de la
sentencia return , con una diferencia esencial.
def fun(n):
for i in range(n):
return i
Se ve extraño, ¿no? Está claro que el bucle for no tiene posibilidad de terminar su
primera ejecución, ya que el return lo romperá irrevocablemente.
Además, invocar la función no cambiará nada: el bucle for comenzará desde cero y se
romperá inmediatamente.
Esto también significa que una función como esta no se puede usar como generador.
def fun(n):
for i in range(n):
yield i
Hemos puesto yield en lugar de return . Esta pequeña enmienda convierte la función
en un generador, y el ejecutar la sentencia yield tiene algunos efectos muy interesantes.
Todos los valores de las variables están congelados y esperan la próxima invocación,
cuando se reanuda la ejecución (no desde cero, como ocurre después de un return ).
Hay una limitación importante: dicha función no debe invocarse explícitamente ya que no
es una función; es un objeto generador.
La invocación devolverá el identificador del objeto, no la serie que esperamos del
generador.
Debido a las mismas razones, la función anterior (la que tiene el return ) solo se puede
invocar explícitamente y no se debe usar como generador.
def fun(n):
for i in range(n):
yield i
for v in fun(5):
print(v)
Revisar
0
1
2
3
4
def powers_of_2(n):
power = 1
for i in range(n):
yield power
power *= 2
for v in powers_of_2(8):
print(v)
¿Puedes adivinar la salida? Ejecuta el código para verificar tus conjeturas.
Los generadores también se pueden usar con listas por comprensión, justo como aquí:
def powers_of_2(n):
power = 1
for i in range(n):
yield power
power *= 2
t = [x for x in powers_of_2(5)]
print(t)
La función list()
def powers_of_2(n):
power = 1
for i in range(n):
yield power
power *= 2
t = list(powers_of_2(3))
print(t)
El operador in
def powers_of_2(n):
power = 1
for i in range(n):
yield power
power *= 2
for i in range(20):
if i in powers_of_2(4):
print(i)
Aquí está:
def fibonacci(n):
p = pp = 1
for i in range(n):
if i in [0, 1]:
yield 1
else:
n = p + pp
pp, p = p, n
yield n
fibs = list(fibonacci(10))
print(fibs)
Adivina la salida (una lista) producida por el generador y ejecuta el código para verificar si
tenías razón.
Existen dos partes dentro del código, ambas crean una lista que contiene algunas de las
primeras potencias naturales de diez.
La primer parte utiliza una forma rutinaria del bucle for , mientras que la segunda hace
uso de listas por comprensión y construye la lista en el momento, sin necesidad de un
bucle o cualquier otro código.
Pareciera que la lista se crea dentro de sí misma; esto es falso, ya que Python tiene que
realizar casi las mismas operaciones que en la primera parte, pero el segundo
formalismo es simplemente más elegante y le evita al lector cualquier detalle innecesario.
list_1 = []
for ex in range(6):
list_1.append(10 ** ex)
print(list_1)
print(list_2)
Es una expresión condicional: una forma de seleccionar uno de dos valores diferentes en
función del resultado de una expresión Booleana.
Observa:
Puede parecer un poco sorprendente a primera vista, pero hay que tener en cuenta que
no es una instrucción condicional. Además, no es una instrucción en lo absoluto. Es un
operador.
El código llena una lista con unos y ceros , si el índice de un elemento particular es impar,
el elemento se establece a 0 , y a 1 de lo contrario.
¿Simple? Quizás no a primera vista. ¿Elegante? Indiscutiblemente.
¿Se puede usar el mismo truco dentro de una comprensión de lista? Sí, por supuesto.
the_list = []
for x in range(10):
the_list.append(1 if x % 2 == 0 else 0)
print(the_list)
Entonces, ¿qué tienen en común, generadores y listas por comprensión? ¿Hay alguna
conexión entre ellos? Si. Una conexión algo suelta, pero inequívoca.
for v in the_list:
print(v, end=" ")
print()
for v in the_generator:
print(v, end=" ")
print()
Son los paréntesis. Los corchetes hacen una comprensión, los paréntesis hacen un
generador.
1 0 1 0 1 0 1 0 1 0
1 0 1 0 1 0 1 0 1 0
salida
¿Cómo puedes saber que la segunda asignación crea un generador, no una lista?
Hay algunas pruebas que podemos mostrarte. Aplica la función len() a ambas
entidades.
En el segundo bucle, no hay ninguna lista, solo hay valores subsecuentes producidos por
el generador, uno por uno.
print(the_list)
La función lambda
La función lambda es un concepto tomado de las matemáticas, más específicamente, de
una parte llamada el Cálculo Lambda, pero estos dos fenómenos no son iguales.
Los matemáticos usan el Cálculo Lambda en sistemas formales conectados con: la lógica,
la recursividad o la demostrabilidad de teoremas. Los programadores usan la
función lambda para simplificar el código, hacerlo más claro y fácil de entender.
Una función lambda es una función sin nombre (también puedes llamarla una función
anónima). Por supuesto, tal afirmación plantea inmediatamente la pregunta: ¿cómo se
usa algo que no se puede identificar?
Afortunadamente, no es un problema, ya que se puede mandar llamar dicha función si
realmente se necesita, pero, en muchos casos la función lambda puede existir y
funcionar mientras permanece completamente de incógnito.
Como de costumbre, un ejemplo será útil. Nuestro ejemplo usa tres funciones lambda ,
pero con nombres. Analízalo cuidadosamente:
two = lambda: 2
sqr = lambda x: x * x
pwr = lambda x, y: x ** y
Vamos a analizarlo:
• La primer lambda es una función anónima sin parámetros que siempre devuelve
un 2 . Como se ha asignado a una variable llamada dos , podemos decir que la
función ya no es anónima, y se puede usar su nombre para invocarla.
• La tercer lambda toma dos parámetros y devuelve el valor del primero elevado al
segundo. El nombre de la variable que lleva la lambda habla por si mismo. No se
utiliza pow para evitar confusiones con la función incorporada del mismo nombre
y el mismo propósito.
4 4
1 1
0 0
1 1
4 4
salida
Este ejemplo es lo suficientemente claro como para mostrar como se declaran las
funciones lambda y cómo se comportan, pero no dice nada acerca de por que son
necesarias y para qué se usan, ya que se pueden reemplazar con funciones de Python de
rutina.
Imagina que necesitamos una función (la nombraremos print_function ) que imprime
los valores de una (otra) función dada para un conjunto de argumentos seleccionados.
• El primero, una lista de argumentos para los que queremos imprimir los
resultados.
• El segundo, una función que debe invocarse tantas veces como el número de
valores que se recopilan dentro del primer parámetro.
Nota: También hemos definido una función llamada poly() , esta es la función cuyos
valores vamos a imprimir. El cálculo que realiza la función no es muy sofisticado: es el
polinomio (de ahí su nombre) de la forma:
f(x) = 2x2 - 4x + 2
f(-2)=18
f(-1)=8
f(0)=2
f(1)=0
f(2)=2
salida
¿Podemos evitar definir la función poly() , ya que no la vamos a usar más de una vez? Si,
podemos: este es el beneficio que puede aportar una función lambda.
lambda x: 2 * x**2 - 4 * x + 2
Permítenos mostrarte otro lugar donde las lambdas pueden ser útiles. Comenzaremos
con una descripción de map() , una función integrada de Python. Su nombre no es
demasiado descriptivo, su idea es simple y la función en sí es muy utilizable.
def poly(x):
return 2 * x**2 - 4 * x + 2
map(function, list)
• Una función.
• Una lista.
La función map() aplica la función pasada por su primer argumento a todos los
elementos de su segundo argumento y devuelve un iterador que entrega todos los
resultados de funciones subsequentes.
Esta es la explicación:
Espera el mismo tipo de argumentos que map() , pero hace algo diferente: filtra su
segundo argumento mientras es guiado por direcciones que fluyen desde la función
especificada en el primer argumento (la función se invoca para cada elemento de la lista,
al igual que en map() ).
Los elementos que devuelven True de la función pasan el filtro, los otros son rechazados.
Nota: hemos hecho uso del módulo random para inicializar el generador de números
aleatorios (que no debe confundirse con los generadores de los que acabamos de hablar)
con la función seed() , para producir cinco valores enteros aleatorios de -
10 a 10 usando la función randint() .
Luego se filtra la lista y solo se aceptan los números que son pares y mayores que cero.
Por supuesto, no es probable que recibas los mismos resultados, pero así es como se
veían nuestros resultados:
[6, 3, 3, 2, -7]
[6, 2]
salida
seed()
data = [randint(-10,10) for x in range(5)]
filtered = list(filter(lambda x: x > 0 and x % 2 == 0, data))
print(data)
print(filtered)
def outer(par):
loc = par
var = 1
outer(var)
print(var)
print(loc)
El ejemplo es obviamente erróneo.
Las dos últimas líneas provocarán una excepción NameError - ni par ni loc son
accesibles fuera de la función. Ambas variables existen cuando y solo cuando la
función exterior() esta siendo ejecutada.
Hay un elemento completamente nuevo - una función (llamada inner ) dentro de otra
función (llamada outer ).
¿Cómo funciona? Como cualquier otra función excepto por el hecho de que inner() solo
se puede invocar desde dentro de outer() . Podemos decir que inner() es una
herramienta privada de outer() , ninguna otra parte del código la puede acceder.
Observa cuidadosamente:
1
salida
def outer(par):
loc = par
def inner():
return loc
return inner
var = 1
fun = outer(var)
print(fun())
def outer(par):
loc = par
def inner():
return loc
return inner
var = 1
fun = outer(var)
print(fun())
La función inner() no tenía parámetros, por lo que tuvimos que invocarla sin
argumentos.
Ahora mira el código en el editor. Es totalmente posible declarar un cierre equipado con
un número arbitrario de parámetros, por ejemplo, al igual que la función power() .
Esto significa que el cierre no solo utiliza el ambiente congelado, sino que también
puede modificar su comportamiento utilizando valores tomados del exterior.
Este ejemplo muestra una circunstancia más interesante: puedes crear tantos cierres
como quieras usando el mismo código. Esto se hace con una función
llamada make_closure() . Nota:
0 0 0
1 1 1
2 4 8
3 9 27
4 16 64
salida
def make_closure(par):
loc = par
def power(p):
return p ** loc
return power
fsqr = make_closure(2)
fcub = make_closure(3)
for i in range(5):
print(i, fsqr(i), fcub(i))
Puntos Clave
1. Un iterator es un objeto de una clase que proporciona al menos dos métodos (sin
contar el constructor):
4. Una función lambda es una herramienta para crear funciones anónimas. Por ejemplo:
5. La función map(fun, list) crea una copia del argumento list , y aplica la
función fun a todos sus elementos, retornando un generador que proporciona el nuevo
contenido de la lista elemento por elemento. Por ejemplo:
6. La función filter(fun, list) crea una copia de aquellos elementos de list , lo cual
hace que la función fun retorne True . El resultado de la función es
un generador proporcionando el nuevo contenido de la lista elemento por elemento. Por
ejemplo
7. Un cierre es una técnica que permite almacenar valores a pesar de que el contexto en
el que han sido creados no existe más. Por ejemplo:
def tag(tg):
tg2 = tg
tg2 = tg[0] + '/' + tg[1:]
def inner(str):
return tg + str + tg2
return inner
b_tag = tag('<b>')
print(b_tag('Monty Python'))
Ejercicio 1
class Vowels:
def __init__(self):
self.vow = "aeiouy " # Sí, sabemos que y no siempre se
considera una vocal.
self.pos = 0
def __iter__(self):
return self
def __next__(self):
if self.pos == len(self.vow):
raise StopIteration
self.pos += 1
return self.vow[self.pos - 1]
vowels = Vowels()
for v in vowels:
print(v, end=' ')
Revisar
a e i o u y
Ejercicio 2
any_list = [1, 2, 3, 4]
even_list = # Completar las líneas aquí.
print(even_list)
Revisar
list(map(lambda n: n | 1, any_list))
Ejercicio 3
def replace_spaces(replacement='*'):
def new_replacement(text):
return text.replace(' ', replacement)
return new_replacement
stars = replace_spaces()
print(stars("And Now for Something Completely Different"))
Revisar
And*Now*for*Something*Completely*Different
Nota
PEP 8, la Guía de Estilo para Código Python, recomienda que las funciones lambdas no
deben asignarse a variables, sino que deben definirse como funciones.
Esto significa que es mejor utilizar una sentencia def , y evita usar una sentencia de
asignación que vincule una expresión lambda a un identificador. Analiza el código a
continuación:
# Recomendado:
# No recomendado:
f = lambda x: 3*x
Es mucho más difícil imaginar la misma tarea cuando hay 20,000 números para ordenar,
y no existe un solo usuario que pueda ingresar estos números sin cometer un error.
Es mucho más fácil imaginar que estos números se almacenan en el archivo que lee el
programa. El programa clasifica los números y no los envía a la pantalla, sino que crea un
nuevo archivo y guarda la secuencia ordenada de números allí.
La respuesta es muy simple: la forma en que Python accede y procesa los archivos se
implementa utilizando un conjunto consistente de objetos. No hay mejor momento para
hablar de esto.
Como puedes ver, los sistemas derivados de Unix/Linux no usan la letra de la unidad de
disco (por ejemplo, C: ) y todos los directorios crecen desde un directorio raíz llamado / ,
mientras que los sistemas Windows reconocen el directorio raíz como \ .
Esta diferencia no es muy importante para el usuario normal, pero es muy importante al
escribir programas en Python.
Para entender por qué, intenta recordar el papel muy específico que
desempeña \ dentro de las cadenas en Python.
Supongamos también que deseas asignar a una cadena el nombre del archivo.
name = "/dir/file"
name = "\dir\file"
Esto significa que los nombres de archivo de Windows deben escribirse de la siguiente
manera:
name = "\\dir\\file"
name = "/dir/file"
name = "c:/dir/file"
Las operaciones realizadas con el stream abstracto reflejan las actividades relacionadas
con el archivo físico.
Para conectar (vincular) el stream con el archivo, es necesario realizar una operación
explícita.
Esta libertad está limitada por las características físicas del archivo y la forma en que se
abrió el archivo.
Digamos nuevamente que la apertura del stream puede fallar, y puede ocurrir debido a
varias razones: la más común es la falta de un archivo con un nombre específico.
También puede suceder que el archivo físico exista, pero el programa no puede abrirlo.
También existe el riesgo de que el programa haya abierto demasiados streams, y el
sistema operativo específico puede no permitir la apertura simultánea de más
de n archivos (por ejemplo, 200).
Si la apertura es exitosa, el programa solo podrá realizar las operaciones que sean
consistentes con el modo abierto declarado.
• Lectura del stream: las porciones de los datos se recuperan del archivo y se
colocan en un área de memoria administrada por el programa (por ejemplo, una
variable).
• Escritura del stream: Las porciones de los datos de la memoria (por ejemplo, una
variable) se transfieren al archivo.
Cuando escribes algo en el stream el mismo cabezal se mueve a lo largo del stream
registrando los datos de la memoria.
Siempre que hablemos de leer y escribir en el stream, trata de imaginar esta analogía.
Los libros de programación se refieren a este mecanismo como la posición actual del
archivo, aquí también usaremos este término.
Los archivos se pueden procesar de muchas maneras diferentes: algunos dependen del
contenido del archivo, otros de las intenciones del programador.
Entre estos dos eventos, puedes usar el objeto para especificar que operaciones se
deben realizar en un stream en particular. Las operaciones que puedes usar están
impuestas por la forma en que abriste el archivo.
En general, el objeto proviene de una de las clases que se muestran aquí:
Nota: nunca se utiliza el constructor para dar vida a estos objetos. La unica forma
de obtenerlos es invocar la función llamada open() .
Para nuestros propósitos, solo nos ocuparemos de los streams representados por los
objetos BufferIOBase y TextIOBase . Entenderás por que pronto.
Este tipo de archivo es escrito (o leído) principalmente carácter por carácter, o línea por
línea.
Los streams binarios no contienen texto, sino una secuencia de bytes de cualquier valor.
Esta secuencia puede ser, por ejemplo, un programa ejecutable, una imagen, un audio o
un videoclip, un archivo de base de datos, etc.
Debido a que estos archivos no contienen líneas, las lecturas y escrituras se relacionan
con porciones de datos de cualquier tamaño. Por lo tanto, los datos se leen y escriben
byte a byte, o bloque a bloque, donde el tamaño del bloque generalmente varía de uno a
un valor elegido arbitrariamente.
Ahora viene un problema pequeño. En los sistemas Unix/Linux, los extremos de la línea
están marcados por un solo carácter llamado LF (código ASCII 10) designado en los
programas de Python como \n .
Otros sistemas operativos, especialmente los derivados del sistema prehistórico CP/M
(que también aplica a los sistemas de la familia Windows) utilizan una convención
diferente: el final de la línea está marcada por un par de caracteres, CR y LF (códigos
ASCII 13 y 10) los cuales se puede codificar como \r\n .
Estas características indeseables del programa, que impiden o dificultan el uso del
programa en diferentes entornos, se denomina falta de portabilidad.
Del mismo modo, el rasgo del programa que permite la ejecución en diferentes entornos
se llama portabilidad. Un programa dotado de tal rasgo se llama programa portable.
Se realizó a nivel de clases, que son responsables de leer y escribir caracteres hacia y
desde el stream. Funciona de la siguiente manera:
• Cuando el stream está abierto y se recomienda que los datos en el archivo
asociado se procesen como texto (o no existe tal aviso), se cambia al modo texto.
• Durante la lectura y escritura de líneas desde y hacia el archivo asociado, no
ocurre nada especial en el entorno Unix, pero cuando se realizan las mismas
operaciones en el entorno Windows, un proceso llamado traducción de caracteres
de nueva línea ocurre: cuando lees una línea del archivo, cada par de
caracteres \r\n se reemplaza con un solo carácter \n , y viceversa; durante las
operaciones de escritura, cada carácter \n se reemplaza con un par de
caracteres \r\n .
• El mecanismo es completamente transparente para el programa, el cual puede
escribirse como si estuviera destinado a procesar archivos de texto Unix/Linux
solamente; el código fuente ejecutado en un entorno Windows también
funcionará correctamente.
• Cuando el stream está abierto, su contenido se toma tal cual es, sin ninguna
conversión - no se agregan, ni se omiten bytes.
Vamos a analizarlo:
Permítenos ahora presentarte los modos de apertura más importantes y útiles. ¿Listo?
Si la cadena del modo termina con una letra t el stream es abierto en modo texto.
Finalmente, la apertura exitosa del archivo establecerá la posición actual del archivo (el
cabezal virtual de lectura/escritura) antes del primer byte del archivo si el modo no es a y
después del último byte del archivo si el modo es a .
Modo texto Modo binario Descripción
rt rb lectura
wt wb escritura
at ab adjuntar
EXTRA
También puedes abrir un archivo para su creación exclusiva. Puedes hacer esto usando el
modo de apertura x . Si el archivo ya existe, la función open() generará una excepción.
¿Cómo abrir ese archivo para leerlo? Aquí está el fragmento del código:
try:
stream = open("C:\Users\User\Desktop\file.txt", "rt")
# El procesamiento va aquí.
stream.close()
except Exception as exc:
print("No se puede abrir el archivo:", exc)
Cuando comienza nuestro programa, los tres streams ya están abiertos y no requieren
ninguna preparación adicional. Además, tu programa puede usar estos streams
explícitamente si tienes cuidado de importar el módulo sys :
import sys
Vamos a analizarlos:
• sys.stdin
o stdin (significa entrada estándar).
o El stream stdin normalmente se asocia con el teclado, se abre previamente
para la lectura y se considera como la fuente de datos principal para los
programas en ejecución.
o La función bien conocida input() lee datos de stdin por default.
• sys.stdout
o stdout (significa salida estándar).
o El stream stdout normalmente está asociado con la pantalla, preabierta
para escritura, considerada como el objetivo principal para la salida de
datos por el programa en ejecución.
o La función bien conocida print() envía los datos al stream stdout .
• sys.stderr
o stderr (significa salida de error estándar).
o El stream stderr normalmente está asociado con la pantalla, preabierta
para escribir, considerada como el lugar principal donde el programa en
ejecución debe enviar información sobre los errores encontrados durante
su trabajo.
o No hemos presentado ningún método para enviar datos a este stream (lo
haremos pronto, lo prometemos).
o La separación de stdout (resultados útiles producidos por el programa)
de stderr (mensajes de error, indudablemente útiles pero no proporcionan
resultados) ofrece la posibilidad de redirigir estos dos tipos de información
a los diferentes objetivos. Una discusión más extensa sobre este tema está
más allá del alcance de nuestro curso. El manual del sistema operativo
proporcionará más información sobre estos temas.
4.2.1.10 Procesando archivos
Cerrando streams
La última operación realizada en un stream (esto no incluye a los streams stdin , stdout ,
y stderr pues no lo requieren) debe ser cerrarlo.
Esa acción se realiza mediante un método invocado desde dentro del objeto del
stream: stream.close() .
Esta creencia está solo parcialmente justificada. Si el stream se abrió para escribir
y luego se realizó una serie de operaciones de escritura, puede ocurrir que los
datos enviados al stream aún no se hayan transferido al dispositivo físico (debido
a los mecanismos de cache o buffer). Dado que el cierre del stream obliga a los
bufers a descargarse, es posible que dichas descargas fallen y, por lo
tanto, close() falle también.
Ya hemos mencionado fallas causadas por funciones que operan con los streams, pero
no mencionamos nada sobre cómo podemos identificar exactamente la causa de la falla.
try:
# Algunas operaciones con streams.
except IOError as exc:
print(exc.errno)
El valor del atributo errno se puede comparar con una de las constantes simbólicas
predefinidas en módulo errno .
El error se produce cuando intentas, por ejemplo, abrir un archivo con atributos
de solo lectura para abrirlo.
El error se produce cuando intentas, por ejemplo, operar un stream sin abrirlo.
El error ocurre cuando intentas crear un archivo que es más grande que el
máximo permitido por el sistema operativo.
• errno.EISDIR → Es un directorio
La lista completa es mucho más larga (incluye también algunos códigos de error no
relacionados con el procesamiento del los streams).
Nota: si pasas un código de error inexistente (un número que no está vinculado a ningún
error real), la función generará una excepción ValueError.
try:
s = open("c:/users/user/Desktop/file.txt", "rt")
# El procesamiento va aquí.
s.close()
except Exception as exc:
print("El archivo no pudo ser abierto:", strerror(exc.errno))
Bueno. Ahora es el momento de tratar con archivos de texto y familiarizarse con algunas
técnicas básicas que puedes utilizar para procesarlos.
import errno
try:
s = open("c:/users/user/Desktop/file.txt", "rt")
# El procesamiento va aquí.
s.close()
except Exception as exc:
if exc.errno == errno.ENOENT:
print("El archivo no existe.")
elif exc.errno == errno.EMFILE:
print("Demasiados archivos abiertos.")
else:
print("El numero del error es:", exc.errno)
Puntos Clave
1. Un archivo necesita ser abierto antes de que pueda ser procesado por un programa, y
debe ser cerrado cuando el procesamiento termine.
El abrir un archivo lo asocia con el stream, que es una representación abstracta de los
datos físicos almacenados en los medios. La forma en que se procesa el stream se
llama modo de apertura. Existen tres modos de apertura:
2. Dependiendo del contenido del archivo físico, se pueden usar diferentes clases de
Python para procesar archivos. En general, BufferedIOBase es capaz de procesar
cualquier archivo, mientras que TextIOBase es una clase especializada dedicada al
procesamiento de archivos de texto (es decir, archivos que contienen textos visibles para
humanos divididos en líneas usando marcadores de nueva línea). Por lo tanto, los
streams se pueden dividir en binarios y de texto.
open(nombre_archivo, modo=modo_apertura,
codificación=codificacion_de_texto)
La invocación crea un objeto stream y lo asocia con el archivo llamado nombre_archivo ,
utilizando el modo modo_apertura y configurando la
especificada codificacion_de_texto , o genera una excepción en caso de un error.
4. Los tres streams predefinidos que ya estan abiertos cuando inicia el programa son:
Ejercicio 1
Revisar
"wt" o "w"
Ejercicio 2
Revisar
Ejercicio 3
¿Cuál es la salida esperada del siguiente código, asumiendo que el archivo llamado file no
existe?
import errno
try:
stream = open("file", "rb")
print("existe")
stream.close()
except IOError as error:
if error.errno == errno.ENOENT:
print("ausente")
else:
print("desconocido")
Revisar
ausente
Te mostraremos algunas técnicas básicas que puedes utilizar para leer el contenido del
archivo y poder procesarlo.
El procesamiento será muy simple: vas a copiar el contenido del archivo a la consola y
contarás todos los caracteres que el programa ha leído.
Si tus archivos de texto contienen algunos caracteres nacionales no cubiertos por el juego
de caracteres ASCII estándar, es posible que necesites un paso adicional. La invocación de
tu función open() puede requerir un argumento que denote una codificación específica
del texto.
Por ejemplo, si estás utilizando un sistema operativo Unix/Linux configurado para usar
UTF-8 como una configuración de todo el sistema, la función open() puede verse de la
siguiente manera:
Nota
Algunos de ellos serán a veces más prácticos y otros más problemáticos. Se flexible. No
tengas miedo de cambiar tus preferencias.
El más básico de estos métodos es el que ofrece la función read() , la cual pudiste ver en
acción en la lección anterior.
try:
counter = 0
stream = open('text.txt', "rt")
char = stream.read(1)
while char != '':
print(char, end='')
counter += 1
char = stream.read(1)
stream.close()
print("\n\nCaracteres en el archivo:", counter)
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
4.3.1.3 Trabajando con archivos reales
Recuerda: el leer un archivo muy grande (en terabytes) usando este método puede dañar
tu sistema operativo.
Vamos a analizarlo:
try:
counter = 0
stream = open('text.txt', "rt")
content = stream.read()
for char in content:
print(char, end='')
counter += 1
stream.close()
print("\n\nCaracteres en el archivo:", counter)
except IOError as e:
print("Se produjo un error de E/S:", strerr(e.errno))
El método intenta leer una línea completa de texto del archivo, y la devuelve como una
cadena en caso de éxito. De lo contrario, devuelve una cadena vacía.
Esto abre nuevas oportunidades: ahora también puedes contar líneas fácilmente, no solo
caracteres.
Como puedes ver, la idea general es exactamente la misma que en los dos ejemplos
anteriores.
try:
character_counter = line_counter = 0
stream = open('text.txt', 'rt')
line = stream.readline()
while line != '':
line_counter += 1
for char in line:
print(char, end='')
character_counter += 1
line = stream.readline()
stream.close()
print("\n\nCaracteres en el archivo:", character_counter)
print("Líneas en el archivo: ", line_counter)
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
Siéntete libre de experimentar con el siguiente código de ejemplo para entender cómo
funciona el método readlines() :
stream = open("text.txt")
print(stream.readlines(20))
print(stream.readlines(20))
print(stream.readlines(20))
print(stream.readlines(20))
stream.close()
El tamaño máximo del búfer de entrada aceptado se pasa al método como argumento.
Puedes esperar que readlines() procese el contenido del archivo de manera más
efectiva que readline() , ya que puede ser invocado menos veces.
Nota: cuando no hay nada que leer del archivo, el método devuelve una lista vacía. Úsalo
para detectar el final del archivo.
Puedes esperar que al aumentar el tamaño del búfer mejore el rendimiento de entrada,
pero no hay una regla de oro para ello: intenta encontrar los valores óptimos por ti
mismo.
Hemos utilizado ese valor para evitar la situación en la que la primera invocación
de readlines() consuma todo el archivo.
Queremos que el método se vea obligado a trabajar más duro y que demuestre sus
capacidades.
try:
character_counter = line_counter = 0
stream = open('text.txt', 'rt')
lines = stream.readlines(20)
while len(lines) != 0:
for line in lines:
line_counter += 1
for char in line:
print(char, end='')
character_counter += 1
lines = stream.readlines(10)
stream.close()
print("\n\nCaracteres en el archivo:", character_counter)
print("Líneas en el archivo: ", line_counter)
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
4.3.1.6 Trabajando con archivos reales
try:
character_counter = line_counter = 0
for line in open('text.txt', 'rt'):
line_counter += 1
for char in line:
print(char, end='')
character_counter += 1
print("\n\nCaracteres en el archivo: ", character_counter)
print("Líneas en el archivo: ", line_counter)
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
El método se llama write() y espera solo un argumento: una cadena que se transferirá
a un archivo abierto (no lo olvides), el modo de apertura debe reflejar la forma en que se
transfieren los datos, escribir en un archivo abierto en modo de lectura no tendrá éxito).
La cadena que se grabará consta de la palabra línea, seguida del número de línea. Hemos
decidido escribir el contenido de la cadena carácter por carácter (esto lo hace el bucle
interno for ) pero no estás obligado a hacerlo de esta manera.
Solo queríamos mostrarte que write() puede operar con caracteres individuales.
línea #1
línea #2
línea #3
línea #4
línea #5
línea #6
línea #7
línea #8
línea #9
línea #10
salida
try:
file = open('newtext.txt', 'wt') # Un nuevo archivo
(newtext.txt) es creado.
for i in range(10):
s = "línea #" + str(i+1) + "\n"
for char in s:
file.write(char)
file.close()
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
Nota: puedes usar el mismo método para escribir en el stream stderr , pero no intentes
abrirlo, ya que siempre está abierto implícitamente.
Por ejemplo, si deseas enviar un mensaje de tipo cadena a stderr para distinguirlo de la
salida normal del programa, puede verse así:
import sys
sys.stderr.write("Mensaje de Error")
try:
file = open('newtext.txt', 'wt')
for i in range(10):
file.write("línea #" + str(i+1) + "\n")
file.close()
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
¿Qué es un bytearray?
Antes de comenzar a hablar sobre archivos binarios, tenemos que informarte sobre una
de las clases especializadas que Python usa para almacenar datos amorfos.
Los datos amorfos son datos que no tienen forma específica, son solo una serie de bytes.
Esto no significa que estos bytes no puedan tener su propio significado o que no puedan
representar ningún objeto útil, por ejemplo, gráficos de mapa de bits.
The most important aspect of this is that in the place where we have contact with the
data, we are not able to, or simply don't want to, know anything about it.
Python tiene más de un contenedor, uno de ellos es una clase especializada llamada
bytearray, como su nombre indica, es un arreglo que contiene bytes (amorfos).
Si deseas tener dicho contenedor, por ejemplo, para leer una imagen de mapa de bits y
procesarla de alguna manera, debes crearlo explícitamente, utilizando uno de los
constructores disponibles.
Observa:
data = bytearray(10)
Bytearrays: continuación
Bytearrays se asemejan a listas en muchos aspectos. Por ejemplo, son mutables, son
susceptibles a la función len() , y puedes acceder a cualquiera de sus elementos usando
indexación convencional.
Existe una limitación importante: no debes establecer ningún elemento del arreglo de
bytes con un valor que no sea un entero (violar esta regla causará una
excepción TypeError) y tampoco está permitido asignar un valor fuera del rango de 0 a
255 (a menos que quieras provocar una excepción ValueError).
Puedes tratar cualquier elemento del arreglo de bytes como un valor entero, al igual que
en el ejemplo en el editor.
Nota: hemos utilizado dos métodos para iterar el arreglo de bytes, y hemos utilizado la
función hex() para ver los elementos impresos como valores hexadecimales.
Ahora te vamos a mostrar como escribir un arreglo de bytes en un archivo binario, como
no queremos guardar su representación legible, queremos escribir una copia uno a uno
del contenido de la memoria física, byte a byte.
data = bytearray(10)
for i in range(len(data)):
data[i] = 10 - i
for b in data:
print(hex(b))
Bytearrays: continuación
Entonces, ¿cómo escribimos un arreglo de bytes en un archivo binario?
Si los valores difieren de la longitud de los argumentos del método, puede significar que
hay algunos errores de escritura.
En este caso, no hemos utilizado el resultado; esto puede no ser apropiado en todos los
casos.
Nota:
data = bytearray(10)
try:
binary_file = open('file.bin', 'rb')
binary_file.readinto(data)
binary_file.close()
for b in data:
print(hex(b), end=' ')
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
Analicémoslo:
• Primero, abrimos el archivo (el que se creó usando el código anterior) con el modo
descrito como rb .
• Luego, leemos su contenido en el arreglo de bytes llamado data , con un tamaño
de diez bytes.
• Finalmente, imprimimos el contenido del arreglo de bytes: ¿Son los mismos que
esperabas?
data = bytearray(10)
for i in range(len(data)):
data[i] = 10 + i
try:
binary_file = open('file.bin', 'wb')
binary_file.write(data)
binary_file.close()
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
Invocado sin argumentos, intenta leer todo el contenido del archivo en la memoria,
haciéndolo parte de un objeto recién creado de la clase bytes.
Esta clase tiene algunas similitudes con bytearray , con la excepción de una diferencia
significativa: es immutable.
Afortunadamente, no hay obstáculos para crear un arreglo de bytes tomando su valor
inicial directamente del objeto de bytes, como aquí:
try:
binary_file = open('file.bin', 'rb')
data = bytearray(binary_file.read())
binary_file.close()
for b in data:
print(hex(b), end=' ')
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
Ten cuidado: no utilices este tipo de lectura si no estás seguro de que el contenido del
archivo se ajuste a la memoria disponible.
data = bytearray(10)
for i in range(len(data)):
data[i] = 10 + i
try:
binary_file = open('file.bin', 'wb')
binary_file.write(data)
binary_file.close()
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
El método intenta leer la cantidad deseada de bytes del archivo, y la longitud del objeto
devuelto puede usarse para determinar la cantidad de bytes realmente leídos.
try:
binary_file = open('file.bin', 'rb')
data = bytearray(binary_file.read(5))
binary_file.close()
for b in data:
print(hex(b), end=' ')
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
Nota: los primeros cinco bytes del archivo han sido leídos por el código; los siguientes
cinco todavía están esperando ser procesados.
data = bytearray(10)
for i in range(len(data)):
data[i] = 10 + i
try:
binary_file = open('file.bin', 'wb')
binary_file.write(data)
binary_file.close()
except IOError as e:
print("Se produjo un error de E/S:", strerror(e.errno))
Por supuesto, el propósito no es crear un reemplazo para los comandos como copy de
(MS Windows) o cp de (Unix/Linux) pero para ver una forma posible de crear una
herramienta de trabajo, incluso si nadie quiere usarla.
buffer = bytearray(65536)
total = 0
try:
readin = source_file.readinto(buffer)
while readin > 0:
written = destination_file.write(buffer[:readin])
total += written
readin = source_file.readinto(buffer)
except IOError as e:
print("No se puede crear el archivo de destino: ", strerror(e.errno))
exit(e.errno)
LABORATORIO
Tiempo Estimado
60 minutos
Nivel de dificultad
Medio
Objetivos
• Mejorar las habilidades del estudiante al operar con la lectura archivos.
• Utilizar colecciones de datos para contar datos numerosos.
Escenario
Un archivo de texto contiene algo de texto (nada inusual) pero necesitamos saber con
qué frecuencia aparece cada letra en el texto. Tal análisis puede ser útil en criptografía,
por lo que queremos poder hacerlo en referencia al alfabeto latino.
aBc
samplefile.txt
b -> 1
c -> 1
salida
Tiempo Estimado
15-30 minutos
Nivel de dificultad
Medio
Prerrequisitos
4.3.1.15
Objetivos
• Mejorar las habilidades del estudiante para operar con archivos en modo
(lectura/escritura).
• Emplear lambdas para cambiar el ordenamiento.
Escenario
El código anterior necesita ser mejorado. Está bien, pero tiene que ser mejor.
cBabAa
samplefile.txt
a -> 3
b -> 2
c -> 1
salida
Tiempo Estimado
60-120 minutos
Nivel de dificultad
Medio-Dificil
Objetivos
• Mejorar las habilidades del alumno para operar con archivos en modo lectura.
• Perfeccionar las habilidades del estudiante para definir y usar excepciones y
diccionarios.
Escenario
El profesor Jekyll dirige clases con estudiantes y regularmente toma notas en un archivo
de texto. Cada línea del archivo contiene 3 elementos: el nombre del alumno, el apellido
del alumno y el número de puntos que el alumno recibió durante ciertas clases.
Los elementos están separados con espacios en blanco. Cada estudiante puede aparecer
más de una vez dentro del archivo del profesor Jekyll.
John Smith 5
Anna Boleyn 4.5
John Smith 2
Anna Boleyn 11
Andrew Cox 1.5
samplefile.txt
salida
Nota:
• Tu programa debe estar completamente protegido contra todas las fallas
posibles: la inexistencia del archivo, el vacío del archivo o cualquier falla en los
datos de entrada; encontrar cualquier error de datos debería causar la
terminación inmediata del programa, y lo erróneo deberá presentarse al usuario.
• Implementa y usa tu propia jerarquía de excepciones: la presentamos en el editor;
la segunda excepción se debe generar cuando se detecta una línea incorrecta y la
tercera cuando el archivo fuente existe pero está vacío.
class StudentsDataException(Exception):
pass
class WrongLine(StudentsDataException):
# Escribe tu código aquí.
class FileEmpty(StudentsDataException):
# Escribe tu código aquí.
Puntos Clave
1.Para leer el contenido de un archivo, se pueden utilizar los siguientes métodos:
2. Para escribir contenido nuevo en un archivo, se pueden utilizar los siguientes métodos:
3. El método open() devuelve un objeto iterable que se puede usar para recorrer todas
las líneas del archivo dentro de un bucle for . Por ejemplo:
El código copia el contenido del archivo a la consola, línea por línea. Nota: el stream se
cierra automáticamente cuando llega al final del archivo.
Ejercicio 1
¿Qué se espera del método readlines() cuando el stream está asociado con un archivo
vacío?
Revisar
Ejercicio 2
Revisar
Copia el contenido del archivo file hacia la consola, ignorando las vocales.
Ejercico 3
try:
stream = open("image.png", "rb")
# Inserta una línea aquí.
stream.close()
except IOError:
print("fallido")
else:
print("exitoso")
Revisar
image = bytearray(stream.read())
4.4.1.1 El módulo os
Introducción al módulo os
En esta sección, aprenderás sobre un módulo llamado os, que te permite interactuar con
tu sistema operativo usando Python.
Proporciona funciones que están disponibles en sistemas Unix y/o Windows. Si estás
familiarizado con la consola de comandos, verás que algunas funciones dan los mismos
resultados que los comandos disponibles en los sistemas operativos.
Un buen ejemplo de esto es la función mkdir , que te permite crear un directorio como el
comando mkdir en Unix y Windows. Si no conoces este comando, no te preocupes.
Pronto tendrás la oportunidad de aprender las funciones del módulo os, para realizar
operaciones en archivos y directorios junto con los comandos correspondientes.
¿Listo?
4.4.1.2 El módulo os
import os
print(os.uname())
Resultado:
posix.uname_result(sysname='Linux', nodename='192d19f04766',
release='4.4.0-164-generic', version='#192-Ubuntu SMP Fri Sep 13
12:02:50 UTC 2019', machine='x86_64')
salida
Como puedes ver, la función uname devuelve un objeto que contiene información sobre
el sistema operativo. El código anterior se ejecutó en Ubuntu 16.04.6 LTS, así que no te
sorprendas si obtienes un resultado diferente, porque depende de tu sistema operativo.
import os
print(os.name)
Resultado:
posix
salida
NOTA: En los sistemas Unix, hay un comando llamado uname que devuelve la misma
información (si lo ejecutas con la opción -a) que la función uname.
4.4.1.3 El módulo os
Creando directorios en Python
El módulo os proporciona una función llamada mkdir, la cual, como el comando mkdir en
Unix y Windows, te permite crear un directorio. La función mkdir requiere una ruta que
puede ser relativa o absoluta. Recordemos cómo se ven ambas rutas en la práctica:
La función mkdir crea un directorio en la ruta especificada. Ten en cuenta que ejecutar el
programa dos veces generará un FileExistsError.
Esto significa que no podemos crear un directorio si ya existe. Además del argumento de
la ruta, la función mkdir puede tomar opcionalmente el argumento mode, que especifica
los permisos del directorio. Sin embargo, en algunos sistemas, el argumento mode se
ignora.
Para cambiar los permisos del directorio, recomendamos la función chmod, que funciona
de manera similar al comando chmod en sistemas Unix. Puedes encontrar más
información al respecto en la documentación.
NOTA: Tanto en Windows como en Unix, hay un comando llamado mkdir, que requiere
una ruta de directorio. El equivalente del código anterior que crea el
directorio my_first_directory es el comando mkdir my_first_directory.
import os
os.mkdir("my_first_directory")
print(os.listdir())
4.4.1.4 El módulo os
['my_second_directory']
salida
Para moverte entre directorios, puedes usar una función llamada chdir, que cambia el
directorio de trabajo actual a la ruta especificada. Como argumento, toma cualquier ruta
relativa o absoluta. En nuestro ejemplo, le pasamos el nombre del primer directorio.
• Windows:
mkdir my_first_directory/my_second_directory
import os
os.makedirs("my_first_directory/my_second_directory")
os.chdir("my_first_directory")
print(os.listdir())
4.4.1.5 El módulo os
Resultado:
.../my_first_directory
.../my_first_directory/my_second_directory
salida
NOTA: En sistemas tipo Unix, el equivalente de la función getcwd es el comando pwd, que
imprime el nombre del directorio de trabajo actual.
import os
os.makedirs("my_first_directory/my_second_directory")
os.chdir("my_first_directory")
print(os.getcwd())
os.chdir("my_second_directory")
print(os.getcwd())
4.4.1.6 El módulo os
import os
os.makedirs("my_first_directory/my_second_directory")
os.removedirs("my_first_directory/my_second_directory")
print(os.listdir())
Al igual que con la función rmdir, si uno de los directorios no existe o no está vacío, se
generará una excepción.
NOTA: Tanto en Windows como en Unix, hay un comando llamado rmdir, que, al igual
que la función rmdir, elimina directorios. Además, ambos sistemas tienen comandos para
eliminar un directorio y su contenido. En Unix, este es el comando rm con el indicador -r.
import os
os.mkdir("my_first_directory")
print(os.listdir())
os.rmdir("my_first_directory")
print(os.listdir())
4.4.1.7 El módulo os
La función system()
Todas las funciones presentadas en esta parte del curso pueden ser reemplazadas por
una función llamada system, que ejecuta un comando que se le pasa como una cadena.
La función system está disponible tanto en Windows como en Unix. Dependiendo del
sistema, devuelve un resultado diferente.
Resultado:
0
salida
Esto significa que se ha creado el directorio my_first_directory. Como parte del ejercicio,
intenta enumerar el contenido del directorio donde se creó el
directorio my_first_directory.
import os
LABORATORIO
Tiempo Estimado
15-30 minutos
Nivel de Dificultad
Fácil
Objetivos
• Mejorar las habilidades del estudiante para interactuar con el sistema operativo.
• Uso práctico de funciones conocidas proporcionadas por el módulo os.
Escenario
No hace falta decir que los sistemas operativos te permiten buscar archivos y directorios.
Mientras estudiabas esta parte del curso, se aprendió sobre las funciones del módulo os,
que tiene todo lo que se necesita para escribir un programa que buscará directorios en
una ubicación determinada.
Para facilitar tu tarea, hemos preparado una estructura de directorio de prueba para ti:
1. Escribe una función o método llamado find que tome dos argumentos
llamados path y dir. El argumento path debe aceptar una ruta relativa o absoluta a
un directorio donde debe comenzar la búsqueda, mientras que el
argumento dir debe ser el nombre de un directorio en el que deseas encontrar la
ruta dada. Tu programa debería mostrar las rutas absolutas si encuentra un
directorio con el nombre dado.
2. La búsqueda en el directorio debe realizarse de forma recursiva. Esto significa que
la búsqueda también debe incluir todos los subdirectorios en la ruta dada.
Entrada de ejemplo:
path="./tree", dir="python"
Salida de ejemplo:
.../tree/python
.../tree/cpp/other_courses/python
.../tree/c/other_courses/Python
3. La función mkdir crea un directorio en la ruta pasada como argumento. La ruta puede
ser relativa o absoluta, por ejemplo:
import os
4. El resultado de la función listdir() es una lista que contiene los nombres de los
archivos y directorios que se encuentran en la ruta pasada como argumento.
Es importante recordar que la función listdir omite las entradas '.' y '..', que se
muestran, por ejemplo, cuando se utiliza el comando ls -a en sistemas Unix. Si no se
pasa la ruta, el resultado se devolverá para el directorio de trabajo actual.
5. Para moverte entre directorios, puedes usar una función llamada chdir() , que cambia
el directorio de trabajo actual a la ruta especificada. Como argumento, toma cualquier
ruta relativa o absoluta.
6. Para eliminar un directorio, puedes usar la función rmdir() , pero para eliminar un
directorio y sus subdirectorios, emplea la función removedirs() .
7. Tanto en Unix como en Windows, puedes usar la función system , que ejecuta el
comando que se le pasa como cadena, por ejemplo:
import os
Ejercicio 1
Revisar
posix
Ejercicio 2
os.mkdir("hello")
print(os.listdir())
Revisar
['hello']
Como puedes adivinar, proporciona clases para trabajar con la fecha y hora. Si crees que
no necesitas profundizar en este tema, hablemos de ejemplos del uso de la fecha y la
hora en la programación.
La fecha y la hora tienen innumerables usos y probablemente sea difícil encontrar una
aplicación de producción que no los utilice. A continuación, se muestran algunos
ejemplos:
• Registro de eventos: gracias al conocimiento de la fecha y la hora, podemos
determinar cuándo ocurre exactamente un error crítico en nuestra aplicación. Al
crear registros, puedes especificar el formato de fecha y hora.
• Seguimiento de cambios en la base de datos: a veces es necesario almacenar
información sobre cuándo se creó o modificó un registro. El módulo datetime será
perfecto para este caso.
• Validación de datos: pronto aprenderás a leer la fecha y hora actuales en Python.
Conociendo la fecha y hora actuales, podrás validar varios tipos de datos, por
ejemplo, si un cupón de descuento ingresado por un usuario en nuestra
aplicación sigue siendo válido.
• Almacenamiento de información importante: ¿te imaginas las transferencias
bancarias sin almacenar la información de cuándo se realizaron? La fecha y la
hora de ciertas acciones deben conservarse y debemos ocuparnos de ello.
La fecha y la hora se utilizan en casi todas las áreas de nuestras vidas, por lo que es
importante familiarizarse con el módulo datetime de Python. ¿Estás listo para una nueva
dosis de conocimiento?
El método today devuelve un objeto del tipo date que representa la fecha local actual.
Toma en cuenta que el objeto date tiene tres atributos: año, mes y día.
Ten cuidado, porque estos atributos son de solo lectura. Para crear un objeto date ,
debes pasar los parámetros año, mes y día de la siguiente manera:
Parámetro Restricciones
año El parámetro año debe ser mayor o igual a 1 (constante MINYEAR) y menor o
igual a 9999 (constante MAXYEAR).
mes El parámetro mes debe ser mayor o igual a 1 y menor o igual a 12.
día El parámetro día debe ser mayor o igual a 1 y menor o igual que el último día del
mes y año indicados.
today = date.today()
print("Hoy:", today)
print("Año:", today.year)
print("Mes:", today.month)
print("Día:", today.day)
Para crear un objeto de fecha a partir de una marca de tiempo, debemos pasar una
marca de tiempo Unix al método fromtimestamp .
Para este propósito, podemos usar el módulo time , que proporciona funciones
relacionadas con el tiempo. Uno de ellos es una función llamada time() , que devuelve el
número de segundos desde el 1 de enero de 1970 hasta el momento actual en forma de
número flotante. Echa un vistazo al ejemplo en el editor.
Si ejecutas el código de muestra varias veces, podrás ver cómo se incrementa la marca de
tiempo. Vale la pena agregar que el resultado de la función time depende de la
plataforma, porque en los sistemas Unix y Windows, los segundos intercalares no se
cuentan .
Nota: En esta parte del curso también hablaremos sobre el módulo time.
timestamp = time.time()
print("Marca de tiempo:", timestamp)
d = date.fromtimestamp(timestamp)
print("Fecha:", d)
El estándar ISO 8601 define cómo se representan la fecha y la hora. Se usa a menudo, por
lo que vale la pena tomarse un momento para familiarizarse con él. Echa un vistazo a la
imagen que describe los valores requeridos por el formato:
d = date.fromisoformat('2019-11-04')
print(d)
El método replace()
A veces, es posible que debas reemplazar el año, el mes o el día con un valor diferente.
No puedes hacer esto con los atributos de año, mes y día porque son de solo lectura. En
este caso, puedes utilizar el método llamado replace .
Resultado:
1991-02-05
1992-01-16
salida
Los parámetros year, month y day son opcionales. Puedes pasar solo un parámetro al
método replace , por ejemplo, año, o los tres como en el ejemplo.
El método replace devuelve un objeto date modificado, por lo que debes recordar
asignarlo a alguna variable.
d = date(1991, 2, 5)
print(d)
Resultado:
0
salida
La clase date tiene un método similar llamado isoweekday , que también devuelve el día
de la semana como un número entero, pero 1 es Lunes y 7 es Domingo:
d = date(2019, 11, 4)
print(d.isoweekday())
Resultado:
1
salida
Como puedes ver, para la misma fecha obtenemos un número entero diferente, pero
expresando el mismo día de la semana. El entero devuelto por el
método isodayweek sigue la especificación ISO 85601.
d = date(2019, 11, 4)
print(d.weekday())
Parámetro Restricciones
hour El párametro hour debe ser mayor o igual que 0 y menor que 23.
minute El párametro minute debe ser mayor o igual que 0 y menor que 59.
second El párametro second debe ser mayor o igual que 0 y menor que 59.
microsecond El párametro microsecond debe ser mayor o igual que 0 y menor que 1000000.
tzinfo El párametro tzinfo debe ser un objeto de la subclase tzinfo o None (por
defecto).
fold El párametro fold debe ser 0 o 1 (predeterminadamente 0).
El párametro tzinfo está asociado con las zonas horarias, mientras que fold está asociado
con el tiempo de pared. No los usaremos durante este curso, pero te recomendamos que
te familiarices con ellos.
Resultado:
Tiempo: 14:53:20.000001
Hora: 14
Minuto: 53
Segundo: 20
Microsegundo: 1
salida
print("Tiempo:", t)
print("Hora:", t.hour)
print("Minuto:", t.minute)
print("Segundo:", t.second)
print("Microsegundo:", t.microsecond)
4.5.1.8 El módulo time
El módulo time
Además de la clase time , la biblioteca estándar de Python ofrece un módulo
llamado time , que proporciona una función relacionada con el tiempo. Ya se tuvo la
oportunidad de aprender la función llamada time cuando se habló de la clase date .
Ahora veremos otra función útil disponible en este módulo.
Debes pasar muchas horas frente a una computadora mientras realiza este curso. A
veces puedes sentir la necesidad de tomar una siesta. ¿Por qué no? Escribamos un
programa que simule la siesta corta de un estudiante. Echa un vistazo al código en el
editor.
Resultado:
Estoy muy cansado. Tengo que echarme una siesta. Hasta luego.
¡Dormí bien! ¡Me siento genial!
salida
La parte más importante del código de muestra es el uso de la función sleep (sí, puedes
recordarla de una de las prácticas de laboratorio anteriores en el curso), que suspende la
ejecución del programa por el determinado número de segundos.
En nuestro ejemplo, son 5 segundos. Tienes razón, es una siesta muy corta.
import time
class Student:
def take_nap(self, seconds):
print("Estoy muy cansado. Tengo que echarme una siesta. Hasta luego.")
time.sleep(seconds)
print("¡Dormí bien! ¡Me siento genial!")
student = Student()
student.take_nap(5)
La función ctime()
El módulo time proporciona una función llamada ctime , que convierte el tiempo en
segundos desde el 1 de enero de 1970 (época Unix) en una cadena.
¿Recuerdas el resultado de la función time ? Eso es lo que necesitas pasar a ctime . Echa
un vistazo al ejemplo en el editor.
Resultado:
La función ctime devuelve una cadena para la marca de tiempo pasada. En nuestro
ejemplo, la marca de tiempo expresa el 4 de noviembre de 2019 a las 14:53:00.
import time
print(time.ctime())
import time
timestamp = 1572879180
print(time.ctime(timestamp))
time.struct_time:
tm_year # Especifica el año.
tm_mon # Especifica el mes (valor de 1 a 12)
tm_mday # Especifica el día del mes (valor de 1 a 31)
tm_hour # Especifica la hora (valor de 0 a 23)
tm_min # Especifica el minuto (valor de 0 a 59)
tm_sec # Especifica el segundo (valor de 0 a 61)
tm_wday # Especifica el día de la semana (valor de 0 a 6)
tm_yday # Especifica el día del año (valor de 1 a 366)
tm_isdst # Especifica si se aplica el horario de verano (1: sí, 0: no, -1: no se sabe)
tm_zone # Especifica el nombre de la zona horaria (valor en forma abreviada)
tm_gmtoff # Especifica el desplazamiento al este del UTC (valor en segundos)
Las excepciones son tm_zone y tm_gmoff, a las que no se puede acceder mediante
índices. Veamos cómo usar la clase struct_time en la práctica. Ejecuta el código en el
editor.
Resultado:
El ejemplo muestra dos funciones que convierten el tiempo transcurrido desde la época
Unix al objeto struct_time. La diferencia entre ellos es que la función gmtime devuelve el
objeto struct_time en UTC, mientras que la función localtime devuelve la hora local.
Para la función gmtime , el atributo tm_isdst es siempre 0.
import time
timestamp = 1572879180
print(time.gmtime(timestamp))
print(time.localtime(timestamp))
Resultado:
La segunda función llamada mktime convierte un objeto struct_time o una tupla que
expresa la hora local al número de segundos desde la época de Unix. En nuestro ejemplo,
le pasamos una tupla, que consta de los siguientes valores:
import time
timestamp = 1572879180
st = time.gmtime(timestamp)
print(time.asctime(st))
print(time.mktime((2019, 11, 4, 14, 53, 0, 0, 308, 0)))
Parámetro Restricciones
year El parámetro year debe ser mayor o igual a 1 (constante MINYEAR) y menor o
igual a 9999 (constante MAXYEAR).
month El parámetro month debe ser mayor o igual a 1 y menor o igual a 12.
day El parámetro day debe ser mayor o igual a 1 y menor o igual al último día del
mes y año indicados.
hour El parámetro hour debe ser mayor o igual que 0 y menor que 23.
minute El parámetro minute debe ser mayor o igual que 0 y menor que 59.
second El parámetro second debe ser mayor o igual que 0 y menor que 59.
microsecond El parámetro microsecond debe ser mayor o igual que 0 y menor que 1000000.
tzinfo El parámetro tzinfo debe ser una subclase del objeto tzinfo o None (de manera
predeterminada).
fold El parámetro fold debe ser 0 o 1 (predeterminadamente 0).
Ahora echemos un vistazo al código en el editor para ver cómo creamos un objeto del
tipo datetime.
Resultado:
• today() : devuelve la fecha y hora local actual con el atributo tzinfo establecido
a None.
• now() : devuelve la fecha y hora local actual igual que el método today, a menos
que le pasemos el argumento opcional tz. El argumento de este método debe ser
un objeto de la subclase tzinfo.
• utcnow() : devuelve la fecha y hora UTC actual con el atributo tzinfo establecido
a None.
Ejecuta el código en el editor para verlos todos en la práctica. ¿Qué puedes decir sobre la
salida?
Como puedes ver, el resultado de los tres métodos es el mismo. Las pequeñas diferencias
se deben al tiempo transcurrido entre llamadas posteriores.
print("hoy:", datetime.today())
print("ahora:", datetime.now())
print("utc_ahora:", datetime.utcnow())
Resultado:
Timestamp: 1601823300.0
salida
Una directiva es una cadena que consta del carácter % (porcentaje) y una letra minúscula
o mayúscula. Por ejemplo, la directiva %Y significa el año con el siglo como número
decimal. Veámoslo en un ejemplo. Ejecuta el código en el editor.
Resultado:
2020/01/04
salida
• %Y : devuelve el año con el siglo como número decimal. En nuestro ejemplo, esto
es 2020.
• %m : devuelve el mes como un número decimal con relleno de ceros. En nuestro
ejemplo, es 01.
• %d : devuelve el día como un número decimal con relleno de ceros. En nuestro
ejemplo, es 04.
d = date(2020, 1, 4)
print(d.strftime('%Y/%m/%d'))
Resultado:
14:53:00
20/November/04 14:53:00
salida
El segundo formato utilizado combina directivas de fecha y hora. Hay dos nuevas
directivas, %Y y %B . La directiva %Y devuelve el año sin siglo como un número decimal con
relleno de ceros (en nuestro ejemplo es 20). La directiva %B devuelve el mes como el
nombre completo.
En general, tienes mucha libertad para crear formatos, pero debes recordar usar las
directivas correctamente. Como ejercicio, puedes comprobar qué sucede si, por ejemplo,
intentas utilizar la directiva %Y en el formato pasado al método strftime del objeto time.
Intenta averiguar por qué se obtuvo este resultado. ¡Buena suerte!
from datetime import time
from datetime import datetime
t = time(14, 53)
print(t.strftime("%H:%M:%S"))
2019/11/04 14:53:00
2020/10/12 12:19:40
salida de muestra
La creación de un formato tiene el mismo aspecto que para los métodos strftime en el
módulo datetime . En nuestro ejemplo, usamos %Y , %m , %d , %H , %M y %S directivas que ya
conoces.
import time
timestamp = 1572879180
st = time.gmtime(timestamp)
Resultado:
2019-11-04 14:53:00
salida
Nota: En el módulo time , puedes encontrar una función llamada strptime , que analiza
una cadena que representa un tiempo en un objeto struct_time. Su uso es análogo al
método strptime en la clase datetime :
import time
print(time.strptime("2019/11/04 14:53:00", "%Y/%m/%d %H:%M:%S"))
El ejemplo muestra la resta para los objetos date y datetime . En el primer caso,
recibimos la diferencia en días, que es de 366 días. Toma en cuenta que también se
muestra la diferencia en horas, minutos y segundos. En el segundo caso, recibimos un
resultado diferente, porque especificamos el tiempo que se incluyó en los cálculos. Como
resultado, recibimos 365 días, 9 horas y 7 minutos.
En un momento aprenderás más sobre la creación de los objetos timedelta y sobre las
operaciones que puedes realizar con ellos.
d1 = date(2020, 11, 4)
d2 = date(2019, 11, 4)
print(d1 - d2)
print(dt1 - dt2)
Por supuesto, también puedes crear un objeto tu mismo. Para ello, vamos a
familiarizarnos con los argumentos aceptados por el constructor de la clase, que
son: days , seconds , microseconds , milliseconds , minutes , hours , y weeks . Cada uno
de ellos es opcional y el valor predeterminado es 0.
Los argumentos deben ser números enteros o de punto flotante, y pueden ser positivos o
negativos. Veamos un ejemplo sencillo en el editor.
Resultado:
16 days, 3:00:00
salida
El resultado de 16 días se obtiene convirtiendo el argumento weeks en días (2 semanas =
14 días) y agregando el argumento days (2 días). Este es un comportamiento normal,
porque el objeto timedelta solo almacena días, segundos y microsegundos
internamente. De manera similar, el argumento hora se convierte en minutos. Echa un
vistazo al siguiente ejemplo:
Resultado:
Días: 16
Segundos: 10800
Microseconds: 0
salida
Observa algunas operaciones admitidas por las clases del módulo datetime . Ejecuta el
código que te proporcionamos en el editor.
Resultado:
16 days, 2:00:00
32 days, 4:00:00
2019-11-05
2019-11-05 18:53:00
salida
El objeto timedelta se puede multiplicar por un número entero. En nuestro ejemplo,
multiplicamos el objeto que representa 16 días y 2 horas por 2. Como resultado,
recibimos un objeto timedelta que representa 32 días y 4 horas.
Toma en cuenta que tanto los días como las horas se han multiplicado por 2. Otra
operación interesante usando el objeto timedelta es la suma. En el ejemplo, hemos
sumado el objeto timedelta a los objetos date y datetime .
Por supuesto, las clases timedelta , date y datetime admiten muchas más operaciones.
Te recomendamos que te familiarices con ellos en la documentación.
delta2 = delta * 2
print(delta2)
LABORATORIO
Tiempo Estimado
15-45 minutos
Nivel de Dificultad
Fácil
Objetivos
• Mejorar las habilidades del estudiante en el formato de fecha y hora.
• Mejorar las habilidades del estudiante en el uso del método strftime .
Escenario
Durante este curso, has aprendido sobre el método strftime , que requiere
conocimiento de las directivas para crear un formato. Ahora es el momento de poner en
práctica estas directivas.
2020/11/04 14:53:00
20/November/04 14:53:00 PM
Wed, 2020 Nov 04
Wednesday, 2020 November 04
Día de la semana: 3
Día del año: 309
Número de semana en el año: 44
salida esperada
Nota: Cada línea de resultado debe crearse llamando al método strftime con al menos
una directiva en el argumento de formato.
Puntos Clave
1. Para crear un objeto date , debes pasar los argumentos de año, mes y día de la
siguiente manera:
El objeto date tiene tres atributos (de solo lectura): año, mes y día.
2. El método today devuelve un objeto de fecha que representa la fecha local actual:
from datetime import date
print("Hoy:", date.today()) # Muestra: Hoy: 2020-09-29
3. En Unix, la marca de tiempo expresa el número de segundos desde el 1 de Enero de
1970 a las 00:00:00 (UTC). Esta fecha se llama la "época de Unix", porque ahí comenzó el
conteo del tiempo en los sistemas Unix. La marca de tiempo es en realidad la diferencia
entre una fecha en particular (incluida la hora) y el 1 de Enero de 1970, 00:00:00 (UTC),
expresada en segundos. Para crear un objeto de fecha a partir de una marca de tiempo,
debemos pasar una marca de tiempo Unix al método fromtimestamp :
timestamp = time.time()
d = date.fromtimestamp(timestamp)
5. El módulo time contiene la función sleep , que suspende la ejecución del programa
durante un número determinado de segundos, por ejemplo:
import time
time.sleep(10)
print("¡Hola mundo!") # Este texto se mostrará después de 10 segundos.
Ejemplo:
d = date(2020, 9, 29)
print(d.strftime('%Y/%m/%d')) # Muestra: 2020/09/29
d1 = date(2020, 11, 4)
d2 = date(2019, 11, 4)
d = d1 - d2
print(d) # Muestra: 366 days, 0:00:00.
print(d * 2) # Muestra: 732 days, 0:00:00.
Lunes 0 calendar.MONDAY
Martes 1 calendar.TUESDAY
Miércoles 2 calendar.WEDNESDAY
Jueves 3 calendar.THURSDAY
Viernes 4 calendar.FRIDAY
Sábado 5 calendar.SATURDAY
Domingo 6 calendar.SUNDAY
Para los meses, los valores enteros se indexan a partir de 1, es decir, Enero se representa
por 1 y diciembre por 12. Desafortunadamente, no hay constantes que expresen los
meses.
La información anterior te resultará útil cuando trabajes con el módulo calendar en esta
parte del curso, pero primero comencemos con algunos ejemplos sencillos de calendario.
4.6.1.2 El módulo calendar
Tu primer calendario
Comenzarás tu aventura con el módulo calendar con una función simple
llamada calendar , que te permite mostrar el calendario para todo el año. Veamos cómo
usarlo para mostrar el calendario de 2020. Ejecuta el código en el editor y ve qué sucede.
La función de calendario requiere que se especifique el año, mientras que los otros
parámetros responsables del formato son opcionales. Te recomendamos que pruebes
estos parámetros tu mismo.
Una buena alternativa a la función anterior es la función llamada prcal, que también toma
los mismos parámetros que la función calendar , pero no requiere el uso de la
función print para mostrar el calendario. Su uso se ve así:
import calendar
calendar.prcal(2020)
import calendar
print(calendar.calendar(2020))
import calendar
print(calendar.month(2020, 11))
La función setfirstweekday()
Como ya sabes, por defecto en el módulo calendar , el primer día de la semana es el
Lunes. Sin embargo, puedes cambiar este comportamiento usando una función
llamada setfirstweekday .
La función weekday()
Otra función útil proporcionada por el módulo calendar es la función llamada weekday ,
que devuelve el día de la semana como un valor entero para el año, mes y día. Veámoslo
en la práctica.
Resultado:
3
salida
La función weekheader()
Probablemente hayas notado que el calendario contiene encabezados semanales en
forma abreviada. Si es necesario, puedes obtener nombres cortos de días de la semana
utilizando el método weekheader .
Resultado:
Mo Tu We Th Fr Sa Su
salida
import calendar
print(calendar.weekheader(2))
Resultado:
True
3
salida
import calendar
print(calendar.isleap(2020))
print(calendar.leapdays(2010, 2021)) # Hasta 2021, pero sin incluirlo.
Durante este curso, ya tuviste la oportunidad de crear calendarios de texto al discutir las
funciones del módulo calendar .
Es hora de probar algo nuevo. Echemos un vistazo más de cerca a los métodos de la
clase calendar .
4.6.1.9 El módulo calendar
El parámetro firstweekday debe ser un valor entero entre 0-6. Para este propósito,
podemos usar las constantes ya conocidas: mira el código en el editor.
6 0 1 2 3 4 5
salida
import calendar
c = calendar.Calendar(calendar.SUNDAY)
El método itermonthdates()
La clase Calendar tiene varios métodos que devuelven un iterador. Uno de ellos es el
método itermonthdates , que requiere especificar el año y el mes.
Como resultado, se devuelven todos los días del mes y año especificados, así como todos
los días antes del comienzo del mes o del final del mes que son necesarios para obtener
una semana completa.
Cada día está representado por un objeto datetime.date . Echa un vistazo al ejemplo en
el editor.
El código muestra todos los días de Noviembre de 2019. Debido a que el primer día de
Noviembre de 2019 fue Viernes, los siguientes días también se devuelven para obtener la
semana completa: 28/10/2019 (Lunes) 29/10/2019 (Martes ) 30/10/2019 (Miércoles)
31/10/2019 (Jueves).
El último día de Noviembre de 2019 fue Sábado, por lo que para mantener la semana
completa, se devuelve un día más el 12/01/2019 (Viernes).
import calendar
c = calendar.Calendar()
Hay otros cuatro métodos similares en la clase Calendar que difieren en los datos
devueltos:
Con fines de prueba, utiliza el ejemplo anterior y ve cómo se ven en la práctica los valores
de retorno de los métodos descritos.
import calendar
c = calendar.Calendar()
El método monthdays2calendar()
La clase Calendar tiene varios otros métodos útiles sobre los que puedes obtener más
información en la documentación (https://docs.python.org/3/library/calendar.html).
Toma en cuenta que los números de los días fuera del mes están representados por 0,
mientras que los números de los días de la semana son un número del 0 al 6, donde 0 es
el Lunes y 6 es el Domingo.
En un momento, este método puede resultar útil para completar una tarea de
laboratorio. ¿Estás listo?
import calendar
c = calendar.Calendar()
LABORATORIO
Tiempo Estimado
30-60 minutos
Nivel de Dificultad
Fácil
Objetivos
• Mejorar las habilidades del estudiante en el uso de la clase Calendar.
Escenario
Durante este curso, echamos un breve vistazo a la clase Calendar . Tu tarea ahora es
ampliar su funcionalidad con un nuevo método llamado count_weekday_in_year , que
toma un año y un día de la semana como parámetros, y luego devuelve el número de
ocurrencias de un día de la semana específico en el año.
Argumentos de muestra
year=2019, weekday=0
Salida esperada
52
Argumentos de muestra
year=2000, weekday=6
Salida esperada
53
Puntos Claves
1. En el módulo calendar , los días de la semana se muestran de Lunes a Domingo. Cada
día de la semana tiene su representación en forma de número entero, donde el primer
día de la semana (Lunes) está representado por el valor 0, mientras que el último día de
la semana (Domingo) está representado por el valor 6.
import calendar
print(calendar.calendar(2020))
Nota: Una buena alternativa a la función anterior es la función llamada prcal , que
también toma los mismos parámetros que la función calendar , pero no requiere el uso
de la función print para mostrar el calendario.
3. Para mostrar un calendario de cualquier mes del año, se emplea la función month ,
pasándole el año y el mes. Por ejemplo:
import calendar
print(calendar.month(2020, 9))
Nota: También puedes usar la función prmonth , que tiene los mismos parámetros que la
función month , pero no requiere el uso de la función print para mostrar el calendario.
import calendar
print(calendar.weekday(2020, 9, 29)) # Esto muestra 1, que significa Martes.
6. La función weekheader devuelve los nombres de los días de la semana en forma
abreviada. El método weekheader requiere que se especifique el ancho en caracteres
para un día de la semana. Si el ancho que proporciona es mayor que 3, aún se obtendrán
los nombres abreviados de los días de la semana que constan de solo tres caracteres. Por
ejemplo:
import calendar
print(calendar.weekheader(2)) # Esto muestra: Mo Tu We Th Fr Sa Su
7. Una función muy útil disponible en el módulo calendar es la función llamada isleap ,
que, como su nombre indica, te permite comprobar si el año es bisiesto o no:
import calendar
print(calendar.isleap(2020)) # Esto muestra: True
8. Puedes crear un objeto calendar tu mismo usando la clase Calendar , que, al crear el
objeto, te permite cambiar el primer día de la semana con el parámetro
opcional firstweekday , por ejemplo:
import calendar
c = calendar.Calendar(2)
iterweekdays devuelve un iterador para los números de los días de la semana. El primer
valor devuelto siempre es igual al valor de la propiedad firstweekday .
Ejercicio 1
import calendar
print(calendar.weekheader(1))
Revisar
M T W T F S S
Ejercicio 2
import calendar
c = calendar.Calendar()
0 1 2 3 4 5 6
• Generadores e iteradores.
• Listas por comprensión.
• Las funciones lambda, map, y filter.
• Cierres.
• El trabajar con archivos (streams, procesamiento de archivos, el diagnosticar
problemas en los streams).
• Procesamiento de archivos de texto y binarios.
• Módulos STL seleccionados de Python: os, datetime, time, y calendar.
Ahora estás listo para realizar el quiz del módulo e intentar el desafío final: el Exámen del
Módulo 4, que te ayudará a evaluar lo que has aprendido hasta ahora.
¡Felicidades!
Has completado Fundamentos de Python 2
¡Bien hecho! Has llegado al final del curso Fundamentos de Python 2, y has completado
un paso importante en tu educación de programación en Python.
Ahora estás preparado para tomar el desafío final, el Examen Global de FP2, que te
ayudará a revisar la información más importante que has leído y probar las habilidades y
conocimientos que has adquirido a lo largo del curso.
Una vez completado el curso, también estás preparado para presentar el examen y
obtener la certificación PCAP - Certified Associate in Python Programming, lo que
garantiza que estás completamente familiarizado con todos los medios principales
proporcionados por Python 3 para que puedas comenzar tus propios estudios y abrirte
camino hacia una carrera como desarrollador, así como un paso más para alcanzar la
certificación PCPP1 - Certified Professional in Python Programming.
¿Estás listo?
Puedes pagar el cupón (voucher) para el examen PCAP-31-03 con las principales tarjetas
de crédito (es decir, Visa, MasterCard, American Express), tarjetas de débito o mediante
una cuenta de PayPal. También puedes solicitar una factura Proforma y realizar tu pago
mediante transferencia bancaria.
El servicio de Supervisión en Línea de OnVUE está disponible las 24 horas del día, los 7
días de la semana, durante todo el año.