Lenguajes Naturales vs. Lenguajes de Programación
Lenguajes Naturales vs. Lenguajes de Programación
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 ese número, divídelo por otro y guarda el resultado".
Ninguna computadora es actualmente capaz de crear un nuevo idioma. Sin embargo, eso puede
cambiar pronto. Por otro lado, las personas también usan varios idiomas muy diferentes, pero estos
idiomas se crearon ellos mismos. Además, todavía están evolucionando.
Cada día se crean nuevas palabras y desaparecen las viejas. Estos lenguajes se llaman lenguajes
naturales.
ALFABETO
Un conjunto de símbolos utilizados para formar palabras de un determinado idioma (por ejemplo, el
alfabeto latino para el inglés, el alfabeto cirílico para el ruso, el kanji para el japonés, etc.).
LÉXICO
(También conocido como diccionario) un conjunto de palabras que el idioma ofrece a sus usuarios
(por ejemplo, la palabra "computadora" proviene del diccionario en inglés, mientras que "abcde" no;
la palabra "chat" está presente en los diccionarios de inglés y francés, pero sus significados son
diferentes.
SINTAXIS
SEMÁNTICA
Un conjunto de reglas que determinan si una frase tiene sentido (por ejemplo, "Me comí una dona"
tiene sentido, pero "Una dona me comió" no lo tiene).
Desafortunadamente, esta lengua está muy lejos de ser una lengua materna humana. Todos (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.
Necesitamos un lenguaje en el que los humanos puedan escribir sus programas y un lenguaje que las
computadoras puedan usar para ejecutar los programas, que es mucho más complejo que el lenguaje
máquina y más sencillo que el lenguaje natural.
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 computadoras que son mucho más
complejas que las ofrecidas por las IL.
Por supuesto, tal composición tiene que ser correcta en muchos sentidos, tales como:
Desafortunadamente, un programador también puede cometer errores en cada uno de los cuatro
sentidos anteriores. Cada uno de ellos puede hacer que el programa se vuelva completamente inútil.
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 de la máquina; ahora
puedes distribuir el archivo en todo el mundo; el programa que realiza esta traducción se llama
compilador o traductor.
INTERPRETACIÓN - Tú (o cualquier usuario del código) puedes traducir el programa fuente cada
vez que se ejecute; el programa que realiza este tipo de transformación se denomina intérprete, ya
que interpreta el código cada vez que está destinado a ejecutarse; también significa que no puede
distribuir el código fuente tal como está, porque el usuario final también necesita que el intérprete lo
ejecute.
Debido a algunas razones muy fundamentales, un lenguaje de programación de alto nivel particular
está diseñado para caer en una de estas dos categorías.
Hay muy pocos idiomas que se pueden compilar e interpretar. Por lo general, un lenguaje de
programación se proyecta con este factor en la mente de sus constructores: ¿Se compilará o
interpretará?
El intérprete lee el código fuente de una manera que es común en la cultura occidental: de arriba
hacía 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).
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ía la entidad del nombre.
Si la línea se ve bien, el intérprete intenta ejecutarla (nota: cada línea generalmente se ejecuta por
separado, por lo que el trío "Lectura - Verificación - Ejecución", pueden repetirse muchas veces, más
veces que el número real de líneas en el archivo fuente, como algunas partes del código pueden
ejecutarse más de una vez).
También es posible que una parte significativa del código se ejecute con éxito antes de que el
intérprete encuentre un error. Este es el comportamiento normal en este modelo de ejecución.
COMPILACIÓN INTERPRETACIÓN
VENTAJAS La ejecución del código Puede ejecutar el código en cuanto
traducido suele ser más lo complete; no hay fases
rápida. adicionales de traducción.
Solo el usuario debe tener el El código se almacena utilizando el
compilador; el usuario final lenguaje de programación, no el de
puede usar el código sin él. la máquina; esto significa que puede
El código traducido se ejecutarse en computadoras que
almacena en lenguaje utilizan diferentes lenguajes
máquina, ya que es muy máquina; no compila el código por
difícil de entender, es separado para cada arquitectura
probable que tus propios diferente.
inventos y trucos de
programación sigan siendo
COMPILACIÓN INTERPRETACIÓN
secreto.
La compilación en sí misma
puede llevar mucho tiempo; No esperes que la interpretación
es posible que no puedas incremente tu código a alta
ejecutar tu código velocidad: tu código compartirá la
inmediatamente después de potencia de la computadora con el
DESVENTAJA
cualquier modificación. intérprete, por lo que no puede ser
S
Tienes que tener tantos realmente rápido.
compiladores como Tanto tú como el usuario final
plataformas de hardware en deben tener el intérprete para
los que deseas que se ejecutar su código.
ejecute su código.
Python es un lenguaje interpretado. Esto significa que hereda todas las ventajas y
desventajas descritas. Por supuesto, agrega algunas de sus características únicas a ambos
conjuntos.
Si deseas programar en Python, necesitarás el intérprete de Python. No podrás ejecutar tu
código sin él. Afortunadamente, Python es gratis. Esta es una de sus ventajas más
importantes.
Debido a razones históricas, los lenguajes diseñados para ser utilizados en la manera de
interpretación a menudo se llaman lenguajes de programación, 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.
Y 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 del programa de televisión.
¿Quién creó Python?
Una de las características sorprendentes de Python es el hecho de que en realidad es
el trabajo de una persona. Por lo general, los grandes lenguajes de programación son
desarrollados y publicados por grandes compañías que emplean a muchos
profesionales, y debido a las normas de derechos de autor, es muy difícil nombrar a
cualquiera de las personas involucradas en el proyecto. Python es una excepción.
No hay muchos idiomas cuyos autores son conocidos por su nombre. Python fue
creado por Guido van Rossum, nacido en 1956 en Haarlem, Países Bajos. Por
supuesto, Guido van Rossum no desarrolló y evolucionó todos los componentes de
Python.
La velocidad con la que Python se ha extendido por todo el mundo es el resultado del
trabajo continuo de miles de (muy a menudo anónimos) programadores, evaluadores,
usuarios (muchos de ellos no son especialistas en TI) y entusiastas, pero hay que decir
que la primera idea (la semilla de la que brotó Python) llegó a una cabeza: la de Guido.
De cualquier manera, todavía ocupa un alto rango en el top ten de la PYPL Popularity
of Programming Language y la TIOBE Programming Community Index.
Tiene muchos seguidores, pero hay muchos que prefieren otros lenguajes y ni siquiera
consideran Python para sus proyectos.
Rivales de Python
Python tiene dos competidores directos, con propiedades y predisposiciones
comparables. Estos son:
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, 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. Como
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 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
Si se va a comenzar un nuevo proyecto de Python, deberías usar Python 3, esta es la
versión de Python que se usará durante este curso.
Es importante recordar que puede haber diferencias mayores o menores entre las
siguientes versiones de Python 3 (p. Ej., Python 3.6 introdujo claves de diccionario
ordenadas de forma predeterminada en la implementación de CPython). La buena
noticia es que todas las versiones más nuevas de Python 3 son compatibles con las
versiones anteriores de Python 3. Siempre que sea significativo e importante, siempre
intentaremos resaltar esas diferencias en el curso.
Todos los ejemplos de código que encontrarás durante el curso se han probado con
Python 3.4, Python 3.6 y Python 3.7.
En primer lugar, están los Pythons que mantienen las personas reunidas en torno a
PSF (Python Software Foundation), una comunidad que tiene como objetivo
desarrollar, mejorar, expandir y popularizar Python y su entorno. El presidente del PSF
es el propio Guido van Rossum, y por esta razón, estos Pythons se llaman canónicos.
También se consideran Pythons de referencia, ya que cualquier otra implementación
del lenguaje debe seguir todos los estándares establecidos por el PSF.
Cython
Otro miembro de la familia Python es Cython.
Cython es una de las posibles soluciones al rasgo de Python más doloroso: la falta de
eficiencia. Los cálculos matemáticos grandes y complejos pueden ser fácilmente
codificados en Python (mucho más fácil que en "C" o en cualquier otro lenguaje
tradicional), pero la ejecución del código resultante puede requerir mucho tiempo.
¿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 para "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.
PyPy y RPython
Echa un vistazo al logo de abajo. Es un rebus. ¿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
Por ejemplo, algunas distribuciones pueden unir sus herramientas específicas con el
sistema y muchas de estas herramientas, como los administradores de paquetes, a
menudo están escritas en Python. Algunas partes de los entornos gráficos disponibles
en el mundo de Linux también pueden usar Python.
python3
Si Python 3 está ausente, consulta la documentación de Linux para saber cómo usar 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 Linux pueden descargar una copia
en https://www.python.org/downloads/.
Deja las configuraciones predeterminadas que el instalador sugiere por ahora, con
una excepción: mira 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
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 elige 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 de 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 de origen.
Haz clic en File (en la nueva ventana), luego haz clic en 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 estándar permite que el sistema operativo abra estos archivos
correctamente.
La línea se ve así:
print("Hisssssss...")
Haz clic en File , Open , señala el archivo que guardaste anteriormente y deja que IDLE
lo lea.
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.
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).
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 el error.
La ventana del editor no proporcionará ninguna información útil sobre el error, pero
es posible que las ventanas de la consola si.
Sandbox
Este curso no requiere que instales ninguna aplicación de software para probar tu
código y hacer los ejercicios.
Es una herramienta integrada dentro del curso, que se puede usar como un Sandbox
de Python basado en el navegador que te permite probar el código discutido a lo
largo del curso, así como un intérprete que te permite iniciar, realizar y probar los
ejercicios de laboratorio diseñados específicamente para este curso.
print("Hola!")
print("¡Bienvenido a Fundamentos de Programación en Python!")
print("ESTO ES EL MODO SANDBOX.")
... luego da clic en el botón Sandbox para ingresar al Modo Sandbox, pega el código en
la ventana del editor y haz clic en el botón Ejecutar para ver que sucede.
Para volver a nuestro curso, haz clic en Back to course en la esquina superior derecha
de la interfaz de Sandbox.
Interfaz de práctica
Este curso contiene cuatro tipos diferentes de interfaces.
Hasta ahora, haz visto la Interfaz de estudio (una o dos ventanas con texto e
imágenes/animación) y la Interfaz de Sandbox, que puedes usar para probar tu
propio código (haz clic en Sandbox para cambiar a la Interfaz de Sandbox).
Lo que ves ahora es la Interfaz de práctica, que te permite estudiar cosas nuevas y
realizar tareas de codificación al mismo tiempo. Utilizarás este tipo de interfaz la
mayor parte del tiempo durante el curso.
¡Hola, Mundo!
Es hora de comenzar a escribir código real y funcional en Python. Por el momento
será muy sencillo.
Ejecuta el código en la ventana del editor a la derecha. Si todo sale bien, veras 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 una
línea 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()
Mira 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 contenido 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 o algunos valores (por ejemplo, la raíz cuadrada de un valor o la
longitud de un texto dado); 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.
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 matemáticas usualmente toman un argumento, por ejemplo, sen (x) toma una x, que es
la medida de un ángulo.
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!")
A pesar del número de argumentos necesarios o proporcionados, las funciones de Python demandan
fuertemente la presencia de un par de paréntesis - el de apertura y de cierre, respectivamente.
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 se puede 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 mas 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?
nombreFunción(argumento)
Veamos:
LABORATORIO
Tiempo Estimado
5 minutos
Nivel de dificultad
Muy fácil
Objetivos
Familiarizarse con la función print() y sus capacidades de formateo.
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()
El efecto es muy útil y espectacular. La función toma los argumentos (puede aceptar más de un
argumento y también puede aceptar menos de un argumento) los convierte en un formato legible
para el ser humano si es necesario (como puedes sospechar, las cadenas no requieren esta acción, ya
que la cadena ya está legible) y envía los datos resultantes al dispositivo de salida (generalmente
la consola); en otras palabras, cualquier cosa que se ponga en la función de print() aparecerá en la
pantalla.
No es de extrañar entonces, que de ahora en adelante, utilizarás print() muy intensamente para
ver los resultados de tus operaciones y evaluaciones.
2. ¿Qué argumentos espera print() ?
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() .
La función print() - instrucciones
A estas alturas ya sabes que este programa contiene una invocación de función. A su
vez, la invocación de función es uno de los posibles tipos de instrucciones de Python.
Por lo tanto, este programa consiste de una sola instrucción.
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. Ejecutalo y nota lo que
ves en la consola.
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 de origen; no se ejecuta la siguiente instrucción hasta
que se complete la anterior (hay algunas excepciones a esta regla, pero puedes
ignorarlas por ahora).
La función print() - instrucciones
¿Qué ocurre?
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.
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ó.
Como se puede observar, aparecen dos nuevas líneas en la canción infantil, en los
lugares donde se ha utilizado \n .
print()
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("\")
2. No todos los pares de escape (la barra invertida junto con otro carácter) significan
algo.
Experimenta con el código en el editor, ejecútalo y observa lo que sucede.
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 mirar el código, verás que no hay espacios dentro de las cadenas.
Los espacios, removidos de las cadenas, han vuelto a aparecer. ¿Puedes explicar
porque?
La forma en que pasamos los argumentos a la función print() es la más común en
Python, y se denomina manera posicional (este nombre proviene del hecho de que el
significado del argumento está dictado por su posición, por ejemplo, el segundo
argumento se emitirá después del primero, y no al revés).
En la ventana del editor se puede ver un ejemplo muy simple de como utilizar un
argumento de palabra clave.
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.
Mi-nombre-es-Monty-Python.
La función print() ahora utiliza un guión, 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 considerar aprender
cómo almacenar y procesar datos en Python.
Mi_nombre_es*Monty*Python.*
LABORATORIO
Tiempo Estimado
5 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() .
Resultado Esperado
Fundamentos***Programación***en...Python
print("Fundamentos","Programación","en", sep=”***”,end=”…”)
print("Python")
LABORATORIO
Tiempo Estimado
5-10 minutos
Nivel de dificultad
Facil
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(" *****")
2.1.2.1 Literales de Python
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.
Que tal este:
¿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.
print("2")
print(2)
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.
No exploraremos las complejidades de los sistemas numéricos posicionales, pero se puede afirmar
que todos los números manejados por las computadoras modernas son de dos tipos:
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.
La característica del valor numérico que determina el tipo, rango y aplicación se denomina el tipo.
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 numero 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 numero: 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. Esta prohibido. ¿Qué es lo que
Python permite? El uso de guion bajo en los literales numéricos.*
Por lo tanto, el número se puede escribir ya sea así: 11111111 , o como sigue: 11_111_111 .
NOTA *Python 3.6 ha introducido el guion bajo en los literales numéricos, permitiendo colocar un
guion bajo entre dígitos y después de especificadores de base para mejorar la legibilidad. Esta
característica no está disponible en versiones anteriores de Python.
¿Cómo se codifican los números negativos en Python? Como normalmente se hace, agregando un
signo de menos. Se puede escribir: -11111111 , o -11_111_111 .
Los números positivos no requieren un signo positivo antepuesto, pero es permitido, si se desea
hacer. Las siguientes líneas describen el mismo número: +11111111 y 11111111 .
Si un numero entero esta precedido por un código 0O o 0o (cero-o), el numero será
tratado como un valor octal. Esto significa que el número debe contener dígitos en el
rango del [0..7] únicamente.
print(0o123)
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 más comas.
Python no lo aceptará, o (en casos poco probables) puede malinterpretar el número, debido a que la
coma tiene su propio significado en Python.
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.
4.0
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.
Por ejemplo, la velocidad de la luz, expresada en metros por segundo. Escrita directamente se vería
de la siguiente manera: 300000000 .
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.
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.
0.0000000000000000000001
print(0.0000000000000000000001)
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?
Supongamos que se desea mostrar un muy sencillo mensaje:
¿Cómo se puede hacer esto sin generar un error? Existen dos posibles soluciones.
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?
Revisar
print('I\'m Monty Python.')
o
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 caracter 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 Algebra Booleana - una parte del algebra 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 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"""
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.
Los sistemas de numeración Octales y Hexadecimales son similares pues emplean 8 y 16 como sus
bases respectivamente. El sistema hexadecimal utiliza los números decimales más seis letras
adicionales.
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).
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
"Hola", "007"
Revisar
Ejercicio 2
Ejercicio 3
1011
Revisar
print(2+2) salida 4
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.
Por ejemplo, como en la aritmética, el signo de + (mas) es un operador el cual es capaz
de sumar dos numeros, dando el resultado de la suma.
Sin embargo, no todos los operadores de Python son tan simples como el signo de
mas, 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:
+ , - , * , / , // , % , **
print(2 ** 3) salida 8
Recuerda: Es posible formular las siguientes reglas con base en los resultados:
print(2 * 3) salida 6
El resultado carece de la parte fraccionaria, está ausente (para los enteros), o siempre es
igual a cero (para los flotantes); esto significa que los resultados siempre son
redondeados.
Se ajusta a la regla entero vs flotante.
print(6 // 3) salida 2
Como se puede observar, una división de entero entre entero da un resultado entero. Todos los
demás casos producen flotantes.
Hagamos algunas pruebas mas avanzadas.
print(6 // 4) salida 1
Imagina que se utilizó / en lugar de // - ¿Podrías predecir los resultados?
El resultado de la división entera siempre se redondea al valor entero inferior mas cercano del
resultado de la división no redondeada.
print(-6 // 4) salida -2
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 division 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 )
Operadores: como no dividir
Como probablemente sabes, la división entre cero no funciona.
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) salida -8
print(4. - 8) salida -4.0
print(-1.1) salida -1.1
Por cierto: también hay un operador + unario. Se puede utilizar de la siguiente manera:
print(+2)
Aunque dicha construcción es sintácticamente correcta, utilizarla no tiene mucho sentido, y sería
difícil encontrar una buena razón para hacerlo.
Observa el fragmento de código que está arriba - ¿Puedes adivinar el resultado o salida?
También, muy seguido encontrarás más de un operador en una expresión, y entonces esta presunción
ya no es tan obvia.
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.
La mayoría de los operadores de Python tienen un enlazado hacia la izquierda, lo que significa que el
calculo de la expresión es realizado de izquierda a derecha.
Este simple ejemplo te mostrará como funciona. Observa:
print(9 % 6 % 2)
El resultado debe ser 1 . El operador tiene un enlazado hacia la izquierda. Pero hay una excepción
interesante.
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.
En lugar de ello, se mostrarán solo algunos, y se irán expandiendo conforme se vayan introduciendo
operadores nuevos.
Prioridad Operador
1 + , - unario
2 **
3 * , / , %
4 + , - binario
Nota: se han enumerado los operadores en orden de la mas alta (1) a la mas baja (4) prioridad.
print(2 * 3 % 5)
Ambos operadores ( * y % ) tienen la misma prioridad, el resultado solo se puede obtener conociendo
el sentido del enlazado. ¿Cuál será el resultado?
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
Lista de prioridades
Como eres nuevo a los operadores de Python, no se presenta por ahora una lista completa de las
prioridades de los operadores.
En lugar de ello, se mostrarán solo algunos, y se irán expandiendo conforme se vayan introduciendo
operadores nuevos.
Prioridad Operador
1 + , - unario
2 **
3 * , / , %
4 + , - binario
Nota: se han enumerado los operadores en orden de la mas alta (1) a la mas baja (4) prioridad.
print(2 * 3 % 5)
Ambos operadores ( * y % ) tienen la misma prioridad, el resultado solo se puede obtener conociendo
el sentido del enlazado. ¿Cuál será el resultado?
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
RESUMEN DE LA SECCIÓN
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 .
6. Algunos operadores actúan antes que otros, a esto se le llama - jerarquía de prioridades:
Ejercicio 1
16 8.0 8
Ejercicio 2
-0.5 0.5 0 -1
Ejercicio 3
-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.
¿Cómo almacenar los resultados intermedios, y después utilizarlos de nuevo para producir resultados
subsecuentes?
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).
Palabras Clave
Observa las palabras que juegan un papel muy importante en cada programa de Python.
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
var = 1
print(var)
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 cual 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
balance_cuenta = 1000.0
nombreCliente = 'John Doe'
print(var, balance_cuenta, nombreCliente)
print(var)
Sin embargo, no se permite utilizar una variable que no exista, (en otras palabras, una variable a la
cual no se le a dado un valor).
var = 1
print(Var)
RECUERDA
Se puede utilizar print() para combinar texto con variables utilizando el operador + para mostrar
cadenas con variables, por ejemplo:
var = "3.7.1"
print("Versión de Python: " + var)
Revisar
El signo de igual es de hecho un operador de asignación. Aunque esto suene un poco extraño, el
operador tiene una sintaxis simple y una interpretación clara y precisa.
var = 1
print(var)
var = var + 1
print(var)
1
2
La primer línea del código crea una nueva variable llamada var y le asigna el valor de 1 .
La declaración se lee de la siguiente manera: asigna el valor de 1 a una variable llamada var .
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.
¿Puedes predecir cuál será el resultado del siguiente fragmento de código?
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.
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
LABORATORIO
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:
juan=3
maria=5
adan=6
print(juan,maria,adan,sep=”,”)
totalmanzanas=(juan+maria+adan)
print(totalmanzanas)
print(“Número total de Manzanas:”,totalmanzanas)
Operadores Abreviados
Es tiempo de explicar el siguiente conjunto de operadores que harán la vida del
programador/desarrollador mas fácil.
Muy seguido, se desea utilizar la misma variable al lado derecho y al lado izquierdo del operador = .
Por ejemplo, si se necesita calcular una serie de valores sucesivos de la potencia de 2, se puede usar
el siguiente código:
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:
oveja = oveja + 1
Python ofrece una manera mas corta de escribir operaciones como estas, lo cual se puede codificar
de la siguiente manera:
x *= 2
oveja+= 1
A continuación se intenta presentar una descripción general para este tipo de operaciones.
Si op es un operador de dos argumentos (esta es una condición muy imporante) y el operador es
utilizado en el siguiente contexto:
i = i + 2 * j ⇒ i += 2 * j
x = x ** 2 ⇒ x **= 2
LABORATORIO
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 millas ).
CONSEJO
Hay una cosa interesante mas 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 numero 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 numero de decimales que se desean mostrar). Se hablará mas
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
millas_a_kilometros = millas*1.61
kilometros_a_millas = kilometros/1.61
print(millas, " millas son ", round(millas_a_kilometros, 2), " kilómetros ")
print(kilometros, " kilómetros son ", round(kilometros_a_millas, 2), " millas ")
LABORATORIO
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.
Prueba de Datos
Datos de Muestra
x = 0
x = 1
x = -1
Salida Esperada
y = -1.0
y = 3.0
y = -9.0
x = valor x
x = float(x)
y = 3*(x**3)-2*(x**2)+3*(x)-1
print("y =", y)
RESUMEN DE LA SECCIÓN
Puntos Clave
1. Una variable es una ubicación nombrada reservada para almacenar valores en la memoria. Una
variable es creada o inicializada automáticamente cuando se le asigna un valor por primera vez.
2. Cada variable debe de tener un nombre único - un identificador. Un nombre valido debe ser aquel
que no contiene espacios, debe comenzar con un guion bajo ( _ ), o una letra, y no puede ser una
palabra reservada de Python. El primer carácter puede estar seguido de guiones bajos, letras, y
dígitos. Las variables en Python son sensibles a mayúsculas y minúsculas.
5. Se les puede asignar valores nuevos a variables ya existentes utilizando el operador de asignación
o un operador abreviado:
var = 2
print(var)
var = 3
print(var)
var += 1
print(var)
var = "007"
print("Agente " + var)
Ejercicio 1
¿Cuál es el resultado del siguiente fragmento de código?
var = 2
var = 3
print(var)
Revisar
Ejercicio 2
my_var
m
101
averylongvariablename
m101
m 101
Del
del
Revisar
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.1.5.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.
En Python, un comentario es un texto que comienza con el símbolo # y se extiende hasta el final de
la línea.
Si se desea colocar un comentario que abarca varias líneas, se debe colocar este símbolo en cada
línea.
a = 3.0
b = 4.0
print("c =", c)
Por ejemplo, si una variable determinada esta diseñada para almacenar el área de un cuadrado, el
nombre areaCuadrado será muchísimo mejor que tiaJuana .
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:
x = 1
y = 2
# y = y + x
print(x + y)
Esto es frecuentemente realizado cuando se esta probando un programa, con el fin de aislar un
fragmento de código donde posiblemente se encuentra un error.
LABORATORIO
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 = 5# numero de horas
RESUMEN DE SECCIÓN
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.
2. Si deseas colocar un comentario que abarque varias líneas, es necesario colocar un # al inicio de
cada línea. Además, se puede utilizar un comentario para marcar un fragmento de código que no es
necesaria en el momento y no se desea ejecutar. (observa la ultima línea de código del siguiente
fragmento), por ejemplo:
3. Cuando sea posible, se deben auto comentar los nombres de las variables, por ejemplo, si se
están utilizando dos variables para almacenar la altura y longitud de algo, los
nombres 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 tu estas 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
¿Cuál es la salida del siguiente fragmento de código?
# 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() .
print() no tiene un resultado utilizable. La importancia de esta nueva función es que regresa un
valor muy utilizable.
La función input() es capaz de leer datos que fueron introducidos por el usuario y pasar esos
datos al programa en ejecución.
El programa entonces puede manipular los datos, haciendo que el código sea verdaderamente
interactivo.
Todos los programas leen y procesan datos. Un programa que no obtiene datos de entrada del
usuario es un programa sordo.
Observa el ejemplo:
print("Dime algo...")
algo = input()
Nota:
Intenta ejecutar el código y permite que la función te muestre lo que puede hacer.
La función input() con un argumento
La función input() puede hacer algo más: puede mostrar un mensaje al usuario sin la ayuda de la
función print() .
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.
Esta variante de la invocación de la función input() simplifica el código y lo hace más claro.
El resultado de la función input()
Se ha dicho antes, pero hay que decirlo sin ambigüedades una vez más: el resultado de la
función input() es una cadena.
Una cadena que contiene todos los caracteres que el usuario introduce desde el teclado. No es un
entero ni un flotante.
Esto significa que no se debe utilizar como un argumento para operaciones matemáticas, por
ejemplo, no se pueden utilizar estos datos para elevarlos al cuadrado, para dividirlos entre algo o por
algo.
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.
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 sigo de + (más), al ser aplicado a dos cadenas, se convierte en un operador de
concatenación:
string + string
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.
cadena * número
número * cadena
Por ejemplo:
RECUERDA
Este sencillo programa "dibuja" un rectángulo, haciendo uso del operador ( + ), pero en
un nuevo rol:
¡Intenta practicar para crear otras figuras o tus propias obras de arte!
str(número)
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.
a=25.3
b=6.0
print(a+b)
print(a-b)
print(a*b)
print(a/b)
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.
y=1/(x+(1/(x+(1/(x+(1/x))))))
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 formateo.
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 minutes de 0 a 59. El resultado debe ser mostrado en la consola.
Prueba el código cuidadosamente. Pista: utilizar el operador % puede ser clave para el
éxito.
Datos de Prueba
Entrada de muestra:12
17
59
58
642
Entrada de muestra:0
2939
minutos=(min+dura)%60
horas=int(hora+(min+dura)/60)%24
print(horas,":",minutos)
RESUMEN DE SECCIÓN
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:
3. Cuando la función input() es llamada o invocada, el flujo del programa se detiene, el símbolo
del cursor se mantiene parpadeando (le está indicando al usuario que tome acción ya que la consola
está en modo de entrada) hasta que el usuario haya ingresado un dato y/o haya presionado la
tecla Enter.
NOTA
3. 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
55
Ejercicio 2
<class 'str'>
Preguntas y respuestas
Una computadora ejecuta el programa y proporciona las respuestas. El programa debe ser capaz
de reaccionar de acuerdo con las respuestas recibidas.
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.
Para hacer preguntas, Python utiliza un conjunto de operadores muy especiales. Revisemos
uno tras otro, ilustrando sus efectos en algunos ejemplos simples.
= es un operador de asignación, por ejemplo, a = b assigna a la varable a el valor de b .
== es una pregunta ¿Son estos valores iguales?; a == b compara a y b .
Es un operador binario con enlazado a la izquierda. Necesita dos argumentos y verifica si son
iguales.
Ejercicios
2 == 2 Revisar
True (verdadero) - por supuesto, 2 es igual a 2. Python responderá True (Recuerda este par
de literales predefinidos, True y False - También son palabras clave de Python).
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
Ten 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.
ovejasNegras == 2 * ovejasBlancas
ovejasNegras == (2 * ovejaBlancas)
print(var == 0)
print(var == 0)
print(var != 0)
print(var != 0)
print(var != 0)
print(var != 0)
False
True
También se puede hacer una pregunta de comparación usando el operador > (mayor que).
Si deseas saber si hay más ovejas negras que blancas, puedes escribirlo de la siguiente manera:
El operador mayor que tiene otra variante especial, una variante no estricta, pero se denota de
manera diferente que la notación aritmética clásica: >= (mayor o igual que).
Ambos operadores (estrictos y no estrictos), así como los otros dos que se analizan en la siguiente
sección, son operadores binarios con enlace en el 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:
Como probablemente ya hayas adivinado, los operadores utilizados en este caso son: El
operador < (menor que) y su hermano no estricto: <= (menor o igual que).
Vamos a comprobar si existe un riesgo de ser multados (la primera pregunta es estricta, la segunda
no).
¿Qué puedes hacer con la respuesta (es decir, el resultado de una operación de comparación) que se
obtiene de la computadora?
Hay al menos dos posibilidades: primero, puedes memorizarlo (almacenarlo en una variable) y
utilizarlo más tarde. ¿Cómo haces eso? Bueno, utilizarías una variable arbitraria como esta:
La segunda posibilidad es más conveniente y mucho más común: puedes utilizar la respuesta que
obtengas para tomar una decisión sobre el futuro del programa.
Necesitas una instrucción especial para este propósito, y la discutiremos muy pronto.
Ahora necesitamos actualizar nuestra tabla de prioridades , y poner todos los nuevos operadores en
ella. Ahora se ve como a continuación:
Prioridad Operador
1 + , - unario
2 **
3 * , / , %
4 + , - binario
6 == , !=
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
n=int(input(“Introduce el número:”))
Print (n>=100)
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 declaración condicional).
Existen varias variantes de la misma. Comenzaremos con la más simple, aumentando la dificultad
lentamente.
La primera forma de una declaración condicional, que puede ver a continuación, está escrita de
manera muy informal pero figurada:
if cierto_o_no:
hacer_esto_si_cierto
Esta declaración condicional consta de los siguientes elementos, estrictamente necesarios en este
orden:
La palabra clave if .
Uno o más espacios en blanco.
Una expresión (una pregunta o una respuesta) cuyo valor se interpretar únicamente en
términos de True (cuando su valor no sea cero) y False (cuando sea igual a cero).
Unos dos puntos seguido de una nueva línea.
Una instrucción con sangría o un conjunto de instrucciones (se requiere absolutamente al
menos una instrucción); la sangría se puede lograr de dos maneras: insertando un número
particular de espacios (la recomendación es usar cuatro espacios de sangría), o usando
el tabulador; nota: si hay mas de una instrucción en la parte con sangría, la sangría debe ser
la misma en todas las líneas; aunque puede parecer lo mismo si se mezclan tabuladores con
espacios, es importante que todas las sangrías sean exactamente iguales Python 3 no
permite mezclar espacios y tabuladores para la sangría.
después, almorzaremos
Como puedes ver, almorzar no es una actividad condicional y no depende del clima.
Sabiendo que condiciones influyen en nuestro comportamiento y asumiendo que tenemos las
funciones sin parámetros irACaminar() y almorzar() , podemos escribir el siguiente
fragmento de código:
if ClimaEsBueno:
irAcaminar()
almorzar()
Puedes leerlo como sigue: si contadorOvejas es mayor o igual que 120 , entonces duerme y
sueña (es decir, ejecuta la función duermeSueña .)
Hemos dicho que las declaraciones 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 contadorOvejas alcanza el límite deseado.
Alimentar a los perros, sin embargo, siempre se hace (es decir, la función alimentarPerros no
tiene sangría y no pertenece al bloque if , lo que significa que siempre se ejecuta).
Ahora vamos a discutir otra variante de la declaración 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.
Podemos decir, por ejemplo: Si el clima es bueno, saldremos a caminar, de lo contrario, iremos al
cine.
Ahora sabemos lo que haremos si se cumplen las condiciones , y sabemos lo que haremos si no
todo sale como queremos . En otras palabras, tenemos un "Plan B".
Python nos permite expresar dichos planes alternativos. Esto se hace con una segunda forma,
ligeramente mas compleja, de la declaración condicional, la declaración if-else :
if condición_true_or_false:
ejecuta_si_condición_true
else:
ejecuta_si_condición_false
Por lo tanto, hay una nueva palabra: else - esta es una palabra 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 climaEsBueno:
irACaminar()
else:
irAlCine()
almorzar()
Todo lo que hemos dicho sobre la sangría funciona de la misma manera dentro de la rama else :
if climaEsBueno:
irACaminar()
Diviertirse()
else:
irAlCine()
disfrutaLaPelicula()
almorzar()
Declaraciones if-else anidadas
Ahora, analicemos dos casos especiales de la declaración condicional.
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 climaEsBueno:
if encontramosBuenRestaurante:
almorzar()
else:
comerSandwich()
else:
if hayBoletosDisponibles:
irAlCine()
else:
irDeCompras()
Este uso de la declaración if se conoce como anidamiento; recuerda que cada else se
refiere al if que se encuentra en el mismo nivel de sangría; se necesita saber esto para
determinar cómo se relacionan los ifs y los elses.
Considera como la sangría mejora la legibilidad y hace que el código sea más fácil de
entender y rastrear.
La declaración 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
declaración 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 elif desempeña su función.
if climaBueno:
iraCaminar()
elif hayBoletosDisponibles:
IralCine()
elif mesasLibres:
almorzar()
else:
jugarAjedrezEnCasa()
Esto puede sonar un poco desconcertante, pero ojalá que algunos ejemplos simples ayuden a
comprenderlo mejor.
Ejemplo 1:
if numero1> numero2:
nmasGrande = numero1
else:
nmasGrande = numero2
#imprimir el resultado
Ejemplo 2:
#imprimir el resultado
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:
Suponemos que el primer valor es el más grande. Luego verificamos esta hipótesis con
los dos valores restantes.
nmasGrande = numero1
nmasGrande = numero2
nmasGrande = numero3
#imprimir el resultado
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?
Por ahora ignoraremos los requisitos de la sintaxis de Python e intentaremos analizar el problema sin
pensar en la programación real. En otras palabras, intentaremos escribir el algoritmo, y cuando
estemos contentos con él, lo implementaremos.
En este caso, utilizaremos un tipo de notación que no es un lenguaje de programación real (no se
puede compilar ni ejecutar), pero está formalizado, es conciso y se puede leer. Se
llama pseudocódigo.
línea 04 print(numeroMayor)
línea 05 exit()
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.
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:
# imprimir el resultado
De la misma manera, puedes usar la función min() para devolver el número más bajo. Puedes
reconstruir el código anterior y experimentar con él en el 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.
LABORATORIO
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
elif nombre==”espatifilo”:
print(“No,¡quiero un gran Espatifilo!”)
else:
print(“¡Espatifilo! ¡No”, nombrem “!”)
LABORATORIO
Tiempo estimado
10-15 minutos
Nivel de dificultad
Fácil/Medio
Objetivos
Familiarizar al estudiante con:
Escenario
Érase una vez una tierra - 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:
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.
Prueba tu código con los datos que hemos proporcionado.
Datos de prueba
Entrada de muestra: 10000
impuesto=round(impuesto, 0)
if impuesto<0:
impuesto=0.0
LABORATORIO
Tiempo estimado
10-15 minutos
Nivel de dificultad
Fácil/Medio
Objetivos
Familiarizar al estudiante con:
Utilizar la declaración if-elif-else.
Encontrar la implementación adecuada de reglas definidas verbalmente.
Emplear el código de prueba usando entrada y salida de muestra.
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
año=int(input(“Introduzca un año:”))
if año<1582:
else:
if año % 4 ¡=0:
print(“Año común”)
print(“Año bisiesto”)
print(“Año común”)
else:
print(“Año bisiesto”)
RESUMEN DE LA SECCIÓN
Puntos clave
1. Los operadores de comparación (o también denominados 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 :
!=
Devuelve True si los valores de los operandos no son iguales, y False de lo x !=
contrario. x !=
Devuelve True si el valor del operando izquierdo es mayor que el valor del x >
>
operando derecho, y False de lo contrario. y >
Devuelve True si el valor del operando izquierdo es menor que el valor del
< x <
operando derecho, y False de lo contrario.
x >=
Devuelve True si el valor del operando izquierdo es mayor o igual al valor del
≥ x >=
operando derecho, y False de lo contrario. y >=
Devuelve True si el valor del operando izquierdo es menor o igual al valor del x <=
≤
operando derecho, y False de lo contrario. y <=
2. Cuando desea ejecutar algún código solo si se cumple una determinada condición, puede usar
una declaración condicional:
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 False
x = 10
if x > 5: # Verdadero
print("x > 5")
if x > 8: # Verdadero
print("x > 8")
else:
print("Se ejecutará el else")
Cada if se prueba por separado. El cuerpo de else se ejecuta si el último if es False .
x = 10
if x == 10: # Verdadero
print("x == 10")
else:
print("No se ejecutará el else")
x = 10
if x > 5: # Verdadero
if x == 6: # Falso
print("anidado: x == 6")
elif x == 10: # Verdadero
print("anidado: x == 10")
else:
print("anidado: else")
else:
print("else")
Ejercicio 1
x = 5
y = 10
z = 8
print(x > y)
print(y > z)
Revisar
False
True
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
Ejercicio 3
x, y, z = 5, 10, 8
x, y, z = z, y, x
print(x > z)
print((y - 5) == x)
Revisar
True
False
Ejercicio 4
x = 10
if x == 10:
print(x == 10)
if x > 5:
print(x > 5)
if x < 10:
else:
print("else")
Revisar
True
True
else
Ejercicio 5
x = "1"
if x == 1:
print("uno")
elif x == "1":
print("dos")
print("tres")
else:
print("cuatro")
if int (x) == 1:
print("cinco")
else:
print("seis")
Revisar
cuatro
cinco
Ejercicio 6
x = 1
y = 1.0
z = "1"
if x == y:
print("uno")
if y == int (z):
print("dos")
elif x == y:
print("tres")
else:
print("cuatro")
Revisar
uno
dos
Ten en cuenta que este registro también declara que, si no hay nada que hacer, nada ocurrirá.
while expresión_condicional:
instrucción
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 expresión_condicional:
instrucción_uno
instruccion_dos
instrucción_tres
instrucción_n
while True:
print("Estoy atrapado dentro de un ciclo")
Si deseas obtener la mejor experiencia de aprendizaje al ver cómo se comporta un ciclo infinito,
inicia IDLE, cree un Nuevo archivo, copia y pega el código anterior, guarda tu archivo y ejecuta el
programa. Lo que verás es la secuencia interminable de cadenas impresas de "Estoy atrapado
dentro de un ciclo". En la ventana de la consola de Python. Para finalizar tu programa,
simplemente presiona Ctrl-C (o Ctrl-Break en algunas computadoras). Esto provocará la
excepción KeyboardInterrupt y permitirá que tu programa salga del ciclo. Hablaremos de ello
más adelante en el curso.
Volvamos al bosquejo del algoritmo que te mostramos recientemente. Te mostraremos como usar
este ciclo recién aprendido para encontrar el número más grande de un gran conjunto de datos
ingresados.
Analiza el programa cuidadosamente. Localiza el cuerpo del ciclo y descubre como se sale del
cuerpo:
numeroMayor = numero
Veamos otro ejemplo utilizando el ciclo while . Sigue los comentarios para descubrir la
idea y la solución.
numerosImpares = 0
numerosPares = 0
# 0 termina la ejecución
while numero != 0:
if numero % 2 == 1:
numerosImpares += 1
else:
numerosPares += 1
Intenta recordar cómo Python interpreta la verdad de una condición y ten en cuenta
que estas dos formas son equivalentes:
contador = 5
while contador != 0:
contador -= 1
Este código está destinado a imprimir la cadena "Dentro del ciclo" y el valor
almacenado en la variable contador durante un ciclo dado exactamente cinco veces.
Una vez que la condición se haya cumplido (la variable contador ha alcanzado 0 ), se
sale del ciclo y aparece el mensaje "Fuera del ciclo". así como el valor
almacenado en contador se imprime.
Pero hay una cosa que se puede escribir de forma más compacta: la condición del
ciclo while .
contador=5
while contador:
contador - = 1
¿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.
LABORATORIO
Tiempo estimado
15 minutos
Nivel de dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
Utilizar el ciclo while.
Reflejar situaciones de la vida real en código de computadora.
Escenario
Un mago junior ha elegido un número secreto. Lo ha escondido en una variable
llamada númeroSecreto . Quiere que todos los que ejecutan su programa jueguen el
juego Adivina el número secreto, y adivina qué número ha elegido para ellos. ¡Quienes
no adivinen el número quedarán atrapados en un ciclo sin fin para siempre!
Desafortunadamente, él no sabe cómo completar el código.
INFO EXTRA
Por cierto, mira la función print() . La forma en que lo hemos utilizado aquí se
llama impresión multilínea . Puede utilizar comillas triples para imprimir cadenas en
varias líneas para facilitar la lectura del texto o crear un diseño especial basado en
texto. Experimenta con ello.
numeroSecreto = 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 ciclo debe ejecutarse exactamente cien veces. Si deseas utilizar el
ciclo while para hacerlo, puede tener este aspecto:
i = 0
while i < 100:
# hacer_algo()
i += 1
Sería bueno si alguien pudiera hacer esta cuenta aburrida por ti. ¿Es eso posible?
Por supuesto que lo es, hay un ciclo especial para este tipo de tareas, y se llama for .
En realidad, el ciclo for está diseñado para realizar tareas más complicadas, puede "explorar"
grandes colecciones de datos elemento por elemento. Te mostraremos como hacerlo pronto, pero
ahora presentaremos una variante más sencilla de su aplicación.
La palabra reservada for abre el ciclo for ; nota - No hay condición después de eso; no
tienes que pensar en las condiciones, ya que se verifican internamente, sin ninguna
intervención.
Cualquier variable después de la palabra reservada for es la variable de control del ciclo;
cuenta los giros del ciclo y lo hace automáticamente.
La palabra reservada in introduce un elemento de sintaxis que describe el rango de valores
posibles que se asignan a la variable de control.
La función range() (esta es una función muy especial) es responsable de generar todos
los valores deseados de la variable de control; en nuestro ejemplo, la función creará (incluso
podemos decir que alimentará el ciclo con) valores subsiguientes del siguiente conjunto: 0,
1, 2 .. 97, 98, 99; nota: en este caso, la función range() comienza su trabajo desde 0 y lo
finaliza un paso (un número entero) antes del valor de su argumento.
Nota la palabra clave pass dentro del cuerpo del ciclo - no hace nada en absoluto; es
una instrucción vacía : la colocamos aquí porque la sintaxis del ciclo for exige al menos
una instrucción dentro del cuerpo (por cierto, if , elif , else y while expresan lo
mismo).
Nuestros próximos ejemplos serán un poco más modestos en el número de repeticiones de ciclo.
for i in range(10):
print("El valor de i es actualmente", i)
Nota:
La invocación de la función range() puede estar equipada con dos argumentos, no solo uno:
En este caso, el primer argumento determina el valor inicial (primero) de la variable de control.
Nota: la función range() solo acepta enteros como argumentos y genera secuencias de enteros.
¿Puedes adivinar la salida del programa? Ejecútalo para comprobar si ahora también estabas en lo
cierto.
El primer valor mostrado es 2 (tomado del primer argumento de range() ).
El valor de i es actualmente 2
El valor de i es actualmente 5
¿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.
Nota: si el conjunto generado por la función range() está vacío, el ciclo no ejecutará
su cuerpo en absoluto.
Nota: el conjunto generado por range() debe ordenarse en un orden ascendente.
No hay forma de forzar el range() para crear un conjunto en una forma diferente.
Esto significa que el segundo argumento de range() debe ser mayor que el primero.
Por lo tanto, tampoco habrá salida aquí:
pow = 1
pow * = 2
La variable exp se utiliza como una variable de control para el ciclo 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 ciclo 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.
Tu tarea es muy simple aquí: escribe un programa que use un ciclo for para "contar
de forma mississippi" hasta cinco. Habiendo contado hasta cinco, el programa debería
imprimir en la pantalla el mensaje final "¡Listo 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 declaración 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 ciclo 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
import time
Las declaraciones break y continue
Hasta ahora, hemos tratado el cuerpo del ciclo como una secuencia indivisible e
inseparable de instrucciones que se realizan completamente en cada giro del ciclo. Sin
embargo, como desarrollador, podrías enfrentar las siguientes opciones:
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
# continua - ejemplo
numeroMayor = -99999999
contador = 0
while True:
numero = int (input ("Ingresa un número o escribe -1 para
finalizar el programa:"))
break
contador = 1
numeroMayor = numero
if contador != 0:
else:
numeroMayor = -99999999
contador = 0
continue
contador = 1
numeroMayor = numero
else:
LABORATORIO
Tiempo estimado
10 minutos
Nivel de dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
Escenario
La instrucción break se usa para salir/terminar un ciclo.
Diseña un programa que use un ciclo 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 ciclo con éxito". Debe
imprimirse en la pantalla y el ciclo debe terminar.
while True:
palabra=input(“Ingresa la palabra clave:”)
if palabra==”chupacabra”:
print(“¡Has dejado el ciclo con éxito”)
break
LABORATORIO
Tiempo estimado
10-15 minutos
Nivel de dificultad
Fácil
Objetivos
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 declaraciones dentro del ciclo.
Un ciclo for .
El concepto de ejecución condicional (if-elif-else).
La declaración continue .
Tu programa debe:
Datos de prueba
Entrada de muestra: Gregory
Salida esperada:
Salida esperada:
Salida esperada:
LABORATORIO
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 ciclo for .
El concepto de ejecución condicional (if-elif-else ).
La declaración continue .
Tu programa debe:
Datos de prueba
Entrada de muestra: Gregory
Salida esperada:
GRGRY
Salida esperada:
BSTMS
Salida esperada:
palabraSinVocal = ""
print(palabraSinVocal)
El while y la opción else
Ambos ciclos, while y for , tienen una característica interesante (y rara vez se usa).
Como pudiste haber sospechado, los ciclos también pueden tener la rama else ,
como los if .
i = 5
while i < 5:
print(i)
i += 1
else:
print("else:", i)
El ciclo for y la rama else
Los ciclos for se comportan de manera un poco diferente: echa un vistazo al
fragmento en el editor y ejecútalo.
i = 111
print(i)
else:
print("else:", i)
Cuando el cuerpo del ciclo no se ejecuta, la variable de control conserva el valor que
tenía antes del ciclo.
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:
Escenario
Escucha esta historia: Un niño y su padre, un programador de computadoras, juegan
con bloques de madera. Están construyendo una pirámide.
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.
Datos de prueba
Entrada de muestra: 6
Entrada de muestra: 2
altura=0
altura=altura+1
bloques=bloque-altura
LABORATORIO
Tiempo estimado
20 minutos
Nivel de dificultad
Media
Objetivos
Familiarizar al estudiante con:
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 .
Datos de prueba
Entrada de muestra: 15
Salida esperada:
46
23
70
35
106
53
160
80
40
20
10
16
pasos = 17
Entrada de muestra: 16
Salida esperada:
pasos = 4
Salida esperada:
3070
1535
4606
2303
6910
3455
10366
5183
15550
7775
23326
11663
34990
17495
52486
26243
78730
39365
118096
59048
29524
14762
7381
22144
11072
5536
2768
1384
692
346
173
520
260
130
65
196
98
49
148
74
37
112
56
28
14
22
11
34
17
52
26
13
40
20
10
16
pasos = 62
c0=int(input(“Ingresa un número)
if c0<1:
pasos=0
while c0 !=1:
if c0 % 2==0:
c0=c0//2
else:
c0=3*c0+1
print(c0)
pasos+=1
print(“pasos:”,pasos)
RESUMEN DE LA SECCIÓN
Puntos clave
El ciclo while ejecuta una sentencia o un conjunto de declaraciones siempre que una
condición booleana especificada sea verdadera, por ejemplo:
# Ejemplo 1
while True:
print("Atascado en un ciclo infinito")
# Ejemplo 2
contador = 5
while contador > 2:
print(contador)
contador -= 1
El ciclo 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
ciclo for para iterar sobre una secuencia de números usando la función
incorporada range . Mira los ejemplos a continuación:
# Ejemplo 1
palabra = "Python"
for letter in palabra:
print(letter, fin = "*")
# 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 ciclo:
Utiliza continue para omitir la iteración actual, y continuar con la siguiente iteración, por
ejemplo:
text = "pyxpyxpyx"
for letter in text:
if letter == "x":
continue
print(letter, end= "")
3. Los ciclos while y for también pueden tener una cláusula else en Python. La
cláusula else se ejecuta después de que el ciclo 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()
4. La función range() genera una secuencia de números. Acepta enteros y devuelve objetos de
rango. La sintaxis de range() tiene el siguiente aspecto: range(start, stop, step) ,
donde:
start es un parámetro opcional que especifica el número de inicio de la secuencia ( 0 por
defecto).
stop es un parámetro opcional que especifica el final de la secuencia generada (no está
incluido).
y step es un parámetro opcional que especifica la diferencia entre los números en la
secuencia es ( 1 por defecto).
Código de ejemplo:
for i in range(3):
print(i, end=" ") # salidas: 0 1 2
Crea un bucle for que cuente de 0 a 10, e imprima números impares en la pantalla. Usa el esqueleto
de abajo:
# línea de código
# línea de código
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
# line of code
# line of code
# line of code
Revisar
Solución de muestra:
x = 1
if x % 2 != 0:
print(x)
x += 1
Ejercicio 3
Crea un programa con un bucle for y una declaración 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 declaración 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:
# 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
n = 3
while n > 0:
print(n + 1)
n -= 1
else:
print(n)
Revisar
0
Ejercicio 6
n = range(4)
for num in n:
print(num - 1)
else:
print(num)
Revisar
-1
Ejercicio 7
print(i)
Revisar
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 esta oración:
La aparición de la palabra or (o) significa que la compra depende de al menos una de estas
condiciones. En lógica, este compuesto se llama una disyunción.
Está claro que Python debe tener operadores para construir conjunciones y disyunciones. Sin ellos, el
poder expresivo del lenguaje se debilitaría sustancialmente. Se llaman operadores lógicos.
and
Un operador de conjunción lógica en Python es la palabra y. Es un operador binario con una
prioridad inferior a la expresada por los operadores de comparación. Nos permite codificar
condiciones complejas sin el uso de paréntesis como este:
El resultado proporcionado por el operador and se puede determinar sobre la base de la tabla de
verdad.
Argumento A Argumento B A y B
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
not
Además, hay otro operador que se puede aplicar para condiciones de construcción. Es un operador
unario que realiza una negación lógica. Su funcionamiento es simple: convierte la verdad en falso
y lo falso en verdad.
Este operador se escribe como la palabra not , y su prioridad es muy alta: igual que el
unario + y - . Su tabla de verdad es simple:
False True
True False
Expresiones lógicas
Creemos una variable llamada var y asignémosle 1 . Las siguientes condiciones son equivalentes a
pares:
print(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
Operadores bitwise
Sin embargo, hay cuatro operadores que le permiten manipular bits de datos individuales. Se
denominan operadores bitwise.
Cubren todas las operaciones que mencionamos anteriormente en el contexto lógico, y un operador
adicional. Este es el operador xor (como en o exclusivo ), y se denota como ^ (signo de
intercalación).
0 1 1
0 1 1
1 1 0
Arg ~Arg
0 1
1 0
Los operadores bitwise 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:
og = 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 000000000000000000000000000 01111
j 000000000000000000000000000 10110
logneg = not i
La variable logneg se establecerá en False : no es necesario hacer nada más.
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 0000000000000000000000000000 1111
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
flagRegister = 0x1234
La variable almacena la información sobre varios aspectos de la operación del sistema. Cada bit de
la variable almacena un valor de si/no. También se te ha dicho que solo uno de estos bits es tuyo,
el tercero (recuerda que los bits se numeran desde cero y el número de bits cero es el más bajo,
mientras que el más alto es el número 31). Los bits restantes no pueden cambiar, porque están
destinados a almacenar otros datos. Aquí está tu bit marcado con la letra x :
flagRegister = 000000000000000000000000000000x000
x & 1 = x
x & 0 = 0
Si aplicas la operación & a la variable flagRegister junto con la siguiente imagen de bits:
00000000000000000000000000001000
(observa el 1 en la posición de tu bit) como resultado, obtendrás una de las siguientes cadenas de
bits:
Dicha secuencia de ceros y unos, cuya tarea es tomar el valor o cambiar los bits seleccionados, se
denomina máscara de bits.
Construyamos una máscara de bits para detectar el estado de tus bits. Debería apuntar a el tercer bit.
Ese bit tiene el peso de 23=8 . Se podría crear una máscara adecuada mediante la siguiente
declaración:
theMask = 8
También puedes hacer una secuencia de instrucciones dependiendo del estado de tu bit i, 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 theMask . Restablecer el bit es simple, y se ve así (elige el que más te guste):
3. Establece tu bit : asigna un 1 a tu bit, mientras que todos los bits restantes deben permanecer sin
cambios; usa la siguiente propiedad de disyunción:
x | 1 = 1
x | 0 = x
Ya estás listo para configurar su bit con una de las siguientes instrucciones:
flagRegister = flagRegister | theMask
flagRegister |= theMask
4. Niega tu bit: reemplaza un 1 con un 0 y un 0 con un 1 . Puedes utilizar una propiedad
interesante del operador ~x :
x ^ 1 = ~x
x ^ 0 = x
flagRegister ^= theMask
12345 × 10 = 123450
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
Nota:
Y aquí está la tabla de prioridades actualizada , que contiene todos los operadores
presentados hasta ahora:
Prioridad Operador
1 ! ~ (tipo) ++ -- + - unario
2 **
3 * / %
4 + - binario
5 << >>
6 <<=>> =
7 == !=
8 &
9 |
10 &&
11 ||
12 = += -= *= /= %= &= ^= |= >>= <<=
var = 17
RESUMEN DE LA SECCIÓN
Puntos clave
and → si ambos operandos son verdaderos, la condición es verdadera, por ejemplo, (True
and True) es True .
or → si alguno de los operandos es verdadero, la condición es verdadera, por
ejemplo, (True or False) es True .
not → devuelve False si el resultado es verdadero y devuelve True si es falso, por
ejemplo, not True es False .
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
x = 1
y = 0
False
Ejercicio 2
x = 4
y = 1
a = x & y
b = x | y
c = ~ x
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).
numeros = [ 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 declaración 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.
Listas de indexación
¿Cómo cambias el valor de un elemento elegido en la lista?
Vamos a asignar un nuevo valor de 111 al primer elemento en la lista. Lo hacemos
de esta manera:
numeros = [10, 5, 7, 2, 1]
numeros[0] = 111
numeros = [10, 5, 7, 2, 1]
numeros[0] = 111
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.
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]
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?
numeros = [10, 5, 7, 2, 1]
print("Contenido de la lista original:", numeros) # imprimiendo el contenido
de la lista original
Longitud de la lista: 5
del numeros[1]
print(len(numeros))
print(numeros)
print(numeros[4])
numeros[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.
print(numeros[-1])
Del mismo modo, el elemento con un índice igual a -2 es el anterior al último en la
lista.
print(numeros[-2])
El último elemento accesible en nuestra lista es numeros[-4] (el primero). ¡No
intentes ir más lejos!
LABORATORIO
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).
# Paso 2: escribe aquí una línea de código que elimine el último elemento
de la lista.
del listaSombrero[-1]
# Paso 3: escribe aquí una línea de código que imprima la longitud de la
lista existente.
print("\nLongitud de la lista:", len(listaSombrero))
print(listaSombrero)
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.
resultado = funcion(argumento)
resultado = 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.
lista.append(valor)
lista.insert(ubicación,valor)
numeros.insert(1,333)
numeros = [111, 7, 2, 1]
print(len(numeros))
print(numeros)
###
numeros.append(4)
print(len(numeros))
print(numeros)
###
numeros.insert(0,222)
print(len(numeros))
print(numeros)
for i in range(5):
miLista.insert(0, i + 1)
print(miLista)
¿Qué pasará ahora? Ejecuta el programa y comprueba si esta vez también tenías
razón.
print(miLista)
[1, 2, 3, 4, 5]
for i in range(5):
miLista.insert(0, i + 1)
print(miLista)
[5, 4, 3, 2, 1]
miLista = [10, 1, 8, 3, 5]
suma = 0
for i in miLista:
suma += i
print(suma)
Imagina que necesitas reorganizar los elementos de una lista, es decir, revertir el
orden de los elementos: el primero y el quinto, así como el segundo y cuarto
elementos serán intercambiados. El tercero permanecerá intacto.
variable1 = 1
variable2 = 2
variable2 = variable1
variable1 = variable2
variable1 = 1
variable2 = 2
auxiliar = variable1
variable1 = variable2
variable2 = auxiliar
Python ofrece una forma más conveniente de hacer el intercambio, echa un vistazo:
variable1 = 1
variable2 = 2
Listas en acción
Ahora puedes intercambiar fácilmente los elementos de la lista para revertir su
orden:
miLista = [10, 1, 8, 3, 5]
print(miLista)
[5, 3, 8, 1, 10]
¿Seguirá siendo aceptable con una lista que contenga 100 elementos? No, no lo hará.
miLista = [10, 1, 8, 3, 5]
longitud = len(miLista)
for i in range (longitud // 2):
miLista[i], miLista[longitud-i-1] = miLista[longitud-i-1],
miLista[i]
print(miLista)
Nota:
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.
Escribe un programa que refleje estos cambios y le permita practicar con el concepto
de listas. Tu tarea es:
# paso 1
beatles=[]
print("Paso 1:", beatles)
# paso 2
beatles.append("John Lennon")
beatles.append("Paul McCartney")
beatles.append("George Harrison")
print("Paso 2:", beatles)
# paso 3
for miembros in range(2):
beatles.append(input("Nuevo miembro de la banda:"))
print("Paso 3:", beatles)
# etapa 4
del beatles [-1]
del beatles [-1]
print("Paso 4:", beatles)
# paso 5
beatles.insert (0, "Ringo Starr")
print("Paso 5:", beatles)
RESUMEN DE LA SECCIÓN
Puntos clave
print (miLista) # salida: [1, '?', True, 'Soy una cadena', 256, 0]
miLista.append ("last")
miLista = [1, 2, 3, 4]
del miLista[2]
5.Las listas pueden ser iteradas mediante el uso del bucle for , por ejemplo:
print(color)
6. La función len() se puede usar para verificar la longitud de la lista, por ejemplo:
print(len(miLista)) # la salidas es 5
del miLista[2]
Ejercicio 1
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
lst = [1, 2, 3, 4, 5]
lst2 = []
agregar = 0
agregar += number
lst2.append (agregar)
print(lst2)
Revisar
Ejercicio 3
lst = []
del lst
print(lst)
Revisar
Ejercicio 4
print(lst[1])
print(len(lst))
Revisar
[2, 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 10 6 2 4
Ahora observa el segundo y el tercer elemento. Están en las posiciones equivocadas. Tenemos que
intercambiarlos:
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
6 2 8 4 10
Ahora el tercer y cuarto elementos, y la segunda pasada, se completa, ya que 8 ya está en su lugar:
6 2 4 8 10
2 6 4 8 10
2 4 6 8 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:
print(miLista)
[2, 4, 6, 8, 10]
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.
miLista.sort()
print(miLista)
Es tan simple como eso.
[2, 4, 6, 8, 10]
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.
miLista = []
swapped = True
num = int (input("¿Cuántos elementos deseas ordenar?:"))
for i in range(num):
val = float(input("Introduce un elemento de la lista:"))
miLista.append(val)
while swapped:
swapped = False
for i in range(len(miLista) - 1):
if miLista[i] > miLista[i + 1]:
swapped = True
miLista[i], miLista[i + 1] = miLista[i + 1], miLista[i]
print("\nOrdenado:")
print(miLista)
RESUMEN DE LA SECCIÓN
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 ()
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()
Ejercicio 1
lst.sort ()
print(lst)
Revisar
Ejercicio 2
a = 3
b = 1
c = 2
lst = [a, c, b]
lst.sort ()
print(lst)
Revisar
[1, 2, 3]
Ejercicio 3
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.
El programa:
Crea una lista de un elemento llamada lista1 .
La asigna a una nueva lista llamada lista2 .
Cambia el único elemento de lista1 .
Imprime la lista2 .
Lee estas dos líneas una vez más, la diferencia es esencial para comprender de que
vamos a hablar a continuación.
lista1 = [1]
lista2 = lista1
lista1[0] = 2
print(lista2)
[2]
Rodajas Poderosas
Afortunadamente, la solución está al alcance de su mano: su nombre es rodaja.
lista1 = [1]
lista2 = lista1[:]
lista1[0] = 2
print(lista2)
Esta parte no visible del código descrito como [:] puede producir una lista
completamente nueva.
miLista[inicio:fin]
Como puedes ver, se asemeja a la indexación, pero los dos puntos en el interior hacen
una gran diferencia.
Una rodaja 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).
miLista = [10, 8, 6, 4, 2]
print(nuevaLista)
La lista nuevaLista contendrá inicio-fin (3-1=2) elementos, los que tienen índices
iguales a 1 y 2 (pero no 3 )
miLista[inicio:fin]
Para repetir:
miLista = [10, 8, 6, 4, 2]
nuevaLista = miLista [1:-1]
print(nuevaLista)
miLista = [10, 8, 6, 4, 2]
nuevaLista = miLista [-1:1]
print(nuevaLista)
Rodajas: continuación
Si omites inicio en tu rodaja, se supone que deseas obtener un segmento que
comienza en el elemento con índice 0 .
miLista[:fin]
miLista = [10, 8, 6, 4, 2]
print(nuevaLista)
Del mismo modo, si omites el fin en tu rodaja, se supone que deseas que el
segmento termine en el elemento con el índice len(miLista) .
miLista[inicio:]
miLista[inicio:len(miLista)]
miLista = [10, 8, 6, 4, 2]
nuevaLista = miLista[3:]
print(nuevaLista)
Rodajas: continuación
Como hemos dicho antes, el omitir inicio y fin hace una copia de toda la lista:
miLista = [10, 8, 6, 4, 2]
print(nuevLista)
miLista = [10, 8, 6, 4, 2]
del miLista[1:3]
print(miLista)
miLista = [10, 8, 6, 4, 2]
del miLista[:]
print(miLista)
Echa un vistazo:
miLista = [10, 8, 6, 4, 2]
del miLista
print(miLista)
La función print() de la última línea del código provocará un error de ejecución.
Los operadores in y not
Python ofrece dos operadores muy poderosos, capaces de revisar la lista para
verificar si un valor específico está almacenado dentro de la lista o no.
elem in miLista
print(5 in miLista)
print(5 not in miLista)
print(12 in miLista)
False
True
True
for i in miLista:
if i > mayor:
mayor = i
print(mayor)
if i > mayor:
mayor = i
print(mayor)
La pregunta es: ¿Cuál de estas dos acciones consume más recursos informáticos: solo
una comparación o partir casi todos los elementos de una lista?
for i in range(len(miLista)):
Encontrado = miLista[i] == Encontrar
if Encontrado:
break
if Encontrado:
print("Elemento encontrado en el índice", i)
else:
print("ausente")
Nota:
print(aciertos)
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.
miLista = [1, 2, 4, 4, 1, 4, 2, 6, 2, 9]
#
# coloca tu código aquí
nuevalista = miLista[2:9]
for i in miLista:
if i in nuevalista:
del miLista[i]
print(miLista)
RESUMEN DE LA SECCIÓN
Puntos clave
1. Si tienes una lista l1 , la siguiente asignación: l2 = l1 no hace una copia de la lista l1 , pero
hace que las variables l1 y l2 apunten a la misma lista en la memoria . Por ejemplo:
vehiculosDos = vehiculosUno
2. Si deseas copiar una lista o parte de la lista, puede hacerlo haciendo uso de rodajas(slicing):
nuevaLista = listaMuestra[2:-1]
miLista = [1, 2, 3, 4, 5]
miLista = [1, 2, 3, 4, 5]
del miLista[:]
Ejercicio 1
l2 = l1
l3 = l2
del l1[0]
del l2[0]
print(l3)
Revisar
['C']
Ejercicio 2
l2 = l1
l3 = l2
del l1[0]
del l2
print(l3)
Revisar
['B', 'C']
Ejercicio 3
l2 = l1
l3 = l2
del l1[0]
del l2[:]
print(l3)
Revisar
[]
Ejercicio 4
l2 = l1[:]
l3 = l2[:]
del l1[0]
del l2[0]
print(l3)
Revisar
['A', 'B', 'C']
Ejercicio 5
Inserte in o not in en lugar de ??? para que el código genere el resultado esperado.
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.
fila = []
for i in range(8):
row.append(PEON_BLANCO)
Crea una lista que contiene ocho elementos que representan la segunda fila del
tablero de ajedrez: la que está llena de peones (supon que PEON_BLANCO es
un símbolo predefinido que representa un peón blanco).
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.
El fragmento de código genera una lista de diez elementos y rellena con cuadrados de
diez números enteros que comienzan desde cero (0, 1, 4, 9, 16, 25, 36, 49, 64, 81)
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 hace una lista con solo los elementos impares de la lista cuadrados .
Entonces, si queremos crear una lista de listas que representan todo el tablero de
ajedrez, se puede hacer de la siguiente manera:
tablero = []
for i in range(8):
fila = [EMPTY for i in range(8)]
tablero.append(fila)
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 tablero .
La parte exterior se repite ocho veces.
En total, la lista tablero 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.
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:
Echando un vistazo a la figura que se muestra arriba, coloquemos algunas piezas de
ajedrez en el tablero. Primero, agreguemos todas las torres:
tablero[0][0] = TORRE
tablero[0][7] = TORRE
tablero[7][0] = TORRE
tablero[7][7] = TORRE
tablero[4][2] = CABALLO
EMPTY = "-"
TORRE = "TORRE"
tablero = []
for i in range(8):
tablero.append (fila)
tablero[0][0] = TORRE
tablero[0][7] = TORRE
tablero[7][0] = TORRE
tablero[7][7] = TORRE
print(tablero)
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):
Toda la matriz está llena de ceros ahora. Puede suponer que se actualiza
automáticamente utilizando agentes de hardware especiales. Lo que tienes que hacer
es esperar a que la matriz se llene con las mediciones.
suma = 0.0
promedio= suma / 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.
Nota:
hotDays = 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 ).
El primer índice ( 0 a 2 ) selecciona uno de los edificios; el segundo( 0 a 14 ) selecciona el
piso, el tercero ( 0 a 19 ) selecciona el número de habitación. Todas las habitaciones
están inicialmente desocupadas.
Ahora ya puedes reservar una habitación para dos recién casados: en el segundo
edificio, en el décimo piso, habitación 14:
habitaciones[1][9][13] = True
habitaciones[0][4][1] = False
vacante = 0
if not habitaciones[2][14][numeroHabitacion]:
vacante += 1
La variable vacante 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!
RESUMEN DE LA SECCIÓN
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 lista de comprensión es la siguiente:
if condicional:
expresión
Este es un ejemplo de una lista de comprensión: 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:
print(tabla)
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:
print(cubo)
4.1.1.2 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, las cuales también son funciones, pero declarados de
una manera muy especifica.
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.
Esta descomposición continua hasta que se obtiene un conjunto de funciones cortas, fáciles de
comprender y probar.
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.
Este tipo de descomposición tiene diferentes propósitos, no solo se trata de compartir el trabajo,
sino también de compartir la responsabilidad entre varios desarrolladores.
Cada uno debe escribir un conjunto bien definido y claro de funciones, las cuales al ser combinadas
dentro de un módulo (esto se clarificara un poco mas 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 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.
Tu primer función
Observa el fragmento de código en el editor.
El mensaje enviado a la consola por la función print() es siempre el mismo. El código
es funcional y no contiene errores, sin embargo imagina tendrías que hacer si tu jefe
pidiera cambiar el mensaje para que fuese mas cortés, por ejemplo, que comience con
la frase "Por favor," .
Tendrías que tomar algo de tiempo para cambiar el mensaje en todos los lugares
donde aparece (podrías hacer uso de copiar y pegar, pero eso no lo haría mas
sencillo). Es muy probable que cometas errores durante el proceso de corrección, eso
traería frustración a ti y a tu jefe.
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 nombreFuncion():
cuerpoFuncion
def mensaje():
print("Ingresa un valor: ")
def mensaje():
print("Ingresa un valor: ")
Se comienza aquí.
Se termina aquí.
def mensaje():
print("Ingresa un valor: ")
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.
Recuerda: Python lee el código de arriba hacia abajo. No va a adelantarse en el código para
determinar si la función invocada esta definida mas adelante, el lugar correcto para definirla es antes
de ser invocada.
def mensaje():
print("Ingresa un valor: ")
Se ha movido la función al final del código. ¿Podrá Python encontrarla cuando la ejecución llegue a
la invocación?
No intentes forzar a Python a encontrar funciones que no están definidas en el lugar correcto.
def mensaje():
print("Ingresa un valor: ")
mensaje = 1
El asignar un valor al nombre "mensaje" causa que Python olvide su rol anterior. La función con el
nombre de mensaje ya no estará disponible.
def mensaje():
print("Ingresa un valor: ")
mensaje()
def mensaje():
print("Ingresa un valor: ")
mensaje()
a = int(input())
mensaje()
b = int(input())
mensaje()
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.
RESUMEN DE SECCIÓ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:
hola()
def hola():
print("hola!")
Revisar
Ejercicio 3
def hola():
print("hola")
hola(5)
Revisar
Se genera una excepción (la excepción TypeError ) - la función hola() no toma argumentos.
Un parámetro es una variable, pero existen dos factores que hacen a un parámetro diferente:
Los parámetros solo existen dentro de las funciones en donde han sido definidos, y el
único lugar donde un parámetro puede ser definido es entre los paréntesis después del
nombre de la función, donde se encuentra la palabra 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 funcion(parametro):
###
Recuerda que:
Se tendrá que modificar la definición def de la función, así es como se ve ahora:
def mensaje(numero):
###
Esta definición especifica que nuestra función opera con un solo parámetro con el nombre
de numero . Se puede utilizar como una variable normal, pero solo dentro de la función - no es
visible en otro lugar.
def mensaje(numero):
print("Ingresa el número:", numero)
Se ha hecho buen uso del parámetro. Nota: No se le ha asignado al parámetro algún valor. ¿Es
correcto?
Si, lo es.
Esto significa que se esta invocando la función pero esta faltando el argumento.
def mensaje(numero):
print("Ingresa un número:", numero)
mensaje(1)
Ingresa un número: 1
¿Puedes ver como 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 numero .
def mensaje(numero):
print("Ingresa un número:", numero)
numero = 1234
mensaje(1)
print(numero)
Ingresa un número: 1
1234
Una función puede tener tantos parámetros como se desee, pero entre más
parámetros, es más difícil memorizar su rol y propósito.
Aquí esta:
def mensaje(que, numero):
print("Ingresa", que, "número", numero)
mensaje("teléfono", 11)
mensaje("precio", 5)
mensaje("número", "número")
Ejecuta el código, modifícalo, agrega mas parámetros y ve como esto afecta la salida.
print(a, b, c)
miFuncion(1, 2, 3)
presentar("Jesse", "Quick")
presentar("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:
presentar("Skywalker" ,"Luke" )
presentar("Quick", "Jesse")
presentar("Kent", "Clark")
introduction(apellido="Skywalker", primerNombre="Luke")
Inténtalo tu mismo.
1 + 2 + 3 = 6
También, se puede reemplazar la invocación actual por una con palabras clave, como
la siguiente:
suma(c = 1, a = 2, b = 3)
2 + 3 + 1 = 6
suma(3, c = 1, b = 2)
Vamos a analizarla:
3 + 2 + 1 = 6
suma(4, 3, c = 2)
Todo es correcto, pero el dejar solo un argumento con palabras 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.
presentar("Jorge", "Pérez")
¿Y? No parece haber cambiado algo, pero cuando se invoca la función de una manera
inusual, como esta:
presentar("Enrique")
o así:
presentar (primerNombre="Guillermo")
Pruébalo.
Puedes hacerlo con mas parámetros, si te resulta útil. Ambos parámetros tendrán sus
valores por default, observa el siguiente código:
presentar ()
presentar(segundoNombre="Rodríguez")
La salida es:
Pruébalo.
Felicidades, has aprendido las maneras básicas de comunicación con funciones.
RESUMEN DE SECCIÓN
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 hola(nombre):
print("Hola,", nombre)
hola("Greg")
holaTodos("Sebastián", "Felipe")
c = input("Calle: ")
cp = input("Código Postal: ")
cd = input("Ciudad: ")
resta(5, 2) # salida: 3
resta(2, 5) # salida: -3
Ejemplo 2
def resta(a, b):
print(a - b)
Ex. 3
def resta(a, b):
print(a - b)
3. Se puede utilizar la técnica de argumentos con palabras clave para asignar valores predefinidos a
los argumentos:
intro()
Revisar
Ejercicio 2
intro(b="Sergio López")
Revisar
Ejercicio 3
intro("Susan")
Revisar
Ejercicio 4
suma(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 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.
print("Tres ...")
print("Dos ...")
print("Uno ...")
if not deseos:
return
felizAñoNuevo()
Tres ...
Dos...
Uno...
felizAñoNuevo(False)
Tres ...
Dos...
Uno ...
funcion():
return expresión
def funcion_aburrida():
return 123
x = funcion_aburrida()
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.
def funcion_aburrida():
return 123
funcion_aburrida()
No olvides:
Espera un segundo, ¿Significa esto que también hay resultados inútiles? Sí, en cierto sentido.
Solo hay dos tipos de circunstancias en las que None se puede usar de manera segura:
valor = None
if valor == None:
print("Lo siento, no tienes 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(strangeFunction(2))
print(strangeFunction(1))
True
None
El primero es: ¿Se puede enviar una lista a una función como un argumento?
¡Por supuesto que se puede! Cualquier entidad reconocible por Python puede
desempeñar el papel de un argumento de función, aunque debes asegurarte de que la
función sea capaz de hacer uso de él.
Entonces, si pasas una lista a una función, la función tiene que manejarla como una
lista.
def sumaDeLista(lst):
sum = 0
sum += elem
return sum
y se invoca así:
print(sumaDeLista([5, 4, 3]))
print(sumaDeLista(5))
Esto se debe al hecho de que el bucle for no puede iterar un solo valor entero.
¡Si, por supuesto! Cualquier entidad reconocible por Python puede ser un resultado de
función.
[4, 3, 2, 1, 0]
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.
LABORATORIO
Tiempo estimado
10-15 minutos
Nivel de dificultad
Fácil
Objetivos
Familiarizar al estudiante con:
Escenario
Tu tarea es escribir y probar una función que toma un argumento (un año) y
devuelve True si el año es un año bisiesto, o False sí no lo es.
Parte del esqueleto de la función ya está en el editor.
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 isYearLeap(year):
#
# coloca tu código aquí
#
1900 ->OK
2000 ->OK
2016 ->OK
1987 ->OK
LABORATORIO
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.
Por supuesto, puedes (y debes) utilizar la función previamente escrita y probada (LAB
4.1.3.6). Puede ser muy útil. Te recomendamos que utilices una lista con los meses.
Puedea crearla dentro de la función; este truco acortará significativamente el código.
Hemos preparado un código de prueba. Amplíalo para incluir más casos de prueba.
def isYearLeap(year):
#
# tu código del laboratorio anterior
#
def isYearLeap(year):
if year % 4 != 0:
return False
elif year % 100 != 0:
return True
elif year % 400 != 0:
return False
else:
return True
def daysInMonth(year,month):
if year < 1582 or month < 1 or month > 12:
return None
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
res = days[month - 1]
if month == 2 and isYearLeap(year):
res = 29
return res
LABORATORIO
Tiempo estimado
20-30 minutos
Nivel de dificultad
Medio
Requisitos previos
LAB 4.1.3.6
LAB 4.1.3.7
Objetivos
Familiarizar al estudiante con:
Debes utilizar las funciones previamente escritas y probadas. Agrega algunos casos de
prueba al código. Esta prueba es solo el comienzo.
def isYearLeap(year):
#
# tu código del LAB 4.1.3.6
#
def isYearLeap(year):
if year % 4 != 0:
return False
elif year % 100 != 0:
return True
elif year % 400 != 0:
return False
else:
return True
def daysInMonth(year,month):
if year < 1582 or month < 1 or month > 12:
return None
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
res = days[month - 1]
if month == 2 and isYearLeap(year):
res = 29
return res
LABORATORIO
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 usar funciones.
Escenario
Un número natural es primo si es mayor que 1 y no tiene divisores más que 1 y si mismo.
La función:
Se llama isPrime .
Toma un argumento (el valor a verificar).
Devuelve True si el argumento es un número primo, y False de lo contrario.
Datos de prueba
Salida esperada:
2 3 5 7 11 13 17 19
def isPrime(num):
#
# coloca tu código aquí
#
def isPrime(num):
divisor = 2
while divisor < num:
if num % divisor == 0:
return False
divisor += 1
return True
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.
Las funciones:
Datos de prueba
Salida esperada:
60.31143162393162
31.36194444444444
23.52145833333333
3.9007393587617467
7.490910297239916
10.009131205673757
def l100kmtompg(liters):
#
# coloca tu código aqui
#
def mpgtol100km(miles):
#
# coloca tu código aqui
#
print(l100kmtompg(3.9))
print(l100kmtompg(7.5))
print(l100kmtompg(10.))
print(mpgtol100km(60.3))
print(mpgtol100km(31.4))
print(mpgtol100km(23.5))
def l100kmtompg(litros):
galones = litros / 3.785411784
millas = 100 * 1000 / 1609.344
return millas / galones
def mpgtol100km(millas):
km100 = millas * 1609.344 / 1000 / 100
litros = 3.785411784
return litros / km100
print(l100kmtompg(3.9))
print(l100kmtompg(7.5))
print(l100kmtompg(10.))
print(mpgtol100km(60.3))
print(mpgtol100km(31.4))
print(mpgtol100km(23.5))
RESUMEN DE LA SECCIÓN
Puntos clave
1. Puedes emplear la palabra clave return para decirle a una función que devuelva algún valor. La
instrucción return termina la función, por ejemplo:
return a * b
return
2. El resultado de una función se puede asignar fácilmente a una variable, por ejemplo:
def deseos():
d = deseos()
print(d) # salida: ¡Felíz Cumpleaños!
# Ejemplo 1
def deseos():
print("Mis deseos")
# Ejemplo 2
def deseos():
print("Mis Deseos")
# ¡Feliz Cumpleaños!
3. Puedes usar una lista como argumento de una función, por ejemplo:
def HolaaTodos(myList):
print("Hola,", nombre)
def createList(n):
myList = []
for i in range(n):
myList.append(i)
return myList
print(createList(5))
Ejercicio 1
def hola():
return
print("¡Hola!")
hola()
Revisar
Ejercicio 2
def isInt(data):
if type(data) == int:
return True
return False
print(isInt(5))
print(isInt(5.0))
print(isInt("5"))
Revisar
True
False
None
Ejercicio 3
def evenNumLst(ran):
lst = []
if num % 2 == 0:
lst.append(num)
return lst
print(evenNumLst(11))
Revisar
[0, 2, 4, 6, 8, 10]
Ejercicio 4
def listUpdater(lst):
updList = []
elem **= 2
updList.append(elem)
return updList
l = [1, 2, 3, 4, 5]
print(listUpdater(l))
Revisar
Vamos a conducir algunos experimentos para mostrar como es que Python define los
alcances y como los puedes utilizar para tu beneficio.
def scopeTest():
x = 123
scopeTest()
print(x)
def miFuncion():
var = 1
miFuncion()
print(var)
¿Conozco a la variable? 1
1
La respuesta es: una variable que existe fuera de una función tiene alcance
dentro del cuerpo de la función.
def miFuncion():
var = 2
print("¿Conozco a la variable?", var)
var = 1
miFuncion()
print(var)
El resultado ha cambiado tambiénm el código arroja una salida con una ligera
diferencia:
¿Conozco a la variable? 2
1
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.
global name
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.
def miFuncion():
global var
var = 2
var = 1
miFuncion()
print(var)
El código en editor nos enseña algo. Como puedes observar, la función cambia el valor
de su parámetro. ¿Este cambio afecta el argumento?
def miFuncion(n):
print("Yo obtuve", n)
n += 1
var = 1
miFuncion(var)
print(var)
Yo obtuve 1
Yo ahora tengo 2
1
La conclusión es obvia - al cambiar el valor del parámetro este no se propaga fuera
de la función (más específicamente, no cuando la variable es un valor escalar, como
en el ejemplo).
Esto también significa que una función recibe el valor del argumento, no el
argumento en sí. Esto es cierto para los valores escalares.
Vale la pena revisar cómo funciona esto con las listas (¿Recuerdas las peculiaridades
de asignar rodajas de listas en lugar de asignar la lista entera?)
def miFuncion(miLista1):
print(miLista1)
miLista1 = [0, 1]
miLista2 = [2, 3]
miFuncion(miLista2)
print(miLista2)
[2, 3]
[2, 3]
def miFuncion(miLista1):
print(miLista1)
del miLista1[0]
miLista2 = [2, 3]
miFuncion(miLista2)
print(miLista2)
[2, 3]
[3]
Intentémoslo:
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 multByVar(x):
return x * var
print(multByVar(7)) # salida: 14
Ejemplo 2:
def mult(x):
var = 5
return x * var
print(mult(7)) # salida: 35
Ejemplo 3:
def multip(x):
var = 7
return x * var
var = 3
print(multip(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 sum(x):
var = 7
return x + var
print(sum(4)) # salida: 11
print(var) # NameError
3. Se puede emplear la palabra 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 retVar():
global var
var = 5
return var
print(retVar()) # 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
Ejercicio 3
a = 1
def fun():
global a
a = 2
print(a)
fun()
a = 3
print(a)
Revisar
Ejercicio 4
a = 1
def fun():
global a
a = 2
print(a)
a = 3
fun()
print(a)
Revisar
Codifiquemos la función.
La función esta completa aquí abajo (y en la ventana de editor):
print(imc(52.5, 1.65))
19.283746556473833
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.
Vamos a comprobar ambos y regresar None si cualquiera de los dos es incorrecto.
return None
print(imc(352.5, 1.65))
Primero, se asegura que los datos que sean ingresados sean correctos, de lo contrario
la salida será:
None
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.
def lbakg(lb):
return lb * 0.45359237
print(lbakg(1))
0.45359237
Haremos lo mismo ahora con los pies y pulgadas: 1 pie = 0.3048 m , y 1 pulgada =
2.54 cm = 0.0254 m .
print(piepulgam(1, 1))
0.3302
Resulta como esperado.
print(piespulgam(6, 0))
Esta es la salida:
1.8288000000000002
Es muy posible que en ocasiones se desee utilizar solo pies sin pulgadas. ¿Python nos
ayudará? Por supuesto que si.
print(piepulgam(6))
1.8288000000000002
def lbsakg(lb):
return lb * 0.45359237
def imc(peso, altura):
return None
La respuesta es:
27.565214082533313
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, esUnTringulo es un buen nombre para dicha función.
if a + b <= c:
return False
if b + c <= a:
return False
if c + a <= b:
return False
return True
True
False
if a + b <= c or b + c <= a or \
c + a <= b:
return False
return True
print(esUnTriangulo(1, 1, 1))
print(esUnTriangulo(1, 1, 3))
if esUnTriangulo(a, b, c):
else:
c2 = a2 + b2
return False
if c > a and c > b:
return c ** 2 == a ** 2 + b ** 2
return a ** 2 == b ** 2 + c ** 2
print(esUnTrianguloRectangulo(5, 3, 4))
print(esUnTrianguloRectangulo(1, 3, 4))
Observa como se establece la relación entre la hipotenusa y los dos catetos. Se eligió
el lado mas largo y se aplico el Teorema de Pitágoras para verificar que todo
estuviese en orden. Esto requiere tres revisiones en total.
p = (a + b + c) / 2
return None
return heron(a, b, c)
0.49999999999999983
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
Escribamos el código. Creemos una función con el nombre factorialFun . Aquí esta el
código:
def factorialFun(n):
if n < 0:
return None
if n < 2:
return 1
producto = 1
producto *= i
return producto
1 1
2 2
3 6
4 24
5 120
fib1 = 1
fib2 = 1
fib3 = 1 + 1 = 2
fib4 = 1 + 2 = 3
fib5 = 2 + 3 = 5
fib6 = 3 + 5 = 8
fib7 = 5 + 8 = 13
def fib(n):
if n < 1:
return None
if n < 3:
return 1
elem1 = elem2 = 1
sum = 0
for i in range(3, n + 1):
sum = elem1 + elem2
elem1, elem2 = elem2, sum
return sum
Analiza el codigo del bucle for cuidadosamente, descifra como se mueven las
variables elem1 y elem2 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
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 ith 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
mas corto y claro.
def fib(n):
if n < 1:
return None
if n < 3:
return 1
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
Aquí esta:
def factorialFun(n):
if n < 0:
return None
if n < 2:
return 1
return n * factorialFun(n - 1)
RESUMEN DE SECCIÓN
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.
Al emplear la recursividad, se deben de tomar en cuenta tanto sus ventajas como desventajas.
def factorial(n):
if n == 1: # la 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
Debido a que el bucle for es una herramienta especialmente diseñada para iterar a través de las
secuencias, podemos definirlas de la siguiente manera: una secuencia es un tipo de dato que puede
ser escaneado por el bucle for .
Hasta ahora, has trabajado con una secuencia en Python, la lista. La lista es un clásico ejemplo de
una secuencia de Python. Aunque existen otras secuencias dignas de mencionar, las cuales se
presentaran a continuación.
La segunda noción - la mutabilidad - es una propiedad de cualquier tipo de dato en Python que
describe su disponibilidad para poder cambiar libremente durante la ejecución de un programa.
Existen dos tipos de datos en Python: mutables e inmutables.
Los datos mutables pueden ser actualizados libremente en cualquier momento, a esta operación
se le denomina "in situ".
In situ es una expresión en Latín que se traduce literalmente como en posición, en el lugar o
momento. Por ejemplo, la siguiente instrucción modifica los datos "in situ":
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
mas 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:
tupla1 = (1, 2, 4, 8)
print(tupla1)
print(tupla2)
(1, 2, 4, 8)
Nota: cada elemento de una tupla puede ser de distinto tipo (punto flotante, entero, cadena, etc.).
tuplaVacia = ()
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:
tuplaUnElemento1 = (1, )
tuplaUnElemento2 = 1.,
El quitar las comas no arruinará el programa en el sentido sintáctico, pero serán variables no tuplas.
print(miTupla[0])
print(miTupla[-1])
print(miTupla[1:])
print(miTupla[:-2])
print(elem)
1000
(1, 10)
10
100
1000
miTupla.append(10000)
del miTupla[0]
miTupla[1] = -10
t2 = miTupla * 3
print(len(t2))
print(t1)
print(t2)
print(10 in miTupla)
La salida es la siguiente:
9
(1, 10, 100, 1000, 10000)
(1, 10, 100, 1, 10, 100, 1, 10, 100)
True
True
Una de las propiedades de las tuplas mas ú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.
Observa el siguiente fragmento de código:
var = 123
t1 = (1, )
t2 = (2, )
t3 = (3, var)
¿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.
Para explicar lo que es un diccionario en Python, es importante comprender de manera literal lo que
es un diccionario.
Un diccionario en Python funciona de la misma manera que un diccionario bilingüe. Por ejemplo,
se tiene la palabra en español "gato" y se necesita su equivalente en francés. Lo que se haría es
buscar en el diccionario para encontrar la palabra "gato". Eventualmente la encontrarás, y sabrás que
la palabra equivalente en francés es "chat".
En el mundo de Python, la palabra que se esta buscando se denomina clave(key) . La palabra que
se obtiene del diccionario es denominada valor .
diccionarioVacio = {}
print(dict)
print(numerosTelefono)
print(diccionarioVacio)
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.
El diccionario entero se puede imprimir con una invocación a la función print() . El fragmento de
código puede producir la siguiente salida:
{}
¿Has notado que el orden de los pares impresos es diferente a la asignación inicial?, ¿Qué significa
esto?
Primeramente, recordemos que los diccionarios no son listas - no guardan el orden de sus datos, el
orden no tiene significado (a diferencia de los diccionarios reales). El orden en que un
diccionario almacena sus datos esta fuera de nuestro control. Esto es normal. (*)
NOTA
print(dict['gato'])
print(numerosTelefono['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' .
diccionarioVacio = {}
print(dict['gato'])
print(numerosTelefono['Suzy'])
chat
22657854310
Ahora algo muy importante: No se puede utilizar una clave que no exista. Hacer
algo como lo siguiente:
print(numerosTelefono['presidente'])
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 .
print(french)
cheval
chien
chat
Observa:
dict['gato'] = 'minou'
print(dict)
La salida es:
Nota: este es un comportamiento muy diferente comparado a las listas, las cuales no
permiten asignar valores a índices no existentes.
dict['cisne'] = 'cygne'
print(dict)
EXTRA
dict.update({"pato" : "canard"})
print(dict)
Eliminado claves
¿Puedes deducir como eliminar una clave de un diccionario?
del dict['perro']
print(dict)
EXTRA
dict.popitem()
while True:
if nombre == 'exit':
break
if nombre in grupo:
grupo[nombre] += (calif,)
else:
grupo[nombre] = (calif,)
sum = 0
contador = 0
sum += calif
contador += 1
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.
Línea 5-6: si el nombre es exit , nos salimos del bucle.
Línea 8: se pide la calificación del alumno (un valor entero en el rango del 1-
10).
Línea 10-11: 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 12-13: 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 15: se itera a través de los nombres ordenados de los estudiantes.
Línea 16-17: inicializa los datos necesarios para calcular el promedio (sumador
y contador).
Línea 18-20: Se itera a través de la tupla, tomado todas las calificaciones
subsecuentes y actualizando la suma junto con el contador.
Línea 21: se calcula e imprime el promedio del alumno junto con su nombre.
Bob : 6.0
RESUMEN SECCIÓN
1. Las Tuplas son colecciones de datos ordenadas e inmutables. Se puede pensar en ellas como listas
inmutables. Se definen con paréntesis:
miTupla = (1, 2, True, "una cadena", (3, 4), [5, 6], None)
print(miTupla)
miLista = [1, 2, True, "una cadena", (3, 4), [5, 6], None]
print(miLista)
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).
tuplaVacia = ()
miTup1 = 1,
miTup2 = 1
5. Las tuplas son inmutables, lo que significa que no se puede agregar, modificar, cambiar o quitar
elementos. El siguiente fragmento de código provocará una excepción:
miTupla = 1, 2, 3,
del miTupla
# Ejemplo 1
t1 = (1, 2, 3)
print(elem)
# Ejemplo 2
t2 = (1, 2, 3, 4)
print(5 in t2)
# Ejemplo 3
t3 = (1, 2, 3, 5)
print(len(t3))
# Ejemplo 4
t4 = t1 + t2
t5 = t3 * 2
print(t4)
print(t5)
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:
print(miTup)
lst = [2, 4, 6]
tup = tuple(lst)
De la misma manera, cuando se desea convertir un iterable en una liste, se puede emplear la función
integrada de Python denominada list() :
tup = 1, 2, 3,
lst = list(tup)
Cada diccionario es un par de clave : valor. Se puede crear empleado la siguiente sintaxis:
miDictionario = {
clave1 : valor1,
clave2 : valor2,
clave3 : valor3,
2. Si se desea acceder a un elemento del diccionario, se puede hacer haciendo referencia a su clave
colocándola dentro de corchetes (ejemplo 1) o utilizando el método get() (ejemplo 2):
polEspDict = {
"kwiat" : "flor",
"woda" : "agua",
"gleba" : "tierra"
}
elemento1 = polEspDict["gleba"] # ejemplo 1
elemento2 = polEspDict.get("woda")
3. Si se desea cambiar el valor asociado a una clave especifica, se puede hacer haciendo referencia a
la clave del elemento, a continuación se muestra un ejemplo:
polEspDict = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
polEspDict["zamek"] = "cerradura"
4. Para agregar o eliminar una clave (junto con su valor asociado), emplea la siguiente sintaxis:
print(miDirectorioTelefonico) # salida: {}
polEspDict.popitem()
5. Se puede emplear el bucle for para iterar a través del diccionario, por ejemplo:
polEspDict = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
# woda
# gleba
6. Si deseas examinar los elementos (claves y valores) del diccionario, puedes emplear el
método items() por ejemplo:
polEspDict = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
polEspDict = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
if "zamek" in polEspDict:
print("SI")
else:
print("NO")
8. Se puede emplear la palabra reservada del para eliminar un elemento, o un diccionario entero.
Para eliminar todos los elementos de un diccionario se debe emplear el método clear() :
polEspDict = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
print(len(polEspDict)) # salida: 3
print(len(polEspDict)) # salida: 2
print(len(polEspDict)) # salida: 0
polEspDict = {
"zamek" : "castillo",
"woda" : "agua",
"gleba" : "tierra"
copyDict = polEspDict.copy()
Ejercicio 1
miTup = (1, 2, 3)
print(miTup[2])
Revisar
Ejercicio 2
tup = 1, 2, 3
a, b, c = tup
print(a * b * c)
Revisar
El programa imprimirá 6 en pantalla. Los elementos de la tupla tup han sido "desempaquetados"
en las variables a , b , y c .
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
duplicados = # tu código
print(duplicados) # salida: 4
Revisar
tup = 1, 2, 3, 2, 4, 5, 6, 2, 7, 2, 8, 9
duplicates = tup.count(2)
print(duplicado) # salida: 4
Ejercicio 4
Escribe un programa que "una" los dos diccionarios ( d1 y d2 ) para crear uno nuevo ( d3 ).
d3 = {}
# tu código
print(d3)
Revisar
Solución Muestra:
d1 = {'Adam Smith':'A', 'Judy Paxton':'B+'}
d3 = {}
for elemento in (d1, d2):
d3.update(elemento)
print(d3)
Ejercicio 5
t = # tu código
print(t)
Revisar
Solución muestra:
l = ["carro", "Ford", "flor", "Tulipán"]
t = tuple(l)
print(t)
Ejercicio 6
# tu código
print(colDict)
Revisar
Solución Muestra:
colores = (("verde", "#008000"), ("azul", "#0000FF"))
colDict = dict(colores)
print(colDict)
Ejercicio 7
copyMiDict = myDict.copy()
miDict.clear()
print(copyMiDict)
Revisar
Ejercicio 8
colores = {
Revisar
rojo : (255, 0, 0)
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:
+-------+-------+-------+
| | | |
| 1 | 2 | 3 |
| | | |
+-------+-------+-------+
| | | |
| 4 | X | 6 |
| | | |
+-------+-------+-------+
| | | |
| 7 | 8 | 9 |
| | | |
+-------+-------+-------+
Ingresa tu movimiento: 1
+-------+-------+-------+
| | | |
| O | 2 | 3 |
| | | |
+-------+-------+-------+
| | | |
| 4 | X | 6 |
| | | |
+-------+-------+-------+
| | | |
| 7 | 8 | 9 |
| | | |
+-------+-------+-------+
+-------+-------+-------+
| | | |
| O | X | 3 |
| | | |
+-------+-------+-------+
| | | |
| 4 | X | 6 |
| | | |
+-------+-------+-------+
| | | |
| 7 | 8 | 9 |
| | | |
+-------+-------+-------+
Ingresa tu movimiento: 8
+-------+-------+-------+
| | | |
| O | X | 3 |
| | | |
+-------+-------+-------+
| | | |
| 4 | X | 6 |
| | | |
+-------+-------+-------+
| | | |
| 7 | O | 9 |
| | | |
+-------+-------+-------+
+-------+-------+-------+
| | | |
| O | X | 3 |
| | | |
+-------+-------+-------+
| | | |
| 4 | X | X |
| | | |
+-------+-------+-------+
| | | |
| 7 | O | 9 |
| | | |
+-------+-------+-------+
Ingresa tu movimiento: 4
+-------+-------+-------+
| | | |
| O | X | 3 |
| | | |
+-------+-------+-------+
| | | |
| O | X | X |
| | | |
+-------+-------+-------+
| | | |
| 7 | O | 9 |
| | | |
+-------+-------+-------+
+-------+-------+-------+
| | | |
| O | X | X |
| | | |
+-------+-------+-------+
| | | |
| O | X | X |
| | | |
+-------+-------+-------+
| | | |
| 7 | O | 9 |
| | | |
+-------+-------+-------+
Ingresa tu movimiento: 7
+-------+-------+-------+
| | | |
| O | X | X |
| | | |
+-------+-------+-------+
| | | |
| O | X | X |
| | | |
+-------+-------+-------+
| | | |
| O | O | 9 |
| | | |
+-------+-------+-------+
¡Has Ganado!
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[fila][columna]
Cada uno de los elementos internos de la lista puede contener 'O' , 'X' , o un
digito representando el número del cuadro (dicho cuadro se considera como
libre).
La apariencia de tablero debe de ser igual a la presentada en el ejemplo.
Implementa las funciones definidas para ti en el editor.
Para obtener un valor numérico aleatorio se puede emplear una función integrada de
Python denominada randrange() . El siguiente ejemplo muestra como utilizarla (El
programa imprime 10 números aleatorios del 1 al 8).
for i in range(10):
print(randrange(8))
def DisplayBoard(board):
print("+-------" * 3,"+",sep="")
print("|")
print("+-------" * 3,"+",sep="")
def EnterMove(board):
ok = len(move) == 1 and move >= '1' and move <= '9' # Es valida?
if not ok:
continue
print("Repite tu tiro!")
continue
def MakeListOfFreeFields(board):
return free
def VictoryFor(board,sgn):
else:
for rc in range(3):
return who
return who
cross1 = False
cross2 = False
if cross1 or cross2:
return who
return None
import random
def DrawMove(board):
free = MakeListOfFreeFields(board) # crear lista de campos libres
cnt = (len(free))
if cnt > 0: # si la lista no está vacía, elija un lugar para 'X' y configurelo
this = random.randrange(cnt)
board[row][col] = 'X'
free = MakeListOfFreeFields(board)
while len(free):
DisplayBoard(board)
if humanturn:
EnterMove(board)
victor = VictoryFor(board,'O')
else:
DrawMove(board)
victor = VictoryFor(board,'X')
if victor != None:
break
free = MakeListOfFreeFields(board)
DisplayBoard(board)
if victor == 'you':
print("Ganaste!")
print("Gane")
else:
print("Jajaja!")
5.1.1.3 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 este abandonado. Un código real, deseado y
ampliamente utilizado se desarrolla continuamente, ya que tanto las demandas de los usuarios como
las expectativas de los usuarios se desarrollan a su propio ritmo.
Un código que no puede responder a las necesidades de los usuarios se olvidará rápidamente y se
reemplazará instantáneamente con un código nuevo, mejor y más flexible. Se debe estar preparado
para esto, y nunca pienses que tus programas están terminados por completo. La finalización es un
estado de transición y generalmente pasa rápidamente, después del primer informe de error. Python
en sí es un buen ejemplo de cómo actúa esta regla.
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 más 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 le
permitan:
Se deben dividir todas las tareas entre los desarrolladores.
Despues, unir todas las partes creadas en un todo funcional.
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. 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 cómo 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 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 sine).
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 cómo 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.
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 Seguro Social de EE. UU.
El número es un buen ejemplo de tal práctica).
Dentro de un determinado namespace, cada nombre debe permanecer único. Esto puede
significar que algunos nombres pueden desaparecer cuando cualquier otra entidad de un nombre ya
conocido ingresa al namespace. Mostraremos cómo funciona y cómo controlarlo, pero primero,
volvamos a las importaciones.
Esto significa que puede tener sus propias entidades llamadas sin o pi y no serán afectadas en
alguna manera por el import.
En este punto, es posible que te estes preguntando cómo acceder al pi el cual viene del
módulo math .
Para hacer esto, se debe de mandar llamar el pi con el su nombre en el 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(1/2π).
print(math.sin(math.pi/2))
Nota: el eliminar cualquiera de las dos indicaciones 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
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))
0.99999999
1.0
Las entidades listadas son las unicas que son importadas del módulo
indicado.
Los nombres de las entidades importadas pueden ser accedidas dentro del
programa.
print(math.e)
Aquí esta:
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 mas a detalle esto.
Importando un módulo: continuación
Observa el código en el editor. Analízalo cuidadosamente:
print(sin(pi/2))
pi = 3.14
def sin(x):
if 2 * x == pi:
return 0.99999999
else:
return None
print(sin(pi/2))
pi = 3.14 # linea 01
def sin(x):
if 2 * x == pi:
return 0.99999999
else:
return None # linea 07
print(sin(pi/2)) # linea 09
print(sin(pi/2)) # linea 14
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 conozca 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.
import math as m
print(m.sin(m.pi/2))
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 nombre as alias puede repetirse: emplea comas para separar las frases,
como a continuación:
print(sine(PI/2))
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.
Trabajando con módulos estándar
Antes de comenzar a revisar algunos módulos estándar de Python, veamos la función dir() . No
tiene nada que ver con el comando dir de las terminales de Windows o Unix. El
comando dir() no muestra el contenido de un directorio o carpeta de disco, pero no se puede negar
que hace algo similar: puede revelar todos los nombres proporcionados a través de un módulo en
particular.
Hay 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, debe 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
print(name, end="\t")
¿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.
Algunos de los nombres pueden traer recuerdos de las lecciones de matemáticas, y probablemente no
tendrás ningún problema en adivinar su significado.
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. Tomate 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.
Todas estas funciones toman un argumento (una medida de ángulo expresada en
radianes) y devuelven el resultado apropiado (ten cuidado con tan() - no todos los
argumentos son aceptados).
asin(x) → el arcoseno de x.
acos(x) → el arcocoseno de x.
atan(x) → el arcotangente de x.
Estas funciones toman un argumento (verifica 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(asin(sin(ar)) == ar)
resultado:
True
True
True
True
Además de las funciones circulares (enumeradas anteriormente), el
módulo math también contiene un conjunto de sus análogos hiperbólicos:
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(log(e, e) == exp(0))
resultado:
False
True
True
Funciones seleccionadas del módulo math:
continuación
El último grupo consta de algunas funciones de propósito general como:
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))
resultado:
1 2
-2 -3
2 3
-1 -2
1 2
-1 -2
Toma en cuenta el prefijo pseudo - los números generados por los módulos pueden parecer
aleatorios en el sentido de que no se pueden predecir, pero no hay que olvidar que todos se calculan
utilizando algoritmos muy refinados.
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 valor de la semilla inicial, establecido durante el inicio del programa, determina el orden en que
aparecerán los valores generados.
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 lanzamiento del programa comience desde un
valor semilla diferente (por lo tanto, usará diferentes números aleatorios).
for i in range(5):
print(random())
resultado:
0.06810374203512803
0.23333692642900283
0.8574434027740527
0.27805252409069037
0.30368882965548816
seed(0)
for i in range(5):
print(random())
0.844421851525
0.75795440294
0.420571580831
0.258916750293
0.511274721369
¿Y tú?
Nota: sus 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.
Funciones seleccionadas del módulo random:
continuación
Si deseas valores aleatorios enteros, una de las siguientes funciones encajaría mejor:
randrange(fin) x
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.
print(randint(0, 1))
resultado:
0 0 0 0
for i in range(10):
9,4,5,4,5,8,9,4,8,4,
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)
print(choice(lst))
print(sample(lst, 5))
print(sample(lst, 10))
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.
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.
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 veremos pronto).
Ahora:
print(platform())
print(platform(1))
print(platform(0, 1))
Windows-Vista-6.0.6002-SP2
Windows-Vista-6.0.6002-SP2
Windows-Vista
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
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
print(platform())
print(platform(1))
print(platform(0, 1))
print(machine())
x86
x86_64
armv7l
print(processor())
x86
armv7l
Funciones seleccionadas del módulo platform:
continuación
Una función llamada system() devuelve el nombre genérico del sistema operativo en
una cadena.
print(system())
Windows
Linux
Linux
print(version())
6.0.6002
print(python_implementation())
print(atr)
CPython
3
6
4
Todo lo que se necesita hacer es encontrar los módulos que se desean y aprender a
cómo usarlos. Es fácil.
¿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.
Tu primer módulo
En esta sección, trabajarás localmente en tu máquina. Comencemos desde cero, de la siguiente
manera:
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 el código real.
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.
Ha aparecido una nueva subcarpeta, ¿puedes verla? Su nombre es __pycache__. Echa un vistazo
adentro. ¿Que ves?
El nombre del archivo es el mismo que el de tu módulo. La parte posterior al primer punto dice qué
implementación de Python ha creado el archivo (CPython) y su número de versión. La ultima parte
(pyc) viene de las palabras Python y compilado.
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 de Python.
Cuando Python importa un módulo por primera vez, traduce el contenido a una forma "semi"
compilada. El archivo no contiene código en lenguaje máquina: es código semi-compilado interno
de Python, listo para ser ejecutado por el intérprete de Python. Como tal archivo no requiere tantas
comprobaciones como las de un archivo fuente, la ejecución comienza más rápido y también se
ejecuta más rápido.
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 se tiene que estar tomando en cuenta.
¿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.
Volvamos al archivo main.py:
Ejecuta el archivo. ¿Que ves? Con suerte, verás algo como esto:
Python puede hacer mucho más. También crea una variable llamada __name__ .
Además, cada archivo fuente usa su propia versión separada de la variable, no se comparte entre
módulos.
Te mostraremos cómo usarlo. Modifica el módulo un poco:
__main__
module
Así es como puedes hacer uso de la variable __main__ para detectar el contexto en el cual se
activó tu código:
Ver código en Sandbox
Sin embargo, hay 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.
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.
A diferencia de muchos otros lenguajes de programación, Python no tiene medios para permitirte
ocultar tales variables a los ojos de los usuarios del módulo. 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.
Nosotros por supuesto, lo respetaremos. Ahora pongamos dos funciones en el módulo: evaluarán la
suma y el producto de los números recopilados en una lista.
Para responder a esta pregunta, tenemos que hablar sobre cómo Python busca 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.
Python examina estas carpetas en el orden en que aparecen en la lista: si el módulo no se puede
encontrar en ninguno de estos directorios, la importación falla.
De lo contrario, se tomará en cuenta la primera carpeta que contenga un módulo con el nombre
deseado (si alguna de las carpetas restantes contiene un módulo con ese nombre, se ignorará).
La variable se llama path (ruta), y es accesible a través del módulo llamado sys . Así es como
puedes verificar su valor:
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
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 resolverlo agregando una carpeta que contenga el módulo a la variable de ruta (path
variable), es completamente modificable.
Nota:
path.append('C:\\Users\\user\\py\\modules')
Hemos usado el método append() , la nueva ruta ocupará el último elemento en la lista de
rutas; si no te gusta la idea, puedes usar en lugar de ello el método insert() .
Tu primer paquete
Imagina que en un futuro no muy lejano, tu y tus socios escriben una gran cantidad de funciones en
Python.
Tu equipo decide agrupar las funciones en módulos separados, y este es el resultado final:
Nota: hemos presentado todo el contenido solo para el módulo omega: 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).
De repente, alguien se da cuenta de que estos módulos forman su propia jerarquía, por lo que
colocarlos a todos en una estructura plana no será una buena idea.
Después de algo de discusión, el equipo llega a la conclusión de que los módulos deben agruparse.
Todos los participantes están de acuerdo en que la siguiente estructura de árbol refleja perfectamente
las relaciones mutuas entre los módulos:
¿Se ve mal? De ninguna manera: analiza la estructura cuidadosamente. Se parece a algo, ¿no?
Parece la estructura de un directorio.
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:
extra.good.best.tau.funT()
Una función marcada como:
extra.ugly.psi.funP()
proviene del módulo psi el cual esta almacenado en 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.
Hemos preparado un archivo zip que contiene todos los archivos de la rama de paquetes. Puedes
descargarlo y usarlo para tus propios experimentos, pero recuerda desempaquetarlo en la carpeta
presentada en el esquema, de lo contrario, no será accesible para el código.
Nota:
Si deseas realizar tus propios experimentos con el paquete que hemos creado, puedes descargarlo a
continuación. Te alentamos a que lo hagas.
Ahora puedes crear módulos y combinarlos en paquetes. Es hora de comenzar una discusión
completamente diferente: sobre errores y fallas.
import math
x = float(input("Ingresa x: "))
y = math.sqrt(x)
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: "))
Ingresa x: -1
y = math.sqrt(x)
¿Puedes protegerte de tales sorpresas? Por supuesto que si. Además, tienes que
hacerlo para ser considerado un buen programador.
Excepciones
Cada vez que tu código intenta hacer algo erroneo, irresponsable o inaplicable, Python hace dos
cosas:
Detiene tu programa.
Crea un tipo especial de dato, llamado excepción.
Ambas actividades llevan por nombre lanzar una excepción. Podemos decir que Python siempre
lanza una excepción (o que una excepción ha sido lanzada) cuando no tiene idea de qué hacer con
el código.
La excepción lanzada 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.
Python proporciona herramientas efectivas que permiten observar, identificar y manejar las
excepciones eficientemente. Esto es posible debido a que todas las excepciones potenciales tienen
un nombre específico, por lo que se pueden clasificar y reaccionar a ellas adecuadamente.
La palabra en rojo es solo el nombre de la excepción. Vamos a familiarizarnos con algunas otras
excepciones.
Excepciones: continuación
Observa el código en el editor. Ejecuta el (obviamente incorrecto) programa.
valor = 1
valor /= 0
valor /= 0
ZeroDivisionError: division by zero
Excepciones: continuación
Observa el código en el editor. ¿Qué pasará cuando lo ejecutes?
lista = []
x = lista[0]
x = lista[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?
if segundoNumero != 0:
print(primerNumero / segundoNumero)
else:
print("FIN.")
Es cierto que esta forma puede parecer la más natural y comprensible, pero en
realidad, este método no facilita la programación. Todas estas revisiones pueden
hacer el código demasiado grande e ilegible.
Excepciones: continuación
Observa el código en el editor. Este es el enfoque favorito de Python.
Nota:
if segundoNumero != 0:
print(primerNumero / segundoNumero)
else:
print("FIN.")
Resumamos esto:
try:
:
:
except:
:
:
Excepciones: continuación
Observa el código en el editor. Te ayudará a comprender este mecanismo.
try:
print("1")
x=1/0
print("2")
except:
print("3")
try:
y=1/x
except:
print("FIN.")
El mensaje: Oh cielos, algo salio mal... que aparece en la consola no dice nada
acerca de la razón, mientras que hay dos posibles causas de la excepción:
Se parece a esto:
try:
:
except exc1:
:
except exc2:
:
except:
:
Excepciones: continuación
Mira el código en el editor. Nuestra solucion esta ahí.
try:
y=1/x
print(y)
except ZeroDivisionError:
except ValueError:
except:
print("THE END.")
0.2
FIN.
Si se ingresa 0 , dirá:
Excepciones: continuación
No olvides que:
try:
y=1/x
print(y)
except ValueError:
except:
print("FIN.")
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.
try:
y=1/x
print(y)
except ValueError:
print("FIN.")
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:
Excepciones
Python 3 define 63 excepciones integradas, y todos ellos 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.
Muestra una pequeña sección del árbol completo de excepciones. Comencemos examinando el árbol
desde la hoja ZeroDivisionError.
Nota:
BaseException
↑
Exception
↑
ArithmeticError
↑
ZeroDivisionError
Te mostraremos cómo funciona esta generalización. Comencemos con un código realmente simple.
Excepciones: continuación
Observa el código en el editor. Es un ejemplo simple para comenzar. Ejecutalo.
try:
y=1/0
except ZeroDivisionError:
print("Uuuppsss...")
print("FIN.")
Uuuppsss...
FIN.
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 .
Por lo tanto, la salida del código permanece sin cambios. Pruébalo.
Vamos a resumir:
Excepciones: continuación
Mira el código en el editor. ¿Qué pasará aquí?
try:
y=1/0
except ZeroDivisionError:
except ArithmeticError:
print("¡Problema aritmético!")
print("FIN.")
¿Cambiará algo si intercambiamos los dos 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.
Recuerda:
Excepciones: continuación
Si deseas manejar dos o mas excepciones de la misma manera, puedes usar la
siguiente sintaxis:
try:
:
except (exc1, exc2):
:
Simplemente tienes que poner todos los nombres de excepción empleados en una
lista separada por comas y no olvidar los paréntesis.
Dentro de la función.
Fuera de la función.
def badFun(n):
try:
return 1 / n
except ArithmeticError:
print("¡Problema aritmético!")
return None
badFun(0)
print("FIN.")
¡Problema aritmético!
FIN.
def badFun(n):
return 1 / n
try:
badFun(0)
except ArithmeticError:
print("¿Que pasó? ¡Se lanzo una excepción!")
print("FIN.")
El problema tiene que ser resuelto por el invocador (o por el invocador del invocador, y
así sucesivamente.).
Ahora vamos a suspender esta discusión, ya que queremos presentarte una nueva
instrucción de Python.
Excepciones: continuación
La instrucción raise genera la excepción especificada denominada exc como si fuese
generada de manera natural:
raise exc
La instrucción permite:
def badFun(n):
raise ZeroDivisionError
try:
badFun(0)
except ArithmeticError:
print("FIN.")
raise
Existe una seria restricción: esta variante de la instrucción raise puede ser
utilizada solamente dentro de la rama except ; usarla en cualquier otro contexto
causa un error.
Gracias a esto, puedes distribuir el manejo de excepciones entre diferentes partes del
código.
def badFun(n):
try:
return n / 0
except:
raise
try:
badFun(0)
except ArithmeticError:
print("¡Ya veo!")
print("FIN.")
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 .
FIN.
Excepciones: continuación
Ahora es un buen momento para mostrarte otra instrucción de Python,
llamada assert (afirmar). Esta es una palabra reservada.
assert expresión
¿Como funciona?
Evalúa la expresión.
Si la expresión se evalúa como True (verdadero) , 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 genera una excepción
llamada AssertionError (en este caso, decimos que la afirmación ha fallado).
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.
import math
x = float(input("Ingresa un numero: "))
x = math.sqrt(x)
print(x)
AssertionError
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:
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
Descripción:
Una excepción concreta generada por la instrucción de aserción cuando su argumento se evalúa
como False (falso), None (ninguno), 0 , o una cadena vacía.
Código :
print(tan(radians(angle)))
BaseException
Ubicación:
BaseException
Descripción:
La excepción más general (abstracta) de todas las excepciones de Python: todas las demás
excepciones se incluyen en esta; se puede decir que las siguientes dos excepciones son
equivalentes: except: y except BaseException: .
IndexError
Ubicación:
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:
# de dejar el bucle
lista = [1, 2, 3, 4, 5]
ix = 0
doit = True
while doit:
try:
print(lista[ix])
ix += 1
except IndexError:
doit = False
print('Listo')
KeyboardInterrupt
Ubicación:
BaseException ← KeyboardInterrupt
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. Nota: esta
excepción no se deriva de la clase Exception. Ejecuta el programa en IDLE.
Código:
# presionando Ctrl-C
seconds = 0
while True:
try:
print(seconds)
seconds += 1
sleep(1)
except KeyboardInterrupt:
print("¡No hagas eso!")
LookupError
Ubicación:
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:
Descripción:
Se produce una excepción concreta cuando no se puede completar una operación debido a la falta de
memoria libre.
Código:
string = 'x'
try:
while True:
print(len(string))
except MemoryError:
print('¡Esto no es gracioso!')
OverflowError
Ubicación:
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:
ImportError
Ubicación:
Descripción:
Código:
try:
import math
import time
import abracadabra
except:
KeyError
Ubicación:
Descripción:
Una excepción concreta que surge cuando intentas acceder al elemento inexistente de una colección
(por ejemplo, el elemento de un diccionario).
Código:
ch = 'a'
try:
while True:
ch = dict[ch]
print(ch)
except KeyError:
Hemos terminado con excepciones por ahora, pero volverán cuando discutamos la programación
orientada a objetos en Python. Puedes usarlos para proteger tu código de accidentes graves, pero
también tienes que aprender a sumergirte en ellos, 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.
5.1.6.4 Leer ints de forma segura
LABORATORIO
Tiempo Estimado
15-25 minutos
Nivel de dificultad
Mediano
Objetivos
Mejorar las habilidades del alumno para definir funciones.
Utilizar excepciones para proporcionar un entorno de entrada 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 debe:
Datos de Prueba
Prueba tu código cuidadosamente.
El número es: 1
¿Como es posible?
¿Cómo puedes hacerlo en Python? Esto es lo que discutiremos ahora. Comencemos con cómo 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.
Podemos crear prácticamente cualquier cantidad de asignaciones de números con caracteres, pero la
vida en un mundo en el que cada tipo de computadora utiliza una codificación de caracteres
diferentes no sería muy conveniente. Este sistema ha llevado a la necesidad de introducir un estándar
universal y ampliamente aceptado, implementado por (casi) todas las computadoras y sistemas
operativos en todo el mundo.
El código proporciona espacio para 256 caracteres diferentes, pero solo nos interesan los primeros
128. Si deseas ver cómo 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
caracter 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
codigo es 65. Ahora calcula la diferencia entre el código de la a y la A. Es igual a 32. Ese es el códgo
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.
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.
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 consecuencia, para determinar el significado de un punto de código específico, debes conocer la
página de códigos de destino.
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.
Unicode asigna caracteres únicos (letras, guiones, ideogramas, etc.) a más de un millón de
puntos de código. Los primeros 128 puntos de código Unicode son idénticos a ASCII, y los
primeros 256 puntos de código Unicode son idénticos a la página de códigos ISO / IEC 8859-1 (una
página de códigos diseñada para idiomas de Europa occidental).
UCS-4
El estándar Unicode no dice nada sobre cómo 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.
Como puedes ver, UCS-4 es un estándar bastante derrochador: aumenta el tamaño de un texto cuatro
veces en comparación con el estándar ASCII. Afortunadamente, hay formas más inteligentes de
codificar textos Unicode.
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.
Puedes usar caracteres codificados Unicode / UTF-8 para nombrar variables y otras
entidades.
Puedes usarlos durante todas las entradas y salidas.
Es muy importante tener en cuenta esto, porque significa que debes esperar un
comportamiento familiar.
# Ejemplo 1
palabra = 'por'
print(len(palabra))
Cualquier cadena puede estar vacía. Si es el caso, su longitud es 0 como en el Ejemplo
2.
# Ejemplo 2
vacio = ''
print(len(vacio))
# Ejemplo 3
yo_soy = 'I\'m'
print(len(yo_soy))
multiLinea = 'Linea #1
Linea #2'
print(len(multiLinea))
Afortunadamente, para este tipo de cadenas, Python ofrece una sintaxis simple,
conveniente y separada.
multiLinea = '''Linea #1
Linea #2'''
print(len(multiLinea))
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.
La Linea #1 contiene ocho caracteres. Las dos líneas juntas contienen 16 caracteres.
¿Perdimos un caracter? ¿Dónde? ¿Cómo?
No, no lo hicimos.
Las cadenas multilínea pueden ser delimitadas también por comillas triples, como
aqui:
multiLinea = """Linea #1
Linea #2"""
print(len(multiLinea))
Concatenadas (unidas).
Replicadas.
Analiza el ejemplo:
str1 = 'a'
str2 = 'b'
print(str1 + str2)
print(str2 + str1)
print(5 * 'a')
print('b' * 4)
El operador + es empleado en dos o más cadenas y produce una nueva cadena
que contiene todos los caracteres de sus argumentos (nota: el orden es
relevante aquí, en contraste con su versión numérica, la cual es conmutativa).
El operador * necesita una cadena y un número como argumentos; en este
caso, el orden no importa: puedes poner el número antes de la cadena, o
viceversa, el resultado será el mismo: una nueva cadena creada por la enésima
replicación de la cadena del argumento.
ab
ba
aaaaa
bbbb
Nota: Los atajos de los operadores anteriores también son aplicables para las cadenas
( += y *= ).
Observa el código en el editor y ejecútalo. Las salida del fragmento de código es:
ch1 = 'a'
print(ord(ch1))
print(ord(ch2))
97
32
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.
Operaciones con cadenas: chr()
Si conoces el punto de código (número) y deseas obtener el carácter correspondiente,
puedes usar la función llamada chr() .
print(chr(97))
print(chr(945))
a
α
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, al igual que en el ejemplo en el editor. Ejecuta el
programa.
# Indexando cadenas
for ix in range(len(exampleString)):
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
Por cierto, los índices negativos también se comportan como se esperaba. Comprueba
esto tú mismo.
for ch in exampleString:
print()
Rodajas o Rebanadas
Todo lo que sabes sobre rodajas o rebanadas es utilizable.
Hemos reunido algunos ejemplos que muestran cómo funcionan las rodajas en el
mundo de las cadenas. Mira el código en el editor, analizalo y ejecútalo.
# Rodajas o 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])
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
adf
beg
Los operadores in y not in
El operador in no debería sorprenderte cuando se aplica a cadenas,
simplemente comprueba si el argumento izquierdo (una cadena) se puede
encontrar en cualquier lugar dentro del argumento derecho (otra cadena).
alpfabeto = "abcdefghijklmnopqrstuvwxyz"
print("f" in alpfabeto)
print("F" in alpfabeto)
print("1" in alpfabeto)
print("ghi" in alpfabeto)
print("Xyz" in alpfabeto)
False
True
False
alfabeto = "abcdefghijklmnopqrstuvwxyz"
False
True
True
False
True
del alfabeto[0]
Lo único que puedes hacer con del y una cadena es eliminar la cadena como un
todo. Intenta hacerlo.
alfabeto = "abcdefghijklmnopqrstuvwxyz"
alfabeto.append("A")
Con la ausencia del método append() , el método insert() también es ilegal:
alfabeto = "abcdefghijklmnopqrstuvwxyz"
alfabeto.insert(0, "A")
Esta forma de código es totalmente aceptable, funcionará sin doblar las reglas de
Python y traerá el alfabeto latino completo a tu pantalla:
alfabeto = "bcdefghijklmnopqrstuvwxy"
abcdefghijklmnopqrstuvwxyz
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.
print(min("aAbByYzZ"))
Nota: Es una A mayúscula. ¿Por qué? Recuerda la tabla ASCII, ¿qué letras ocupan las
primeras posiciones, mayúsculas o minúsculas?
t = [0, 1, 2]
print(min(t))
Como puedes ver, presentan más que solo cadenas. El resultado esperado se ve de la
siguiente manera:
[ ]
Nota: hemos utilizado corchetes para evitar que el espacio se pase por alto en tu
pantalla.
print(max("aAbByYzZ"))
Nota: es una z minúscula.
Ahora veamos la función max() a los mismos datos del ejemplo anterior. Observa
los Ejemplos 2 y 3 en el editor.
t = [0, 1, 2]
print(max(t))
[¡]
2
Realiza tus propios experimentos.
Operaciones con cadenas: el método index()
El método index() (es un método, no una función) busca la secuencia desde el
principio, para encontrar el primer elemento del valor especificado en su
argumento.
Nota: el elemento buscado debe aparecer en la secuencia - su ausencia causará una
excepción ValueError.
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).
print(list("abcabc"))
La salida es:
print("abcabc".count("b"))
print('abcabc'.count("d"))
Es:
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:
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.
print('aBcD'.capitalize())
Abcd
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.
[Beta]
[Beta]
[ Beta ]
La variante de dos parámetros de center() hace uso del caracter del segundo
argumento, en lugar de un espacio. Analiza el siguiente ejemplo:
[*******gamma********]
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.
if "epsilon".endswith("on"):
print("si")
else:
print("no")
si
t = "zeta"
print(t.endswith("a"))
print(t.endswith("A"))
print(t.endswith("et"))
print(t.endswith("eta"))
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:
print("Eta".find("ta"))
print("Eta".find("mma"))
El ejemplo imprime:
-1
Nota: no se debe de emplear find() si deseas verificar si un solo carácter aparece
dentro de una cadena - el operador in será significativamente más rápido.
print(t.find('eta'))
print(t.find('et'))
print(t.find('te'))
print(t.find('ha'))
1
1
0
-1
print('kappa'.find('a', 2))
fnd = txt.find('the')
print(fnd)
fnd = txt.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
print('kappa'.find('a', 1, 4))
print('kappa'.find('a', 2, 4))
-1
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.
print('lambda'.isalnum())
print('30'.isalnum())
print('@'.isalnum())
print('lambda_30'.isalnum())
print(''.isalnum())
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
t = 'Six lambdas'
print(t.isalnum())
False
t = 'ΑβΓδ'
print(t.isalnum())
True
t = '20E1'
print(t.isalnum())
True
print("Moooo".isalpha())
print('Mu40'.isalpha())
True
False
El método isdigit()
Al contrario, el método isdigit() busca sólo dígitos - cualquier otra cosa
produce False (falso) como resultado.
print('2018'.isdigit())
print("Año2019".isdigit())
True
False
El método islower()
El método islower() es una variante de isalpha() - solo acepta letras minúsculas.
print("Moooo".islower())
print('moooo'.islower())
False
True
El método isspace()
El método isspace() identifica espacios en blanco solamente - no tiene en cuenta
ningún otro caracter (el resultado es entonces False ).
print(' \n '.isspace())
print(" ".isspace())
True
True
False
El método isupper()
El método isupper() es la versión en mayúscula de islower() - se concentra solo
en letras mayúsculas.
print("Moooo".isupper())
print('moooo'.isupper())
print('MOOOO'.isupper())
False
False
True
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
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.
print("SiGmA=60".lower())
sigma=60
Los corchetes no son parte del resultado, solo muestran los límites del resultado.
[tau ]
print("www.cisco.com".lstrip("w."))
cisco.com
print("pythoninstitute.org".lstrip(".org"))
pythoninstitute.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.
print("www.netacad.com".replace("netacad.com", "pythoninstitute.org"))
print("This is it!".replace("is", "are"))
El segundo argumento puede ser una cadena vacía (lo que hace es eliminar en lugar
de reemplazar), pero el primer argumento no puede estar vacío.
www.pyhoninstitute.org
Thare are it!
Apple
Thare is it!
Thare are it!
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).
8
-1
4
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.
Mira el ejemplo en el editor. ¿Puedes adivinar su salida? Ejecuta el código para verificar
tus conjeturas.
print("cisco.com".rstrip(".com"))
[ upsilon]
cis
El método split()
El método split() divide la cadena y crea una lista de todas las subcadenas
detectadas.
print("phi chi\npsi".split())
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.
print("omega".startswith("om"))
print()
False
True
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]
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.
yO SÉ QUE NO SÉ NADA.
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 qué cosas podemos
hacer con las cadenas.
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.
def misplit(strng):
return strng.split()
print(misplit(" "))
print(misplit(""))
Salida esperada
['Ser', 'o', 'no', 'ser', 'esa', 'es,', 'la', 'pregunta']
[]
['abc']
[]
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 ser de ninguna
manera) de problemas lingüísticos sutiles, simplemente compara valores de puntos
de código, caracter por caracter.
Los resultados que 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 en los mismos caracteres en el mismo
orden. Del mismo modo, dos cadenas no son iguales cuando no consisten en los
mismos caracteres en el mismo orden.
'alfa' == 'alfa'
'alfa' != 'Alfa'
'10' == '010'
'10' > '010'
'10' > '8'
'20' < '8'
'20' < '80'
False
True
False
True
True
Las únicas comparaciones que puede realizar con impunidad son aquellas
simbolizadas por los operadores == y != . El primero siempre devuelve False ,
mientras que el segundo siempre devuelve True .
Vamos a verlo:
'10' == 10
'10' != 10
'10' == 1
'10' != 1
'10' > 10
False
True
False
True
TypeError exception
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 devuelve 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).
firstGreek2 = sorted(firstGreek)
print(firstGreek)
print(firstGreek2)
print()
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() .
print(secondGreek)
secondGreek.sort()
print(secondGreek)
El resultado no ha cambiado:
itg = 13
flt = 1.3
si = str(itg)
sf = str(flt)
13 1.3
Emplea la función int() si deseas obtener un entero, y float() si necesitas un valor
punto flotante.
print(itg + flt)
14.3
LABORATORIO
Tiempo Estimado
30 minutos
Nivel de dificultad
Medio
Objetivos
Mejorar las habilidades del alumno para 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:
# ### ### # # ### ### ### ### ### ###
# # # # # # # # # # # # # #
# # # # # # # # # # # # #
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:
# # # # # # # # # # # # # #
# # # # # # # # # # # # #
### ### ### # # ### ### ### ### #
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 Z, la cual se convierte en A.
# Cifrado César
cifrado = ''
if not char.isalpha():
continue
char = char.upper()
code = ord(char) + 1
code = ord('A')
cifrado += chr(code)
print(cifrado)
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 caracter 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
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.
#Procesador de números
strings = linea.split()
total = 0
try:
total += float(substr)
except:
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 del error.
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 valido.
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 dividiendolo entre 97. Si el residuo es 1, pasa la prueba de
verificación de dígitos y el IBAN puede ser válido.
if not iban.isalnum():
else:
iban2 = ''
for ch in iban:
if ch.isdigit():
iban2 += ch
else:
ibann = int(iban2)
if ibann % 97 == 1:
else:
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 caracter es un digito...
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).
Si eres residente de la UE, puedes usar tu propio número de cuenta para hacer
pruebas.
LABORATORIO
Tiempo Estimado
30-45 minutos
Nivel de Dificultad
Difícil
Prerrequisitos
Módulo 5.1.11.1, Módulo 5.1.11.2
Objetivos
Mejorar las habilidades del alumno para manipular cadenas.
Convertir caracteres en código ASCII y viceversa.
Escenario
Ya estás familiarizado con el cifrado César, y es por eso que queremos que mejores el
código que te mostramos recientemente.
El cifrado César original cambia cada caracter por otro a se convierte en b, z se
convierte en a, y así sucesivamente. Hagámoslo un poco más difícil y permitamos que
el valor desplazado provenga del rango 1 al 25.
Además, dejemos que el código conserve las mayúsculas y minúsculas (las minúsculas
permanecerán en minúsculas) y todos los caracteres no alfabéticos deben permanecer
intactos.
Datos de Prueba
Entrada Muestra:
abcxyzABCxyz 123
2
Salida Muestra:
cdezabCDEzab 123
Entrada Muestra:
25
Salida Muestra:
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
Mejorar las habilidades del alumno para manipular cadenas.
Alentar al alumno a buscar soluciones no obvias.
Escenario
¿Sabes qué es un palíndromo?
Es una palabra que se ve igual cuando se lee hacia adelante y hacia atrás. Por ejemplo,
"kayak" es un palíndromo, mientras que "leal" no lo es.
Nota:
Datos de Prueba
Entrada Muestra:
Salida Muestra:
Es un palíndromo
Entrada Muestra:
Salida Muestra:
No es un palíndromo
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
Mejorar las habilidades del alumno para trabajar con cadenas.
Convertir cadenas en listas, y viceversa.
Escenario
Un anagrama es una nueva palabra formada al reorganizar las letras de una palabra,
usando todas las letras originales exactamente una vez. Por ejemplo, las frases "rail
safety" y "fairy tales" son anagramas, mientras que "I am" y "You are" no lo son.
Nota:
Datos de Prueba
Entrada de Ejemplo:
Listen
Silent
Anagramas
Entrada de Ejemplo:
modern
norman
No son Anagramas
LABORATORIO
Tiempo Estimado
10-15 minutos
Nivel de Dificultad
Fácil
Objetivos
Mejorar las habilidades del alumno para trabajar con cadenas.
Convertir enteros en cadenas, y viceversa.
Escenario
Algunos dicen que el Dígito de la Vida es un dígito calculado usando el cumpleaños de
alguien. Es simple: solo necesitas sumar todos los dígitos de la fecha. Si el resultado
contiene más de un dígito, se debe repetir la suma hasta obtener exactamente un
dígito. Por ejemplo:
19991229
Entrada de Ejemplo:
20000101
LABORATORIO
Tiempo Estimado
15-20 minutos
Nivel de Dificultad
Medio
Objetivos
Mejorar las habilidades del alumno para trabajar con cadenas.
Emplear el método find() para realizar busquedas dentro de las cadenas.
Escenario
Vamos a jugar un juego. Le daremos dos cadenas: una es una palabra (por ejemplo,
"dog") y la segunda es una combinación de un grupo de caracteres.
Tu tarea es escribir un programa que responda la siguiente pregunta: ¿Los caracteres
que comprenden la primera cadena están ocultos dentro de la segunda cadena?
Por ejemplo:
Consejos:
Debes usar las variantes de dos argumentos de las funciones pos() dentro de
tu código.
No te preocupes por mayúsculas y minúsculas.
Datos de Prueba
Entrada de Ejemplo:
donor
Nabucodonosor
Si
Entrada de Ejemplo:
donut
Nabucodonosor
No
LABORATORIO
Tiempo Estimado
60 minutos
Nivel de Dificultad
Difícil
Objetivos
Mejorar las habilidades del estudiante para trabajar con cadenas y listas.
Convertir cadenas en listas.
Escenario
Como probablemente sabes, Sudoku es un rompecabezas de colocación de números
jugado en un tablero de 9x9. El jugador tiene que llenar el tablero de una manera muy
específica:
Cada fila del tablero debe contener todos los dígitos del 0 al 9 (el orden no
importa).
Cada columna del tablero debe contener todos los dígitos del 0 al 9
(nuevamente, el orden no importa).
Cada subcuadro de 3x3 de la tabla debe contener todos los dígitos del 0 al 9.
Lea las 9 filas del Sudoku, cada una con 9 dígitos (verifica cuidadosamente si los
datos ingresados son válidos).
Da como salida Si si el Sudoku es válido y No de lo contrario.
Datos de Prueba
Entrada de Muestra:
295743861
431865927
876192543
387459216
612387495
549216738
763524189
928671354
154938672
Salida de la Muestra:
Yes
Entrada de Muestra:
195743862
431865927
876192543
387459216
612387495
549216738
763524189
928671354
254938671
Salida de la Muestra
No
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 pueden 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.
El enfoque orientado a objetos sugiere una forma de pensar completamente diferente. Los datos y
el código están encapsulados juntos en el mismo mundo, divididos en clases.
Cada clase es como una receta que se puede usar cuando quieres crear un objeto útil. Puedes
producir tantos objetos como necesites para resolver tu problema.
Cada objeto tiene un conjunto de rasgos (se denominan propiedades o atributos; usaremos ambas
palabras como sinónimos) y es capaz de realizar un conjunto de actividades (que se denominan
métodos).
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)
estan 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.
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.
En este ejemplo, discutiremos solo la primera subclase: vehículos terrestres. Si lo deseas, puedes
continuar con las clases restantes.
Los vehículos terrestres pueden dividirse aún más, según el método con el que impactan el suelo.
Entonces, podemos enumerar:
Vehículos de ruedas.
Vehículos oruga.
Aerodeslizadores.
Ten en cuenta la dirección de las flechas: siempre apuntan a la superclase. La clase de nivel superior
es una excepción: no tiene su propia superclase.
Podemos decir que todos los animales (nuestra clase de nivel superior) se puede dividir en cinco
subclases:
Mamíferos.
Reptiles.
Pájaros.
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.
Por ejemplo: cualquier automóvil personal es un objeto que pertenece a la clase vehículos terrestres.
También significa que el mismo automóvil pertenece a todas las superclases de su clase local; por lo
tanto, también es miembro de la clase vehículos. Tu perro (o tu gato) es un objeto incluido en la
clase Mamíferos domesticados, lo que significa explícitamente que también está incluido en la
clase animales.
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.
¿Qué contiene un objeto?
La programación orientada a objetos supone que cada objeto existente puede estar equipado con
tres grupos de atributos:
Hay 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:
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. Echa un vistazo al siguiente ejemplo:
class ClaseSimple:
pass
Hemos definido una clase. La clase es bastante pobre: no contiene propiedades ni actividades.
Esta vacía, pero eso no importa por ahora. Cuanto más simple sea la clase, mejor para nuestros
propósitos.
La definición comienza con la palabra clave reservada class . La palabra clave reservada es
seguida por un identificador que nombrará 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.
miPrimerObjeto = ClaseSimple()
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.
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.
El nombre alternativo para una pila (pero solo en la terminología de TI) es UEPS (LIFO son sus
siglas en íngles). 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 cómo hacerlo
en dos enfoques independientes: de manera procedimental y orientado a objetos.
pila = []
Estamos listos para definir una función que pone un valor en la pila. Aquí están las
presuposiciones para ello:
El nombre para la función es push .
La función obtiene un parámetro (este es el valor que se debe colocar en la
pila).
La función no devuelve nada.
La función agrega el valor del parámetro al final de la pila.
def push(val):
pila.append(val)
Ahora es tiempo de que una función quite un valor de la pila. Así es como puedes
hacerlo:
def pop():
val = pila[-1]
del pila[-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.
1
2
3
Pruébalo.
pila = []
def push(val):
pila.append(val)
def pop():
val = pila[-1]
del pila[-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:
pila[0] = 0
El funcionamiento de la pila estará completamente desorganizado.
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:
La capacidad de ocultar (proteger) los valores seleccionados contra el acceso no autorizado
se llama encapsulamiento; no se puede acceder a los valores encapsulados ni
modificarlos si deseas utilizarlos exclusivamente.
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.
class Pila:
¿Cómo garantizar que dicha actividad tiene lugar cada vez que se crea una nueva pila?
Hay una manera simple de hacerlo - tienes que equipar a la clase con una función
específica:
class Pila:
def __init__(self):
print("¡Hola!")
objetoPila = Pila()
¡Hola!
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 listaPila .
class Pila:
def __init__(self):
self.listaPila = []
objetoPila = Pila()
print(len(objetoPila.listaPila))
Nota:
class Pila:
def __init__(self):
self.listaPila = []
objetoPila = Pila()
print(len(objetoPila.listaPila))
class Pila:
def __init__(self):
self.__listaPila = []
objetoPila = Pila()
print(len(objetoPila.__listaPila))
¿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 la clase.
No puedes verlo desde el mundo exterior. Así es como Python implementa el concepto
de encapsulación.
class Pila:
def __init__(self):
self.listaPila = []
objetoPila = Pila()
print(len(objetoPila.__listaPila))
Queremos invocar estas funciones para agregar (push) y quitar (pop) valores de
la pila. Esto significa que ambos deben ser accesibles para el usuario de la clase (en
contraste con la lista previamente construida, que está oculta para los usuarios de la
clase ordinaria).
class Pila:
def __init__(self):
self.__listaPila = []
def pop(self):
val = self.__listaPila[-1]
del self.__listaPila[-1]
return val
objetoPila = Pila()
objetoPila.push(3)
objetoPila.push(2)
objetoPila.push(1)
print(objetoPila.pop())
print(objetoPila.pop())
print(objetoPila.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.
Aquí, ambas funciones tienen un parámetro llamado self en la primera posición de la
lista de parámetros.
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 __listaPila .
class Pila:
def __init__(self):
self.__listaPila = []
self.__listaPila.append(val)
def pop(self):
val = self.__listaPila[-1]
del self.__listaPila[-1]
return val
objetoPila1 = Pila()
objetoPila2 = Pila()
objetoPila1.push(3)
objetoPila2.push(objetoPila1.pop())
print(objetoPila2.pop())
Resultado: 3
class Pila:
def __init__(self):
self.__listaPila = []
self.__listaPila.append(val)
def pop(self):
val = self.__listaPila[-1]
del self.__listaPila[-1]
return val
pequeñaPila = Pila()
otraPila = Pila()
graciosaPila = Pila()
pequeñaPila.push(1)
otraPila.push(pequeñaPila.pop() + 1)
graciosaPila.push(otraPila.pop() - 2)
print(graciosaPila.pop())
Resultado: 0
El primer paso es fácil: solo define una nueva subclase que apunte a la clase que se
usará como superclase.
class SumarPila(Pila):
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. Sera 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 cómo
hacerlo, pero hay algo realmente intrigante dentro del constructor. Echa un vistazo:
class SumarPila(Pila):
def __init__(self):
Pila.__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.
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 Pila:
def __init__(self):
self.__listaPila = []
def pop(self):
val = self.__listaPila[-1]
del self.__listaPila[-1]
return val
class SumarPila(Pila):
def __init__(self):
Pila.__init__(self)
self.__sum = 0
El enfoque orientado a objetos: una pila desde cero
(continuación)
En segundo lugar, agreguemos dos métodos. Pero, ¿realmente estamos agregándolos?
Ya tenemos estos métodos en la superclase. ¿Podemos hacer algo así?
Se dice que el método push ha sido anulado - el mismo nombre que en la superclase
ahora representa una funcionalidad diferente.
def pop(self):
val = Pila.pop(self)
self.__sum -= val
return val
Aquí está:
def getSuma(self):
return self.__sum
class Pila:
def __init__(self):
self.__listaPila = []
def pop(self):
val = self.__listaPila[-1]
del self.__listaPila[-1]
return val
class SumarPila(Pila):
def __init__(self):
Pila.__init__(self)
self.__sum = 0
def getSuma(self):
return self.__sum
def pop(self):
val = Pila.pop(self)
self.__sum -= val
return val
objetoPila = SumarPila()
for i in range(5):
objetoPila.push(i)
print(objetoPila.getSuma())
for i in range(5):
print(objetoPila.pop())
10
4
3
2
1
0
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.
Además, se puede hacer en cualquier momento de la vida del objeto. Es importante mencionar
también que cualquier propiedad existente se puede eliminar en cualquier momento.
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 a ellas.
class ClaseEjemplo:
def __init__(self, val = 1):
self.primera = val
objetoEjemplo1 = ClaseEjemplo()
objetoEjemplo2 = ClaseEjemplo(2)
objetoEjemplo2.setSegunda(3)
objetoEjemplo3 = ClaseEjemplo(4)
objetoEjemplo3.tercera = 5
print(objetoEjemplo1.__dict__)
print(objetoEjemplo2.__dict__)
print(objetoEjemplo3.__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.
Los objetos de Python, cuando se crean, están dotados de un pequeño conjunto de propiedades y
métodos predefinidos. Cada objeto los tiene, los quieras o no. Uno de ellos es una variable
llamada __dict__ (es un diccionario).
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.
La clase también tiene un método que crea otra variable de instancia, llamada segunda .
Hemos creado tres objetos de la clase ClaseEjemplo , pero todas estas instancias difieren:
La salida del programa muestra claramente que nuestras suposiciones son correctas: aquí están:
{'primera': 1}
{'primera': 2, 'segunda': 3}
{'primera': 4, 'tercera': 5}
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.
class ClaseEjemplo:
self.__primera = val
self.__segunda = val
objetoEjemplo1 = ClaseEjemplo()
objetoEjemplo2 = ClaseEjemplo(2)
objetoEjemplo2.setSegunda(3)
objetoEjemplo3 = ClaseEjemplo(4)
objetoEjemplo3.__tercera = 5
print(objetoEjemplo1.__dict__)
print(objetoEjemplo2.__dict__)
print(objetoEjemplo3.__dict__)
Es casi lo mismo que el anterior. La única diferencia está en los nombres de las
propiedades. Hemos agregado dos guiones bajos ( __ ) en frente de ellos.
Como sabes, tal adición hace que la variable de instancia sea privada - se vuelve
inaccesible desde el mundo exterior.
{'_ClaseEjemplo__primera': 1}
{'_ClaseEjemplo__primera': 2, '_ClaseEjemplo__segunda': 3}
{'_ClaseEjemplo__primera': 4, '__tercera': 5}
¿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(objetoEjemplo1._ClaseEjemplo__primera)
Como puedes ver, hacer que una propiedad sea privada es limitado.
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 en la clase; existe una variable de
clase en una copia, incluso si no hay objetos en la clase.
class ClaseEjemplo:
contador = 0
def __init__(self, val = 1):
self.__primera = val
ClaseEjemplo.contador += 1
objetoEjemplo1 = ClaseEjemplo()
objetoEjemplo2 = ClaseEjemplo(2)
objetoEjemplo3 = ClaseEjemplo(4)
print(objetoEjemplo1.__dict__, objetoEjemplo1.contador)
print(objetoEjemplo2.__dict__, objetoEjemplo2.contador)
print(objetoEjemplo3.__dict__, objetoEjemplo3.contador)
Observa:
{'_ClaseEjemplo__primera': 1} 3
{'_ClaseEjemplo__primera': 2} 3
{'_ClaseEjemplo__primera': 4} 3
class ClaseEjemplo:
__contador = 0
def __init__(self, val = 1):
self.__primera = val
ClaseEjemplo.__contador += 1
objetoEjemplo1 = ClaseEjemplo()
objetoEjemplo2 = ClaseEjemplo(2)
objetoEjemplo3 = ClaseEjemplo(4)
print(objetoEjemplo1.__dict__, objetoEjemplo1._ClaseEjemplo__contador)
print(objetoEjemplo2.__dict__, objetoEjemplo2._ClaseEjemplo__contador)
print(objetoEjemplo3.__dict__, objetoEjemplo3._ClaseEjemplo__contador)
Resultado:
{'_ClaseEjemplo__primera': 1} 3
{'_ClaseEjemplo__primera': 2} 3
{'_ClaseEjemplo__primera': 4} 3
class ClaseEjemplo:
varia = 1
ClaseEjemplo.varia = val
print(ClaseEjemplo.__dict__)
objetoEjemplo = ClaseEjemplo(2)
print(ClaseEjemplo.__dict__)
print(objetoEjemplo.__dict__)
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 ClaseEjemplo:
if val % 2 != 0:
self.a = 1
else:
self.b = 1
objetoEjemplo = ClaseEjemplo(1)
print(objetoEjemplo.a)
print(objetoEjemplo.b)
El objeto creado por el constructor solo puede tener uno de los dos atributos
posibles: a o b .
print(objetoEjemplo.b)
Como puedes ver, acceder a un atributo de objeto (clase) no existente provoca una
excepción AttributeError.
class ClaseEjemplo:
if val % 2 != 0:
self.a = 1
else:
self.b = 1
objetoEjemplo = ClaseEjemplo(1)
print(objetoEjemplo.a)
try:
print(objetoEjemplo.b)
except AttributeError:
pass
La función retorna True o False.
class ClaseEjemplo:
def __init__(self, val):
if val % 2 != 0:
self.a = 1
else:
self.b = 1
objetoEjemplo = ClaseEjemplo(1)
print(objetoEjemplo.a)
if hasattr(objetoEjemplo, 'b'):
print(objetoEjemplo.b)
¿Puedes adivinar la salida del código? Ejecútalo para verificar tus conjeturas.
class ClaseEjemplo:
attr = 1
print(hasattr(ClaseEjemplo, 'attr'))
print(hasattr(ClaseEjemplo, 'prop'))
class ClaseEjemplo:
a = 1
def __init__(self):
self.b = 2
objetoEjemplo = ClaseEjemplo()
print(hasattr(objetoEjemplo, 'b'))
print(hasattr(objetoEjemplo, 'a'))
print(hasattr(ClaseEjemplo, 'b'))
print(hasattr(ClaseEjemplo, 'a'))
True
True
False
True
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.
Como ya sabes, un método es una función que está dentro de una clase.
class conClase:
def metodo(self):
print("método")
obj = conClase()
obj.metodo()
método
class conClase:
def metodo(self, par):
print("método:", par)
obj = conClase()
obj.metodo(1)
obj.metodo(2)
obj.metodo(3)
método: 1
método: 2
método: 3
class conClase:
varia = 2
def metodo(self):
print(self.varia, self.var)
obj = conClase()
obj.var = 3
obj.metodo()
2 3
El parámetro self también se usa para invocar otros métodos desde dentro de la
clase.
class conClase():
def otro(self):
print("otro")
def metodo(self):
print("método")
self.otro()
obj = conClase()
obj.metodo()
método
otro
El constructor:
class conClase:
self.var = valor
obj1 = conClase("objeto")
print(obj1.var)
objeto
class conClase:
self.var = valor
obj1 = conClase("objeto")
obj2 = conClase()
print(obj1.var)
print(obj2.var)
El código da como salida:
objeto
None
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 conClase:
def visible(self):
print("visible")
def __oculto(self):
print("oculto")
obj = conClase()
obj.visible()
try:
obj.__oculto()
except:
print("fallido")
obj._conClase__oculto()
visible
fallido
oculto
Observemos cómo esta propiedad trata con los métodos: mira el código en el editor.
class conClase:
varia = 1
def __init__(self):
self.var = 2
def metodo(self):
pass
def __oculto(self):
pass
obj = conClase()
print(obj.__dict__)
print(conClase.__dict__)
Nota: el atributo __name__ está ausente del objeto - existe solo dentro de las clases.
Si deseas encontrar la clase de un objeto en particular, puedes usar una función
llamada type() , la cual es capaz (entre otras cosas) de encontrar una clase que se
haya utilizado para crear instancias de cualquier objeto.
class conClase:
pass
print(conClase.__name__)
obj = conClase()
print(type(obj).__name__)
conClase
conClase
class conClase:
pass
print(conClase.__module__)
obj = conClase()
print(obj.__module__)
__main__
__main__
Como sabes, cualquier módulo llamado __main__ en realidad no es un módulo, sino
es el archivo actualmente en ejecución.
Además, te mostraremos cómo usar este atributo cuando discutamos los aspectos
orientados a objetos de las excepciones.
class SuperUno:
pass
class SuperDos:
pass
pass
def printBases(cls):
for x in cls.__bases__:
print(')')
printBases(SuperUno)
printBases(SuperDos)
printBases(Sub)
( object )
( object )
( SuperUno SuperDos )
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:
En otras palabras, no tienes que conocer la definición completa de clase/objeto para manipular el
objeto, ya que el objeto y/o su clase contienen los metadatos que te permiten reconocer sus
características durante la ejecución del programa.
Investigando Clases
¿Qué puedes descubrir acerca de las clases en Python? La respuesta es simple: todo.
pass
obj = MiClase()
obj.a = 1
obj.b = 2
obj.i = 3
obj.ireal = 3.5
obj.entero = 4
obj.z = 5
def incIntsI(obj):
if name.startswith('i'):
if isinstance(val, int):
print(obj.__dict__)
incIntsI(obj)
print(obj.__dict__)
¡Eso es todo!
class Estrella:
self.nombre = nombre
self.galaxia = galaxia
print(sol)
El programa imprime solo una línea de texto, que en nuestro caso es:
El método por default __str__() devuelve la cadena anterior: fea y poco informativa.
Puedes cambiarlo definiendo tu propio método del nombre.
class Estrella:
self.nombre = nombre
self.galaxia = galaxia
def __str__(self):
print(sol)
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?
La herencia es una práctica común (en la programación de objetos) de pasar atributos y métodos
de la superclase (definida y existente) a una clase recién creada, llamada subclase.
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.
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 Vehiculo:
pass
class VehiculoTerrestre(Vehiculo):
pass
class VehiculoOruga(VehiculoTerrestre):
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).
Herencia: issubclass()
Python ofrece una función que es capaz de identificar una relación entre dos clases,
y aunque su diagnóstico no es complejo, puede verificar si una clase particular es
una subclase de cualquier otra clase.
issubclass(ClaseUno, ClaseDos)
class Vehiculo:
pass
class VehiculoTerrestre(Vehiculo):
pass
class VehiculoOruga(VehiculoTerrestre):
pass
print()
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.
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.
isinstance(nombreObjeto, nombreClase)
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.
class Vehiculo:
pass
class VehiculoTerrestre(Vehiculo):
pass
class VehiculoOruga(VehiculoTerrestre):
pass
miVehiculo = Vehiculo()
miVehiculoTerrestre = VehiculoTerrestre()
miVehiculoOruga = VehiculoOruga()
print()
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.
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á:
objetoUno is objetoDos
El operador is verifica si dos variables (en este caso objetoUno y objetoDos ) 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.
class ClaseMuestra:
def __init__(self, val):
self.val = val
ob1 = ClaseMuestra(0)
ob2 = ClaseMuestra(2)
ob3 = ob1
ob3.val += 1
print(ob1 is ob2)
print(ob2 is ob3)
print(ob3 is ob1)
str1 += "corderito"
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
Los resultados prueban que ob1 y ob3 son en realidad los mismos objetos, mientras
que str1 y str2 no lo son, a pesar de que su contenido sea el mismo.
Cómo Python encuentra propiedades y métodos
Ahora veremos cómo Python trata con los métodos de herencia.
class Super:
self.nombre = nombre
def __str__(self):
class Sub(Super):
Super.__init__(self, nombre)
obj = Sub("Andy")
print(obj)
Existe una clase llamada Super , que define su propio constructor utilizado para
asignar la propiedad del objeto, llamada nombre .
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 cómo lo hemos hecho: Super.__init__(self, nombre) .
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.
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 .
super().__init__(nombre)
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.
class Super:
def __init__(self, nombre):
self.nombre = nombre
def __str__(self):
return "Mi nombre es " + self.nombre + "."
class Sub(Super):
def __init__(self, nombre):
super().__init__(nombre)
obj = Sub("Andy")
print(obj)
Resultado:
Mi nombre es Andy.
Cómo Python encuentra propiedades y métodos:
continuación
Intentemos hacer algo similar, pero con propiedades (más precisamente
con: variables de clase).
class Super:
supVar = 1
class Sub(Super):
subVar = 2
obj = Sub()
print(obj.subVar)
print(obj.supVar)
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:
class Super:
def __init__(self):
self.supVar = 11
class Sub(Super):
def __init__(self):
super().__init__()
self.subVar = 12
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 .
12
11
Cuando intentes acceder a una entidad de cualquier objeto, Python intentará (en este
orden):
class Nivel1:
varia1 = 100
def __init__(self):
self.var1 = 101
def fun1(self):
return 102
class Nivel2(Nivel1):
varia2 = 200
def __init__(self):
super().__init__()
self.var2 = 201
def fun2(self):
return 202
class Nivel3(Nivel2):
varia3 = 300
def __init__(self):
super().__init__()
self.var3 = 301
def fun3(self):
return 302
obj = Nivel3()
print(obj.varia1, obj.var1, obj.fun1())
Resultado:
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 SuperA:
varA = 10
def funA(self):
return 11
class SuperB:
varB = 20
def funB(self):
return 21
pass
obj = Sub()
print(obj.varA, obj.funA())
print(obj.varB, obj.funB())
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
¿Qué crees que sucederá si más de una de las superclases define una entidad con un
nombre en particular?
class Nivel1:
var = 100
def fun(self):
return 101
class Nivel2:
var = 200
def fun(self):
return 201
class Nivel3(Nivel2):
pass
obj = Nivel3()
print(obj.var, obj.fun())
Tanto la clase Nivel1 como la Nivel2 definen un método llamado fun() y una
propiedad llamada var . ¿Significará esto el objeto de la clase Nivel3 podrá acceder a
dos copias de cada entidad? De ningún modo.
200 201
Como puedes ver, la variable de clase var y el método fun() de la clase Nivel2 anula
las entidades de los mismos nombres derivados de la clase Nivel1 .
También podemos decir que Python busca una entidad de abajo hacia arriba, y
está completamente satisfecho con la primera entidad del nombre deseado que
encuentre.
¿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 Izquierda:
var = "I"
varIzquierda = "II"
def fun(self):
return "Izquierda"
class Derecha:
var = "D"
varDerecha = "DD"
def fun(self):
return "Derecha"
pass
obj = Sub()
La clase Sub hereda todos los bienes de dos superclases, Izquierda y Derecha (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á invocado
desde Izquierda o desde Derecha ? Ejecutemos el programa: la salida será:
I II DD Izquierda
Esto prueba que ambos casos poco claros tienen una solución dentro de la
clase Izquierda . ¿Es esta una premisa suficiente para formular una regla general? Sí
lo es.
D II DD Derecha
Si divides un problema entre las clases y decides cuál de ellas debe ubicarse en la
parte superior y cuál debe ubicarse en la parte inferior de la jerarquía, debes analizar
cuidadosamente el problema, pero antes de mostrarte cómo hacerlo (y cómo 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 cómo funcionan algunos códigos y cómo se puede
usar este efecto para construir un conjunto flexible de clases.
class Uno:
def hazlo(self):
print("hazlo de Uno")
def haz_algo(self):
self.hazlo()
class Dos(Uno):
def hazlo(self):
print("hazlo de Dos")
uno = Uno()
dos = Dos()
uno.haz_algo()
dos.haz_algo()
Existen dos clases llamadas Uno y Dos , se entiende que Dos es derivada
de Uno . Nada especial. Sin embargo, algo es notable: el método doit() .
El método doit() está definido dos veces: originalmente dentro de Uno y
posteriormente dentro de Dos . La esencia del ejemplo radica en el hecho de
que es invocado solo una vez - dentro de Uno .
La pregunta es: ¿cuál de los dos métodos será invocado por las dos últimas líneas del
código?
hazlo de Uno
hazlo de Dos
import time
class VehiculoOruga:
pass
def girar(izquierda):
control_de_pista(izquierda, True)
time.sleep(0.25)
control_de_pista(izquierda, False)
class VehiculoTerrestre:
pass
def girar(izquierda):
girar_ruedas_delanteras(izquierda, True)
time.sleep(0.25)
girar_ruedas_delanteras(izquierda, False)
¿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 girar() 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.
class Vehiculo:
pass
def girar(izquierda):
cambiardireccion(izquierda, True)
time.sleep(0.25)
cambiardireccion(izquierda, False)
class VehiculoOruga(Vehiculo):
pass
control_de_pista(izquierda, on)
class VehiculoTerrestre(Vehiculo):
pass
girar_ruedas_delanteras(izquierda, on)
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 girar() , lo cual se puede hacer en un solo lugar, ya que todos
los vehículos lo obedecerán.
import time
class Pistas:
class Ruedas:
class Vehiculo:
self.controlador = controlador
self.controlador.cambiardireccion(izquierda, True)
time.sleep(0.25)
self.controlador.cambiardireccion(izquierda, False)
conRuedas = Vehiculo(Ruedas())
conPistas = Vehiculo(Pistas())
conRuedas.girar(True)
conPistas.girar(False)
Existen dos clases llamadas Pistas y Ruedas - ellas saben cómo controlar la dirección
del vehículo. También hay una clase llamada Vehiculo 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.
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 puede hacer que la anulación sea extremadamente difícil; además, el
emplear la función super() se vuelve ambiguo.
class A:
pass
class B(A):
pass
class C(A):
pass
pass
d = D()
Los diamantes son preciosos y valiosos ... pero no en la programación. Evítalos por tu propio bien.
La primera característica que queremos analizar aquí es una rama adicional posible
que se puede colocar dentro (o más bien, directamente detrás) del bloque try-except:
es la parte del código que comienza con else - justo como el ejemplo en el editor.
0.5
División fallida
None
def reciproco(n):
try:
n=1/n
except ZeroDivisionError:
print("División fallida")
return None
else:
print("Todo salió bien")
return n
print(reciproco(2))
print(reciproco(0))
Nota: estas dos variantes ( else y finally ) no son dependientes entre si, y pueden
coexistir u ocurrir de manera independiente.
def reciproco(n):
try:
n=1/n
except ZeroDivisionError:
print("División fallida")
n = None
else:
finally:
return n
print(reciproco(2))
print(reciproco(0))
Su salida es:
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.
Código:
try:
i = int("Hola!")
except Exception as e:
print(e)
print(e.__str__())
Resultado:
invalid literal for int() with base 10: 'Hola!'
invalid literal for int() with base 10: 'Hola!'
if nest > 1:
if nest > 0:
print(thisclass.__name__)
printExcTree(subclass, nest + 1)
printExcTree(BaseException)
Este programa muestra todas las clases de las excepciónes predefinidas en forma de
árbol.
Comencemos desde la raíz del árbol: la raíz de las clases de excepciónes 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:
Ten en cuenta cómo hemos dibujado las ramas. La impresión no está ordenada de
alguna manera: si deseas un desafío, puedes intentar ordenarla tu 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
Anatomía detallada de las excepciones
Echemos un vistazo más de cerca al objeto de la excepción, ya que hay algunos
elementos realmente interesantes aquí (volveremos al tema pronto cuando
consideremos las técnicas base de entrada y salida de Python, ya que su subsistema
de excepción extiende un poco estos objetos).
Hemos preparado una función simple para imprimir la propiedad args de una
manera elegante, puedes ver la función en el editor.
def printargs(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:
printargs(e.args)
try:
except Exception as e:
print(e, e.__str__(), sep=' : ', end=' : ')
printargs(e.args)
try:
except Exception as e:
printargs(e.args)
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 lanzada 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 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')
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.
class MyZeroDivisionError(ZeroDivisionError):
pass
def doTheDivision(mine):
if mine:
else:
try:
doTheDivision(mode)
except ZeroDivisionError:
try:
doTheDivision(mode)
except MyZeroDivisionError:
print('Mi división entre cero')
except ZeroDivisionError:
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 una rama except (la más general), las
dos últimas invocan dos ramas diferentes, capaces de distinguir las
excepciones (no lo olvides: el orden de las ramas hace una diferencia
fundamental).
Resultado:
class PizzaError(Exception):
def __init__(self, pizza, mensaje):
Exception.__init__(mensaje)
self.pizza = pizza
class DemasiadoQuesoError(PizzaError):
self.queso = queso
class PizzaError(Exception):
Exception.__init__(self, mensaje)
self.pizza = pizza
class DemasiadoQuesoError(PizzaError):
def __init__(self, pizza, queso, mensaje):
self.queso = queso
print("¡Pizza lista!")
try:
makePizza(pz, ch)
Resultado:
¡Pizza lista!
demasiado queso : 110
no hay tal pizza en el menú : mafia
Nota:
El remover la rama que comienza con except DemasiadoQuesoError hará
que todas las excepciones que aparecen se clasifiquen como PizzaError .
El remover la rama que comienza con except PizzaError provocará que la
excepción DemasiadoQuesoError no pueda ser manejada, y hará que el
programa finalice.
class PizzaError(Exception):
Exception.__init__(self, mensaje)
self.pizza = pizza
class DemasiadoQuesoError(PizzaError):
self.queso = queso
raise PizzaError
raise DemasiadoQuesoError
print("¡Pizza lista!")
for (pz, ch) in [('calzone', 0), ('margherita', 110), ('mafia',
20)]:
try:
hacerPizza(pz, ch)
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)
Resultado:
0
1
2
3
4
¿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.
Un generador devuelve una serie de valores, y en general, se invoca (implícitamente)
más de una vez.
__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á lanzar 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:
class Fib:
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
raise StopIteration
return 1
return ret
for i in Fib(10):
print(i)
__init__
__iter__
__next__
__next__
__next__
__next__
__next__
__next__
__next__
13
__next__
21
__next__
34
__next__
55
__next__
Observa:
class Fib:
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
raise StopIteration
return 1
ret = self.__p1 + self.__p2
return ret
class Class:
self.__iter = Fib(n)
def __iter__(self):
print("Class iter")
return self.__iter;
object = Class(8)
for i in object:
print(i)
Hemos puesto 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 .
Resultado:
Class iter
1
1
2
3
5
8
13
21
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.
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.
Podemos decir que dicha función no puede guardar y restaurar su estado en invocaciones
posteriores.
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
def potenciasDe2(n):
potencia = 1
for i in range(n):
yield potencia
potencia *= 2
for v in potenciasDe2(8):
print(v)
1
2
4
8
16
32
64
128
def potenciasDe2(n):
potencia = 1
for i in range(n):
yield potencia
potencia *= 2
t = [x for x in potenciasDe2(5)]
print(t)
def potenciasDe2(n):
potencia = 1
for i in range(n):
yield potencia
potencia *= 2
t = list(potenciasDe2(3))
print(t)
def potenciasDe2(n):
potencia= 1
for i in range(n):
yield potencia
potencia*= 2
for i in range(20):
if i in potenciasDe2(4):
print(i)
Aquí está:
def Fib(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(Fib(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 la comprensión de listas 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.
listaUno = []
for ex in range(6):
listaUno.append(10 ** ex)
print(listaUno)
print(listaDos)
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.
lst = []
for x in range(10):
lst.append(1 if x % 2 == 0 else 0)
print(lst)
Resultado:
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
El código llena una lista con unos y ceros , si el índice de un elemento particular es
impar, el elemento se establece en 0 , y a 1 de lo contrario.
¿Se puede usar el mismo truco dentro de una lista de comprensión? Sí, por supuesto.
print(lst)
for v in lst:
print()
for v in genr:
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
¿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.
print()
print()
En el segundo bucle, no hay ninguna lista, solo hay valores subsequentes producidos
por el generador, uno por uno.
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?
Como de costumbre, un ejemplo será útil. Nuestro ejemplo usa tres funciones lambda , pero con
nombres. Analizalo cuidadosamente:
dos = lambda : 2
cuadrado = lambda x : x * x
potencia = lambda x, y : x ** y
Vamos a analizarlo:
La primer lambda es una función anónima sin parametros 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 parametros y devuelve el valor del primero elevado al
segundo. El nombre de la variable que lleva la lambda habla por si mismo.
El programa produce el siguiente resultado:
4 4
1 1
0 0
1 1
4 4
Este ejemplo es lo suficientemente claro como para mostrar cómo se declaran las
funciones lambda y cómo se comportan, pero no dice nada acerca de por qué son necesarias y para
qué se usan, ya que se pueden reemplazar con funciones de Python de rutina.
for x in args:
def poli(x):
return 2 * x**2 - 4 * x + 2
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 poli() - 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
¿Podemos evitar definir la función poli() , ya que no la vamos a usar más de una vez?
Sí, podemos: este es el beneficio que puede aportar una función lambda.
Permítenos mostrarte otro lugar donde las lambdas pueden ser útiles. Comenzaremos
con una descripción de map() , una función de Python incorporada. Su nombre no es
demasiado descriptivo, su idea es simple y la función en sí es muy utilizable.
Lambdas y la función map()
En el más simple de todos los casos posibles, la función map() toma dos argumentos:
Una función.
Una lista.
map(función, lista)
El segundo argumento map() puede ser cualquier entidad que se pueda iterar
(por ejemplo, una tupla o un generador).
map() puede aceptar más de dos argumentos.
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 posteriores. Puedes usar el iterador resultante en un
bucle o convertirlo en una lista usando la función list() .
print(lista2)
print()
Resultado:
[1, 2, 4, 8, 16]
1 4 16 64 256
Esta es la explicación:
Lambdas y la función filter()
Otra función de Python que se puede embellecer significativamente mediante la
aplicación de una lambda es filter() .
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 regresan True de la función pasan el filtro - los otros son
rechazados.
seed()
print(data)
print(filtered)
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]
def exterior(par):
loc = par
var = 1
exterior(var)
print(var)
print(loc)
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.
def exterior(par):
loc = par
def interior():
return loc
return interior
var = 1
fun = exterior(var)
print(fun())
def exterior(par):
loc = par
def interior():
return loc
return interior
var = 1
fun = exterior(var)
print(fun()))
La función interior() no tenía parámetros, por lo que tuvimos que invocarla sin
argumentos.
def crearcierre(par):
loc = par
def potencia(p):
return p ** loc
return potencia
fsqr = crearcierre(2)
fcub = crearcierre(3)
for i in range(5):
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 crearcierre() . Nota:
El primer cierre obtenido de crearcierre() define una herramienta que eleva
al cuadrado su argumento.
El segundo está diseñado para elevar el argumento al cubo.
0 0 0
1 1 1
2 4 8
3 9 27
4 16 64
Es fácil imaginar un programa que clasifique 20 números, y es igualmente fácil imaginar que el
usuario de este programa ingrese estos veinte números directamente desde el teclado.
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í.
Si queremos implementar una base de datos simple, la única forma de almacenar la información
entre ejecuciones del programa es guardarla en un archivo (o archivos si tu base de datos es más
compleja).
Puedes preguntarte por qué hemos esperado hasta ahora para mostrarte esto.
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.
Nombres de archivos
Los diferentes sistemas operativos pueden tratar a los archivos de diferentes maneras. Por ejemplo,
Windows usa una convención de nomenclatura diferente a la adoptada en los sistemas Unix/Linux.
Si utilizamos la noción de un nombre de archivo canónico (un nombre que define de forma exclusiva
la ubicación del archivo, independientemente de su nivel en el árbol de directorios), podemos darnos
cuenta de que estos nombres se ven diferentes en Windows y en Unix/Linux:
Como puedes ver, los sistemas derivados de Unix/Linux no usan la letra de la unidad de disco (p.
Ejemplo, C: ) y todos los directorios crecen desde un directorio raíz llamado / , mientras que los
sistemas Windows reconocen el directorio raíz como \ .
Además, los nombres de archivo de sistemas Unix/Linux distinguen entre mayúsculas y minúsculas.
Los sistemas Windows almacenan mayúsculas y minúsculas en el nombre del archivo, pero no
distinguen entre ellas.
EsteEsElNombreDelArchivo
y
esteeselnombredelarchivo
describen dos archivos diferentes en sistemas Unix/Linux, pero tienen el mismo nombre para un solo
archivo en sistemas Windows.
La diferencia principal y más llamativa es que debes usar dos separadores diferentes para los
nombres de directorio: \ en Windows y / en Unix/Linux.
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.
Nombres de Archivo: continuación
Supongamos que estás interesado en un archivo en particular ubicado en el directorio dir, y con el
nombre de archivo.
Supongamos también que deseas asignar a una cadena el nombre del archivo.
nombre = "/dir/archivo"
nombre = "\dir\archivo"
obtendrás una sorpresa desagradable: Python generará un error o la ejecución del programa se
comportará de manera extraña, como si el nombre del archivo se hubiera distorsionado de alguna
manera.
De hecho, no es extraño en lo absoluto, pero es bastante obvio y natural. Python usa la \ como un
caracter de escape (como \n ).
Esto significa que los nombres de archivo de Windows deben escribirse de la siguiente manera:
nombre = "\\dir\\archivo"
Afortunadamente, también hay una solución más. Python es lo suficientemente inteligente como
para poder convertir diagonales en diagonales invertidas cada vez que descubre que el sistema
operativo lo requiere.
nombre = "/dir/archivo"
nombre = "c:/dir/archivo"
Cualquier programa escrito en Python (y no solo en Python, porque esa convención se aplica a
prácticamente todos los lenguajes de programación) no se comunica con los archivos directamente,
sino a través de algunas entidades abstractas que se nombran de manera diferente en los distintos
lenguajes o entornos, los términos más utilizados son handles (un tipo de puntero
inteligente) o streams (una especie de canal) (los usaremos como sinónimos aquí).
El programador, que tiene un conjunto de funciones y métodos, puede realizar ciertas operaciones en
el stream, que afectan los archivos reales utilizando mecanismos contenidos en el núcleo del sistema
operativo.
De esta forma, puedes implementar el proceso de acceso a cualquier archivo, incluso cuando el
nombre del archivo es desconocido al momento de escribir el programa.
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.
Por lo tanto, la conclusión es que la primera operación realizada en el stream es siempre open
(abrir) y la ultima es close (cerrar) . El programa, en efecto, es libre de manipular el
stream entre estos dos eventos y manejar el archivo asociado.
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).
Un programa bien escrito debe detectar estas aperturas fallidas y reaccionar en consecuencia.
Streams para Archivos
La apertura del stream no solo está asociada con el archivo, sino que también se debe declarar la
manera en que se procesará el stream. Esta declaración se llama un open mode (modo abierto).
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.
Antes de discutir cómo manipular los streams, te debemos una explicación. El stream se comporta
casi como una grabadora.
Cuando lees algo de un stream, un cabezal virtual se mueve sobre la transmisión de acuerdo con el
número de bytes transferidos desde el stream.
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.
Ahora es necesario mostrarte el objeto responsable de representar los streams en los programas.
Manejo de Archivos
Python supone que cada archivo está oculto detrás de un objeto de una clase adecuada.
Los archivos se pueden procesar de muchas maneras diferentes: algunos dependen del contenido del
archivo, otros de las intenciones del programador.
Un objeto de una clase adecuada es creado cuando abres el archivo y lo aniquilas al momento de
cerrarlo.
Entre estos dos eventos, puedes usar el objeto para especificar qué 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.
Para nuestros propósitos, solo nos ocuparemos de los streams representados por los
objetos BufferIOBase y TextIOBase . Entenderás por qué pronto.
Los streams de texto están estructurados en líneas; es decir, contienen caracteres tipográficos (letras,
dígitos, signos de puntuación, etc.) dispuestos en filas (líneas), como se ve a simple vista cuando se
mira el contenido del archivo en el editor.
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 .
Esta ambigüedad puede causar varias consecuencias desagradables.
Si creas un programa responsable de procesar un archivo de texto y está escrito para Windows,
puedes reconocer los extremos de las líneas al encontrar los caracteres \r\n , pero si el mismo
programa se ejecuta en un entorno Unix/Linux será completamente inútil, y viceversa: el programa
escrito para sistemas Unix/Linux podría ser inútil en Windows.
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 caracter \
n , y viceversa; durante las operaciones de escritura, cada caracter \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:
Nota: el modo y los argumentos de codificación pueden omitirse; en dado caso, se tomarán sus
valores predeterminados. El modo de apertura predeterminado es leer en modo de texto, mientras
que la codificación predeterminada depende de la plataforma utilizada.
Permítenos ahora presentarte los modos de apertura más importantes y útiles. ¿Listo?
Abriendo los streams: modos
Modo de apertura r : lectura
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() lanzará una excepción.
¿Cómo abrir ese archivo para leerlo? Aquí está el fragmento del código:
try:
stream.close()
Hemos abierto el bloque try-except ya que queremos manejar los errores de tiempo de
ejecución suavemente.
Se emplea la función open() para intentar abrir el archivo especificado (ten en cuenta la
forma en que hemos especificado el nombre del archivo).
El modo de apertura se define como texto para leer (como texto es la configuración
predeterminada, podemos omitir la t en la cadena de modo).
En caso de éxito obtenemos un objeto de la función open() y lo asignamos a la variable
del stream.
Si open() falla, manejamos la excepción imprimiendo la información completa del error
(es bueno saber qué sucedió exactamente).
Streams pre-abiertos
Dijimos anteriormente que cualquier operación del stream debe estar precedida por la invocación de
la función open() . Hay tres excepciones bien definidas a esta regla.
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.
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 búferes 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:
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, operar un stream sin abrirlo.
El error se produce cuando intentas, por ejemplo, cambiar el nombre de un archivo con su nombre
anterior.
El error ocurre cuando intentas crear un archivo que es más grande que el máximo permitido por el
sistema operativo.
El error se produce cuando intentas tratar un nombre de directorio como el nombre de un archivo
ordinario.
El error se produce cuando intentas abrir simultáneamente más streams de los aceptables para el
sistema operativo.
La lista completa es mucho más larga (incluye también algunos códigos de error no relacionados con
el procesamiento del stream).
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:
else:
Su función es simple: proporciona un número de error y una cadena que describe el significado del
error.
Nota: Si pasas un código de error inexistente (un número que no está vinculado a ningún error real),
la función lanzará una excepción ValueError.
try:
s = open("c:/users/user/Desktop/file.txt", "rt")
# el procesamiento va aquí
s.close()
Bueno. Ahora es el momento de tratar con archivos de texto y familiarizarse con algunas técnicas
básicas que puedes utilizar para procesarlos.
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.
Es por eso que debes evitar crear el archivo utilizando un procesador de texto
avanzado como MS Word, LibreOffice Writer o algo así. Utiliza los conceptos básicos
que ofrece tu sistema operativo: Bloc de notas, vim, gedit, etc.
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:
INFORMACIÓ N
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:
cnt = 0
s = open('text.txt', "rt")
ch = s.read(1)
while ch != '':
print(ch, end='')
cnt += 1
ch = s.read(1)
s.close()
Resultado:
Recuerda - el leer un archivo muy grande (en terabytes) usando este método
puede dañar tu sistema operativo.
try:
cnt = 0
s = open('text.txt', "rt")
content = s.read()
for ch in content:
print(ch, end='')
cnt += 1
ch = s.read(1)
s.close()
except IOError as e:
Vamos a analizarlo:
Resultado:
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.
try:
ccnt = lcnt = 0
s = open('text.txt', 'rt')
line = s.readline()
lcnt += 1
for ch in line:
print(ch, end='')
ccnt += 1
line = s.readline()
s.close()
except IOError as e:
Como puedes ver, la idea general es exactamente la misma que en los dos ejemplos
anteriores.
Resultado:
s = open("text.txt")
print(s.readlines(20))
print(s.readlines(20))
print(s.readlines(20))
print(s.readlines(20))
s.close()
Resultado:
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.
try:
ccnt = lcnt = 0
s = open('text.txt', 'rt')
lines = s.readlines(20)
while len(lines) != 0:
lcnt += 1
for ch in line:
print(ch, end='')
ccnt += 1
lines = s.readlines(10)
s.close()
except IOError as e:
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.
Resultado:
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Creemos que puede sorprenderte - el objeto es una instancia de la clase iterable.
try:
ccnt = lcnt = 0
lcnt += 1
for ch in line:
print(ch, end='')
ccnt += 1
except IOError as e:
No se agrega carácter de nueva línea al argumento de write() , por lo que debes
agregarlo tu mismo si deseas que el archivo se complete con varias líneas.
try:
for i in range(10):
for ch in s:
fo.write(ch)
fo.close()
except IOError as e:
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
try:
fo = open('newtext.txt', 'wt')
for i in range(10):
fo.close()
except IOError as e:
print("Se produjo un error de E/S: ", strerr(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")
¿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.
Los datos amorfos no pueden almacenarse utilizando ninguno de los medios presentados
anteriormente: no son cadenas ni listas.
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(100)
Bytearrays: continuación
Bytearrays se asemejan a listas en muchos aspectos. Por ejemplo, son mutables, son
suceptibles 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).
data = bytearray(10)
for i in range(len(data)):
data[i] = 10 - i
for b in data:
print(hex(b))
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.
Resultado:
0xa
0x9
0x8
0x7
0x6
0x5
0x4
0x3
0x2
0x1
Bytearrays: continuación
Entonces, ¿cómo escribimos un arreglo de bytes en un archivo binario?
for i in range(len(data)):
data[i] = 10 + i
try:
bf = open('file.bin', 'wb')
bf.write(data)
bf.close()
except IOError as e:
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:
bf = open('file.bin', 'rb')
bf.readinto(data)
bf.close()
for b in data:
except IOError as e:
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?
Ejecuta el código y verifica si funciona.
Esta clase tiene algunas similitudes con bytearray , con la excepción de una diferencia
significativa: es immutable.
try:
bf = open('file.bin', 'rb')
data = bytearray(bf.read())
bf.close()
for b in data:
except IOError as e:
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.
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.
Puedes usar el método como aquí:
try:
bf = open('file.bin', 'rb')
data = bytearray(bf.read(5))
bf.close()
for b in data:
except IOError as e:
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.
try:
except IOError as e:
exit(e.errno)
dstname = input("¿Nombre del archivo de destino?: ")
try:
except Exception as e:
src.close()
exit(e.errno)
buffer = bytearray(65536)
total = 0
try:
readin = src.readinto(buffer)
written = dst.write(buffer[:readin])
total += written
readin = src.readinto(buffer)
except IOError as e:
exit(e.errno)
src.close()
dst.close()
LABORATORIO
Tiempo Estimado
30 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
b -> 1
c -> 1
Tip:
LABORATORIO
Tiempo Estimado
15-20 minutos
Nivel de dificultad
Medio
Prerrequisitos
05_9.15.1
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
b -> 2
c -> 1
Tip:
LABORATORIO
Tiempo Estimado
30 minutos
Nivel de dificultad
Medio
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 autodefinidos.
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
John Smith 2
Anna Boleyn 11
Nota:
class ExcepcionDatosAlumnos(Exception):
pass
class LineaErronea(ExcepcionDatosAlumnos):
# coloca tu código aquí
class ArchivoVacio(ExcepcionDatosAlumnos):
# coloca tu código aquí