Está en la página 1de 500

PROGRAMACIÓN PRÁCTICA

PARA PRINCIPIANTES TOTALES


ALSWEIGART
AUTOMATIZAR
LA COSA
CONPYTHON
SHELVE IN:
PROGRAMA
M
ING idiomas /
PITÓN
$ 29.95 ($ 34.95 CDN)
www.nostarch.com TH EFIN
EST INGEEKE NTE RTA INME NT ™
Si alguna vez pasó horas cambiando el nombre de los archivos o actualizando
cientos de celdas de hojas de cálculo, sabe lo tediosas
que pueden ser estas tareas. Pero, ¿y si pudieras hacer que
tu computadora los haga por ti?
minutos, lo que le llevaría horas hacer a mano:
aprenda a usar Python para escribir programas que se hacen en
In Automate the Boring Stuff with Python ,
No se requiere experiencia previa en programación. Una vez
cree programas de Python que sin esfuerzo realicen
hazañas de automatización útiles e impresionantes para:
" ILIEF LAT".
Este libro usa una leyenda duradera que no se cerrará de golpe.
has dominado los conceptos básicos de programación, podrás
• Buscar texto en un archivo o en varios archivos
• Crear, actualizar, mover y renombrar archivos y
carpetas
• Buscar en la Web y descargar contenido en línea
• Actualizar y formatear datos en hojas de cálculo de Excel
de cualquier tamaño
No pierdas tu tiempo haciendo un trabajo que un mono bien entrenado
podría hacer. Incluso si nunca has escrito una línea
• Enviar correos electrónicos de recordatorio y notificaciones de texto
• Completar formularios en línea
Las instrucciones paso a paso lo guiarán a través de cada
programa y los proyectos de práctica al final de cada
capítulo lo desafiarán a mejorar esos programas y
utilizar sus nuevas habilidades para automatizar tareas similares.
• Divide, fusiona, marca de agua y encripta archivos PDF
GETSTUFFDONE.
APRENDIZAJE
COVERSPYTHON 3
de código, puede hacer que su computadora haga el trabajo duro.
Aprenda cómo en Automatizar las cosas aburridas con Python .
Libros de Python para principiantes, incluido Hacking Secret
SOBRE EL AUTOR
Al Sweigart es un desarrollador de software y enseña programación
a niños y adultos. Ha escrito varios
Cifra con Python , inventa tus propios juegos de computadora
con Python y crea juegos con Python y Pygame.
SFI-00000
Automatiza las cosas aburridas
con Python
A utom A tethe
B oring S
toff con P ython
P roctical P rogramming
Fortotal B eginners
por Al Sweigart
San Francisco
Automatiza las cosas aburridas con Python. Copyright © 2015 por Al Sweigart.
Todos los derechos reservados. Ninguna parte de este trabajo puede ser reproducida o transmitida
de ninguna forma o por ningún medio,
electrónico o mecánico, incluida la fotocopia, grabación o cualquier sistema de almacenamiento o
recuperación de información
, sin el permiso previo por escrito del propietario de los derechos de autor y el editor.
Impreso en EE. UU.
Tercera impresión
19 18 17 16 15 3 4 5 6 7 8 9
ISBN-10: 1-59327-599-4
ISBN-13: 978-1-59327-599-0
Editor: William Pollock
Editor de producción: Laurel Chun
Ilustración de portada: Josh Ellingson
Diseño de interiores: Octopod Studios
Editores de desarrollo: Jennifer Griffith-Delgado, Greg Poulos y Leslie Shen
Revisor técnico: Ari Lacenski Redactor
: Kim Wimpsett
Compositor: Susan Glinert Stevens
Corrector de pruebas: Lisa Devoto Farrell
Indexador: BIM Indexing and Proofreading Services
Para obtener información sobre distribución, traducciones o ventas al por mayor,
comuníquese directamente con No Starch Press, Inc.:
No Starch Press, Inc.
245 8th Street, San Francisco, CA 94103
teléfono: 415.863.9900; info@nostarch.com
www.nostarch.com
Número de control de la Biblioteca del Congreso: 2014953114
No Starch Press y el logotipo de No Starch Press son marcas registradas de No Starch Press, Inc.
Otros
nombres de productos y compañías mencionados aquí pueden ser marcas comerciales de sus
respectivos propietarios En lugar
de usar un símbolo de marca registrada con cada aparición de un nombre de marca registrada,
estamos usando los nombres solo
de forma editorial y para beneficio del propietario de la marca registrada, sin intención de infringir
la
marca registrada.
La información en este libro se distribuye "tal cual", sin garantía. Si bien
se han tomado todas las precauciones en la preparación de este trabajo, ni el autor ni No Starch
Press, Inc. serán
responsables ante ninguna persona o entidad con respecto a cualquier pérdida o daño causado o
presuntamente causado directamente o
indirectamente por el información contenida en el mismo.
Este trabajo está licenciado bajo la Licencia Creative Commons Reconocimiento-NoComercial-
CompartirIgual 3.0 Estados
Unidos. Para ver una copia de esta licencia, visite http://creativecommons.org/licenses/by-nc-
sa/3.0/us/
o envíe una carta a Creative Commons, PO Box 1866, Mountain View, CA 94042, EE. UU.
SFI-00000
Para mi sobrino Jack
Sobre el autor
Al Sweigart es un desarrollador de software y autor de libros tecnológicos que vive en San
Francisco. Python es su lenguaje de programación favorito, y es el
desarrollador de varios módulos de código abierto para ello. Sus otros libros están
disponibles gratuitamente bajo una licencia Creative Commons en su sitio web http: // www
.inventwithpython.com / . Su gato pesa 14 libras.
Acerca del crítico técnico
Ari Lacenski es un desarrollador de aplicaciones de Android y software de Python.
Ella vive en San Francisco, donde escribe sobre la programación de Android en
http://gradlewhy.ghost.io/ y es mentora de Women Who Code. Ella también es un
guitarrista popular.

Contenidos breves
Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
Introducción. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
PARTE I: BASES DE PROGRAMACIÓN DE PITON. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Capítulo 1: Conceptos básicos de
Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Capítulo 2: Control de flujo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Capítulo 3: Funciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Capítulo 4: Listas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Capítulo 5: Diccionarios y estructuración de datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Capítulo 6: Manipulación de cuerdas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
PARTE II: TAREAS DE
AUTOMATIZACIÓN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Capítulo 7: Coincidencia de patrones con expresiones
regulares. . . . . . . . . . . . . . . . . . . . . . . . . . 147
Capítulo 8: Lectura y escritura de archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Capítulo 9: Organización de archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Capítulo 10: Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Capítulo 11: Desguace web. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Capítulo 12: Trabajar con hojas de cálculo de Excel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Capítulo 13: Trabajar con documentos PDF y Word. . . . . . . . . . . . . . . . . . . . . . . . . . 295
Capítulo 14: Trabajo con archivos CSV y datos JSON. . . . . . . . . . . . . . . . . . . . . . . . . . 319
Capítulo 15: Mantener el tiempo, programar tareas y ejecutar programas. . . . . . . . . . . . . . 335
Capítulo 16: Envío de correos electrónicos y mensajes de
texto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
Capítulo 17: Manipulación de imágenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
Capítulo 18: Control del teclado y el mouse con la automatización de la GUI. . . . . . . . . . . . . 413
Apéndice A: Instalación de módulos de terceros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
Apéndice B: Programas en ejecución. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
Apéndice C: Respuestas a las preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
Índice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
C ontenido S en D et A il
Agradecimientos xxiii
introducción 1
¿Para quién es este libro? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
convenciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
¿Qué es la programación? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
¿Qué es python? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Los
programadores no necesitan saber mucho de matemáticas. . . . . . . . . . . . . . . . . . . . . . . . 4 La
programación es una actividad creativa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5
Sobre este libro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Descarga e instalación de Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Iniciando IDLE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7
La cáscara interactiva. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Cómo encontrar ayuda. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Hacer preguntas de programación inteligente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Resumen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
PARTE i: Conceptos básicos de programación
de
Python 11 1 Conceptos básicos de Python 13
Introducción de expresiones en el Shell interactivo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Tipos de datos de enteros, de punto flotante y de cadena. . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Concatenación y replicación de cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Almacenamiento de valores en variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
años
Declaraciones de asignación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Nombres de variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Tu primer programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Disección de su programa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
La función print (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
La función input (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Impresión del nombre del usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
La función len (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Las funciones str (), int () y float (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2
control de flujo 31
valores booleanos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Operadores de comparación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
operadores booleanos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
x Contenido en detalle
Operadores booleanos binarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
El no operador. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Mezcla de operadores booleanos y de comparación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Elementos de control de flujo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Condiciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
bloques de código. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Ejecución del programa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Declaraciones de control de flujo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
si declaraciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
declaraciones más. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
declaraciones elif. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
mientras que las declaraciones de bucle. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
declaraciones de descanso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
continúan declaraciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
para Loops y la función range (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Importando Módulos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
de declaraciones de importación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Finalización temprana de un programa con sys .exit
(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Resumen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3
funciones
S 61 def Declaraciones con parámetros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Valores de retorno y declaraciones de retorno. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
El valor ninguno. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Argumentos de palabras clave e impresión (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Alcance local y global. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Las variables locales no se pueden usar en el ámbito global. . . . . . . . . . . . . . . . . . 67
Los ámbitos locales no pueden usar variables en otros ámbitos locales. . . . . . . . . . . . . . . 68
Las variables globales se pueden leer desde un ámbito local. . . . . . . . . . . . . . . . . . . . 69
Variables locales y globales con el mismo nombre. . . . . . . . . . . . . . . . . . . . . 69
La declaración global. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Manejo de excepciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Un programa corto: adivina el número. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Resumen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
La secuencia de Collatz. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Validación de entrada. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4
LISTAS 79
El tipo de datos de la lista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Obtención de valores individuales en una lista con índices. . . . . . . . . . . . . . . . . . . . . . . 80
índices negativos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Obtención de sublistas con sectores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Obtención de la longitud de una lista con len (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Cambio de valores en una lista con índices. . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Contenido en detalle xi
Concatenación de listas y replicación de listas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Eliminación de valores de listas con declaraciones del. . . . . . . . . . . . . . . . . . . . . . . 84
Trabajando con listas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Uso de bucles con listas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Los operadores en y no en. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
El truco de la asignación múltiple. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Operadores de asignación aumentada. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
métodos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Encontrar un valor en una lista con el método index (). . . . . . . . . . . . . . . . . . . . . 89
Agregar valores a las listas con los métodos append () e insert (). . . . . . . . . . . . 89
Eliminación de valores de las listas con remove (). . . . . . . . . . . . . . . . . . . . . . . . . . 90
Ordenar los valores en una lista con el método sort (). . . . . . . . . . . . . . . . . . . . . 91 91
Programa de ejemplo: Magic 8 Ball con una lista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Tipos de lista: cadenas y tuplas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Tipos de datos mutables e inmutables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
El tipo de datos Tuple. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Conversión de tipos con las funciones list () y tuple (). . . . . . . . . . . . . . . . . . . 97
Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Referencias pasajeras. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
La copia Funciones del módulo copy () y deepcopy (). . . . . . . . . . . . . . . . . . 100
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Código de coma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Cuadrícula de imagen de personaje. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5
dicciones y estructura dAtA 105
El tipo de datos del diccionario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Diccionarios vs. Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Las teclas (), los valores () y los elementos () Métodos. . . . . . . . . . . . . . . . . . . . . . . . . . 107
Comprobación de si existe una clave o un valor en un diccionario. . . . . . . . . . . . . . . 109
El método get (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
El método setdefault (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Bonita impresión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Uso de estructuras de datos para modelar cosas del mundo real. . . . . . . . . . . . . . . . . . . . . . . . . . 112
Un tablero de tres en raya. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Diccionarios y listas anidados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Inventario de juegos de fantasía. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Función List to Dictionary para Fantasy Game Inventory. . . . . . . . . . . . . . . . . 120
6
MAnPULAting StringS 123
Trabajar con cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Literales de cuerda. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Indexación y corte de cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Los operadores con y sin cadenas con cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . 127
xii Contenido en detalle
Métodos de cadena útiles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Los métodos de cadena upper (), lower (), isupper () e islower (). . . . . . . . . . . . 128
Los métodos de cadena isX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Los métodos de cadena comienza con () y termina con (). . . . . . . . . . . . . . . . . . . . . . 131
Los métodos de cadena join () y split (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Justificación del texto con rjust (), ljust () y center (). . . . . . . . . . . . . . . . . . . . . . . 133
Eliminación de espacios en blanco con strip (), rstrip () y lstrip (). . . . . . . . . . . . . . . . . 134
Copiar y pegar cadenas con el módulo pyperclip. . . . . . . . . . . . . . . . 135
Proyecto: Contraseña Locker. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Paso 1: Diseño del programa y estructuras de datos. . . . . . . . . . . . . . . . . . . . . . . 136
Paso 2: manejar los argumentos de la línea de comandos. . . . . . . . . . . . . . . . . . . . . . . . . 137
Paso 3: Copie la contraseña correcta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Proyecto: Agregar viñetas al marcado de Wiki. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Paso 1: copiar y pegar desde el portapapeles. . . . . . . . . . . . . . . . . . . . . . . . 139
Paso 2: Separe las líneas de texto y agregue la estrella. . . . . . . . . . . . . . . . . . 140
Paso 3: Unir las líneas modificadas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Proyecto de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Impresora de mesa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
PARTE II: TAREAS DE AUTOMATIZACIÓN 145
7
EMPAREJAMIENTO DE PATRONES CON EXPOSICIONES REGULARES 147
Búsqueda de patrones de texto sin expresiones regulares. . . . . . . . . . . . . . . . . . . . . . . . 148
Búsqueda de patrones de texto con expresiones regulares. . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Creación de objetos Regex. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
objetos de expresiones regulares coincidentes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Revisión de la coincidencia de expresiones regulares. . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Más coincidencia de patrones con expresiones regulares. . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Agrupación con paréntesis. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Emparejamiento de múltiples grupos con la tubería. . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Coincidencia opcional con el signo de interrogación. . . . . . . . . . . . . . . . . . . . . . . . 154
Coincidencia de cero o más con la estrella. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Combinando uno o más con el Plus. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
repeticiones específicas coincidentes con llaves. . . . . . . . . . . . . . . . . . . . 156
Emparejamiento codicioso y no codicioso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
El método findall (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
clases de personajes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Haciendo sus propias clases de personajes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Los personajes Caret y Dollar Sign. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
El personaje comodín. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Combinando todo con Dot-Star. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Nuevas líneas coincidentes con el personaje de punto. . . . . . . . . . . . . . . . . . . . . . . . 162
Revisión de los símbolos de expresiones
regulares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Coincidencia de mayúsculas y minúsculas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Contenido en detalle xiii
Sustituir cadenas con el método sub (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Gestión de expresiones regulares complejas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Combinando re .IGNORECASE, re .DOTALL y re .VERBOSE. . . . . . . . . . . . . . . . . . . 164
Proyecto: Extractor de número de teléfono y dirección de correo
electrónico. . . . . . . . . . . . . . . . . . . . . . . . 165
Paso 1: Crea una expresión regular para números de teléfono. . . . . . . . . . . . . . . . . . . . . . . . 166
Paso 2: Cree una expresión regular para direcciones de correo
electrónico. . . . . . . . . . . . . . . . . . . . . . . . 166
Paso 3: Buscar todas las coincidencias en el texto del portapapeles. . . . . . . . . . . . . . . . . . . . . . 167
Paso 4: Une las coincidencias en una cadena para el portapapeles. . . . . . . . . . . . . . . . 168
Ejecución del programa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Detección de contraseña segura. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Versión Regex de strip (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
8
lectura y escritura de archivos 173
Archivos y rutas de archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Backslash en Windows y Forward Slash en OS X y Linux. . . . . . . . . . . 174
El directorio de trabajo actual. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Absoluto vs. Caminos relativos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Creación de nuevas carpetas con os .makedirs (). . . . . . . . . . . . . . . . . . . . . . . . . . 176
El módulo os .path. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Manejo de rutas absolutas y relativas. . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Búsqueda de tamaños de archivo y contenido de carpeta. . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Comprobación de la validez de la ruta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
El proceso de lectura / escritura de archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Apertura de archivos con la función open (). . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Lectura del contenido de los archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Escritura en archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Guardar variables con el módulo de estantería. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Guardar variables con la función pprint .pformat (). . . . . . . . . . . . . . . . . . . . . . . . . 185
Proyecto: Generación de archivos de prueba
aleatorios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Paso 1: Almacene los datos de la prueba en un diccionario. . . . . . . . . . . . . . . . . . . . . . . . 187
Paso 2: Cree el archivo de prueba y baraje el orden de las preguntas. . . . . . . . . . . . 188
Paso 3: Cree las opciones de respuesta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Paso 4: Escribir contenido en el cuestionario y responder archivos clave. . . . . . . . . . . . . . . 189
Proyecto: Multiclipboard. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Paso 1: Comentarios y configuración de estante. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Paso 2: Guardar el contenido del portapapeles con una palabra clave. . . . . . . . . . . . . . . . . . . . 192
Paso 3: Listar palabras clave y cargar el contenido de una palabra clave. . . . . . . . . . . . . . . . . 193
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Extendiendo el Multiclipboard. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Mad Libs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Búsqueda de expresiones regulares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
xiv Contenido en detalle
9
orgAnizing fileS 197
El módulo shutil. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
Copiar archivos y carpetas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
Mover y renombrar archivos y carpetas. . . . . . . . . . . . . . . . . . . . . . . . . . 199
Eliminación permanente de archivos y carpetas. . . . . . . . . . . . . . . . . . . . . . . . . . . 200
eliminaciones seguras con el módulo send2trash. . . . . . . . . . . . . . . . . . . . . . . . . . 201
Caminando por un árbol de directorios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Comprimir archivos con el módulo zipfile. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Lectura de archivos ZIP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Extracción de archivos ZIP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Creación y adición de archivos ZIP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Proyecto: Cambiar el nombre de archivos con fechas de estilo americano a fechas de estilo
europeo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Paso 1: Crea una expresión regular para fechas de estilo americano. . . . . . . . . . . . . . . . . . . . 206
Paso 2: Identifique las partes de fecha a partir de los nombres de
archivo. . . . . . . . . . . . . . . . . . . . 207
Paso 3: Forme el nuevo nombre de archivo y cambie el nombre de los
archivos. . . . . . . . . . . . . . . . . 209
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Proyecto: Copia de seguridad de una carpeta en un archivo
ZIP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Paso 1: Calcule el nombre del archivo ZIP. . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Paso 2: Cree el nuevo archivo ZIP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Paso 3: recorra el árbol de directorios y agregue al archivo ZIP. . . . . . . . . . . . . . . 211
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Copia selectiva. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Eliminación de archivos innecesarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Rellenar los vacíos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
10
deBugging 215
Aumento de excepciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Obteniendo el rastreo como una cadena. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Afirmaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Uso de una aserción en una simulación de semáforo. . . . . . . . . . . . . . . . . . . . . . 219
Desactivar afirmaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Inicio sesión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Uso del módulo de registro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
No depure con print (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
niveles de registro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Deshabilitar el registro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Registro en un archivo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Depurador de IDLE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Go. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
paso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
más. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
fuera. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Contenido en detalle xv
Dejar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Depuración de un programa de suma de números. . . . . . . . . . . . . . . . . . . . . . . . . . . 227
puntos de interrupción. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Proyecto de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Depuración de lanzamiento de moneda. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
11 Proyecto
weB ScrAPing 233
: mapIt .py con el módulo webbrowser. . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Paso 1: descifrar la URL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Paso 2: Manejar los argumentos de la línea de comando. . . . . . . . . . . . . . . . . . . . . . 235
Paso 3: Maneje el contenido del portapapeles e inicie el navegador. . . . . . . . . . 236
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
Descarga de archivos de la Web con el módulo de solicitudes. . . . . . . . . . . . . . . . . . . . 237
Descarga de una página web con la función request .get (). . . . . . . . . . . . . 237
Comprobación de errores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
Guardar archivos descargados en el disco duro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
HTML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
Recursos para aprender HTML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
A Actualización rápida. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
Visualización del código fuente HTML de una página web. . . . . . . . . . . . . . . . . . . . . . . . . 241
Apertura de las herramientas de desarrollo de su navegador. . . . . . . . . . . . . . . . . . . . . . . . . . 242
Uso de las herramientas de desarrollador para encontrar elementos
HTML. . . . . . . . . . . . . . . . . . . . 244
Analizando HTML con el Módulo BeautifulSoup. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Creación de un objeto BeautifulSoup a partir de HTML. . . . . . . . . . . . . . . . . . . . . . . . 245
Encontrar un elemento con el método select (). . . . . . . . . . . . . . . . . . . . . . . . 246
Obtención de datos de los atributos de un elemento. . . . . . . . . . . . . . . . . . . . . . . . . 248
Proyecto: Búsqueda de Google "Me siento afortunado". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
Paso 1: Obtenga los argumentos de la línea de comando y solicite la página de búsqueda. . . . 249
Paso 2: Encuentre todos los resultados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
Paso 3: Abra los navegadores web para cada resultado. . . . . . . . . . . . . . . . . . . . . . . 250
ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Proyecto: Descargando todos los cómics de XKCD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Paso 1: Diseñe el programa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
Paso 2: Descargue la página web. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Paso 3: Encuentra y descarga la imagen cómica. . . . . . . . . . . . . . . . . . . . . . 254
Paso 4: Guarde la imagen y encuentre el cómic anterior. . . . . . . . . . . . . . . . . 255
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Control del navegador con el módulo de selenio. . . . . . . . . . . . . . . . . . . . . . . . . . 256
Inicio de un navegador controlado por selenio. . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Encontrar elementos en la página. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Al hacer clic en la página. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 Cómo
llenar y enviar formularios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Envío de llaves especiales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
Hacer clic en los botones del navegador. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Más información sobre selenio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
xvi Contenido en detalle
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Línea de comando Emailer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Image Site Downloader. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
2048. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Verificación de enlace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
12
trabajando con Excel SPreAdSheetS 265
documentos de Excel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
Instalación del módulo openpyxl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
Lectura de documentos de Excel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
Abrir documentos de Excel con OpenPyXL. . . . . . . . . . . . . . . . . . . . . . . . . 267
Obteniendo hojas del libro de trabajo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
Obteniendo células de las hojas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
Conversión entre letras y números de columna. . . . . . . . . . . . . . . . . . . . 270
Obtención de filas y columnas de las hojas. . . . . . . . . . . . . . . . . . . . . . . . 270
libros de trabajo, hojas, celdas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Proyecto: Lectura de datos de una hoja de cálculo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Paso 1: Lea los datos de la hoja de cálculo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Paso 2: llenar la estructura de datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Paso 3: Escriba los resultados en un archivo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
Redacción de documentos Excel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Crear y guardar documentos de Excel. . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Creación y eliminación de hojas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Escribir valores en celdas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Proyecto: Actualización de una hoja de cálculo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
Paso 1: Configure una estructura de datos con la información de actualización. . . . . . . . . . . . 280
Paso 2: Verifique todas las filas y actualice los precios incorrectos. . . . . . . . . . . . . . . . . . 281
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Establecer el estilo de fuente de las celdas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
Objetos de fuente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
Fórmulas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
Ajuste de filas y columnas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Configuración de altura de fila y ancho de columna. . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Fusión y fusión de celdas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
paneles de congelación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Gráficos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
Resumen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Multiplication Table Maker. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Insertador de fila en blanco. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Inversor de celda de hoja de cálculo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Archivos de texto a hoja de cálculo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
Hoja de cálculo para archivos de texto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
Contenido en detalle xvii
13
trabajar con documentos PDF y WordS 295 documentos
PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Extracción de texto de archivos PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Descifrar archivos PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
Creación de archivos PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Proyecto: Combina páginas seleccionadas de muchos archivos
PDF. . . . . . . . . . . . . . . . . . . . . . . . . . 303
Paso 1: Encuentra todos los archivos PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
Paso 2: Abra cada PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
Paso 3: Agregue cada página. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
Paso 4: Guarde los resultados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
Documentos de Word . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
Lectura de documentos de Word. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
Obtención del texto completo de un archivo .docx. . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
Párrafo de estilo y objetos de ejecución. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Creación de documentos de Word con estilos no predeterminados. . . . . . . . . . . . . . . . . . . 310
Atributos de ejecución. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Escribir documentos de Word. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Agregar encabezados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Agregar saltos de línea y página. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Agregar imágenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
PDF Paranoia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
invitaciones personalizadas como documentos de Word. . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Brute-Force PDF Password Breaker. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
14
trabajar con archivos cSV y JSon dAtA 319
El módulo csv. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
Lector de objetos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
Lectura de datos de los objetos del lector en un bucle for. . . . . . . . . . . . . . . . . . . . 322
objetos de escritor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
Delimitador y lineterminator Argumentos de palabras clave. . . . . . . . . . . . . . . . . . 323
Proyecto: Eliminar el encabezado de los archivos CSV. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
Paso 1: recorrer cada archivo CSV. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
Paso 2: Leer en el archivo CSV. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
Paso 3: Escriba el archivo CSV sin la primera fila. . . . . . . . . . . . . . . . . 326
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
JSON y API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
El módulo json. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
Lectura de JSON con la función load (). . . . . . . . . . . . . . . . . . . . . . . . . . 328
Escribir JSON con la función dumps (). . . . . . . . . . . . . . . . . . . . . . . . . . 329
Proyecto: Obteniendo datos meteorológicos actuales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Paso 1: Obtener ubicación del argumento de la línea de comando. . . . . . . . . . . . . . . . 330
Paso 2: Descargue los datos JSON. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
Paso 3: Cargue datos JSON e imprima el clima. . . . . . . . . . . . . . . . . . . . . . . . 331
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
xviii Contenido en detalle
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Proyecto de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Convertidor de Excel a CSV. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
15
tiempo de mantenimiento, tareas de programación
y programas de inicio 335
El módulo de tiempo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
La función time .time (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
La función time .sleep (). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
Números de redondeo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
Proyecto: Super cronómetro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
Paso 1: Configure el programa para rastrear tiempos. . . . . . . . . . . . . . . . . . . . . . . . . 339
Paso 2: Seguimiento e impresión de tiempos de vuelta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
El módulo de fecha y hora. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
El tipo de datos timedelta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Pausa hasta una fecha específica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
Conversión de objetos de fecha y hora en cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . 344
Conversión de cadenas en objetos de fecha y hora. . . . . . . . . . . . . . . . . . . . . . . . . . 345
Revisión de las funciones de tiempo de Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
Multithreading. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Pasar argumentos a la función de destino del hilo. . . . . . . . . . . . . . . . . . . 348
Cuestiones de concurrencia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
Proyecto: Descargador XKCD multiproceso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Paso 1: Modifique el programa para usar una función. . . . . . . . . . . . . . . . . . . . . . 350
Paso 2: Crear e iniciar hilos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
Paso 3: Espere a que todos los hilos terminen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
Lanzamiento de otros programas desde Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
Pasando argumentos de línea de comando a Popen (). . . . . . . . . . . . . . . . . . . . . . . 354
Programador de tareas, launchd y cron. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
Apertura de sitios web con Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Ejecución de otros scripts de Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Apertura de archivos con aplicaciones predeterminadas. . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Proyecto: Programa simple de cuenta regresiva. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
Paso 1: Cuenta atrás. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
Paso 2: Reproduzca el archivo de sonido. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
Ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
Cronómetro Prettificado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Descargador de cómics
web programado 360
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
16
Envío de mensajes de correo electrónico y mensajes de texto 361
SMTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Envío de correo electrónico. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Conexión a un servidor SMTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
Envío del mensaje SMTP "Hola". . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
Contenido en detalle xix
Iniciando el cifrado TLS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
Iniciar sesión en el servidor SMTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
Envío de un correo electrónico. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
Desconexión del servidor SMTP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
IMAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
Recuperación y eliminación de correos electrónicos con
IMAP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
Conexión a un servidor IMAP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
Iniciar sesión en el servidor IMAP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Buscando correo electrónico. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Obtener un correo electrónico y marcarlo como leído. . . . . . . . . . . . . . . . . . . . . . . . . 372
Obtención de direcciones de correo electrónico de un mensaje sin
formato. . . . . . . . . . . . . . . . . . . . . . 373
Obteniendo el cuerpo de un mensaje sin procesar. . . . . . . . . . . . . . . . . . . . . . . . . . . 374
Eliminar correos electrónicos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
Desconexión del servidor IMAP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
Proyecto: Envío de correos electrónicos de recordatorio de cuotas de
miembros. . . . . . . . . . . . . . . . . . . . . . . . . . . 376
Paso 1: Abra el archivo de Excel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
Paso 2: Encuentre todos los miembros sin pagar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Paso 3: Enviar recordatorios personalizados por correo
electrónico. . . . . . . . . . . . . . . . . . . . . . . . . 378
Envío de mensajes de texto con Twilio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
Registrarse para una cuenta Twilio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
Envío de mensajes de texto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
Proyecto: Módulo "Just Text Me". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
Resumen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
Emailer de asignación de tareas aleatorias. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Recordatorio de paraguas 385 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
Desuscriptor automático. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
Control de su computadora a través del correo electrónico. . . . . . . . . . . . . . . . . . . . . . . . . 386
17
IMÁGENES DE MANIPULACIÓN 387
Fundamentos de la imagen de la computadora. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
Colores y valores RGBA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
Coordenadas y tuplas de caja. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
Manipulación de imágenes con almohada. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Trabajar con el tipo de datos de imagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
Recorte de imágenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Copiar y pegar imágenes en otras imágenes. . . . . . . . . . . . . . . . . . . . . 394
Cambiar el tamaño de una imagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
Rotación y volteo de imágenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
Cambio de píxeles individuales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
Proyecto: Agregar un logotipo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
Paso 1: Abra la imagen del logotipo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
Paso 2: recorrer todos los archivos e abrir imágenes. . . . . . . . . . . . . . . . . . . . . . 402
Paso 3: Cambiar el tamaño de las imágenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
Paso 4: Agregue el logotipo y guarde los cambios. . . . . . . . . . . . . . . . . . . . . . . 404
ideas para programas similares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Dibujo sobre imágenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Dibujo de formas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
Dibujo de texto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
xx Contenido en detalle
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Ampliación y reparación de los programas de proyectos capitulares. . . . . . . . . . . . . . . . . . . 411
Identificación de carpetas de fotos en el disco duro. . . . . . . . . . . . . . . . . . . . . . . . 411
tarjetas de asientos personalizados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
18
control de keyBoArd y mouSe
con gui AutomAtion 413
Instalación del módulo pyautogui. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
Permanecer en el camino. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
Cerrar todo cerrando la sesión. . . . . . . . . . . . . . . . . . . . . . . . . 414
Pausas y cajas de seguridad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
Control del movimiento del ratón. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
Moviendo el Ratón. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
Obtener la posición del mouse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Proyecto: "¿Dónde está el mouse ahora?". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Paso 1: Importar el módulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
Paso 2: Configure el código de salida y el bucle infinito. . . . . . . . . . . . . . . . . . . . . . 418
Paso 3: Obtenga e imprima las coordenadas del mouse. . . . . . . . . . . . . . . . . . . . . . . 418
Control de la interacción del ratón. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Haciendo clic con el mouse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Arrastrando el mouse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Desplazamiento del mouse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
Trabajando con la pantalla. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
Obtención de una captura de pantalla. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
Análisis de la captura de pantalla. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
Proyecto: Ampliación del programa mouseNow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
Reconocimiento de imagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
Control del teclado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
Enviar una cadena desde el teclado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
Nombres clave. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
Presionando y soltando el teclado. . . . . . . . . . . . . . . . . . . . . . . . . . . . 428 combinaciones de teclas
de acceso
rápido. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
Revisión de las funciones PyAutoGUI. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Proyecto 430
: Relleno automático de formularios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
Paso 1: descubre los pasos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
Paso 2: Configurar coordenadas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
Paso 3: Comience a escribir datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
Paso 4: Manejar las listas de selección y los botones de radio. . . . . . . . . . . . . . . . . . . . . . . 435
Paso 5: envíe el formulario y espere. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
Preguntas de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
Proyectos de práctica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
Buscando ocupado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
Bot de mensajería instantánea. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438
Tutorial de Bot de juego. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Contenido en detalle xxi
Un
terceros Montar los módulos 441
La herramienta PIP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
Instalación de módulos de terceros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
B
PROGRAMAS DE CORRIENTE 443
Línea Shebang. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
Ejecución de programas Python en Windows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
Ejecución de programas Python en OS X y Linux. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
Ejecución de programas Python con aserciones deshabilitadas. . . . . . . . . . . . . . . . . . . . . . . . . 445
C
Respuestas a las preguntas de práctica 447
Capítulo 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
Capítulo 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
Capítulo 3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Capítulo 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
Capítulo 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
Capítulo 6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
Capítulo 7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452
Capítulo 8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
Capítulo 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
Capítulo 10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
Capítulo 11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
Capítulo 12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
Capítulo 13. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
Capítulo 14. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
Capítulo 15. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
Capítulo 16. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
Capítulo 17. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
Capítulo 18. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
Índice 461
Conocimiento de CA D smento S
No podría haber escrito un libro como este sin la
ayuda de mucha gente. Me gustaría agradecer a Bill Pollock;
mis editores, Laurel Chun, Leslie Shen, Greg Poulos
y Jennifer Griffith-Delgado; y el resto del personal
de No Starch Press por su valiosa ayuda. Gracias a
mi crítico técnico, Ari Lacenski, por sus excelentes sugerencias,
ediciones y soporte.
Muchas gracias a nuestro benevolente Dictador por la vida, Guido van Rossum,
y a todos en la Python Software Foundation por su gran trabajo. La
comunidad Python es la mejor que he encontrado en la industria tecnológica.
Finalmente, me gustaría agradecer a mi familia, amigos y la pandilla de
Shotwell's por no preocuparse por la vida ocupada que he tenido al escribir este libro.
¡Salud!
Introducción
" Acabas de hacer en dos horas lo que nos toma a
nosotros dos días hacer". Mi universidad
compañero de cuarto trabajaba en una tienda minorista de electrónica
a principios de la década de 2000. De vez en cuando, la tienda
recibiría una hoja de cálculo de miles de
precios de productos de su competidor. Un equipo de tres empleados
imprimiría la hoja de cálculo en una gruesa pila de papel y la dividiría entre
ellos. Para cada precio de producto, buscarían el precio de su tienda
y anotarían todos los productos que sus competidores vendieron por menos. Usualmente tomaba
un par de días.
" Sabes, podría escribir un programa para hacerlo si tienes el
archivo original para las impresiones", les dijo mi compañero de cuarto, cuando los vio sentados
en el suelo con papeles dispersos y apilados a su alrededor.
Después de un par de horas, tuvo un breve programa que leía
el precio de un competidor de un archivo, encontró el producto en la base de datos de la tienda y
observó
si el competidor era más barato. Todavía era nuevo en programación, y
2 Introducción
Pasó la mayor parte de su tiempo buscando documentación en un
libro de programación . El programa real solo tardó unos segundos en ejecutarse. Mi compañero de
cuarto
y sus compañeros de trabajo tomaron un almuerzo extra largo ese día.
Este es el poder de la programación de computadoras. Una computadora es como una
navaja suiza que puedes configurar para innumerables tareas. Muchas personas pasan
horas haciendo clic y escribiendo para realizar tareas repetitivas, sin saber que la
máquina que están usando podría hacer su trabajo en segundos si le dan las instrucciones correctas
.
¿Para quién es este libro?
El software es el núcleo de muchas de las herramientas que usamos hoy en día: casi todos
usan las redes sociales para comunicarse, muchas personas tienen
computadoras conectadas a Internet en sus teléfonos, y la mayoría de los trabajos de oficina
implican interactuar con una
computadora para hacer el trabajo. Como resultado, la demanda de personas que pueden codificar
se
ha disparado. Innumerables libros, tutoriales web interactivos y
campos de entrenamiento para desarrolladores prometen convertir a los principiantes ambiciosos en
ingenieros de software
con salarios de seis cifras.
Este libro no es para esas personas. Es para todos los demás.
Por sí solo, este libro no lo convertirá en un desarrollador de software profesional.
Oper más de unas pocas lecciones de guitarra te convertirá en una estrella de rock. Pero si
usted es un empleado de oficina, administrador, académico o cualquier otra persona que usa una
computadora para trabajar o divertirse, aprenderá los conceptos básicos de la programación para
que
pueda automatizar tareas simples como las siguientes:

• Mover y renombrar miles de archivos y clasificarlos en carpetas • Completar formularios en línea,


no requiere escritura • Descargar archivos o copiar texto de un sitio web cada vez que se
actualiza • Tener el texto de su computadora con notificaciones personalizadas • Actualizar o
formatear hojas de cálculo de Excel • Verificar su correo electrónico y envío de respuestas
preescritas

Estas tareas son simples pero requieren mucho tiempo para los humanos, y a
menudo son tan triviales o específicas que no hay un software listo para realizarlas
. Armado con un poco de conocimiento de programación, puede hacer que
su computadora haga estas tareas por usted.
convenciones
Este libro no está diseñado como un manual de referencia; Es una guía para principiantes
. El estilo de codificación a veces va en contra de las mejores prácticas (por ejemplo,
algunos programas usan variables globales), pero eso es una compensación para simplificar el
aprendizaje del código . Este libro está hecho para que las personas escriban códigos desechables,
por lo
que no se dedica mucho tiempo al estilo y la elegancia. Conceptos sofisticados de programación
, como programación orientada a objetos, listas de comprensión,
Introducción 3
y generadores, no están cubiertos debido a la complejidad que agregan.
Los programadores veteranos pueden señalar formas en que el código de este libro podría
cambiarse para mejorar la eficiencia, pero este libro se ocupa principalmente de
hacer que los programas funcionen con la menor cantidad de esfuerzo.
¿Qué es la programación?
Los programas de televisión y las películas a menudo muestran a los programadores tipeando
furiosamente
secuencias crípticas de 1s y 0s en pantallas brillantes, pero la programación moderna no es tan
misteriosa. La programación es simplemente el acto de ingresar instrucciones para que
la computadora las realice. Estas instrucciones pueden procesar algunos números,
modificar texto, buscar información en archivos o comunicarse con otras computadoras a
través de Internet.
Todos los programas usan instrucciones básicas como bloques de construcción. Estos son algunos
de los más comunes, en inglés:
“ Haz esto; entonces haz eso. "
" Si esta condición es verdadera, realiza esta acción; de lo contrario, realice esa acción "."
Realice esta acción tantas veces como quiera "."
Siga haciendo eso hasta que esta condición sea verdadera ".
Puede combinar estos componentes básicos para implementar elementos más complejos.
decisiones también. Por ejemplo, aquí están las instrucciones de programación, llamado
el código fuente , para un programa simple escrito en la programación Python
lenguaje. Comenzando en la parte superior, el software Python ejecuta cada línea de código
(algunas líneas sólo se ejecutan si una determinada condición es verdadera o demás Python se
ejecuta
alguna otra línea) hasta que llega a la parte inferior.
u passwordFile = open ('SecretPasswordFile.txt')
v secretPassword = passwordFile.read ()
w print ('Ingrese su contraseña')
typedPassword = input ()
x if typedPassword == secretPassword:
y print ('Acceso otorgado')
z if typedPassword == '12345':
{print ('Esa contraseña es la que un idiota pone en su equipaje')
más:
| print ('Acceso denegado')
Es posible que no sepa nada acerca de la programación, pero probablemente podría
hacer una suposición razonable sobre lo que hace el código anterior con solo leerlo
. Primero, se abre el archivo SecretPasswordFile.txt u, y
se lee la contraseña secreta v. Luego, se le solicita al usuario que ingrese una contraseña (desde el
teclado
) w. Estas dos contraseñas se comparan x, y si son iguales,
el programa imprime el Acceso otorgado a la pantalla y. Luego, el programa verifica
si la contraseña es 12345 z y sugiere que esta opción podría no
ser la mejor para una contraseña {. Si las contraseñas no son las mismas, el programa
imprime Acceso denegado a la pantalla |.
4 Introducción
¿Qué es python?
Python se refiere al lenguaje de programación Python (con reglas de sintaxis para
escribir lo que se considera código Python válido) y al
software de intérprete de Python que lee el código fuente (escrito en el lenguaje Python) y realiza
sus instrucciones. El intérprete de Python se puede descargar gratuitamente desde
http://python.org/ , y hay versiones para Linux, OS X y Windows.
El nombre Python proviene del surrealista grupo de comedia británico Monty
Python, no de la serpiente. Los programadores de Python son cariñosamente llamados
Pythonistas, y tanto Monty Python como las referencias serpentinas usualmente complementan los
tutoriales y la documentación de Python.
Los programadores no necesitan saber mucho de matemáticas
La ansiedad más común que escucho sobre aprender a programar es que la gente
piensa que requiere muchas matemáticas. En realidad, la mayoría de la programación no requiere
matemática más allá de la aritmética básica. De hecho, ser bueno en la programación no es tan
diferente de ser bueno para resolver acertijos de Sudoku.
Para resolver un rompecabezas de Sudoku, se deben completar los números del 1 al 9 para
cada fila, cada columna y cada cuadrado interior de 3 × 3 del tablero completo de 9 × 9.
Usted encuentra una solución aplicando deducción y lógica a partir de los números iniciales
. Por ejemplo, dado que 5 aparece en la parte superior izquierda del rompecabezas de Sudoku que se
muestra
en la Figura 0-1, no puede aparecer en ningún otro lugar de la fila superior, en la
columna más a la izquierda o en el cuadrado 3 × 3 superior izquierdo. Resolver una fila, columna o
cuadrado a la
vez proporcionará más pistas numéricas para el resto del rompecabezas.
Figura 0-1: Un nuevo rompecabezas de Sudoku (izquierda) y su solución (derecha). A pesar de usar
números,
Sudoku no involucra muchas matemáticas. (Imágenes © Wikimedia Commons)
Solo porque Sudoku involucra números no significa que tengas que
ser bueno en matemáticas para encontrar la solución. Lo mismo se
aplica a la programación . Al igual que resolver un rompecabezas de Sudoku, escribir programas
implica dividir
un problema en pasos individuales y detallados. Del mismo modo, al depurar programas (es decir,
encontrar y corregir errores), observará pacientemente lo que está haciendo el programa y
encontrará la causa de los errores. Y como todas las habilidades, cuanto más programes, mejor
serás.

Introducción 5
La programación es una actividad creativa La
programación es una tarea creativa, algo así como construir un castillo con
ladrillos LEGO. Comienzas con una idea básica de cómo quieres
que se vea tu castillo e inventarias tus bloques disponibles. Entonces comienzas a construir.
Una vez que haya terminado de construir su programa, puede modificar su código
tal como lo haría con su castillo.
La diferencia entre la programación y otras actividades creativas es
que al programar, tiene todas las materias primas que necesita en su
computadora; no necesita comprar lienzo, pintura, película, hilo,
ladrillos LEGO o componentes electrónicos adicionales . Cuando se escribe su programa, se
puede compartir fácilmente en línea con todo el mundo. Y aunque cometerás
errores al programar, la actividad sigue siendo muy divertida.
Acerca de este libro
La primera parte de este libro cubre conceptos básicos de programación de Python, y
la segunda parte cubre varias tareas que puede hacer que su computadora se automatice.
Cada capítulo en la segunda parte tiene programas de proyectos para que estudies. Aquí hay
un breve resumen de lo que encontrará en cada capítulo:
Parte I: Conceptos básicos de programación de Python
Capítulo 1: Conceptos básicos de Python Cubre expresiones, el tipo más básico de
instrucción de Python y cómo usar el software de shell interactivo de Python
para experimentar con el código.
Capítulo 2: Control de flujo Explica cómo hacer que los programas decidan
qué instrucciones ejecutar para que su código pueda responder de manera inteligente a
diferentes condiciones.
Capítulo 3: Funciones Le indica cómo definir sus propias funciones
para que pueda organizar su código en fragmentos más manejables.
Capítulo 4: Listas Presenta el tipo de datos de la lista y explica cómo
organizar los datos.
Capítulo 5: Diccionarios y estructuración de datos Presenta el tipo
de datos del diccionario y le muestra formas más eficaces de organizar los datos.
Capítulo 6: Manipulación de cadenas Cubiertas que trabajan con datos de texto
(llamadas cadenas en Python).
Parte II: Automatización de tareas
Capítulo 7: Coincidencia de patrones con expresiones regulares Cubre cómo
Python puede manipular cadenas y buscar patrones de texto con
expresiones regulares .
Capítulo 8: Lectura y escritura de archivos Explica cómo sus programas
pueden leer el contenido de los archivos de texto y guardar información en los archivos de su
disco duro.
Capítulo 9: Organización de archivos Muestra cómo Python puede copiar, mover,
renombrar y eliminar grandes cantidades de archivos mucho más rápido que un usuario humano
. También explica la compresión y descompresión de archivos.
6 Introducción
Capítulo 10: Depuración Muestra cómo utilizar las diversas
herramientas de detección y corrección de errores de Python .
Capítulo 11: Web Scraping Muestra cómo escribir programas que pueden
descargar automáticamente páginas web y analizarlas para obtener información.
Esto se llama raspado web .
Capítulo 12: Trabajar con hojas de cálculo de Excel Cubre
manipulando programáticamente hojas de cálculo de Excel para que no tenga que leerlas
. Esto es útil cuando la cantidad de documentos que tiene que
analizar es de cientos o miles.
Capítulo 13: Trabajar con cubiertas de documentos PDF y Word mediante
lectura programática de documentos Word y PDF.
Capítulo 14: Trabajar con archivos CSV y datos JSON Continúa
explicando cómo manipular mediante programación los documentos con
archivos CSV y JSON.
Capítulo 15: Mantener el tiempo, programar tareas y ejecutar
programas Explica cómo los programas de Python manejan la hora y las fechas
y cómo programar su computadora para realizar tareas en determinados
momentos. Este capítulo también muestra cómo sus programas Python pueden iniciar programas
que
no sean Python.
Capítulo 16: Envío de correos electrónicos y mensajes de texto Explica cómo escribir
programas que pueden enviar correos electrónicos y mensajes de texto en su nombre.
Capítulo 17: Manipulación de imágenes Explica cómo
manipular mediante programación imágenes como archivos JPEG o PNG.
Capítulo 18: Control del teclado y el mouse con GUI Automation Explica cómo controlar
mediante programación el mouse y el teclado para automatizar los clics y las pulsaciones de teclas.
descarga e instalación de Python
Puede descargar Python para Windows, OS X y Ubuntu de forma gratuita desde
http://python.org/downloads/ . Si descarga la última versión de la
página de descarga del sitio web, todos los programas de este libro deberían funcionar.
w Advertencia: asegúrese de descargar una versión de Python 3 (como 3.4.0). Los programas en
este libro
están escritos para ejecutarse en Python 3 y pueden no ejecutarse correctamente, si es que lo
hacen, en Python 2.
Encontrará instaladores de Python para computadoras de 64 bits y 32 bits para cada
sistema operativo en la página de descarga, así que primero descubra qué instalador
necesita. Si compró su computadora en 2007 o posterior, lo más probable es que sea un
sistema de 64 bits. De lo contrario, tiene una versión de 32 bits, pero aquí está cómo averiguarlo
con seguridad:
• En Windows, seleccione Inicio 4 Panel de control 4 Sistema y compruebe si Tipo de sistema dice
64 bits o 32 bits.
Introducción 7
• En OS X, vaya al menú Apple, seleccione Acerca de esta Mac 4 Más información 4 Informe
del sistema 4 Hardware , y luego mire el campo Nombre del procesador . Si dice Intel Core Solo o
Intel Core Duo, tienes una máquina de 32 bits . Si dice algo más (incluido Intel Core 2 Duo), tiene
una máquina de 64 bits.

• En Ubuntu Linux, abra una Terminal y ejecute el comando uname -m . Una respuesta de i686
significa 32 bits, y x86_64 significa 64 bits.
En Windows, descargue el instalador de Python (el nombre del archivo terminará
con .msi ) y haga doble clic en él. Siga las instrucciones que muestra el instalador
en la pantalla para instalar Python, como se detalla aquí:
1. Seleccione Instalar para todos los usuarios y luego haga clic en Siguiente .
2. Instale en la carpeta C: \ Python34 haciendo clic en Siguiente .
3. Haga clic en Siguiente nuevamente para omitir la sección Personalizar Python.
En Mac OS X, descargue el archivo .dmg adecuado para su versión de
OS X y haga doble clic en él. Siga las instrucciones que muestra el instalador en
la pantalla para instalar Python, como se detalla aquí:
1. Cuando el paquete DMG se abra en una nueva ventana, haga doble clic en el
archivo Python.mpkg. Es posible que deba ingresar la contraseña de administrador.
2. Haga clic en Continuar a través de la sección de Bienvenida y haga clic en Acepto para aceptar
la licencia.
3. Seleccione HD Macintosh (o el nombre que tenga su disco duro) y
haga clic en Instalar .
Si está ejecutando Ubuntu, puede instalar Python desde la Terminal
siguiendo estos pasos:
1. Abra la ventana de Terminal.
2. Ingrese sudo apt-get install python3 .
3. Ingrese sudo apt-get install idle3 .
4. Ingrese sudo apt-get install python3-pip .
Inicio inactivo
Mientras que el intérprete de Python es el software que ejecuta sus programas de Python,
el software de entorno de desarrollo interactivo (IDLE) es donde ingresará a
sus programas, al igual que un procesador de textos. Comencemos IDLE ahora.
• En Windows 7 o posterior, haga clic en el icono de Inicio en la esquina inferior izquierda de su
pantalla, ingrese IDLE en el cuadro de búsqueda y seleccione IDLE (Python GUI) .
• En Windows XP, haga clic en el botón Inicio y luego seleccione Programas 4 Python
3.4 4 IDLE (Python GUI) .
8 Introducción
• En Mac OS X, abra la ventana del Finder, haga clic en Aplicaciones , haga clic en Python 3.4 y
luego haga clic en el icono IDLE.
• En Ubuntu, seleccione Aplicaciones 4 Accesorios 4 Terminal y luego ingrese idle3 . (También
puede hacer clic en Aplicaciones en la parte superior de la pantalla, seleccionar Programación y
luego hacer clic en IDLE 3 ).

El Shell interactivo
No importa qué sistema operativo esté ejecutando, la ventana IDLE que
aparece primero debe estar en blanco en su mayoría, excepto por el texto que se ve
así:
Python 3.4.0 (v3.4.0: 04f714765c13, 16 de marzo de 2014, 19:25:23) [MSC v.1600 64
bit (AMD64)] en win32 Escriba "copyright", "créditos" o "licencia ()" para
obtener más información .
>>>
Esta ventana se llama shell interactivo . Un shell es un programa que le permite
escribir instrucciones en la computadora, al igual que el Terminal o el
Símbolo del sistema en OS X y Windows, respectivamente. El shell interactivo de Python le
permite
ingresar instrucciones para que se ejecute el software de intérprete de Python. El equipo
lee las instrucciones que ingresa y las ejecuta de inmediato.
Por ejemplo, ingrese lo siguiente en el shell interactivo al lado del
indicador >>>:
>>> print ('¡Hola mundo!')
Después de escribir esa línea y presionar enter, el shell interactivo debería
mostrar esto en respuesta:
>>> print ('¡Hola mundo!')
¡Hola mundo!
cómo encontrar ayuda
Resolver problemas de programación por su cuenta es más fácil de lo que
piensa. Si no está convencido, provoquemos un error a propósito: ingrese
'42' + 3 en el shell interactivo. No necesita saber qué significa esta instrucción en este
momento, pero el resultado debería verse así:
>>> '42' + 3
u Traceback (última llamada más reciente):
Archivo "<pyshell # 0>", línea 1, en <module>
'42' + 3
v TypeError: no se puede convertir el objeto 'int' en str implícitamente
>>>
Introducción 9
El mensaje de error v apareció aquí porque Python no pudo entender
sus instrucciones. La parte de rastreo u del mensaje de error muestra
la instrucción específica y el número de línea con los que Python tuvo problemas. Si
no está seguro de qué hacer con un mensaje de error en particular, busque en línea
el mensaje de error exacto. Ingrese " TypeError: No se puede convertir el objeto 'int' a
str implícitamente" (incluidas las comillas) en su motor de búsqueda favorito, y
debería ver toneladas de enlaces que explican qué significa el mensaje de error y
qué lo causa, como se muestra en la Figura 0 -2.
Figura 0-2: Los resultados de Google para un mensaje de error pueden ser muy útiles.
A menudo encontrará que alguien más tenía la misma pregunta que usted y
que otra persona útil ya la respondió. Nadie puede
saber todo acerca de la programación, por lo que una parte cotidiana del trabajo de
cualquier desarrollador de software
es buscar respuestas a preguntas técnicas.
Cómo hacer preguntas de programación inteligente
Si no puede encontrar la respuesta buscando en línea, intente preguntar a las personas en un
foro web como Stack Overlow (http://stackoverflow.com/) o el
subreddit "aprender programación" en http: // reddit .com / r / learnprogramming / . Pero tenga
en cuenta que hay formas inteligentes de hacer preguntas de programación que ayudan a
otros a ayudarlo. Asegúrese de leer las secciones de Preguntas frecuentes que
tienen estos sitios web sobre la forma correcta de publicar preguntas.
10 Introducción
Cuando haga preguntas de programación, recuerde hacer lo siguiente:
• Explique lo que está tratando de hacer, no solo lo que hizo. Esto le permite a su ayudante saber si
está en el camino equivocado.
• Especifique el punto en el que ocurre el error. ¿Ocurre al comienzo del programa o solo después
de realizar una determinada acción?
• Copie y pegue el mensaje de error completo y su código en http: // pastebin .com
/ o http://gist.github.com/ .
Estos sitios web facilitan compartir grandes cantidades de código con
personas a través de la Web, sin el riesgo de perder el formato de texto. Usted
puede entonces poner la URL del código enviado por ellos de su correo electrónico o mensaje en el
foro.
Por ejemplo, aquí hay algunas piezas de código que he publicado: http://pastebin.com/
SzP2DbFx / y https://gist.github.com/asweigart/6912168/ .
• Explique lo que ya intentó hacer para resolver su problema. Esto le dice a las personas que ya has
trabajado para resolver las cosas por tu cuenta.
• Enumere la versión de Python que está usando. (Existen algunas diferencias clave entre los
intérpretes de Python de la versión 2 y los de Python de la versión 3 ). Además, indique qué sistema
operativo y qué versión está ejecutando.

• Si el error se produjo después de realizar un cambio en su código, explique exactamente lo que


cambió.
• Indique si puede reproducir el error cada vez que ejecuta el programa o si ocurre solo después de
realizar ciertas acciones. Explique cuáles son esas acciones, si es así.
Siempre siga una buena etiqueta en línea también. Por ejemplo, no publique
sus preguntas en mayúsculas ni haga demandas irrazonables a las personas que
intentan ayudarlo.
Resumen
Para la mayoría de las personas, su computadora es solo un dispositivo en lugar de una
herramienta. Pero
al aprender a programar, obtendrá acceso a una de las
herramientas más poderosas del mundo moderno y se divertirá en el camino. La programación
no es cirugía cerebral: está bien que los aficionados experimenten y cometan errores.
Me encanta ayudar a las personas a descubrir Python. Escribo tutoriales de programación
en mi blog en http://inventwithpython.com/blog/ , y pueden contactarme si tienen
preguntas en al@inventwithpython.com .
Este libro lo iniciará desde cero conocimiento de programación, pero
puede tener preguntas más allá de su alcance. Recuerde que hacer
preguntas efectivas y saber cómo encontrar respuestas son herramientas invaluables en su
viaje de programación.
¡Vamos a empezar!
Parte I
P ython P rogr A mming
BAS i CS
1
P ython BAS i CS
El lenguaje de programación Python tiene
una amplia gama de construcciones sintácticas,
funciones de biblioteca estándar y características de entorno de desarrollo interactivo
. Por suerte,
puedes ignorar la mayor parte de eso; solo necesita aprender lo
suficiente para escribir algunos pequeños programas útiles.
Sin embargo, tendrá que aprender algunos conceptos básicos de programación
antes de poder hacer algo. Como un mago en entrenamiento, podrías pensar que
estos conceptos parecen arcanos y tediosos, pero con algo de conocimiento y
práctica, podrás controlar tu computadora como una varita mágica para
realizar hazañas increíbles.
Este capítulo tiene algunos ejemplos que lo alientan a escribir en el
shell interactivo, que le permite ejecutar las instrucciones de Python de una en una
y le muestra los resultados al instante. Usar el shell interactivo es excelente para
aprender lo que hacen las instrucciones básicas de Python, así que pruébalo mientras sigues
. Recordarás las cosas que haces mucho mejor que las cosas
que solo lees.
14 Capítulo 1
ingresar expresiones en el Shell interactivo
Usted ejecuta el shell interactivo iniciando IDLE, que instaló con
Python en la introducción. En Windows, abra el menú Inicio, seleccione Todos los
programas 4 Python 3.3 y luego seleccione IDLE (Python GUI) . En OS X,
seleccione Aplicaciones 4 MacPython 3.3 4 IDLE . En Ubuntu, abra una nueva
ventana de Terminal e ingrese idle3 .
Debería aparecer una ventana con el indicador >>>; Ese es el
shell interactivo . Ingrese 2 + 2 en el indicador para que Python haga algunas matemáticas simples.
>>> 2 + 2
4
La ventana IDLE ahora debería mostrar un texto como este:
Python 3.3.2 (v3.3.2: d047928ae3f6, 16 de mayo de 2013, 00:06:53) [MSC v.1600 64 bit
(AMD64)] en win32
Escriba "copyright", "créditos" o "licencia ()" para más información.
>>> 2 + 2
4
>>>
En Python, 2 + 2 se denomina expresión , que es el tipo más básico de
instrucción de programación en el lenguaje. Las expresiones consisten en valores (como 2)
y operadores (como +), y siempre pueden evaluar (es decir, reducir) a un solo valor. Eso significa
que puede usar expresiones en cualquier parte del código de Python que también podría usar un
valor.

En el ejemplo anterior, 2 + 2 se evalúa a un solo valor, 4.


Un único valor sin operadores también se considera una expresión, aunque
solo se evalúa a sí mismo, como se muestra aquí:
>>> 2
2
er rorS A re ok ¡Ay!
Los programas se bloquearán si contienen código que la computadora no puede entender, lo que
hará que Python muestre un mensaje de error. Sin
embargo, un mensaje de error no dañará su computadora, así que no tenga miedo de cometer
errores. Un bloqueo solo significa que
el programa dejó de ejecutarse inesperadamente.
Si desea obtener más información sobre un mensaje de error, puede buscar el
texto exacto del mensaje en línea para obtener más información sobre ese error específico. También
puede
consultar los recursos en http://nostarch.com/automatestuff/ para ver una lista
de mensajes de error comunes de Python y sus significados.
Conceptos básicos de Python 15
También hay muchos otros operadores que puedes usar en las expresiones de Python
. Por ejemplo, la Tabla 1-1 enumera todos los operadores matemáticos en Python.
tabla 1-1: Operadores matemáticos desde la
operación de operador de precedencia más alta a la más baja Ejemplo Evalúa a ...
** Exponente 2 ** 3 8
% Módulo / resto 22% 8 6
// División entera / cociente con piso 22 // 8 2
/ División 22 / 8 2.75
* Multiplicación 3 * 5 15
- Resta 5 - 2 3
+ Suma 2 + 2 4
El orden de las operaciones (también llamado precedencia ) de los
operadores matemáticos de Python es similar al de las matemáticas. El operador ** se evalúa
primero;
los operadores *, /, // y% se evalúan a continuación, de izquierda a derecha; y los
operadores + y - se evalúan en último lugar (también de izquierda a derecha). Puede usar
paréntesis para anular la precedencia habitual si es necesario. Ingrese las
siguientes expresiones en el shell interactivo:
>>> 2 + 3 * 6
20
>>> (2 + 3) * 6
30
>>> 48565878 * 578,453
28093077826734
>>> 2 ** 8
256
>>> 23/ 7
3,2857142857142856
>>> 23 // 7
3
>>> 23% 7
2
>>> 2 + 2
4
>>> (5 - 1) * ((7 + 1) / (3 - 1))
16.0
En cada caso, usted como programador debe ingresar la expresión, pero
Python hace la parte difícil de evaluarla a un solo valor. Python
seguirá evaluando partes de la expresión hasta que se convierta en un valor único,
como se muestra en la Figura 1-1.
16 Capítulo 1
(5 - 1) * ((7 + 1) / (3 - 1))
4 * ((7 + 1) / (3 - 1))
4 * () / (3 - 1)) 8
4 * () / () 8 2
4 * 4.0
16,0
Figura 1-1: La evaluación de una
expresión la reduce a un solo valor.
Estas reglas para agrupar operadores y valores para formar expresiones
son una parte fundamental de Python como lenguaje de programación, al
igual que las reglas gramaticales que nos ayudan a comunicarnos. Aquí hay un ejemplo:
Esta es una oración gramaticalmente correcta en inglés.
Gramaticalmente esta oración no es correcta en inglés a.
La segunda línea es difícil de analizar porque no sigue las reglas
De Inglés. Del mismo modo, si escribe una instrucción de Python incorrecta, Python no
podrá entenderla y mostrará un mensaje de error SyntaxError, como se
muestra aquí:
>>> 5 +
Archivo "<stdin>", línea 1
5+
^
SyntaxError: sintaxis no válida
>>> 42 + 5 + * 2
Archivo "<stdin>", línea 1
42 + 5 + * 2
^
SyntaxError: sintaxis no válida
Siempre puede probar para ver si una instrucción funciona escribiéndola en
el shell interactivo. No se preocupe por romper la computadora: lo peor
que puede pasar es que Python responda con un mensaje de error.
Los desarrolladores de software profesionales reciben mensajes de error mientras escriben código
todo
el tiempo.
los tipos de datos de entero, coma flotante y cadena
Recuerde que las expresiones son solo valores combinados con operadores,
y siempre se evalúan en un solo valor. Un tipo de datos es una categoría
para valores, y cada valor pertenece exactamente a un tipo de datos. Lo mas
Conceptos básicos de Python 17
Los tipos de datos comunes en Python se enumeran en la Tabla 1-2. Se
dice que los valores -2 y 30, por ejemplo, son valores enteros . El tipo de datos entero (o int )
indica valores que son números enteros. Los números con un punto decimal, como
3.14, se llaman números de coma flotante (o flotantes). Tenga en cuenta que aunque el
valor 42 es un número entero, el valor 42.0 sería un número de coma flotante.
tabla 1-2: Tipos de
datos comunes Tipo de datos Ejemplos
Enteros -2, -1, 0, 1, 2, 3, 4, 5
Números de coma flotante -1.25, -1.0, --0.5, 0.0, 0.5, 1.0, 1.25
Cadenas 'a', 'aa', 'aaa', '¡Hola!', '11 gatos '
Los programas de Python también pueden tener valores de texto llamados cadenas ,
o cadenas (se pronuncia
"stirs"). Siempre rodee su cadena con caracteres de comillas simples (')
(como en' ¡Hola 'o' Adiós mundo cruel! ') Para que Python sepa dónde
comienza y dónde termina la cadena . Incluso puede tener una cadena sin caracteres '',
llamada cadena en blanco . Las cadenas se explican con mayor detalle en el Capítulo 4.
Si alguna vez ve el mensaje de error SyntaxError: EOL al escanear el
literal de la cadena , probablemente olvidó el carácter final de comillas simples al final de
la cadena, como en este ejemplo:
>>> 'Hola mundo!
SyntaxError: EOL al escanear literal de cadena
Concatenación y replicación de cadenas
El significado de un operador puede cambiar en función de los tipos de datos de los
valores a su lado. Por ejemplo, + es el operador de suma cuando opera en
dos enteros o valores de punto flotante. Sin embargo, cuando se usa + en dos
valores de cadena , une las cadenas como el operador de concatenación de cadenas . Ingrese lo
siguiente en el shell interactivo:
>>> 'Alice' + 'Bob'
'AliceBob'
La expresión se evalúa como un único valor de cadena nuevo que
combina el texto de las dos cadenas. Sin embargo, si intenta utilizar el operador + en
una cadena y un valor entero, Python no sabrá cómo manejar esto y
mostrará un mensaje de error.
>>> 'Alice' + 42
Traceback (última llamada más reciente):
Archivo "<pyshell # 26>", línea 1, en <module>
'Alice' + 42
TypeError: No se puede convertir el objeto 'int' a str implícitamente
18 Capítulo 1
El mensaje de error No se puede convertir el objeto 'int' en una cadena implícitamente significa
que Python pensó que estaba tratando de concatenar un entero a la cadena
'Alice'. Su código tendrá que convertir explícitamente el entero en una cadena,
porque Python no puede hacer esto automáticamente. (La conversión de tipos de datos se
explicará en “Disección de su programa” en la página 22 cuando se hable
de las funciones str (), int () y float ()).
El operador * se usa para la multiplicación cuando opera en dos
valores enteros o de punto flotante. Pero cuando el operador * se usa en un
valor de cadena y un valor entero, se convierte en el operador de replicación de cadena . Ingrese
una cadena multiplicada por un número en el shell interactivo para ver esto en acción.
>>> 'Alice' * 5
'AliceAliceAliceAliceAlice'
La expresión se evalúa en un solo valor de cadena que repite el
original varias veces igual al valor entero. La replicación de cadenas es un
truco útil, pero no se usa con tanta frecuencia como la concatenación de cadenas.
El operador * se puede usar con solo dos valores numéricos (para multiplicación
) o un valor de cadena y un valor entero (para replicación de cadena).
De lo contrario, Python solo mostrará un mensaje de error.
>>> 'Alice' * 'Bob'
Traceback (última llamada más reciente):
Archivo "<pyshell # 32>", línea 1, en <módulo>
'Alice' * 'Bob'
TypeError: no se puede multiplicar la secuencia por no -int del tipo 'str'
>>> 'Alice' * 5.0
Traceback (última llamada más reciente):
Archivo "<pyshell # 33>", línea 1, en <module>
'Alice' * 5.0
TypeError: no se puede multiplicar secuencia por no int del tipo 'float'
Tiene sentido que Python no entienda estas expresiones:
no se pueden multiplicar dos palabras y es difícil replicar una cadena arbitraria un
número fraccional de veces.
Almacenamiento de valores en variables
Una variable es como un cuadro en la memoria de la computadora donde puede almacenar un
solo valor. Si desea utilizar el resultado de una expresión evaluada más adelante en
su programa, puede guardarlo dentro de una variable.
Declaraciones de asignación
Almacenará valores en variables con una declaración de asignación . Una
declaración de asignación consta de un nombre de variable, un signo igual (llamado operador
de asignación ) y el valor que se almacenará. Si ingresa la declaración de asignación spam = 42,
entonces una variable llamada spam tendrá el valor entero 42 almacenado en ella.
Conceptos básicos de Python 19
Piense en una variable como un cuadro etiquetado en el que se coloca un valor, como en la
Figura 1-2.
Figura 1-2: spam = 42 es como decirle al programa:
"La variable spam ahora tiene el valor entero 42".
Por ejemplo, ingrese lo siguiente en el shell interactivo:
u >>> spam = 40
>>> spam
40
>>> huevos = 2
v >>> spam + huevos
42
>>> spam + huevos + spam
82
w >>> spam = spam + 2
>>> spam
42
Una variable se inicializa (o crea) la primera vez que se almacena un valor en ella.
Después de eso, puede usarlo en expresiones con otras variables y valores v.
Cuando a una variable se le asigna un nuevo valor w, se olvida el valor anterior, por lo
que el correo no deseado se evaluó a 42 en lugar de 40 al final del ejemplo. Esto se
llama sobrescribir la variable. Ingrese el siguiente código en el shell interactivo
para intentar sobrescribir una cadena:
>>> spam = 'Hola'
>>> spam
'Hola'
>>> spam = 'Adiós'
>>> spam
'Adiós'
Al igual que en el cuadro de la Figura 1-3, la variable de spam en este ejemplo almacena
'Hola' hasta que lo reemplace con 'Adiós'.
agregar crédito de imagen
Nota: la imagen de la caja de cartón proviene
de http://commoNs.wikimedia.org/
wiki / file: opeN _ cartón _ box _
husky.pNg y se lanzó al
público domaiN. la fuente es la escritura de
ammy, que se encuentra en la lista de datos.
com como piojos "gratis".
20 Capítulo 1
Figura 1-3: Cuando se asigna un nuevo valor a una variable,
se olvida el anterior.
Nombres de variables La
Tabla 1-3 tiene ejemplos de nombres de variables legales. Puede nombrar cualquier variable
siempre que obedezca las siguientes tres reglas:
1. Puede ser solo una palabra.
2. Solo puede usar letras, números y el carácter de subrayado (_).
3. No puede comenzar con un número.
tabla 1-3: Nombres de variables válidos e inválidos Nombres de
variables válidos Nombres de variables inválidos
balance current-balance (no se permiten guiones)
currentBalance balance actual (no se permiten espacios)
current_balance 4account (no puede comenzar con un número)
_spam 42 (can no comience con un número)
SPAM total_ $ um (no se permiten caracteres especiales como $)
cuenta4 'hola' (no se permiten caracteres especiales como ')
Conceptos básicos de Python 21
Los nombres de las variables distinguen entre mayúsculas y minúsculas, lo que significa que spam,
SPAM, Spam y sPaM
son cuatro variables diferentes. Es una convención de Python comenzar sus variables
con una letra minúscula.
Este libro usa camelcase para nombres de variables en lugar de guiones bajos;
es decir, variables lookLikeThis en lugar de look_like_this. Algunos
programadores experimentados pueden señalar que el estilo de código oficial de Python, PEP 8,
dice
que se deben usar guiones bajos. Sin pedir disculpas prefiero camelcase y apunto
a "Una tonta consistencia es el duende de Little Minds" en la PEP 8
:
“La coherencia con la guía de estilo es importante. Pero lo más importante
: sepa cuándo ser inconsistente, a veces la guía de estilo
simplemente no se aplica. En caso de duda, use su mejor juicio.
Un buen nombre de variable describe los datos que contiene. Imagina que te
mudaste a una casa nueva y etiquetaste todas tus cajas de mudanzas como cosas . ¡
Nunca encontrarás nada! Los nombres de variables spam, huevos y tocino se usan como
nombres genéricos para los ejemplos en este libro y en gran parte de la documentación de Python
(inspirada en el boceto "Spam" de Monty Python), pero en sus programas
, un nombre descriptivo ayudará a que su código sea más legible.
su primer programa
Si bien el shell interactivo es bueno para ejecutar instrucciones de Python de una en
una, para escribir programas completos de Python, escribirá las instrucciones en
el editor de archivos. El editor de archivos es similar a los editores de texto como el Bloc de notas o
TextMate, pero tiene algunas características específicas para escribir el código fuente. Para
abrir el editor de archivos en IDLE, seleccione File4New Window.
La ventana que aparece debe contener un cursor en espera de su entrada,
pero es diferente del shell interactivo, que ejecuta las instrucciones de Python
tan pronto como presiona enter. El editor de archivos le permite escribir muchas instrucciones,
guardar el archivo y ejecutar el programa. A continuación, le mostramos cómo puede diferenciar
entre los dos:
• La ventana del shell interactivo siempre será la que tenga el indicador >>>. • La ventana del
editor de archivos no tendrá el indicador >>>.

¡Ahora es el momento de crear tu primer programa! Cuando se abra la ventana del editor de
archivos
, escriba lo siguiente:
u # Este programa dice hola y me pide mi nombre.
v print ('¡Hola mundo!')
print ('¿Cuál es tu nombre?') # pregunta por su nombre
w myName = input ()
x print ('Es un placer conocerte' + myName)
y print ('La longitud de tu nombre es:')
print (len (miNombre))
22 Capítulo 1
z print ('¿Cuál es su edad?') # pregunte por su edad
myAge = input ()
print ('Usted será' + str (int (myAge) + 1) + 'en un año.')
Una vez que haya ingresado su código fuente, guárdelo para que no tenga
que volver a escribirlo cada vez que inicie IDLE. Desde el menú en la parte superior de la
ventana del editor de archivos , seleccione Archivo 4 Guardar como . En la ventana Guardar
como, ingrese hello.py en el campo Nombre de archivo y luego haga clic en Guardar.
Debe guardar sus programas de vez en cuando a medida que los escribe.
De esa manera, si la computadora falla o si sale accidentalmente de IDLE,
no perderá el código. Como acceso directo, puede presionar ctrl-S en Windows y
Linux o zS en OS X para guardar su archivo.
Una vez que haya guardado, ejecutemos nuestro programa. Seleccione Ejecutar 4 Ejecutar
módulo o simplemente presione la tecla F5 . Su programa debe ejecutarse en la ventana del shell
interactivo que apareció cuando inició IDLE por primera vez. Recuerde, debe presionar F5 desde la
ventana del editor de archivos, no desde la ventana del shell interactivo. Ingrese su nombre cuando
su programa lo solicite. La salida del programa en el shell interactivo debería verse así:

Python 3.3.2 (v3.3.2: d047928ae3f6, 16 de mayo de 2013, 00:06:53) [MSC v.1600 64 bit
(AMD64)] en win32
Escriba "copyright", "créditos" o "licencia ()" para más información.
>>> ================================ REINICIAR ==============
==================
>>>
¡Hola mundo!
¿Cuál es su nombre?
Al
Es un placer conocerte, Al
La longitud de tu nombre es:
2
¿Cuál es tu edad?
4
Serás 5 en un año.
>>>
Cuando no hay más líneas de código para ejecutar, el programa Python
termina ; es decir, deja de funcionar. (También se puede decir que el pitón pro
gram salidas ).
Puede cerrar el editor de archivos haciendo clic en la X en la parte superior de la ventana.
Para volver a cargar un programa guardado, seleccione Archivo 4 Abrir en el menú. Haga eso
ahora,
y en la ventana que aparece, elija hello.py y haga clic en el botón Abrir .
Su programa hello.py previamente guardado debería abrirse en la ventana del editor de archivos.
disección de su programa
Con su nuevo programa abierto en el editor de archivos, hagamos un recorrido rápido por las
instrucciones de Python que usa al observar lo que hace cada línea de código.
Conceptos básicos de Python 23
Comentarios
La siguiente línea se llama comentario .
u # Este programa dice hola y me pide mi nombre.
Python ignora los comentarios, y puede usarlos para escribir notas o
recordar lo que el código está tratando de hacer. Cualquier texto para el resto de la
línea que sigue a una marca hash (#) es parte de un comentario.
A veces, los programadores ponen un # delante de una línea de código para
eliminarlo temporalmente mientras prueban un programa. Esto se denomina código para comentar y
puede ser útil cuando intenta averiguar por qué un programa no funciona. Puede eliminar el # más
tarde cuando esté listo para volver a colocar la línea .

Python también ignora la línea en blanco después del comentario. Puede agregar
tantas líneas en blanco a su programa como desee. Esto puede hacer que su código
sea más fácil de leer, como los párrafos de un libro.
La función print ()
La función print () muestra el valor de la cadena dentro de los paréntesis en la
pantalla.
v print ('¡Hola mundo!')
print ('¿Cuál es tu nombre?') # pregunta por su nombre
La línea de impresión ('¡Hola mundo!') Significa “Imprime el texto en la cadena
'¡Hola mundo!'”. Cuando Python ejecuta esta línea, dices que Python
llama a la función print () y se pasa el valor de la cadena a la función
. Un valor que se pasa a una llamada de función es un argumento . Tenga en cuenta que
las comillas no se imprimen en la pantalla. Simplemente marcan dónde comienza y termina la
cuerda
; no son parte del valor de la cadena.
nota También puede usar esta función para poner una línea en blanco en la pantalla; simplemente
llame a print () sin
nada entre paréntesis.
Al escribir el nombre de una función, los paréntesis de apertura y cierre al
final lo identifican como el nombre de una función. Es por eso que en este libro
verá print () en lugar de print. El Capítulo 2 describe las funciones con más detalle.
La función input ()
La función input () espera a que el usuario escriba algo de texto en el teclado
y presione Intro.
w myName = input ()
Esta llamada de función se evalúa como una cadena igual al texto del usuario, y la
línea de código anterior asigna la variable myName a este valor de cadena.
24 Capítulo 1
Puede pensar en la llamada a la función input () como una expresión que
evalúa cualquier cadena que el usuario haya ingresado. Si el usuario ingresó 'Al', entonces la
expresión se evaluaría como myName = 'Al'.
Imprimir el nombre del usuario
La siguiente llamada a print () en realidad contiene la expresión 'Es un
placer conocerte' + myName entre paréntesis.
x print ('Es un placer conocerte' + myName)
Recuerde que las expresiones siempre pueden evaluar a un solo valor. Si 'Al'
es el valor almacenado en myName en la línea anterior, entonces esta expresión
evalúa 'Es un placer conocerte, Al'. Este valor de cadena único se pasa a
print (), que lo imprime en la pantalla.
La función len ()
Puede pasar a la función len () un valor de cadena (o una variable que contenga una
cadena), y la función evalúa el valor entero del número de
caracteres en esa cadena.
y print ('La longitud de su nombre es:')
print (len (myName))
Ingrese lo siguiente en el shell interactivo para probar esto:
>>> len ('hola')
5
>>> len ('Mi monstruo muy enérgico solo bufó nachos.')
46
>>> len ('')
0
Al igual que esos ejemplos, len (myName) se evalúa como un número entero. Luego se
pasa a print () para que se muestre en la pantalla. Tenga en cuenta que print () le permite
pasar valores enteros o valores de cadena. Pero observe el error que
aparece cuando escribe lo siguiente en el shell interactivo:
>>> print ('I am' + 29 + 'years old.')
Traceback (última llamada más reciente):
Archivo "<pyshell # 6>", línea 1, en <module>
print ('I am' + 29 + 'años')
TypeError: no se puede convertir el objeto 'int' a str implícitamente
La función print () no está causando ese error, sino que es la
expresión que intentó pasar a print (). Obtiene el mismo mensaje de error si escribe
la expresión en el shell interactivo por sí solo.
Conceptos básicos de Python 25
>>> 'Tengo' + 29 + 'años'.
Rastreo (última llamada más reciente):
Archivo "<pyshell # 7>", línea 1, en <módulo>
'Soy' + 29 + 'años'.
TypeError: no se puede convertir el objeto 'int' a str implícitamente
Python da un error porque puede usar el operador + solo para agregar
dos enteros juntos o concatenar dos cadenas. No puede agregar un número entero
a una cadena porque esto no es gramatical en Python. Puede solucionar esto
usando una versión de cadena del entero, como se explica en la siguiente sección.
Las funciones str (), int () y float ()
Si desea concatenar un entero como 29 con una cadena para pasar a
print (), necesitará obtener el valor '29', que es la cadena forma de 29. La función
str () puede pasar un valor entero y se evaluará a una versión de valor de cadena
de la siguiente manera:
>>> str (29)
'29'
>>> print ('Soy' + str (29) + 'años.')
Tengo 29 años.
Dado que str (29) se evalúa como '29', la expresión 'I am' + str (29) +
'años'. se evalúa como 'Tengo' + '29' + 'años', lo que a su vez se
evalúa como 'Tengo 29 años'. Este es el valor que se pasa a la función
print ().
Las funciones str (), int () y float () evaluarán las
formas de cadena, número entero y punto flotante del valor que pase, respectivamente. Intente
convertir
algunos valores en el shell interactivo con estas funciones y observe
lo que sucede.
>>> str (0)
'0'
>>> str (-3.14)
'-3.14'
>>> int ('42 ')
42
>>> int (' - 99 ')
-99
>>> int (1.25 )
1
>>> int (1.99)
1
>>> float ('3.14')
3.14
>>> float (10)
10.0
26 Capítulo 1
Los ejemplos anteriores llaman a las funciones str (), int () y float ()
y les pasan valores de los otros tipos de datos para obtener una forma de cadena, número entero
o punto flotante de esos valores.
La función str () es útil cuando tiene un número entero o flotante que
desea concatenar en una cadena. La función int () también es útil si
tiene un número como valor de cadena que desea usar en algunas matemáticas.
Por ejemplo, la función input () siempre devuelve una cadena, incluso si el usuario
ingresa un número. Ingrese spam = input () en el shell interactivo e ingrese 101 cuando espera su
texto.
>>> spam = input ()
101
>>> spam
'101'
El valor almacenado dentro del spam no es el entero 101 sino la cadena '101'.
Si desea hacer matemáticas usando el valor en spam, use la función int () para
obtener la forma entera de spam y luego almacene esto como el nuevo valor en spam.
>>> spam = int (spam)
>>> spam
101
Ahora debería poder tratar la variable de spam como un entero en lugar
de una cadena.
>>> spam * 10/
5202.0
Tenga en cuenta que si pasa un valor a int () que no puede evaluar como un entero
, Python mostrará un mensaje de error.
>>> int ('99 .99 ')
Traceback (última llamada más reciente):
Archivo "<pyshell # 18>", línea 1, en <module>
int ('99 .99')
ValueError: literal no válido para int () con base 10 : '99 .99 '
>>> int (' doce ')
Rastreo (última llamada más reciente):
Archivo "<pyshell # 19>", línea 1, en <módulo>
int (' doce ')
ValueError: literal no válido para int ( ) con base 10: 'doce'
La función int () también es útil si necesita redondear un número de punto flotante
hacia abajo.
Conceptos básicos de Python 27
>>> int (7.7)
7
>>> int (7.7) + 1
8
En su programa, utilizó las funciones int () y str () en las últimas
tres líneas para obtener un valor del tipo de datos apropiado para el código.
z print ('¿Cuál es su edad?') # pregunte por su edad
myAge = input ()
print ('Usted será' + str (int (myAge) + 1) + 'en un año.')
La variable myAge contiene el valor devuelto por input (). Como
la función input () siempre devuelve una cadena (incluso si el usuario escribió un número
), puede usar el código int (myAge) para devolver un valor entero de la cadena
en myAge. Este valor entero se agrega a 1 en la expresión int (myAge) + 1.
El resultado de esta adición se pasa a la función str (): str (int (myAge)
+ 1). El valor de cadena devuelto se concatena con las cadenas 'Usted
será' y 'en un año'. evaluar a un valor de cadena grande. Esta cadena grande
finalmente se pasa a print () para que se muestre en la pantalla.
Digamos que el usuario ingresa la cadena '4' para myAge. La cadena '4' se convierte
en un entero, por lo que puede agregarle uno. El resultado es 5. La función str ()
convierte el resultado nuevamente en una cadena, por lo que puede concatenarlo con la
segunda cadena, 'en un año', para crear el mensaje final. Estos pasos de evaluación
se parecerían a la Figura 1-4.
text A nD numBe r equi vA le nCe
Aunque el valor de cadena de un número se considera un
valor completamente diferente del número entero o la versión de punto flotante, un número entero
puede ser igual a un
punto flotante.
>>> 42 == '42'
Falso
>>> 42 == 42.0
Verdadero
>>> 42.0 == 0042.000
Verdadero
Python hace esta distinción porque las cadenas son texto, mientras que los enteros y los
flotantes son ambos números.
28 Capítulo 1
print ('Serás' + str (int (myAge) + 1) + 'en un año.')
print ('Serás' + str (int () + 1) + 'en un año.')
print ('Serás' + str () + 'en un año.')
print ('Serás' + str () + 'en un año.')
print ('Serás' + + 'en un año.')
'4'
'5'
print ('Serás 5' + 'en un año.')
print ('Serás 5 en un año')
55
4+1
Figura 1-4: Los pasos de evaluación, si 4 se almacenó en myAge
Resumen
Puede calcular expresiones con una calculadora o escribir concatenaciones de cadenas
con un procesador de textos. Incluso puede hacer una replicación de cadenas fácilmente
copiando y pegando texto. Pero las expresiones y sus valores componentes (
operadores, variables y llamadas a funciones) son los componentes básicos
que crean los programas. Una vez que sepa cómo manejar estos elementos,
podrá indicarle a Python que opere en grandes cantidades de datos por usted.
Es bueno recordar los diferentes tipos de operadores (+, -, *, /, //,%
y ** para operaciones matemáticas, y + y * para operaciones de cadena) y los tres
tipos de datos (enteros, coma flotante números y cadenas) introducidos en este
capítulo.
También se introdujeron algunas funciones diferentes. Las
funciones print () y input () manejan la salida de texto simple (a la pantalla) y la entrada (desde el
teclado
). La función len () toma una cadena y se evalúa a un int del número
de caracteres en la cadena. Las funciones str (), int () y float ()
evaluarán la forma de cadena, número entero o número de punto flotante del valor
que se pasan.
En el próximo capítulo, aprenderá a decirle a Python que tome
decisiones inteligentes sobre qué código ejecutar, qué código omitir y qué código
repetir según los valores que tenga. Esto se conoce como control de flujo y le permite
escribir programas que toman decisiones inteligentes.
Preguntas de práctica
1. ¿Cuáles de los siguientes son operadores y cuáles son valores?
*
'hola'
-88.8
-
/
+
5
Conceptos básicos de Python 29
2. ¿Cuál de las siguientes es una variable y cuál es una cadena?
spam
'spam'
3. Nombra tres tipos de datos.
4. ¿De qué está compuesta una expresión? ¿Qué hacen todas las expresiones?
5. Este capítulo introdujo declaraciones de asignación, como spam = 10. ¿Qué es
La diferencia entre una expresión y una declaración?
6. ¿Qué contiene la variable tocino después de que se ejecuta el siguiente código?
tocino = 20
tocino + 1
7. ¿Qué deberían evaluar las siguientes dos expresiones?
'spam' + 'spamspam'
'spam' * 3
8. ¿Por qué huevos es un nombre de variable válido mientras que 100 no es válido?
9. ¿Qué tres funciones se pueden usar para obtener el entero, punto flotante?
número o versión de cadena de un valor?
10. ¿Por qué esta expresión causa un error? ¿Cómo puedes arreglarlo?
'He comido' + 99 + 'burritos'.
Crédito adicional: busque en línea la documentación de Python para la función len ()
. Estará en una página web titulada "Funciones incorporadas". Hojee la
lista de otras funciones que tiene Python, busque lo que hace la función round ()
y experimente con ella en el shell interactivo.
2
f bajo C ontrol
Entonces conoce los conceptos básicos de las instrucciones individuales
y que un programa es solo un
serie de instrucciones Pero la verdadera fuerza
de la programación no es solo ejecutar (o ejecutar )
una instrucción tras otra como una
lista de recados de fin de semana . Según cómo se evalúan las expresiones, el programa
puede decidir omitir instrucciones, repetirlas
o elegir una de varias instrucciones para ejecutar. De hecho, casi nunca desea que
sus programas comiencen desde la primera línea de código y simplemente ejecuten cada
línea, directamente hasta el final. Las instrucciones de control de flujo pueden decidir
qué instrucciones de Python
ejecutar en qué condiciones.
Estas declaraciones de control de flujo corresponden directamente a los símbolos en un
diagrama de flujo, por lo que proporcionaré versiones de diagrama de flujo del código discutido en
este
capítulo. La Figura 2-1 muestra un diagrama de flujo de qué hacer si está lloviendo. Siga
el camino hecho por las flechas de principio a fin.
32 Capítulo 2
No
si
si
No
No, ve afuera.
Espera un momento.
comienzo
Fin
¿Está lloviendo? ¿Tienes paraguas?
¿Está lloviendo? si
Figura 2-1: un diagrama de flujo para decirle qué hacer si está lloviendo
En un diagrama de flujo, generalmente hay más de una forma de ir desde el principio
hasta el final. Lo mismo es cierto para las líneas de código en un programa de computadora. Los
diagramas de flujo representan estos puntos de ramificación con diamantes, mientras que los otros
pasos se representan con rectángulos. Los pasos inicial y final se
representan con rectángulos redondeados.
Pero antes de aprender acerca de las declaraciones de control de flujo, primero debe
aprender a representar esas opciones sí y no , y debe comprender
cómo escribir esos puntos de ramificación como código Python. Con ese fin,
exploremos los valores booleanos, los operadores de comparación y los operadores booleanos.
Valores booleanos
Mientras que los tipos de datos enteros, de coma flotante y de cadena tienen un
número ilimitado de valores posibles, el tipo de datos booleanos tiene solo dos valores: verdadero
y falso. (Booleano está en mayúscula porque el tipo de datos lleva el nombre del
matemático George Boole). Cuando se escribe como código Python, los
valores booleanos Verdadero y Falso carecen de las comillas que coloca alrededor de las cadenas, y
siempre comienzan con una T o F mayúscula , con el resto de la palabra en minúsculas.
Ingrese lo siguiente en el shell interactivo. (Algunas de estas instrucciones
son intencionalmente incorrectas y harán que aparezcan mensajes de error).
Control de flujo 33
u >>> spam = verdadero
>>> spam
verdadero
v >>> Traceback verdadero
(última llamada más reciente):
Archivo "<pyshell # 2>", línea 1, en <module>
true
NameError: el nombre 'true' no está definido
w >>> True = 2 + 2
SyntaxError: asignación a la palabra clave
Como cualquier otro valor, los valores booleanos se usan en expresiones y se
pueden almacenar en las variables u. Si no usa el caso apropiado v o intenta usar
Verdadero y Falso para los nombres de variables w, Python le dará un mensaje de error.
operadores de comparación Los operadores de
comparación comparan dos valores y evalúan a un solo
valor booleano. La Tabla 2-1 enumera los operadores de comparación.
tabla 2-1: Operador Operador de comparación
que significa
== ¡Igual a
! = No es igual a
<Menor que
> Mayor que
<= Menor o igual que
> = Mayor o igual que
Estos operadores evalúan a Verdadero o Falso dependiendo de los valores que
les dé. Probemos algunos operadores ahora, comenzando con == y! =.
>>> 42 == 42
Verdadero
>>> 42 == 99
Falso
>>> 2! = 3
Verdadero
>>> 2! = 2
Falso
Como es de esperar, == (igual a) se evalúa como verdadero cuando los valores
en ambos lados son iguales, y! = (No es igual a) se evalúa como verdadero cuando
los dos valores son diferentes. Los operadores == y! = Realmente pueden trabajar con
valores de cualquier tipo de datos.
34 Capítulo 2
>>> 'hello' == 'hello'
True
>>> 'hello' == 'Hello'
False
>>> 'dog'! = 'cat'
True
>>> True == True
True
>>> True! = Falso
Verdadero
>>> 42 == 42.0
Verdadero
u >>> 42 == '42'
Falso
Tenga en cuenta que un valor entero o de punto flotante siempre será desigual a un
valor de cadena. La expresión 42 == '42' u se evalúa como False porque Python
considera que el entero 42 es diferente de la cadena '42'.
Los operadores <,>, <= y> =, por otro lado, funcionan correctamente solo
con valores enteros y de coma flotante.
>>> 42 <100
Verdadero
>>> 42> 100
Falso
>>> 42 <42
Falso
>>> eggCount = 42
u >>> eggCount <= 42
True
>>> myAge = 29
v >>> myAge> = 10
verdadero
LA DIFERENCIA NECESE Tweent == A nD = oPe r AtorS
Es posible que haya notado que el operador == (igual a) tiene dos signos iguales,
mientras que el operador = (asignación) tiene solo un signo igual. Es fácil confundir
estos dos operadores entre sí. Solo recuerde estos puntos:
• El operador == (igual a) pregunta si dos valores son iguales a cada uno
otro.
• El operador = (asignación) coloca el valor a la derecha en la variable
a la izquierda .
Para ayudar a recordar cuál es cuál, observe que el operador == (igual a)
consta de dos caracteres, al igual que el operador! = (no igual a) consta de
dos caracteres.
Control de flujo 35
A menudo usará operadores de comparación para comparar el valor de una variable con
algún otro valor, como en los ejemplos eggCount <= 42 u y myAge> = 10 v.
(Después de todo, en lugar de escribir 'dog'! = 'Cat' en su código, podría haber
escrito True ). Verá más ejemplos de esto más adelante cuando aprenda sobre
las declaraciones de control de flujo.
Operadores booleanos
Los tres operadores booleanos (y, o, y no) se utilizan para comparar
valores booleanos . Al igual que los operadores de comparación, evalúan estas expresiones
hasta un valor booleano. Exploremos estos operadores en detalle, comenzando con el
operador y.
Operadores booleanos binarios Los operadores
y / o siempre toman dos valores booleanos (o expresiones),
por lo que se consideran operadores binarios . El operador y evalúa una
expresión como Verdadero si ambos valores booleanos son Verdaderos; de lo contrario, se evalúa
como False.
Ingrese algunas expresiones usando y en el shell interactivo para verlo en acción.
>>> Verdadero y verdadero
Verdadero
>>> Verdadero y falso
Falso
Una tabla de verdad muestra todos los resultados posibles de un operador booleano. La tabla 2-2
es la tabla de verdad para el operador y.
tabla 2-2: La
expresión de la tabla de verdad del operador y se evalúa como ...
Verdadero y verdadero Verdadero
verdadero y falso Falso
falso y verdadero Falso
Falso y Falso Falso
Por otro lado, el operador o evalúa una expresión como True si
alguno de los dos valores booleanos es True. Si ambos son falsos, se evalúa como falso.
>>> Falso o Verdadero
Verdadero
>>> Falso o Falso
Falso
Puede ver todos los resultados posibles del operador o en su tabla de verdad, que se
muestra en la Tabla 2-3.
36 Capítulo 2
tabla 2-3: La
expresión de la tabla de verdad o del operador se evalúa como ...
Verdadero o verdadero Verdadero
Verdadero o Falso Verdadero
Falso o Verdadero Verdadero
Falso o Falso Falso
El operador no
A diferencia de y y o, el operador no opera solo con un valor booleano (o
expresión). El operador no simplemente evalúa el valor booleano opuesto.
>>> no es cierto
falso
u >>> no no no no es cierto
cierto
Al igual que con el uso de negativos dobles en el habla y la escritura, puede anidar
no operadores u, aunque nunca hay ninguna razón para hacerlo en programas reales
. La tabla 2-4 muestra la tabla de verdad para no.
tabla 2-4: La
expresión de tabla de verdad del operador no se evalúa como ...
no es verdadero Falso
no es falso Verdadero
mezcla de operadores booleanos y de comparación
Dado que los operadores de comparación evalúan los valores booleanos, puede usarlos
en expresiones con los operadores booleanos.
Recuerde que los operadores and, or y not se llaman operadores booleanos
porque siempre operan en los valores booleanos Verdadero y Falso. Si bien las
expresiones como 4 <5 no son valores booleanos, son expresiones que se evalúan
hasta valores booleanos. Intente ingresar algunas expresiones booleanas que
usan operadores de comparación en el shell interactivo.
>>> (4 <5) y (5 <6)
Verdadero
>>> (4 <5) y (9 <6)
Falso
>>> (1 == 2) o (2 == 2)
Verdadero
Control de flujo 37
La computadora evaluará primero la expresión izquierda
y luego evaluará la expresión derecha. Cuando
conoce el valor booleano para cada uno, evaluará
toda la expresión hasta un valor booleano. Puede
pensar en el proceso de evaluación de la computadora para
(4 <5) y (5 <6) como se muestra en la Figura 2-2.
También puede usar múltiples operadores booleanos en una
expresión, junto con los operadores de comparación.
>>> 2 + 2 == 4 y no 2 + 2 == 5 y 2 * 2 == 2 + 2
Verdadero
Los operadores booleanos tienen un orden de operaciones al igual que los
operadores matemáticos. Después de que cualquier operador matemático y de comparación evalúe,
Python evalúa primero los operadores no, luego los operadores y, y luego
los operadores o.
elementos de control de
flujo Las instrucciones de control de flujo a menudo comienzan con una parte llamada condición ,
y a todas
les sigue un bloque de código llamado cláusula . Antes de que aprenda sobre
las declaraciones de control de flujo específicas de Python, cubriré qué son una condición y un
bloque.
Condiciones
Las expresiones booleanas que has visto hasta ahora podrían considerarse
condiciones, que son lo mismo que expresiones; condición es solo un
nombre más específico en el contexto de las declaraciones de control de flujo. Las condiciones
siempre se
evalúan hasta un valor booleano, verdadero o falso. Una declaración de control de flujo
decide qué hacer en función de si su condición es Verdadera o Falsa, y
casi todas las declaraciones de control de flujo usan una condición.
Bloques de código Las
líneas de código Python se pueden agrupar en bloques . Puede saber cuándo
comienza y termina un bloque desde la sangría de las líneas de código. Hay
tres reglas para los bloques.
1. Los bloques comienzan cuando aumenta la sangría.
2. Los bloques pueden contener otros bloques.
3. Los bloques terminan cuando la sangría disminuye a cero o a un contenedor
sangría del bloque.
(4 <5) y (5 <6)
Verdadero y (5 <6)
Verdadero y verdadero
Cierto
Figura 2-2: El
proceso de evaluación
(4 <5) y
(5 <6) como Verdadero.
38 Capítulo 2
Los bloques son más fáciles de entender mirando un código sangrado, así que
busquemos los bloques en parte de un pequeño programa de juegos, que se muestra aquí:
if name == 'Mary':
u print ('Hola Mary')
if password == 'swordfish':
v print ('Acceso otorgado')
de lo contrario:
w print ('Contraseña incorrecta')
El primer bloque de código u comienza en la línea de impresión ('Hola Mary') y contiene
todas las líneas que siguen. Dentro de este bloque hay otro bloque v, que tiene
una sola línea: print ('Acceso concedido'). El tercer bloque w también tiene
una línea de longitud: print ('Contraseña incorrecta').
Ejecución del programa
En el programa hello.py del capítulo anterior , Python comenzó a ejecutar
instrucciones en la parte superior del programa, una tras otra. La
ejecución del programa (o simplemente, ejecución ) es un término para la instrucción actual que se
está ejecutando. Si imprime el código fuente en papel y coloca su dedo
en cada línea a medida que se ejecuta, puede pensar en su dedo como la ejecución del programa
.
Sin embargo, no todos los programas se ejecutan simplemente yendo hacia abajo. Si
usa su dedo para rastrear un programa con instrucciones de control de flujo,
es probable que se salte el código fuente en función de las condiciones
, y probablemente omita cláusulas completas.
Declaraciones de control de flujo
Ahora, exploremos la pieza más importante de control de flujo: las declaraciones
mismas. Las declaraciones representan los diamantes que vio en el diagrama de flujo
de la Figura 2-1, y son las decisiones reales que tomarán sus programas.
Declaraciones if
El tipo más común de declaración de control de flujo es la declaración if. Una
cláusula de la declaración if (es decir, el bloque que sigue a la declaración if) se ejecutará
si la condición de la declaración es True. La cláusula se omite si la condición es
False.
En inglés simple, una declaración if podría leerse como, "Si esta condición es
verdadera, ejecute el código en la cláusula". En Python, una declaración if consiste en
lo siguiente:

• La palabra clave if • Una condición (es decir, una expresión que se evalúa como Verdadero o
Falso) • Dos puntos • A partir de la siguiente línea, un bloque de código sangrado (llamado cláusula
if)

Control de flujo 39
Por ejemplo, supongamos que tiene un código que verifica si
el nombre de alguien es Alice. (Pretender nombre se le asignó algún valor anteriormente).
if name == 'Alice':
print ('Hola, Alice')
Todas las declaraciones de control de flujo terminan con dos puntos y van seguidas de un
nuevo bloque de código (la cláusula). Esta cláusula de la declaración if es el bloque con
print ('Hola, Alice'). La Figura 2-3 muestra cómo se vería un diagrama de flujo de este código
.
print ('Hola, Alice')
comienzo
Fin
nombre == 'Alice' Verdadero
Falso
Figura 2-3: El diagrama de flujo para una declaración if

sentencias else Una cláusula if puede ser seguida opcionalmente por una sentencia else. La cláusula
else
se ejecuta solo cuando la condición de la instrucción if es False. En inglés simple,
una instrucción else podría leerse como: “Si esta condición es verdadera, ejecute este
código. O bien, ejecute ese código ”. Una instrucción else no tiene una
condición, y en el código, una instrucción else siempre consta de lo siguiente:

• La palabra clave else • Dos puntos • Comenzando en la siguiente línea, un bloque de código
sangrado (llamado el else

cláusula)
Volviendo al ejemplo de Alice, veamos un código que usa una
instrucción else para ofrecer un saludo diferente si el nombre de la persona no es Alice.
if name == 'Alice':
print ('Hola, Alice')
40 Capítulo 2
más:
print ('Hola, extraño')
La Figura 2-4 muestra cómo se vería un diagrama de flujo de este código.
print ('Hola, Alice')
comienzo
Fin
nombre == 'Alice'
print ('Hola, extraño')
Cierto
Falso
Figura 2-4: El diagrama de flujo para una instrucción else
Declaraciones elif
Si bien solo una de las cláusulas if o else se ejecutará, es posible que tenga un caso
en el que desee que se ejecute una de las muchas cláusulas posibles. La declaración elif
es una declaración "else if" que siempre sigue a una declaración if u otra declaración elif.
Proporciona otra condición que se verifica solo si alguna de las condiciones anteriores
era False. En el código, una declaración elif siempre consta de lo siguiente:

• La palabra clave elif • Una condición (es decir, una expresión que se evalúa como Verdadero o
Falso) • Dos puntos • A partir de la siguiente línea, un bloque de código sangrado (llamado
elif

cláusula)
Agreguemos un elif al comprobador de nombres para ver esta declaración en acción.
if name == 'Alice':
print ('Hi, Alice.')
elif age <12:
print ('You are not Alice, kiddo.')
Control de flujo 41
Esta vez, verifica la edad de la persona y el programa le dirá
algo diferente si es menor de 12 años. Puede ver el diagrama de flujo
en la Figura 2-5.
print ('Hola, Alice')
comienzo
Fin
nombre == 'Alice'
print ('No eres Alice, chico') edad <12
Cierto
Falso
Cierto
Falso
Figura 2-5: El diagrama de flujo para una declaración elif
La cláusula elif se ejecuta si age <12 es True y name == 'Alice' es False.
Sin embargo, si ambas condiciones son falsas, se
omiten ambas cláusulas . Se no garantiza que al menos una de las cláusulas se eje-
recortado. Cuando hay una cadena de declaraciones elif, solo
se ejecutará una o ninguna de las cláusulas. Una vez que se encuentra que una de las condiciones de
las declaraciones es
Verdadera, el resto de las cláusulas elif se omiten automáticamente. Por ejemplo,
abra una nueva ventana del editor de archivos e ingrese el siguiente código, guardándolo como
vampire.py :
if name == 'Alice':
print ('Hi, Alice.')
elif age <12:
print ('You are not Alice, kiddo.')
elif age> 2000:
print ('A diferencia de ti, Alice no es un no muerto , vampiro inmortal. ')
elif age> 100:
print (' No eres Alice, abuelita ')
42 Capítulo 2
Aquí he agregado dos declaraciones elif más para hacer que el corrector de nombres
salude a una persona con diferentes respuestas según la edad. La Figura 2-6 muestra el
diagrama de flujo para esto.
print ('Hola, Alice')
Fin
nombre == 'Alice'
print ('No eres Alice, chico') edad <12
Cierto
Falso
Cierto
Falso
edad> 100
Cierto
Falso
print ('No eres Alice, abuelita')
edad> 2000
Cierto
Falso
comienzo
print ('A diferencia de ti, Alice no es un vampiro inmortal ni
muerto viviente').
Figura 2-6: Diagrama de flujo para múltiples declaraciones elif en el programa vampiro .py
Control de flujo 43
Sin embargo, el orden de las declaraciones elif es importante. Vamos a reorganizarlos
para introducir un error. Recuerde que el resto de las cláusulas elif se
omiten automáticamente una vez que se ha encontrado una condición Verdadera, por lo que
si cambia
algunas de las cláusulas en vampire.py , se encuentra con un problema. Cambie
el código para que tenga el siguiente aspecto y guárdelo como vampire2.py :
if name == 'Alice':
print ('Hi, Alice.')
elif age <12:
print ('You are not Alice, kiddo.')
u elif age> 100:
print ('No eres Alice, abuelita')
elif age> 2000:
print ('A diferencia de ti, Alice no es un vampiro inmortal ni muerto viviente').
Digamos que la variable de edad contiene el valor 3000 antes de que se ejecute este código.
Puede esperar que el código imprima la cadena "A diferencia de usted, Alice no es
un vampiro inmortal e inmortal". Sin embargo, debido a que la condición de edad> 100 es
Verdadera (después de todo, 3000 es mayor que 100) u, la cadena 'No eres Alice,
abuelita'. se imprime y el resto de las declaraciones elif se
omiten automáticamente . Recuerde, como máximo solo se ejecutará una de las cláusulas, y
para las declaraciones elif, ¡el orden importa!
La Figura 2-7 muestra el diagrama de flujo del código anterior. Observe cómo se intercambian los
diamantes para edades> 100 y edades> 2000.
Opcionalmente, puede tener una instrucción else después de la última instrucción elif.
En ese caso, se garantiza que al menos una (y sólo una) de las cláusulas
se ejecutará. Si las condiciones en cada instrucción if y elif son False,
entonces se ejecuta la cláusula else. Por ejemplo, volvamos a crear el programa Alice
para usar las cláusulas if, elif y else.
if name == 'Alice':
print ('Hola, Alice.')
elif age <12:
print ('No eres Alice, kiddo.')
sino:
print ('No eres Alice ni una niña pequeña')
La Figura 2-8 muestra el diagrama de flujo para este nuevo código, que
guardaremos como littleKid.py .
En inglés simple, este tipo de estructura de control de flujo sería: “Si la
primera condición es verdadera, haga esto. De lo contrario, si la segunda condición es verdadera,
hazlo.
De lo contrario, haga otra cosa ”. Cuando use estas tres declaraciones
juntas, recuerde estas reglas sobre cómo ordenarlas para evitar errores como
el de la Figura 2-7. Primero, siempre hay exactamente una declaración if. Cualquier
declaración elif que necesite debe seguir la declaración if. En segundo lugar, si desea
asegurarse de que se ejecute al menos una cláusula, cierre la estructura con una instrucción else
.
44 Capítulo 2
print ('Hola, Alice')
comienzo
Fin
print ('No eres Alice, chico')
Cierto
Falso
Cierto
Falso
print ('A diferencia de ti, Alice no es un vampiro inmortal ni
muerto viviente').
Cierto
Falso
print ('No eres Alice, abuelita')
Falso
X
nombre == 'Alice'
edad <12
edad> 2000
edad> 100
Cierto
Figura 2-7: Diagrama de flujo del programa vampire2 .py. El camino tachado
lógicamente nunca sucederá, porque si la edad fuera mayor a 2000, ya hubiera
sido mayor a 100.
Control de flujo 45
print ('Hola, Alice')
comienzo
Fin
nombre == 'Alice'
print ('No eres Alice, chico') edad <12
Cierto
Falso
Cierto
Falso
print ('No eres ni Alice
ni una niña pequeña')
Figura 2-8: Diagrama de flujo para el programa littlepyid .py anterior
declaraciones de bucle while
Puede hacer que un bloque de código se ejecute una y otra vez con una declaración while
. El código en una cláusula while se ejecutará siempre que la condición del estado while
sea True. En el código, una instrucción while siempre consta de lo
siguiente:

• La palabra clave while • Una condición (es decir, una expresión que se evalúa como Verdadero o
Falso) • Dos puntos • A partir de la siguiente línea, un bloque de código sangrado (llamado
while

cláusula)
46 Capítulo 2
Puede ver que una declaración while es similar a una declaración if. La
diferencia está en cómo se comportan. Al final de una cláusula if, la
ejecución del programa continúa después de la instrucción if. Pero al final de una cláusula while,
la ejecución del programa vuelve al inicio de la instrucción while. La
cláusula while a menudo se denomina bucle while o simplemente bucle .
Veamos una declaración if y un ciclo while que usan la misma
condición y toman las mismas acciones basadas en esa condición. Aquí está el código
con una declaración if:
spam = 0
si spam <5:
print ('Hola, mundo')
spam = spam + 1
Aquí está el código con una declaración while:
spam = 0
mientras spam <5:
print ('Hola, mundo')
spam = spam + 1
Estas declaraciones son similares: tanto si verifican el valor del correo no deseado
como si lo hacen , y si son menos de cinco, imprimen un mensaje. Pero cuando ejecuta estos dos
fragmentos de código, sucede algo muy diferente para cada uno. Para la
instrucción if , la salida es simplemente "Hola, mundo". Pero para la declaración while,
es "Hola, mundo". repite cinco veces! Eche un vistazo a los diagramas de flujo de
estas dos piezas de código, Figuras 2-9 y 2-10, para ver por qué sucede esto.
print ('Hola, mundo')
comienzo
Fin
spam <5
spam = spam + 1
Cierto
Falso
Figura 2-9: El diagrama de flujo para el código de instrucción if
Control de flujo 47
print ('Hola, mundo')
comienzo
Fin
spam <5
spam = spam + 1
Cierto
Falso
Figura 2-10: El diagrama de flujo para el código de instrucción while
El código con la instrucción if verifica la condición e imprime
Hello, world. solo una vez si esa condición es verdadera. El código con el bucle while,
por otro lado, lo imprimirá cinco veces. Se detiene después de cinco impresiones porque
el número entero en el correo no deseado se incrementa en uno al final de cada iteración del bucle,
lo
que significa que el bucle se ejecutará cinco veces antes de que el correo no deseado <5 sea Falso.
En el ciclo while, la condición siempre se verifica al comienzo de cada
iteración (es decir, cada vez que se ejecuta el ciclo). Si la condición es Verdadera,
entonces se ejecuta la cláusula, y luego, la condición se verifica nuevamente.
La primera vez que se descubre que la condición es False, se omite la cláusula while.
un molesto mientras Loop
Aquí hay un pequeño programa de ejemplo que le pedirá que escriba, literalmente,
su nombre. Seleccione File4New Window para abrir una nueva ventana del editor de archivos,
ingrese
el siguiente código y guarde el archivo como yourName.py:
u name = ''
v while name! = 'tu nombre':
print ('Por favor escriba su nombre')
w nombre = input ()
x print ('¡Gracias!')
Primero, el programa establece la variable de nombre u en una cadena vacía. Esto es para
que la condición name! = 'Your name' se evalúe como True y la ejecución del programa
ingrese la cláusula v del ciclo while.
48 Capítulo 2
El código dentro de esta cláusula le pide al usuario que escriba su nombre, que
se asigna a la variable de nombre w. Como esta es la última línea del bloque,
la ejecución retrocede al inicio del ciclo while y vuelve a evaluar la
condición. Si el valor en el nombre no es igual a la cadena 'su nombre', entonces
la condición es Verdadera y la ejecución ingresa nuevamente la cláusula while.
Pero una vez que el usuario escriba su nombre , la condición del bucle while será
'your name'! = 'Your name', que se evalúa como False. La condición ahora es
Falsa y, en lugar de que la ejecución del programa vuelva a ingresar la
cláusula while , se salta y continúa ejecutando el resto del programa x.
La Figura 2-11 muestra un diagrama de flujo para el programa yourName.py.
print ('Por favor escriba su nombre')
comienzo
Fin
¡nombre! = 'tu nombre'
nombre = input ()
Cierto
Falso
nombre = "
print ('¡Gracias!')
Figura 2-11: Diagrama de flujo del programa yourName .py
Ahora, veamos yourName.py en acción. Presione F5 para ejecutarlo e ingrese algo que
no sea su nombre varias veces antes de darle al programa lo que quiere.
Por favor escriba su nombre.
Al
Por favor escriba su nombre.
Albert
Control de flujo 49
Por favor escriba su nombre.
% # @ #% * (^ & !!!
Por favor escriba su nombre.
Su nombre ¡
Gracias!
Si nunca ingresa su nombre , la condición del ciclo while nunca
será False, y el programa seguirá preguntando para siempre. Aquí, la
llamada input () permite al usuario ingresar la cadena correcta para hacer que el programa
avance. En
otros programas, la condición podría nunca cambiar realmente, y eso puede
ser un problema. Veamos cómo puedes salir de un ciclo while.
declaraciones de interrupción
Hay un atajo para lograr que la ejecución del programa se salga de una
cláusula while antes de tiempo. Si la ejecución alcanza una declaración de interrupción,
sale inmediatamente de la cláusula del bucle while. En el código, una declaración de interrupción
simplemente contiene
la palabra clave de interrupción.
Bastante simple, ¿verdad? Aquí hay un programa que hace lo mismo que el
programa anterior, pero usa una instrucción break para escapar del ciclo. Ingrese el
siguiente código y guarde el archivo como yourName2.py:
u while True:
print ('Por favor escriba su nombre')
v name = input ()
w if name == 'tu nombre':
x break
y print ('¡Gracias!')
La primera línea u crea un bucle infinito; Es un ciclo while cuya condición
siempre es verdadera. (La expresión Verdadero, después de todo, siempre se evalúa hasta el
valor Verdadero). La ejecución del programa siempre entrará en el bucle y saldrá
solo cuando se ejecute una declaración de interrupción. (Un bucle infinito que nunca sale
es un error de programación común).
Al igual que antes, este programa le pide al usuario que escriba su nombre v. Ahora,
sin embargo, mientras la ejecución todavía está dentro del ciclo while,
se ejecuta una instrucción if w para verificar si el nombre es igual a su nombre. Si esta
condición es Verdadera, la instrucción break se ejecuta x, y la ejecución se mueve fuera del
ciclo para imprimir ('¡Gracias!') Y. De lo contrario,
se omite la cláusula de la instrucción if con la instrucción break, lo que coloca la ejecución al final
del
ciclo while. En este punto, la ejecución del programa vuelve al inicio de la
instrucción while u para volver a verificar la condición. Dado que esta condición es simplemente
el valor booleano verdadero, la ejecución ingresa al bucle para pedirle al usuario que escriba
su nombre nuevamente. Consulte la Figura 2-12 para ver el diagrama de flujo de este
programa.
Ejecute yourName2.py e ingrese el mismo texto que ingresó para yourName.py .
El programa reescrito debe responder de la misma manera que el original.
50 Capítulo 2
print ('Por favor escriba su nombre')
comienzo
Fin
Cierto
nombre = input ()
Cierto
nombre = "
print ('¡Gracias!')
nombre == 'tu nombre' breakTrue
Falso
XFalse
Figura 2-12: El diagrama de flujo para el programa yourName2 .py con un bucle infinito. Tenga en
cuenta
que la ruta X nunca sucederá lógicamente porque la condición del bucle siempre es verdadera.
declaraciones continuas
Al igual que las declaraciones de interrupción, las declaraciones continuas se usan dentro de los
bucles. Cuando la
ejecución del programa alcanza una instrucción de continuación, la ejecución del programa
salta inmediatamente al inicio del ciclo y vuelve a evaluar la
condición del ciclo . (Esto también es lo que sucede cuando la ejecución llega al final
del ciclo).
Control de flujo 51
Usemos continuar para escribir un programa que solicite un nombre y una contraseña.
Ingrese el siguiente código en una nueva ventana del editor de archivos y guarde el programa
como swordfish.py.
while True:
print ('¿Quién eres?')
nombre = input ()
u if name! = 'Joe':
v continuar
print ('Hola, Joe. ¿Cuál es la contraseña? (Es un pez.)')
w contraseña = input ()
if password == 'swordfish':
x break
y print ('Acceso otorgado')
Si el usuario ingresa algún nombre además de Joe u, la instrucción continue v
hace que la ejecución del programa salte al inicio del ciclo. Cuando
reevalúa la condición, la ejecución siempre entrará en el ciclo, ya que
la condición es simplemente el valor Verdadero. Una vez que lo superan
, si se hace una declaración , se le solicita al usuario una contraseña w. Si la contraseña ingresada es
pez espada,
entonces se ejecuta la instrucción break x, y la ejecución salta del
bucle while para imprimir Acceso otorgado y. De lo contrario, la ejecución continúa hasta el
final del ciclo while, donde luego vuelve al inicio del ciclo. Consulte la
Figura 2-13 para ver el diagrama de flujo de este programa.
tr A PPe D en A n inf ini te looP?
Si alguna vez ejecuta un programa que tiene un error que hace que se atasque en un
bucle infinito , presione ctrl-C. Esto enviará un error KeyboardInterrupt a su programa
y hará que se detenga inmediatamente. Para probarlo, cree un bucle infinito simple en el
editor de archivos y guárdelo como infiniteloop.py.
while True:
print ('¡Hola mundo!')
Cuando ejecute este programa, imprimirá Hello world! a la pantalla para siempre,
porque la condición de la instrucción while es siempre True. En la
ventana del shell interactivo de IDLE , solo hay dos formas de detener este programa: presione ctrl-
C o seleccione
Shell4restart Shell en el menú. ctrl-C es útil si alguna vez desea
finalizar su programa de inmediato, incluso si no está atascado en un bucle infinito.
52 Capítulo 2
print ('¿Quién eres?')
comienzo
Fin
Cierto
nombre = input ()
Cierto
nombre = "
print ('Acceso concedido')
name! = 'Joe'continue True
X
print ('Hola, Joe. ¿Cuál es la contraseña? (Es un pez)')
contraseña = input ()
contraseña == 'pez espada'
romper verdad
Falso
Falso
Falso
Figura 2-13: Un diagrama de flujo para el pez espada .py. La ruta X nunca sucederá lógicamente
porque la condición del bucle
siempre es verdadera.
Control de flujo 53
Ejecute este programa y dele algo de entrada. Hasta que afirme ser Joe, no
debe solicitar una contraseña, y una vez que ingrese la contraseña correcta,
debe salir.
¿Quién eres tú?
Estoy bien, gracias. ¿Quién eres tú?
¿Quién eres tú?
Joe
Hola, Joe. ¿Cual es la contraseña? (Es un pez)
Mary
¿Quién eres?
Joe
Hola, Joe. ¿Cual es la contraseña? (Es un pez). Pez
espada
Acceso concedido.
para bucles y la función range ()
El bucle while continúa en bucle mientras su condición es True (que es la razón
de su nombre), pero ¿qué sucede si desea ejecutar un bloque de código solo un cierto
número de veces? Puede hacer esto con una declaración de bucle for y la función range ()
.
“ T ru thy” Y “fA l Se y” vA lue S
Hay algunos valores en otros tipos de datos que las condiciones considerarán equivalentes
a Verdadero y Falso. Cuando se usa en condiciones, 0, 0.0 y '' (la
cadena vacía ) se consideran falsos, mientras que todos los demás valores se consideran
verdaderos. Por
ejemplo, mira el siguiente programa:
name = ''
mientras no name: u
print ('Ingrese su nombre:')
name = input ()
print ('¿Cuántos invitados tendrá?')
numOfGuests = int (input ())
if numOfGuests: v
print (' Asegúrese de tener suficiente espacio para todos sus invitados. ') W
imprimir (' Listo ')
Si el usuario ingresa una cadena en blanco para el nombre, la condición de la instrucción while
será True u, y el programa continúa pidiendo un nombre. Si el valor de
numOfGuests no es 0 v, entonces la condición se considera Verdadera y el
programa imprimirá un recordatorio para el usuario w.
Podría haber escrito not name! = '' En lugar de not name, y numOfGuests
! = 0 en lugar de numOfGuests, pero el uso de los valores truey y falsey puede hacer que
su código sea más fácil de leer.
54 Capítulo 2
En el código, una instrucción for se parece a i en el rango (5): y
siempre incluye lo siguiente:

• La palabra clave for • Un nombre de variable • La palabra clave in • Una llamada al método range
() con hasta tres números enteros pasados • Dos puntos • Comenzando en la siguiente línea, un
bloque de código sangrado (llamado para

cláusula)
Creemos un nuevo programa llamado fiveTimes.py para ayudarlo a ver un bucle for
en acción.
print ('Mi nombre es')
para i en el rango (5):
print ('Jimmy Five Times (' + str (i) + ')')
El código en la cláusula del bucle for se ejecuta cinco veces. La primera vez que
se ejecuta, la variable i se establece en 0. La llamada print () en la cláusula imprimirá
Jimmy Five Times (0). Después de que Python finaliza una iteración a través de todo el código
dentro de la cláusula del bucle for, la ejecución vuelve a la parte superior del bucle
y la instrucción for aumenta i por uno. Esta es la razón por la que el rango (5) da como resultado
cinco iteraciones a través de la cláusula, con i establecido en 0, luego 1, luego 2, luego
3 y luego 4. La variable subiré, pero no incluirá, el entero
pasado al rango (). La Figura 2-14 muestra un diagrama de flujo para el programa fiveTimes.py.
print ('Jimmy Five Times (' + str (i) + ')')
comienzo
Fin
para i en rango (5)
Bucle
Hecho bucle
print ('Mi nombre es')
Figura 2-14: Diagrama de flujo de cinco tiempos .py
Control de flujo 55
Cuando ejecuta este programa, debe imprimir Jimmy Five Times seguido
del valor de i cinco veces antes de abandonar el bucle for.
Mi nombre es
Jimmy Five Times (0)
Jimmy Five Times (1)
Jimmy Five Times (2)
Jimmy Five Times (3)
Jimmy Five Times (4)
note También puede usar declaraciones de interrupción y continuación para bucles. La
instrucción continue continuará al siguiente valor del contador del bucle for, como si la
ejecución del programa hubiera llegado al final del bucle y regresado al inicio. De hecho, puede
usar las declaraciones continuar y romper solo dentro de while y para bucles. Si intenta usar
estas declaraciones en otro lugar, Python le dará un error.
Como otro ejemplo de bucle, considere esta historia sobre el matemático
Karl Friedrich Gauss. Cuando Gauss era un niño, un maestro quería darle a
la clase algo de trabajo ocupado. La maestra les dijo que sumaran todos los números
del 0 al 100. Young Gauss ideó un ingenioso truco para descubrir la
respuesta en unos segundos, pero puede escribir un programa Python con un bucle for
para hacer este cálculo por usted .
u total = 0
v para num en rango (101):
w total = total + num
x print (total)
El resultado debe ser 5.050. Cuando el programa se inicia por primera vez, la
variable total se establece en 0 u. El bucle for v luego ejecuta total = total + num w
100 veces. Para cuando el ciclo haya terminado todas sus 100 iteraciones, todos los
enteros de 0 a 100 se habrán agregado al total. En este punto, el total se
imprime en la pantalla x. Incluso en las computadoras más lentas, este programa tarda
menos de un segundo en completarse.
(Young Gauss descubrió que había 50 pares de números que sumaban
100: 1 + 99, 2 + 98, 3 + 97, y así sucesivamente, hasta 49 + 51. Dado que 50 × 100 es
5,000, cuando agrega eso medio 50, la suma de todos los números del 0 al
100 es 5.050. ¡Niño inteligente!)
un bucle while equivalente
Puede usar un bucle while para hacer lo mismo que un bucle for; porque los
bucles son más concisos. Reescribamos fiveTimes.py para usar un ciclo while
equivalente a un ciclo for.
print ('Mi nombre es')
i=0
mientras i <5:
print ('Jimmy Five Times (' + str (i) + ')')
i=i+1
56 Capítulo 2
Si ejecuta este programa, la salida debería verse igual que el
programa fiveTimes.py, que utiliza un bucle for.
los argumentos de Inicio, Parada y Paso a rango ()
Algunas funciones se pueden invocar con varios argumentos separados por una
coma, y rango () es uno de ellos. Esto le permite cambiar el número entero pasado
a range () para seguir cualquier secuencia de números enteros, incluso comenzar en un número
distinto de cero.
para i en rango (12, 16):
imprimir (i)
El primer argumento será donde comienza la variable del bucle for, y el
segundo argumento será hasta, pero sin incluir, el número para detenerse.
12
13
14
15
La función range () también se puede invocar con tres argumentos. Los
dos primeros argumentos serán los valores de inicio y detención, y el tercero será el
argumento de paso . El paso es la cantidad que aumenta la variable después de
cada iteración.
para i en rango (0, 10, 2):
imprimir (i)
Por lo tanto, el rango de llamada (0, 10, 2) contará de cero a ocho por intervalos de dos.
0
2
4
6
8
La función range () es flexible en la secuencia de números que produce
para los bucles. Por ejemplo (nunca me disculpo por mis juegos de palabras), incluso puede usar
un número negativo para el argumento de paso para hacer que el bucle for cuente hacia atrás en
lugar de hacia arriba.
para i en rango (5, -1, -1):
print (i)
Ejecutar un bucle for para imprimir i con rango (5, -1, -1) debería imprimir de
cinco a cero.
5
4
Control de flujo 57
3
2
1
0
Importar módulos
Todos los programas de Python pueden llamar a un conjunto básico de funciones llamadas
funciones integradas ,
incluidas las funciones print (), input () y len () que has visto antes. Python
también viene con un conjunto de módulos llamados la biblioteca estándar . Cada módulo
es un programa de Python que contiene un grupo relacionado de funciones que pueden
integrarse en sus programas. Por ejemplo, el módulo matemático tiene
funciones relacionadas con las matemáticas , el módulo aleatorio tiene funciones relacionadas con
números aleatorios,
y así sucesivamente.
Antes de poder usar las funciones en un módulo, debe importar el
módulo con una declaración de importación. En el código, una declaración de importación consta
de
lo siguiente:

• La palabra clave de importación • El nombre del módulo • Opcionalmente, más nombres de


módulo, siempre que estén separados por

comas
Una vez que importe un módulo, puede usar todas las funciones interesantes de ese
módulo. Intentemos con el módulo aleatorio, que nos dará acceso
a la función random.randint ().
Ingrese este código en el editor de archivos y guárdelo como printRandom.py:
importación aleatoria
para i en rango (5):
print (random.randint (1, 10))
Cuando ejecutas este programa, la salida se verá así:
4
1
8
4
1
La llamada a la función random.randint () se evalúa como un valor entero aleatorio
entre los dos enteros que le pasa. Como randint () está en el
módulo aleatorio , primero debe escribir random. delante del nombre de la función para decirle a
Python que busque esta función dentro del módulo aleatorio.
Aquí hay un ejemplo de una declaración de importación que importa cuatro módulos diferentes
:
importar al azar, sys, os, matemáticas
58 Capítulo 2
Ahora podemos usar cualquiera de las funciones en estos cuatro módulos. Aprenderemos
más sobre ellos más adelante en el libro.
Declaraciones de importación
Una forma alternativa de la declaración de importación se compone de la
palabra clave from , seguida del nombre del módulo, la palabra clave de importación y una
estrella; por
ejemplo, de importación aleatoria *.
Con esta forma de declaración de importación, las llamadas a funciones al azar no
necesitarán el azar. prefijo. Sin embargo, usar el nombre completo hace que el código sea más
legible
, por lo que es mejor usar la forma normal de la declaración de importación.
finalización temprana de un programa con sys.exit ()
El último concepto de control de flujo a cubrir es cómo finalizar el programa.
Esto siempre sucede si la ejecución del programa llega al final de las
instrucciones. Sin embargo, puede hacer que el programa finalice o salga
llamando a la función sys.exit (). Dado que esta función está en el módulo sys,
debe importar sys antes de que su programa pueda usarla.
Abra una nueva ventana del editor de archivos e ingrese el siguiente código, guardándolo como
exitExample.py :
sistema de importación
while True:
print ('Escribe exit to exit.')
respuesta = input ()
if response == 'exit':
sys.exit () print (' Escribiste
' + respuesta + '.')
Ejecute este programa en IDLE. Este programa tiene un bucle infinito sin una
declaración de ruptura en su interior. La única forma en que este programa finalizará es si el usuario
ingresa a
exit, haciendo que se llame a sys.exit (). Cuando la respuesta es igual a la salida, el programa
finaliza. Como la variable input () establece la variable de respuesta, el usuario
debe ingresar exit para detener el programa.
Resumen
Al usar expresiones que evalúan como Verdadero o Falso (también llamadas condiciones ),
puede escribir programas que tomen decisiones sobre qué código ejecutar y
qué código omitir. También puede ejecutar código una y otra vez en un bucle
mientras una determinada condición se evalúa como Verdadera. Las declaraciones de interrupción y
continuación
son útiles si necesita salir de un ciclo o volver al inicio.
Estas declaraciones de control de flujo le permitirán escribir programas mucho más inteligentes
. Hay otro tipo de control de flujo que puede lograr escribiendo
sus propias funciones, que es el tema del próximo capítulo.
Control de flujo 59
Preguntas de práctica
1. ¿Cuáles son los dos valores del tipo de datos booleanos? Cómo
escribirlos?
2. ¿Cuáles son los tres operadores booleanos?
3. Escriba las tablas de verdad de cada operador booleano (es decir, cada
posible combinación de valores booleanos para el operador y lo
que evalúan).
4. ¿Qué evalúan las siguientes expresiones?
(5> 4) y (3 == 5)
no (5> 4)
(5> 4) o (3 == 5)
no ((5> 4) o (3 == 5))
(Verdadero y verdadero) y (Verdadero == Falso)
(no falso) o (no verdadero)
5. ¿Cuáles son los seis operadores de comparación?
6. ¿Cuál es la diferencia entre el operador igual a y la asignación?
operador de ment?
7. Explica qué es una condición y dónde usarías una.
8. Identifique los tres bloques en este código:
spam = 0
si spam == 10:
print ('huevos')
si spam> 5:
print ('tocino')
más:
print ('jamón')
print ('spam')
print ('spam')
9. Escriba un código que imprima Hola si 1 se almacena en correo no deseado, imprime Howdy si 2
se
almacena en correo no deseado e imprime ¡Saludos! si algo más se almacena en el correo no
deseado.
10. ¿Qué puede presionar si su programa está atascado en un bucle infinito?
11. ¿Cuál es la diferencia entre break y continue?
12. ¿Cuál es la diferencia entre rango (10), rango (0, 10) y rango (0, 10, 1)
en un bucle for?
13. Escriba un programa corto que imprima los números del 1 al 10 usando un bucle for.
Luego escriba un programa equivalente que imprima los números del 1 al 10 usando
un ciclo while.
14. Si tuviera una función llamada bacon () dentro de un módulo llamado spam, ¿cómo
lo llamaría después de importar spam?
Crédito adicional: busque las funciones round () y abs () en Internet
y descubra qué hacen. Experimente con ellos en el shell interactivo.
3
f unción S
Ya está familiarizado con las funciones print (),
input () y len () de la versión anterior.
ous capítulos. Python proporciona varias
funciones integradas como estas, pero también puede escribir
tus propias funciones Una función es como un mini programa
dentro de un programa.
Para comprender mejor cómo funcionan las funciones, creemos una. Escriba este
programa en el editor de archivos y guárdelo como helloFunc.py:
u def hello (): v print ('¡ Hola
!')
print ('¡ Hola !')
print ('¡Hola!')
w hola ()
hola ()
hola ()
62 Capítulo 3
La primera línea es una declaración def u, que define una función llamada
hello (). El código en el bloque que sigue a la declaración def v es el cuerpo
de la función. Este código se ejecuta cuando se llama a la función, no cuando
se define por primera vez.
Las líneas hello () después de la función w son llamadas a funciones. En el código, una
llamada de función es solo el nombre de la función seguido de paréntesis, posiblemente
con algún número de argumentos entre paréntesis. Cuando la
ejecución del programa llegue a estas llamadas, saltará a la línea superior de la
función y comenzará a ejecutar el código allí. Cuando llega al final de
la función, la ejecución vuelve a la línea que llamó a la función
y continúa moviéndose a través del código como antes.
Como este programa llama a hello () tres veces, el código en la función hello ()
se ejecuta tres veces. Cuando ejecuta este programa, el resultado se
ve así:
Hola!
Hola !!!
Hola a todos.
Hola!
Hola !!!
Hola a todos.
Hola!
Hola !!!
Hola a todos.
Un propósito principal de las funciones es agrupar el código que se ejecuta varias
veces. Sin una función definida, tendría que copiar y pegar
este código cada vez, y el programa se vería así:
print ( '¡Hola!')
print ( 'Hola !!!')
print ( 'Hola.')
print ( '¡Hola!')
print ( 'Hola !!!')
print ( 'Hola'.)
de impresión ( 'Howdy!')
Print ('Howdy !!!')
print ('¡Hola!')
En general, siempre debe evitar duplicar el código, porque si
alguna vez decide actualizar el código, si, por ejemplo, encuentra un error que necesita
corregir, deberá recordar cambiar el código en todas partes donde lo copió.
A medida que obtenga más experiencia en programación, a menudo se encontrará
deduplicando código, lo que significa deshacerse del
código duplicado o copiado y pegado. La deduplicación hace que sus programas sean más cortos,
más fáciles de leer
y más fáciles de actualizar.
Funciones 63
def declaraciones con parámetros
Cuando se llama a la función len () print () o, que pasan en los valores, llamados argumentos
mentos en este contexto, escribiéndolos entre los paréntesis. También puede
definir sus propias funciones que aceptan argumentos. Escriba este ejemplo en
el editor de archivos y guárdelo como helloFunc2.py:
u def hello (nombre):
v print ('Hola' + nombre)
w hola ('Alice')
hola ('Bob')
Cuando ejecuta este programa, el resultado se ve así:
Hola alice
hola bob
La definición de la función hello () en este programa tiene un parámetro
llamado nombre u. Un parámetro es una variable en la que se almacena un argumento cuando
se llama a una función. La primera vez que se llama a la función hello (), es con el
argumento 'Alice' w. La ejecución del programa ingresa a la función, y el
nombre de la variable se establece automáticamente en 'Alice', que es lo que imprime la
instrucción print () v.
Una cosa especial a tener en cuenta sobre los parámetros es que el valor almacenado
en un parámetro se olvida cuando la función regresa. Por ejemplo, si
agregó print (name) después de hello ('Bob') en el programa anterior, el programa
le daría un NameError porque no hay una variable llamada name. Esta
variable se destruyó después de que la llamada a la función hello ('Bob') había regresado, por lo
que
print (nombre) se referiría a una variable de nombre que no existe.
Esto es similar a cómo se olvidan las variables de un programa cuando el programa
termina. Hablaré más sobre por qué sucede eso más adelante en el capítulo,
cuando discuta cuál es el alcance local de una función.
Valores de retorno y declaraciones de retorno
Cuando llama a la función len () y le pasa un argumento como 'Hola',
la llamada a la función se evalúa como el valor entero 5, que es la longitud de la
cadena que le pasó. En general, el valor al que se evalúa una llamada de función se
llama valor de retorno de la función.
Al crear una función usando la declaración def, puede especificar cuál
debería ser el valor de retorno con una declaración return. Una declaración de devolución
consta de lo siguiente:

• La palabra clave return • El valor o expresión que la función debería devolver

64 Capítulo 3
Cuando se usa una expresión con una declaración de retorno, el valor de retorno
es lo que evalúa esta expresión. Por ejemplo, el siguiente programa
define una función que devuelve una cadena diferente dependiendo de qué número
se pasa como argumento. Escriba este código en el editor de archivos y guárdelo
como magic8Ball.py :
importas al azar
v def getAnswer (answerNumber):
w if answerNumber == 1:
return 'Es cierto'
elif answerNumber == 2:
return ' Definitivamente es así'
elif answerNumber == 3:
return 'Sí'
elif answerNumber == 4:
return 'Respuesta confusa intente nuevamente'
elif answerNumber == 5:
return ' Preguntar más tarde '
elif answerNumber == 6:
return' Concentrate and ask again '
elif answerNumber == 7:
return' Mi respuesta es no '
elif answerNumber == 8:
return' Outlook no es tan bueno '
elif answerNumber == 9:
return 'Muy dudoso'
xr = random.randint (1, 9)
y fortune = getAnswer (r)
z print (fortuna)
Cuando se inicia este programa, Python primero importa el módulo aleatorio u.
Luego se define la función getAnswer () v. Debido a que la función se está
definiendo (y no se llama), la ejecución omite el código que contiene . Luego, la función
random.randint () se llama con dos argumentos, 1 y 9 x. Se
evalúa a un entero aleatorio entre 1 y 9 (incluidos 1 y 9),
y este valor se almacena en una variable llamada r.
La función getAnswer () se llama con r como argumento y. La
ejecución del programa se mueve a la parte superior de la función getAnswer () w, y el
valor r se almacena en un parámetro llamado answerNumber. Luego, dependiendo de
este valor en answerNumber, la función devuelve uno de los muchos
valores de cadena posibles . La ejecución del programa vuelve a la línea en la parte inferior del
programa
que originalmente llamó getAnswer () y. La cadena devuelta se asigna a
una variable llamada fortuna, que luego se pasa a una llamada print () z y se
imprime en la pantalla.
Funciones 65
Tenga en cuenta que, dado que puede pasar valores de retorno como argumento a otra
llamada de función, podría acortar estas tres líneas:
r = random.randint (1, 9)
fortuna = getAnswer (r)
print (fortuna)
a esta sola línea equivalente:
print (getAnswer (random.randint (1, 9)))
Recuerde, las expresiones están compuestas de valores y operadores. Se puede utilizar una llamada
de función
en una expresión porque se evalúa a su valor de retorno.
el valor none
En Python hay un valor llamado None, que representa la ausencia de un
valor. Ninguno es el único valor del tipo de datos NoneType. (Otros
lenguajes de programación pueden llamar a este valor nulo, nulo o indefinido). Al igual que los
valores booleanos verdadero y falso, ninguno debe escribirse con una N mayúscula .
Este valor sin valor puede ser útil cuando necesita almacenar algo
que no se confunda con un valor real en una variable. Un lugar donde
se usa None es como el valor de retorno de print (). La función print () muestra
texto en la pantalla, pero no necesita devolver nada de la misma manera que
len () o input (). Pero como todas las llamadas a funciones deben evaluarse a un
valor de retorno , print () devuelve None. Para ver esto en acción, ingrese lo siguiente en el
shell interactivo:
>>> spam = print ('¡Hola!')
¡Hola!
>>> Ninguno == spam
verdadero
Detrás de escena, Python agrega return None al final de cualquier
definición de función sin declaración de retorno. Esto es similar a cómo un
ciclo while o for termina implícitamente con una instrucción continue. Además, si utiliza una
declaración de retorno
sin un valor (es decir, solo la palabra clave return por sí misma), entonces se devuelve None
.
palabras clave Argumentos e print ()
La mayoría de los argumentos se identifican por su posición en la llamada a la función. Por
ejemplo, random.randint (1, 10) es diferente de random.randint (10, 1). La
función llamada random.randint (1, 10) devolverá un entero aleatorio entre 1
y 10, porque el primer argumento es el extremo inferior del rango y el
segundo argumento es el extremo superior (mientras que random.randint (10, 1) provoca un error).
66 Capítulo 3
Sin embargo, los argumentos de palabras clave se identifican por la palabra clave antepuesta
en la llamada de función. Los argumentos de palabras clave a menudo se usan para
parámetros opcionales . Por ejemplo, la función print () tiene los parámetros opcionales
end y sep para especificar qué se debe imprimir al final de sus argumentos
y entre sus argumentos (separándolos), respectivamente.
Si ejecutó el siguiente programa:
print ('Hola')
print ('Mundo')
la salida se vería así:
Hola
mundo
Las dos cadenas aparecen en líneas separadas porque la función print ()
agrega automáticamente un carácter de nueva línea al final de la cadena que se pasa.
Sin embargo, puede establecer el argumento de palabra clave final para cambiar esto a
una cadena diferente
. Por ejemplo, si el programa fuera este:
print ('Hola', fin = '')
print ('Mundo')
la salida se vería así:
Hola Mundo
La salida se imprime en una sola línea porque ya no hay una nueva
línea impresa después de 'Hola'. En cambio, se imprime la cadena en blanco. Esto es
útil si necesita deshabilitar la nueva línea que se agrega al final de cada
llamada a la función print ().
Del mismo modo, cuando pasa varios valores de cadena a print (), la función
los separará automáticamente con un solo espacio. Ingrese lo siguiente
en el shell interactivo:
>>> print ('gatos', 'perros', 'ratones')
gatos perros ratones
Pero podría reemplazar la cadena de separación predeterminada pasando el argumento de la palabra
clave sep
. Ingrese lo siguiente en el shell interactivo:
>>> print ('gatos', 'perros', 'ratones', sep = ',')
gatos, perros, ratones
También puede agregar argumentos de palabras clave a las funciones que escribe, pero
primero tendrá que aprender sobre la lista y los tipos de datos del diccionario en los próximos
dos capítulos. Por ahora, solo sepa que algunas funciones tienen argumentos opcionales de palabras
clave
que se pueden especificar cuando se llama a la función.
Funciones 67

Se dice
que los parámetros de alcance local y global y las variables que se asignan en una función
llamada existen en el alcance local de esa función .
Se dice que las variables que se asignan fuera de todas las funciones existen en el ámbito
global . Una variable que existe en un
ámbito local se denomina variable local , mientras que una variable que existe en el ámbito global
se denomina variable global . Una variable debe ser una u otra; No puede ser
tanto local como global.
Piense en un ámbito como un contenedor de variables. Cuando se destruye un alcance,
se olvidan todos los valores almacenados en las variables del alcance. Solo hay un
alcance global y se crea cuando comienza el programa. Cuando
finaliza su programa , se destruye el alcance global y se olvidan todas sus variables
. De lo contrario, la próxima vez que ejecute su programa, las variables
recordarán sus valores de la última vez que lo ejecutó.
Se crea un ámbito local cada vez que se llama a una función. Cualquier variable
asignada en esta función existe dentro del ámbito local. Cuando la función
regresa, el alcance local se destruye y estas variables se olvidan. La
próxima vez que llame a esta función, las variables locales no recordarán los
valores almacenados en ellas desde la última vez que se llamó a la función.
Los alcances importan por varias razones:

• El código en el ámbito global no puede usar ninguna variable local. • Sin embargo, un ámbito
local puede acceder a variables globales. • El código en el ámbito local de una función no puede
usar variables en ningún otro

Alcance local.
• Puede usar el mismo nombre para diferentes variables si están en diferentes
alcances diferentes. Es decir, puede haber una variable local llamada spam y una
variable global también llamada spam.
La razón por la que Python tiene diferentes ámbitos en lugar de hacer que todo sea
una variable global es que cuando el código modifica las variables
en una llamada particular a una función, la función interactúa con el resto del
programa solo a través de sus parámetros y el retorno valor. Esto
reduce las líneas de código de la lista que pueden estar causando un error. Si su programa
no contiene más que variables globales y tiene un error debido a que una variable
se configuró en un valor incorrecto, entonces sería difícil rastrear dónde se estableció este
valor incorrecto . Podría haberse configurado desde cualquier parte del programa, ¡y
su programa podría tener cientos o miles de líneas de largo! Pero si el error
se debe a una variable local con un valor incorrecto, sabe que solo el código
en esa función podría haberlo configurado incorrectamente.
Si bien el uso de variables globales en pequeños programas está bien, es un mal hábito
confiar en las variables globales a medida que sus programas se hacen cada vez más grandes.
Las variables locales no se pueden usar en el alcance global
Considere este programa, que causará un error cuando lo ejecute:
def spam ():
huevos = 31337
68 Capítulo 3
spam ()
imprimir (huevos)
Si ejecuta este programa, el resultado se verá así:
Rastreo (última llamada más reciente):
archivo "C: /test3784.py", línea 4, en <module>
print (eggs)
NameError: el nombre 'eggs' no está definido
El error ocurre porque la variable de los huevos existe solo en el
ámbito local creado cuando se llama a spam (). Una vez que la ejecución del programa regresa
del correo no deseado, ese ámbito local se destruye y ya no hay una variable
llamada huevos. Entonces, cuando su programa intenta ejecutar print (eggs), Python le da
un error diciendo que eggs no está definido. Esto tiene sentido si lo piensas
; cuando la ejecución del programa está en el ámbito global, no
existen ámbitos locales , por lo que no puede haber ninguna variable local. Es por eso que solo se
pueden usar variables globales
en el ámbito global.
Los ámbitos locales no pueden usar variables en otros ámbitos
locales Se crea un nuevo ámbito local cada vez que se llama a una función, incluso cuando
se llama a una función desde otra función. Considere este programa:
def spam ():
u eggs = 99
v tocino ()
w print (huevos)
tocino def ():
jamón = 101
x huevos = 0
y spam ()
Cuando se inicia el programa, la función spam () se llama y, y
se crea un ámbito local . La variable local eggs u se establece en 99. Luego, la función bacon ()
se llama v, y se crea un segundo ámbito local. Pueden
existir múltiples ámbitos locales al mismo tiempo. En este nuevo ámbito local, la variable local
ham se establece en 101, y una variable local eggs, que es diferente de la del
ámbito local de spam (), también se crea x y se establece en 0.
Cuando bacon () regresa, el alcance local para esa llamada se destruye. La
ejecución del programa continúa en la función spam () para imprimir el valor de eggs w,
y dado que el alcance local para la llamada a spam () todavía existe aquí, la variable eggs
se establece en 99. Esto es lo que programa de impresiones.
El resultado es que las variables locales en una función están completamente separadas
de las variables locales en otra función.
Funciones 69
Las variables globales se pueden leer desde un ámbito local
Considere el siguiente programa:
def spam ():
print (huevos)
huevos = 42
spam ()
print (huevos)
Como no hay ningún parámetro llamado eggs o ningún código que asigne a los huevos un
valor en la función spam (), cuando eggs se usa en spam (), Python lo considera
una referencia a los huevos de variable global. Por eso se imprime 42 cuando
se ejecuta el programa anterior.
Variables locales y globales con el mismo nombre
Para simplificar su vida, evite usar variables locales que tengan el mismo nombre
que una variable global u otra variable local. Pero técnicamente, es perfectamente
legal hacerlo en Python. Para ver qué sucede, escriba el siguiente código en
el editor de archivos y guárdelo como sameName.py:
def spam ():
u eggs = 'spam local'
print (huevos) # imprime 'spam local'
tocino def ():
v huevos = 'tocino local'
print (huevos) # imprime 'tocino local'
spam ()
print (huevos) # imprime 'tocino local'
w huevos =
tocino 'global' ()
print (huevos) # imprime 'global'
Cuando ejecuta este programa, genera lo siguiente:
tocino local
spam local
tocino local
global
En realidad, hay tres variables diferentes en este programa, pero confusamente
, todas se denominan huevos. Las variables son las siguientes:
Una variable llamada huevos que existe en un ámbito local cuando se llama spam ().
v Una variable denominada eggs que existe en un ámbito local cuando se llama a bacon ().
w Una variable denominada huevos que existe en el ámbito global.
70 Capítulo 3
Dado que estas tres variables separadas tienen el mismo nombre, puede ser
confuso hacer un seguimiento de cuál se está utilizando en un momento dado. Es
por eso que debe evitar usar el mismo nombre de variable en diferentes ámbitos.
La declaración global
Si necesita modificar una variable global desde una función, use la
declaración global . Si tiene una línea como huevos globales en la parte superior de una función,
le dice a Python: "En esta función, los huevos se refieren a la variable global, así que no
cree una variable local con este nombre". Por ejemplo, escriba el siguiente
código en el editor de archivos y guárdelo como sameName2.py:
def spam ():
u global eggs
v eggs = 'spam'
huevos =
spam 'global' ()
imprimir (huevos)
Cuando ejecuta este programa, la llamada final print () generará esto:
correo no deseado
Debido a que los huevos se declaran globales en la parte superior del correo no deseado () u, cuando
los huevos se configuran como
'correo no deseado' v, esta asignación se realiza a los huevos con alcance global. No se crea una
variable local de huevos
.
Existen cuatro reglas para determinar si una variable está en un ámbito local o
global:
1. Si se usa una variable en el ámbito global (es decir, fuera de todas las
funciones), siempre es una variable global.
2. Si hay una declaración global para esa variable en una función, es una variable global
.
3. De lo contrario, si la variable se usa en una declaración de asignación en la
función, es una variable local.
4. Pero si la variable no se usa en una declaración de asignación, es una variable global
.
Para tener una mejor idea de estas reglas, aquí hay un programa de ejemplo. Escriba
el siguiente código en el editor de archivos y guárdelo como sameName3.py:
def spam ():
u huevos globales
huevos = 'spam' # este es el global
tocino def ():
v huevos = 'tocino' # este es un local
Funciones 71
def ham ():
w print (huevos) # este es el global

huevos = 42 # este es el
spam global ()
imprimir (huevos)
En la función spam (), los huevos son la variable global de los huevos, porque hay
una declaración global para los huevos al comienzo de la función u. En bacon (),
eggs es una variable local, porque hay una declaración de asignación para ella en
esa función v. En ham () w, eggs es la variable global, porque no hay una
declaración de asignación o declaración global para esa función. Si ejecuta
sameName3.py , el resultado se verá así:
correo no deseado
En una función, una variable siempre será global o local.
No hay forma de que el código en una función pueda usar una variable local llamada
eggs y luego, en esa misma función, usar la variable global eggs.
note Si alguna vez desea modificar el valor almacenado en una variable global de una función,
debe usar una declaración global en esa variable.
Si intenta usar una variable local en una función antes de asignarle un valor
, como en el siguiente programa, Python le dará un error. Para ver esto,
escriba lo siguiente en el editor de archivos y guárdelo como sameName4.py:
def spam ():
print (huevos) # ERROR!
u eggs = 'spam local'
v eggs = spam 'global'
()
Si ejecuta el programa anterior, genera un mensaje de error.
Rastreo (última llamada más reciente):
Archivo "C: /test3784.py", línea 6, en <módulo>
spam ()
Archivo "C: /test3784.py", línea 2, en
impresión de spam (huevos) # ¡ERROR!
UnboundLocalError: variable local 'huevos' referenciados antes de la asignación
Este error ocurre porque Python ve que hay una
declaración de asignación para los huevos en la función spam () u y, por lo tanto, considera que los
huevos
son locales. Pero debido a que print (eggs) se ejecuta antes de que se asigne
algo a eggs, la variable local eggs no existe. Python no recurrirá al uso de
la variable global eggs v.
72 Capítulo 3
manejo de excepciones
En este momento, obtener un error o una excepción en su programa Python significa que
todo el programa se bloqueará. No quiere que esto suceda en programas del mundo real
. En su lugar, desea que el programa detecte errores, los maneje y
luego continúe ejecutándose.
Por ejemplo, considere el siguiente programa, que tiene un
error de "dividir por cero". Abra una nueva ventana del editor de archivos e ingrese el siguiente
código,
guardándolo como zeroDivide.py :
def spam (divideBy):
devuelve 42 / divideBy
print (spam (2))
print (spam (12))
print (spam (0))
print (spam (1))
Hemos definido una función llamada spam, le hemos dado un parámetro y luego
imprimimos el valor de esa función con varios parámetros para ver qué sucede
. Este es el resultado que obtienes cuando ejecutas el código anterior:
21.0
3.5
Rastreo (última llamada reciente):
Archivo "C: /zeroDivide.py", línea 6, en <module>
print (spam (0))
Archivo "C: /zeroDivide.py", línea 2, en
devolución de spam 42 / divideBy
ZeroDivisionError: división por cero
Un error ZeroDivisionError ocurre cada vez que intenta dividir un número por
cero. Desde el número de línea proporcionado en el mensaje de error, sabe que la
declaración de devolución en spam () está causando un error.
f unC ión iones como "Bl ACk Box e S"
A menudo, todo lo que necesita saber sobre una función son sus entradas (los parámetros)
y el valor de salida; no siempre tiene que cargar con cómo funciona
realmente el código de la función . Cuando piensa en las funciones de esta manera de alto nivel
, es común decir que está tratando la función como un "recuadro negro".
Esta idea es fundamental para la programación moderna. Los capítulos posteriores de este
libro le mostrarán varios módulos con funciones que fueron escritas por otras
personas. Si bien puede echar un vistazo al código fuente si tiene curiosidad,
no necesita saber cómo funcionan estas funciones para usarlas. Y debido a que
se recomienda escribir funciones sin variables globales, generalmente no tiene
que preocuparse de que el código de la función interactúe con el resto de su programa.
Funciones 73
Los errores se pueden manejar con las declaraciones try y except. El código que
potencialmente podría tener un error se coloca en una cláusula try. La ejecución del programa se
mueve al inicio de un siguiente, excepto la cláusula si ocurre un error.
Puede poner el código anterior de dividir por cero en una cláusula try y tener
una cláusula except que contenga código para controlar lo que sucede cuando se produce este error.
def spam (divideBy):
prueba:
devuelve 42 / divideBy
excepto ZeroDivisionError:
print ('Error: argumento no válido')
print (spam (2))
print (spam (12))
print (spam (0))
print (spam (1))
Cuando el código en una cláusula try causa un error, la ejecución del programa
se mueve inmediatamente al código en la cláusula except. Después de ejecutar ese
código, la ejecución continúa de manera normal. La salida del programa anterior
es la siguiente:
21.0
3.5
Error: argumento no válido.
Ninguno
42.0
Tenga en cuenta que también se detectarán los errores que ocurran en las llamadas a funciones en
un bloque de prueba
. Considere el siguiente programa, que en su lugar tiene las llamadas de spam ()
en el bloque de prueba:
def spam (divideBy):
devuelve 42 / divideBy
try:
print (spam (2))
print (spam (12))
print (spam (0))
print (spam (1))
excepto ZeroDivisionError:
print ('Error: argumento no válido')
Cuando se ejecuta este programa, el resultado se ve así:
21.0
3.5
Error: argumento no válido.
74 Capítulo 3
La razón por la cual print (spam (1)) nunca se ejecuta es porque una vez que la ejecución
salta al código en la cláusula except, no vuelve a la cláusula try
. En cambio, simplemente continúa bajando como de costumbre.
Un programa corto: adivina el número
Los ejemplos de juguetes que te he mostrado hasta ahora son útiles para presentar conceptos
básicos
, pero ahora veamos cómo todo lo que has aprendido se combina en un
programa más completo. En esta sección, te mostraré un simple
juego de "adivina el número". Cuando ejecuta este programa, la salida se verá más o menos
así:
Estoy pensando en un número entre 1 y 20.
Adivina.
10
Tu suposición es demasiado baja.
Adivina.
15
Tu suposición es demasiado baja.
Adivina.
17
Tu suposición es demasiado alta.
Adivina.
16 ¡
Buen trabajo! ¡Adivinaste mi número en 4 conjeturas!
Escriba el siguiente código fuente en el editor de archivos y guarde el archivo como
guessTheNumber.py :
# Esto es un juego de adivinanzas.
import random
secretNumber = random.randint (1, 20)
print ('Estoy pensando en un número entre 1 y 20.')
# Pídale al jugador que adivine 6 veces.
para conjeturas Tomado en el rango (1, 7):
print ('Adivina'.)
guess = int (input ())
if guess <secretNumber:
print ('Su conjetura es demasiado baja')
elif guess> secretNumber:
print ('Su conjetura es demasiado alta').
else:
break # ¡Esta condición es la suposición correcta!
if guess == secretNumber:
print ('¡Buen trabajo! Has adivinado mi número en' + str (guesssesTaken) + 'guessses!')
else:
print ('No, el número en el que estaba pensando era' + str (secretNumber))
Funciones 75
Veamos este código línea por línea, comenzando en la parte superior.
# Esto es un juego de adivinanzas.
import random
secretNumber = random.randint (1, 20)
Primero, un comentario en la parte superior del código explica lo que hace el programa
. Luego, el programa importa el módulo aleatorio para que pueda usar la función
random.randint () para generar un número para que el usuario adivine. El
valor de retorno, un entero aleatorio entre 1 y 20, se almacena en la variable
secretNumber.
print ('Estoy pensando en un número entre 1 y 20.')
# Pídale al jugador que adivine 6 veces.
para conjeturas Tomado en el rango (1, 7):
print ('Adivina'.)
guess = int (input ())
El programa le dice al jugador que ha encontrado un número secreto
y le dará al jugador seis oportunidades de adivinarlo. El código que permite al jugador
ingresar una suposición y verifica que esa suposición esté en un bucle for que se repetirá como
máximo seis
veces. Lo primero que sucede en el bucle es que el jugador escribe una
suposición. Como input () devuelve una cadena, su valor de retorno se pasa directamente a
int (), que traduce la cadena a un valor entero. Esto se almacena en una
variable llamada conjetura.
if guess <secretNumber:
print ('Su conjetura es demasiado baja'.)
elif guess> secretNumber:
print ('Su conjetura es demasiado alta')
Estas pocas líneas de código verifican si la suposición es menor o
mayor que el número secreto. En cualquier caso, se imprime una pista en la pantalla.
más:
descanso # ¡Esta condición es la suposición correcta!
Si la suposición no es mayor ni menor que el número secreto, entonces
debe ser igual al número secreto, en cuyo caso desea que la ejecución del programa
salga del bucle for.
if guess == secretNumber:
print ('¡Buen trabajo! Has adivinado mi número en' + str (guesssesTaken) + 'guessses!')
else:
print ('No, el número en el que estaba pensando era' + str (secretNumber))
Después del ciclo for, la instrucción if ... else anterior verifica si el
jugador ha adivinado correctamente el número e imprime un mensaje apropiado
en la pantalla. En ambos casos, el programa muestra una variable que contiene
76 Capítulo 3
un valor entero (guesssesTaken y secretNumber). Como debe concatenar
estos valores enteros a cadenas, pasa estas variables a la función str (),
que devuelve la forma del valor de cadena de estos enteros. Ahora estas cadenas
se pueden concatenar con los operadores + antes de pasar finalmente a
la llamada a la función print ().
Las
funciones de resumen son la forma principal de compartimentar su código en
grupos lógicos . Dado que las variables en las funciones existen en sus propios ámbitos locales, el
código en una función no puede afectar directamente los valores de las variables en otras
funciones. Esto limita qué código podría estar cambiando los valores de sus variables
, lo que puede ser útil cuando se trata de depurar su código.
Las funciones son una gran herramienta para ayudarlo a organizar su código. Puede
pensar en ellos como cajas negras: tienen entradas en forma de parámetros
y salidas en forma de valores de retorno, y el código en ellos no
afecta a las variables en otras funciones.
En capítulos anteriores, un solo error podría causar que sus programas se bloqueen.
En este capítulo, aprendió sobre las declaraciones try y except, que pueden ejecutar
código cuando se detecta un error. Esto puede hacer que sus programas sean más
resistentes a los casos de error comunes.
Preguntas de práctica
1. ¿Por qué es ventajoso tener funciones en sus programas?
2. Cuándo se ejecuta el código en una función: cuando la función es
definido o cuando se llama a la función?
3. ¿Qué enunciado crea una función?
4. ¿Cuál es la diferencia entre una función y una llamada a función?
5. ¿Cuántos alcances globales hay en un programa Python? Cuántos
ámbitos locales?
6. ¿Qué les sucede a las variables en un ámbito local cuando vuelve la llamada a la función?
7. ¿Qué es un valor de retorno? ¿Puede un valor de retorno ser parte de una expresión?
8. Si una función no tiene una declaración de retorno, ¿cuál es el valor de retorno?
de una llamada a esa función?
9. ¿Cómo puede forzar que una variable en una función se refiera a la variable global?
10. ¿Cuál es el tipo de datos de Ninguno?
11. ¿Qué hace la declaración areallyourpetsnamederic de importación?
12. Si tuviera una función llamada bacon () en un módulo llamado spam, ¿cómo
¿Lo llamarías después de importar spam?
13. ¿Cómo puede evitar que un programa se bloquee cuando recibe un error?
14. ¿Qué incluye la cláusula try? ¿Qué va en la cláusula excepto?
Funciones 77
Proyectos de
práctica Para practicar, escriba programas para realizar las siguientes tareas.
La secuencia de Collatz
Escriba una función llamada collatz () que tiene un parámetro llamado número. Si el
número es par, entonces collatz () debería imprimir el número // 2 y devolver este valor.
Si el número es impar, entonces collatz () debería imprimir y devolver 3 * número + 1.
Luego, escriba un programa que permita al usuario escribir un número entero y que siga
llamando a collatz () en ese número hasta que la función devuelva el valor 1.
(Sorprendentemente, esta secuencia realmente funciona para cualquier número entero, tarde
o temprano , usando esta secuencia, llegarás a 1. Incluso los matemáticos no están
seguros de por qué. Tu programa está explorando lo que se llama la secuencia de Collatz , a
veces llamada "el problema matemático imposible más simple".
Recuerde convertir el valor de retorno de input () a un entero con
la función int (); de lo contrario, será un valor de cadena.
Sugerencia: un número entero es par si el número% 2 == 0, y es impar si el
número% 2 == 1.
El resultado de este programa podría verse así:
Ingrese el número:
3
10
5
16
8
4
2
1
Validación de entrada
Agregue sentencias try y except al proyecto anterior para detectar si el
usuario escribe en una cadena no entera. Normalmente, la función int () generará un
error ValueError si se pasa una cadena no entera, como en int ('cachorro'). En la
cláusula except, imprima un mensaje al usuario diciéndole que debe ingresar un número entero.
4
liStS
Un tema más que deberá comprender
antes de comenzar a escribir programas en
serio es el tipo de datos de la lista y su primo,
la tupla. Las listas y las tuplas pueden contener múltiples
valores, lo que facilita la escritura de programas que
manejan grandes cantidades de datos. Y dado que las listas mismas
pueden contener otras listas, puede usarlas para
organizar los datos en estructuras jerárquicas.
En este capítulo, discutiré los conceptos básicos de las listas. También le enseñaré acerca de los
métodos, que son funciones que están vinculadas a valores de un determinado tipo de datos.
Luego, cubriré brevemente los tipos de datos de cadena y tupla tipo lista y cómo se
comparan con los valores de lista. En el próximo capítulo, le presentaré el tipo de datos del
diccionario
.
80 Capítulo 4
el tipo de datos de lista
Una lista es un valor que contiene múltiples valores en una secuencia ordenada. El
término valor de lista se refiere a la lista en sí (que es un valor que se puede almacenar en una
variable o pasar a una función como cualquier otro valor), no a los valores dentro
del valor de la lista. Un valor de lista se ve así: ['gato', 'murciélago', 'rata', 'elefante'].
Al igual que los valores de cadena se escriben con comillas para marcar dónde
comienza y termina la cadena, una lista comienza con un corchete de apertura y
termina con un corchete de cierre, []. Los valores dentro de la lista también se denominan
elementos . Los elementos se separan con comas (es decir, están delimitados por comas ).
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> [1, 2, 3]
[1, 2, 3]
>>> ['gato', 'murciélago', 'rata', 'elefante']
['gato', 'murciélago', 'rata', 'elefante']
>>> ['hola', 3.1415, verdadero, ninguno, 42]
['hola', 3.1415, verdadero, ninguno, 42]
u >>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> spam
['gato', 'murciélago', 'rata', 'elefante']
A la variable de spam u todavía se le asigna un solo valor: el valor de la lista. Pero
el valor de la lista en sí contiene otros valores. El valor [] es una lista vacía que
no contiene valores, similar a '', la cadena vacía.
Obtener valores individuales en una lista con índices
Supongamos que tiene la lista ['cat', 'bat', 'rat', 'elephant'] almacenada en una variable
llamada spam. El código Python spam [0] se evaluaría como 'cat', y el spam [1]
se evaluaría como 'bat', y así sucesivamente.
El número entero dentro de los corchetes
que sigue a la lista se llama
índice. El primer valor de la lista está en el
índice 0, el segundo valor está en el índice
1, el tercer valor está en el índice 2, y
así sucesivamente. La Figura 4-1 muestra un valor de lista
asignado al spam, junto con lo
que evaluarían las expresiones de índice.
Por ejemplo, escriba las siguientes expresiones en el shell interactivo.
Comience asignando una lista a la variable spam.
>>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> spam [0]
'gato'
>>> spam [1]
'murciélago
>>> spam [2]
' rata '
>>> spam [3]
' elefante '
spam = ["gato", "murciélago", "rata", "elefante"]
spam [0] spam [1] spam [2] spam [3]
Figura 4-1: Un valor de lista almacenado en el
correo no deseado variable , que muestra a qué valor se refiere cada
índice
Listas 81
>>> ['gato', 'murciélago', 'rata', 'elefante'] [3]
'elefante'
u >>> 'Hola' + spam [0]
v 'Hola gato'
>>> 'El' + spam [1] + 'se comió el' + spam [0] + '.'
'El murciélago se comió al gato'.
Observe que la expresión 'Hola' + spam [0] u se evalúa como 'Hola' +
'cat' porque el spam [0] se evalúa como la cadena 'cat'. Esta expresión a su vez se
evalúa como el valor de cadena 'Hello cat' v.
Python le dará un mensaje de error IndexError si usa un índice
que excede el número de valores en su valor de lista.
>>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> spam [10000]
Rastreo (última llamada última):
Archivo "<pyshell # 9>", línea 1, en <module>
spam [10000]
IndexError: índice de la lista fuera de rango
Los índices pueden ser solo valores enteros, no flotantes. El siguiente ejemplo
causará un error TypeError:
>>> spam = ['cat', 'bat', 'rat', 'elephant']
>>> spam [1]
'bat'
>>> spam [1.0]
Traceback (última llamada):
Archivo "< pyshell # 13> ", línea 1, en <module>
spam [1.0]
TypeError: los índices de la lista deben ser enteros, no flotantes
>>> spam [int (1.0)]
'bat'
Las listas también pueden contener otros valores de lista. Se puede acceder a los valores en estas
listas de listas
utilizando múltiples índices, de esta manera:
>>> spam = [['' gato ',' murciélago '], [10, 20, 30, 40, 50]]
>>> spam [0]
[' gato ',' murciélago ']
>>> spam [0 ] [1]
'murciélago'
>>> spam [1] [4]
50
El primer índice dicta qué valor de lista usar, y el segundo indica
el valor dentro del valor de lista. Por ejemplo, el spam [0] [1] imprime 'bat', el
segundo valor en la primera lista. Si solo usa un índice, el programa imprimirá
el valor de la lista completa en ese índice.
82 Capítulo 4
Índices negativos
Mientras que los índices comienzan en 0 y suben, también puede usar enteros negativos para
el índice. El valor entero -1 se refiere al último índice de una lista, el valor -2 se
refiere al índice penúltimo de una lista, y así sucesivamente. Ingrese lo siguiente
en el shell interactivo:
>>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> spam [-1]
'elefante'
>>> spam [-3]
'murciélago'
>>> 'El' + spam [-1] + 'tiene miedo de' + spam [-3] + '.'
'El elefante le tiene miedo al murciélago'.
Conseguir Sublistas con rodajas
Del mismo modo que un índice se puede obtener un único valor de una lista, una rebanada puede
obtener varios valores
de una lista, en forma de una nueva lista. Un segmento se escribe entre corchetes,
como un índice, pero tiene dos enteros separados por dos puntos. Observe la diferencia
entre índices y sectores.

• spam [2] es una lista con un índice (un entero). • spam [1: 4] es una lista con un segmento (dos
enteros).

En un segmento, el primer entero es el índice donde comienza el segmento. El segundo


entero es el índice donde termina el segmento. Un segmento sube, pero no
incluirá, el valor en el segundo índice. Un segmento se evalúa como un nuevo valor de lista.
Ingrese lo siguiente en el shell interactivo:
>>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> spam [0: 4]
['gato', 'murciélago', 'rata', 'elefante']
>> > spam [1: 3]
['bat', 'rat']
>>> spam [0: -1]
['cat', 'bat', 'rat']
Como método abreviado, puede omitir uno o ambos índices a cada lado
del colon en el corte. Dejar el primer índice es lo mismo que usar 0,
o el comienzo de la lista. Dejar de lado el segundo índice es lo mismo que
usar la longitud de la lista, que se dividirá al final de la lista. Ingrese lo
siguiente en el shell interactivo:
>>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> spam [: 2]
['gato', 'murciélago']
>>> spam [1:]
['murciélago ',' rata ',' elefante ']
Listas 83
>>> spam [:]
['gato', 'murciélago', 'rata', 'elefante']
Obtención de la longitud de una lista con len ()
La función len () devolverá el número de valores que están en un valor de lista que se le
pasó, al igual que puede contar el número de caracteres en un valor de cadena.
Ingrese lo siguiente en el shell interactivo:
>>> spam = ['gato', 'perro', 'alce']
>>> len (spam)
3
Cambio de valores en una lista con índices
Normalmente, un nombre de variable aparece en el lado izquierdo de una declaración de asignación
, como spam = 42. Sin embargo, también puede usar un índice de una lista para cambiar
el valor en ese índice. Por ejemplo, spam [1] = 'aardvark' significa "Asignar el
valor en el índice 1 en la lista de spam a la cadena 'aardvark'". Ingrese lo siguiente
en el shell interactivo:
>>> spam = ['cat', 'bat', 'rat', 'elephant']
>>> spam [1] = 'aardvark'
>>> spam
['cat', 'aardvark', 'rat', 'elefante']
>>> spam [2] = spam [1]
>>> spam
['cat', 'aardvark', 'aardvark', 'elephant']
>>> spam [-1] = 12345
>>> spam
['gato', 'oso hormiguero', 'oso hormiguero', 12345]
Concatenación de
listas y replicación de listas El operador + puede combinar dos listas para crear un nuevo valor de
lista de la misma
manera que combina dos cadenas en un nuevo valor de cadena. El operador * también se
puede usar con una lista y un valor entero para replicar la lista. Ingrese lo
siguiente en el shell interactivo:
>>> [1, 2, 3] + ['A', 'B', 'C']
[1, 2, 3, 'A', 'B', 'C']
>>> ['X' , 'Y', 'Z'] * 3
['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z']
>> > spam = [1, 2, 3]
>>> spam = spam + ['A', 'B', 'C']
>>> spam
[1, 2, 3, 'A', 'B', ' C']
84 Capítulo 4
Eliminar valores de listas con declaraciones del
La declaración del eliminará valores en un índice en una lista. Todos los valores
en la lista después del valor eliminado se moverán hacia arriba un índice. Por ejemplo,
ingrese lo siguiente en el shell interactivo:
>>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> del spam [2]
>>> spam
['gato', 'murciélago', 'elefante']
>>> del spam [2]
>>> spam
['gato', 'murciélago']
La instrucción del también se puede usar en una variable simple para eliminarla, como
si fuera una instrucción "sin asignación". Si intenta usar la variable después de
eliminarla, recibirá un error de NameError porque la variable ya no existe.
En la práctica, casi nunca necesita eliminar variables simples. La declaración del
se utiliza principalmente para eliminar valores de las listas.
trabajar con listas
Cuando comienza a escribir programas, es tentador crear muchas
variables individuales para almacenar un grupo de valores similares. Por ejemplo, si quisiera
almacenar los nombres de mis gatos, podría tener la tentación de escribir código como este:
catName1 = 'Zophie'
catName2 = 'Pooka'
catName3 = 'Simon'
catName4 = 'Lady Macbeth'
catName5 = 'Fat-tail'
catName6 = 'Miss Cleo'
(No tengo muchos gatos, lo juro). Resulta que esta es una
mala forma de escribir código. Por un lado, si el número de gatos cambia, su
programa nunca podrá almacenar más gatos de los que tiene variables. Estos
tipos de programas también tienen muchos códigos duplicados o casi idénticos
. Considere cuánto código duplicado hay en el siguiente programa,
que debe ingresar en el editor de archivos y guardar como allMyCats1.py:
print ('Ingrese el nombre del gato 1:')
catName1 = input ()
print ('Ingrese el nombre del cat 2:')
catName2 = input ()
print ('Ingrese el nombre del cat 3:')
catName3 = input ( )
print ('Ingrese el nombre del gato 4:')
catName4 = input ()
print ('Ingrese el nombre del gato 5:')
catName5 = input ()
Listas 85
print ('Ingrese el nombre del gato 6:')
catName6 = input ()
print ('Los nombres del gato son:')
print (catName1 + '' + catName2 + '' + catName3 + '' + catName4 + '' +
catName5 + '' + catName6)
En lugar de usar múltiples variables repetitivas, puede usar una sola
variable que contenga un valor de lista. Por ejemplo, aquí hay una
versión nueva y mejorada del programa allMyCats1.py . Esta nueva versión utiliza una lista única y
puede almacenar cualquier cantidad de gatos que el usuario
escriba . En una nueva ventana del editor de archivos , escriba el siguiente código fuente y guárdelo
como allMyCats2.py :
catNames = []
while True:
print ('Ingrese el nombre de cat' + str (len (catNames) + 1) +
'(O ingrese nada para detenerlo):')
name = input ()
if name == '' :
break
catNames = catNames + [nombre] # lista concatenación
print ('Los nombres de los gatos son:')
para el nombre en catNames:
print ('' + nombre)
Cuando ejecutas este programa, la salida se verá así:
Ingrese el nombre del gato 1 (O ingrese nada para detener):
Zophie
Ingrese el nombre del gato 2 (O ingrese nada para detener):
Pooka
Ingrese el nombre del gato 3 (O ingrese nada para detener):
Simon
Ingrese el nombre del gato 4 (O ingrese nada para detener):
Lady Macbeth
Ingrese el nombre del gato 5 (O ingrese nada para detener.):
Fat-tail
Ingrese el nombre del gato 6 (O ingrese nada para detener):
Miss Cleo
Ingrese el nombre del gato 7 (o ingrese nada para detenerlo):
Los nombres de los gatos son:
Zophie
Pooka
Simon
Lady Macbeth
Fat-tail
Miss Cleo
El beneficio de usar una lista es que sus datos ahora están en una estructura, por lo que su
programa es mucho más flexible en el procesamiento de los datos de lo que sería con
varias variables repetitivas.
86 Capítulo 4
Uso de bucles for con listas
En el Capítulo 2, aprendió a usar bucles for para ejecutar un bloque de
código un cierto número de veces. Técnicamente, un bucle for repite el
bloque de código una vez para cada valor en una lista o valor similar a una lista. Por ejemplo, si
ejecutó
este código:
para i en rango (4):
imprimir (i)
El resultado de este programa sería el siguiente:
0
1
2
3
Esto se debe a que el valor de retorno del rango (4) es un valor
similar a una lista que Python considera similar a [0, 1, 2, 3]. El siguiente programa tiene el
mismo resultado que el anterior:
para i en [0, 1, 2, 3]:
imprimir (i)
Lo que realmente hace el bucle anterior es recorrer su cláusula
con la variable que configuré en un valor sucesivo en la lista [0, 1, 2, 3] en cada
iteración.
note En este libro, utilizo el término lista para referirme a los tipos de datos que técnicamente se
denominan
secuencias. Sin embargo, no necesita conocer las definiciones técnicas de este término.
Una técnica común de Python es usar range (len ( someList )) con un
bucle for para iterar sobre los índices de una lista. Por ejemplo, ingrese lo siguiente
en el shell interactivo:
>>> suministros = ['plumas', 'grapadoras', 'lanzallamas', 'carpetas']
>>> para i en rango (len (suministros)):
print ('Índice' + str (i) + ' en suministros es: '+ suministros [i])
El índice 0 en suministros es: bolígrafos El
índice 1 en suministros es: grapadoras El
índice 2 en suministros es: lanzallamas El
índice 3 en suministros es: aglutinantes
El uso del rango (len (suministros)) en el bucle anterior mostrado es útil
porque el código en el bucle puede acceder al índice (como la variable i) y
al valor en ese índice (como suministros [i]). Lo mejor de todo es que range (len (suministros))
recorrerá en iteración todos los índices de suministros, sin importar cuántos elementos
contenga.
Listas 87
Los operadores in y no in
Puede determinar si un valor está o no en una lista con los
operadores in y no en . Al igual que otros operadores, in y not in se usan en expresiones y
conectan dos valores: un valor para buscar en una lista y la lista donde se puede
encontrar. Estas expresiones se evaluarán a un valor booleano. Ingrese lo siguiente
en el shell interactivo:
>>> 'howdy' en ['hola', 'hola', 'howdy', 'heyas']
Verdadero
>>> spam = ['hola', 'hola', 'hola', 'heyas']
>>> 'cat' en spam
False
>>> 'howdy' no en spam
False
>>> 'cat' no en spam
True
Por ejemplo, el siguiente programa permite al usuario escribir el nombre de una mascota
y luego verifica si el nombre está en una lista de mascotas. Abra una nueva
ventana del editor de archivos , ingrese el siguiente código y guárdelo como myPets.py :
myPets = ['Zophie', 'Pooka', 'Fat-tail']
print ('Ingrese un nombre de mascota:')
name = input ()
si el nombre no está en myPets:
print ('No tengo una mascota llamada' + nombre)
else:
print (nombre + 'es mi mascota')
El resultado puede verse más o menos así:
Ingrese un nombre de mascota:
Footfoot
No tengo una mascota llamada Footfoot
El truco de asignación múltiple
El truco de asignación múltiple es un atajo que le permite asignar múltiples variables
con los valores en una lista en una línea de código. Entonces, en lugar de hacer esto:
>>> gato = ['gordo', 'negro', 'fuerte']
>>> tamaño = gato [0]
>>> color = gato [1]
>>> disposición = gato [2]
podría escribir esta línea de código:
>>> gato = ['gordo', 'negro', 'fuerte']
>>> tamaño, color, disposición = gato
88 Capítulo 4
El número de variables y la longitud de la lista deben ser exactamente
iguales, o Python le dará un ValueError:
>>> cat = ['gordo', 'negro', 'fuerte']
>>> tamaño, color, disposición, nombre = Cat
Traceback (última llamada reciente):
Archivo "<pyshell # 84>", línea 1, en <module>
tamaño, color, disposición, nombre = cat
ValueError: necesita más de 3 valores para descomprimir
Operadores de asignación aumentada
Al asignar un valor a una variable, con frecuencia usará la variable
misma. Por ejemplo, después de asignar 42 a la variable spam, aumentaría
el valor en spam en 1 con el siguiente código:
>>> spam = 42
>>> spam = spam + 1
>>> spam
43
Como acceso directo, puede usar el operador de asignación aumentada + = para hacer
lo mismo:
>>> spam = 42
>>> spam + = 1
>>> spam
43
Hay operadores de asignación aumentada para los operadores +, -, *, / y%
, descritos en la Tabla 4-1.
Tabla 4-1: Los operadores de
asignación aumentada Declaración de asignación aumentada Declaración de asignación equivalente
spam + = 1 spam = spam + 1
spam - = 1 spam = spam - 1
spam * = 1 spam = spam * 1
spam / = 1 spam = spam / 1
spam% = 1 spam = spam% 1
El operador + = también puede realizar la concatenación de cadenas y listas, y el
operador * = puede hacer la replicación de cadenas y listas. Ingrese lo siguiente en el
shell interactivo:
>>> spam = 'Hola'
>>> spam + = 'mundo!'
>>> spam
'¡Hola mundo!'
Listas 89
>>> tocino = ['Zophie']
>>> tocino * = 3
>>> tocino
['Zophie', 'Zophie', 'Zophie']
métodos
Un método es lo mismo que una función, excepto que se "llama" a un valor.
Por ejemplo, si un valor de lista se almacenara en spam, llamaría al
método de lista index () (que explicaré a continuación) en esa lista de la siguiente manera:
spam.index ('hola').
La parte del método viene después del valor, separada por un punto.
Cada tipo de datos tiene su propio conjunto de métodos. El tipo de datos de la lista, por
ejemplo, tiene varios métodos útiles para buscar, agregar, eliminar y
manipular valores en una lista.
Encontrar un valor en una lista con el método index () Los
valores de la lista tienen un método index () al que se le puede pasar un valor, y si ese
valor existe en la lista, se devuelve el índice del valor. Si el valor no está
en la lista, Python produce un error ValueError. Ingrese lo siguiente en
el shell interactivo:
>>> spam = ['hola', 'hola', 'hola', 'heyas']
>>> spam.index ('hola')
0
>>> spam.index ('heyas')
3
>>> spam .index ('howdy howdy howdy')
Traceback (última llamada reciente):
Archivo "<pyshell # 31>", línea 1, en <module>
spam.index ('howdy howdy howdy')
ValueError: 'howdy howdy howdy' no está en la lista
Cuando hay duplicados del valor en la lista,
se devuelve el índice de su primera aparición. Ingrese lo siguiente en el shell interactivo y
observe que index () devuelve 1, no 3:
>>> spam = ['Zophie', 'Pooka', 'Fat-tail', 'Pooka']
>>> spam.index ('Pooka')
1
Agregar valores a las listas con los métodos append () e insert ()
Para agregar nuevos valores a una lista, use los métodos append () e insert (). Ingrese lo
siguiente en el shell interactivo para llamar al método append () en un valor de lista
almacenado en la variable spam:
>>> spam = ['gato', 'perro', 'murciélago']
>>> spam.append ('alce')
90 Capítulo 4
>>> spam
['gato', 'perro', 'murciélago', 'alce']
La llamada al método append () anterior agrega el argumento al final de
la lista. El método insert () puede insertar un valor en cualquier índice de la lista.
El primer argumento para insert () es el índice para el nuevo valor, y el
segundo argumento es el nuevo valor a insertar. Ingrese lo siguiente en el
shell interactivo:
>>> spam = ['gato', 'perro', 'murciélago']
>>> spam.insert (1, 'pollo' )
>>> spam
['gato', 'pollo', 'perro', 'murciélago ']
Observe que el código es spam.append ('alce') y spam.insert (1, 'pollo'),
no spam = spam.append ('alce') y spam = spam.insert (1, 'pollo'). Ni
append () ni insert () dan el nuevo valor de spam como su valor de retorno. (De hecho,
el valor de retorno de append () e insert () es None, por lo que definitivamente no
querrá almacenar esto como el nuevo valor de la variable). En cambio, la lista se modifica en su
lugar . La modificación de una lista en el lugar se trata con más detalle más adelante en “ Tipos de
datos mutables
e inmutables” en la página 94.
Los métodos pertenecen a un solo tipo de datos. Los métodos append () e insert ()
son métodos de lista y solo se pueden invocar en valores de lista, no en otros valores
como cadenas o enteros. Ingrese lo siguiente en el shell interactivo
y observe los mensajes de error AttributeError que aparecen:
>>> eggs = 'hello'
>>> eggs.append ('world')
Traceback (última llamada más reciente):
Archivo "<pyshell # 19>", línea 1, en <module>
eggs.append ('world' )
AttributeError: el objeto 'str' no tiene el atributo 'append'
>>> bacon = 42
>>> bacon.insert (1, 'world')
Traceback (última llamada más reciente):
Archivo "<pyshell # 22>", línea 1, en <module>
bacon.insert (1, 'world')
AttributeError: el objeto 'int' no tiene el atributo 'insert'
Eliminar valores de las listas con remove ()
El método remove () pasa el valor que se eliminará de la lista en la que se
invoca. Ingrese lo siguiente en el shell interactivo:
>>> spam = ['gato', 'murciélago', 'rata', 'elefante']
>>> spam.remove ('murciélago')
>>> spam
['gato', 'rata', 'elefante']
Listas 91
Intentar eliminar un valor que no existe en la lista dará como resultado
un error de ValueError. Por ejemplo, ingrese lo siguiente en el shell interactivo
y observe el error que se muestra:
>>> spam = ['cat', 'bat', 'rat', 'elephant']
>>> spam.remove ('chicken')
Traceback (última llamada más reciente):
Archivo "<pyshell # 11>", línea 1, en <module>
spam.remove ('chicken')
ValueError: list.remove (x): x no está en la lista
Si el valor aparece varias veces en la lista, solo se eliminará la primera instancia del
valor. Ingrese lo siguiente en el shell interactivo:
>>> spam = ['cat', 'bat', 'rat', 'cat', 'hat', 'cat']
>>> spam.remove ('cat')
>>> spam
['bat', 'rata', 'gato', 'sombrero', 'gato']
La declaración del es buena para usar cuando conoce el índice del valor
que desea eliminar de la lista. El método remove () es bueno cuando
conoce el valor que desea eliminar de la lista.
Ordenar los valores en una lista con el método sort () Las
listas de valores numéricos o listas de cadenas se pueden ordenar con el método sort ()
. Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> spam = [2, 5, 3.14, 1, -7]
>>> spam.sort ()
>>> spam
[-7, 1, 2, 3.14, 5]
>>> spam = ['hormigas' , 'gatos', 'perros', 'tejones', 'elefantes']
>>> spam.sort ()
>>> spam
['hormigas', 'tejones', 'gatos', 'perros', 'elefantes']
También puede pasar True para que el argumento de la palabra clave inversa haga que sort ()
ordene los valores en orden inverso. Ingrese lo siguiente en el shell interactivo:
>>> spam.sort (reverse = True)
>>> spam
['elefantes', 'perros', 'gatos', 'tejones', 'hormigas']
Hay tres cosas que debe tener en cuenta sobre el método sort (). Primero,
el método sort () ordena la lista en su lugar; no intente capturar el valor de retorno
escribiendo código como spam = spam.sort ().
92 Capítulo 4
En segundo lugar, no puede ordenar las listas que tienen valores numéricos y de cadena
, ya que Python no sabe cómo comparar estos valores.
Escriba lo siguiente en el shell interactivo y observe el error TypeError:
>>> spam = [1, 3, 2, 4, 'Alice', 'Bob']
>>> spam.sort ()
Traceback (última llamada más reciente):
Archivo "<pyshell # 70>", línea 1, en <module>
spam.sort ()
TypeError: tipos no ordenados: str () <int ()
En tercer lugar, sort () utiliza el "orden ASCIIbetical" en lugar del
orden alfabético real para ordenar las cadenas. Esto significa que las letras mayúsculas van antes
que las minúsculas
. Por lo tanto, la minúscula a se ordena de modo que viene después de la Z
mayúscula . Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> spam = ['Alice', 'hormigas', 'Bob', 'tejones', 'Carol', 'gatos']
>>> spam.sort ()
>>> spam
['Alice', 'Bob' , 'Carol', 'hormigas', 'tejones', 'gatos']
Si necesita ordenar los valores en orden alfabético regular, pase str.
menor para el argumento clave de la palabra clave en la llamada al método sort ().
>>> spam = ['a', 'z', 'A', 'Z']
>>> spam.sort (key = str.lower)
>>> spam
['a', 'A', 'z ',' Z ']
Esto hace que la función sort () trate todos los elementos de la lista como si
fueran minúsculas sin cambiar realmente los valores de la lista.
Programa de ejemplo: Magic 8 Ball con una lista
Utilizando las listas, puede escribir una versión mucho más elegante del
programa Magic 8 Ball del capítulo anterior . En lugar de varias líneas de
sentencias elif casi idénticas , puede crear una sola lista con la que funciona el código. Abra una
nueva
ventana del editor de archivos e ingrese el siguiente código. Guárdelo como magic8Ball2.py.
importar al azar
mensajes = ['Es seguro',
'
Definitivamente es así', 'Sí definitivamente',
'Responda nebulosa intente nuevamente',
'Pregunte nuevamente más tarde',
'Concéntrese y pregunte nuevamente',
'Mi respuesta es no',
'Outlook no tan bueno ",
" Muy dudoso "]
print (messages [random.randint (0, len (messages) - 1)])
Listas 93
Cuando ejecute este programa, verá que funciona igual que el
anterior programa magic8Ball.py .
Observe la expresión que usa como índice en los mensajes: random
.randint (0, len (messages) - 1). Esto produce un número aleatorio para usar
para el índice, independientemente del tamaño de los mensajes. Es decir, obtendrá un
número aleatorio entre 0 y el valor de len (mensajes) - 1. El beneficio de
este enfoque es que puede agregar y quitar cadenas fácilmente a la
lista de mensajes sin cambiar otras líneas de código. Si luego actualiza su código,
habrá menos líneas que tendrá que cambiar y menos posibilidades de
introducir errores.
tipos de lista: cadenas y tuplas Las
listas no son los únicos tipos de datos que representan secuencias ordenadas de valores.
Por ejemplo, las cadenas y las listas son realmente similares, si considera que una cadena
es una "lista" de caracteres de texto único. Muchas de las cosas que puedes hacer con listas
e xCe P t ionS to inDe n tAt ion rul e S in Py t hon
En la mayoría de los casos, la cantidad de sangría para una línea de código le dice a Python en qué
bloque se encuentra. Sin embargo, hay algunas excepciones a esta regla. Por ejemplo, las listas
pueden abarcar varias líneas en el archivo de código fuente. La sangría de estas
líneas no importa; Python sabe que hasta que vea el corchete final,
la lista no está terminada. Por ejemplo, puede tener un código similar a este:
spam = ['manzanas',
'naranjas',
'bananas',
'gatos']
print (spam)
Por supuesto, prácticamente hablando, la mayoría de las personas usan el comportamiento de
Python para
hacer que sus listas se vean bonitas y legibles, como la lista de mensajes en el programa Magic 8
Ball.
También puede dividir una sola instrucción en varias líneas utilizando el
carácter de continuación \ line al final. Piense en \ como diciendo, “Esta instrucción
continúa en la siguiente línea”. La sangría en la línea después de una continuación de \ line
no es significativa. Por ejemplo, el siguiente es un código válido de Python:
print ('Cuatro puntajes y siete' + \
'años atrás ...')
Estos trucos son útiles cuando desea reorganizar largas líneas de código Python
para que sea un poco más legible.
94 Capítulo 4
También se puede hacer con cadenas: indexación; rebanar y usarlos con
bucles for , con len () y con los operadores in y no in. Para ver esto, ingrese lo
siguiente en el shell interactivo:
>>> nombre = 'Zophie'
>>> nombre [0]
'Z'
>>> nombre [-2]
'i'
>>> nombre [0: 4]
'Zoph'
>>> 'Zo' en nombre
Verdadero
>>> 'z' en nombre
False
>>> 'p' no en nombre
False
>>> para i en nombre:
print ('* * *' + i + '* * *')

***Z***
***o***
***p***
***h***
***i***
***e***
Tipos de datos mutables e inmutables
Pero las listas y las cadenas son diferentes de manera importante. Un valor de lista es un tipo de
datos mutable : puede tener valores agregados, eliminados o modificados. Sin embargo, una
cadena es inmutable : no se puede cambiar. Intentar reasignar un solo carácter en una cadena da
como resultado un error TypeError, como puede ver ingresando lo siguiente en el shell interactivo:
>>> name = 'Zophie a cat'
>>> name [7] = 'the'
Traceback (última llamada más reciente):
Archivo "<pyshell # 50>", línea 1, en <module>
name [7] = 'the'
TypeError: el objeto 'str' no admite la asignación de elementos
La forma correcta de "mutar" una cadena es utilizar el corte y la concatenación
para construir una nueva cadena copiando partes de la cadena anterior. Ingrese lo
siguiente en el shell interactivo:
>>> name = 'Zophie a cat'
>>> newName = name [0: 7] + 'the' + name [8:12]
>>> name
'Zophie a cat'
Listas 95
>>> nuevoNombre
'Zophie el gato'
Utilizamos [0: 7] y [8:12] para referirnos a los caracteres que no deseamos
reemplazar. Observe que la cadena original 'Zophie a cat' no se modifica
porque las cadenas son inmutables.
Aunque un valor de lista es mutable, la segunda línea en el siguiente código
no modifica los huevos de la lista:
>>> huevos = [1, 2, 3]
>>> huevos = [4, 5, 6]
>>> huevos
[4, 5, 6]
El valor de la lista en huevos no se cambia aquí; más bien, un
valor de lista completamente nuevo y diferente ([4, 5, 6]) está sobrescribiendo el valor de lista
anterior ([1, 2, 3]).
Esto se representa en la Figura 4-2.
Si realmente desea modificar la lista original en huevos para que contenga
[4, 5, 6], tendría que hacer algo como esto:
>>> huevos = [1, 2, 3]
>>> del eggs [2]
>>> del eggs [1]
>>> del eggs [0]
>>> eggs.append (4)
>>> huevos. anexar (5)
>>> huevos.aprender (6)
>>> huevos
[4, 5, 6]
Figura 4-2: Cuando se ejecutan los huevos = [4, 5, 6], el contenido de los huevos se reemplaza con
un
nuevo valor de lista.
En el primer ejemplo, el valor de lista con el que termina egg es el mismo
valor de lista con el que comenzó. Es solo que esta lista ha cambiado, en lugar de
sobrescribirse. La Figura 4-3 muestra los siete cambios realizados por las primeras siete
líneas en el ejemplo de shell interactivo anterior.
96 Capítulo 4
Figura 4-3: La instrucción del y el método append () modifican el mismo valor de lista
en su lugar.
El cambio de un valor de un tipo de datos mutable (como lo que hacen la instrucción del
y el método append () en el ejemplo anterior) cambia el valor en su
lugar, ya que el valor de la variable no se reemplaza con un nuevo valor de lista.
Los tipos mutables versus inmutables pueden parecer una distinción sin sentido
, pero “Pasar referencias” en la página 100 explicará el
comportamiento diferente al llamar a funciones con argumentos mutables versus argumentos
inmutables
. Pero primero, descubramos el tipo de datos de tupla, que es
una forma inmutable del tipo de datos de la lista.
El tipo de datos de tupla
El tipo de datos de tupla es casi idéntico al tipo de datos de la lista, excepto de dos
maneras. Primero, las tuplas se escriben entre paréntesis, (y), en lugar de
corchetes, [y]. Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> huevos = ('hola', 42, 0.5)
>>> huevos [0]
'hola'
>>> huevos [1: 3]
(42, 0.5)
>>> len (huevos)
3
Pero la forma principal en que las tuplas son diferentes de las listas es que las tuplas,
como las cadenas, son inmutables. Las tuplas no pueden tener sus valores modificados,
agregados o eliminados. Ingrese lo siguiente en el shell interactivo y
mire el mensaje de error TypeError:
>>> eggs = ('hola', 42, 0.5)
>>> eggs [1] = 99
Traceback (última llamada más reciente):
Archivo "<pyshell # 5>", línea 1, en <module>
eggs [1 ] = 99
TypeError: el objeto 'tupla' no admite la asignación de elementos
Listas 97
Si solo tiene un valor en su tupla, puede indicarlo colocando
una coma final después del valor dentro de los paréntesis. De lo contrario, Python
pensará que acabas de escribir un valor dentro de paréntesis regulares. La coma
es lo que le permite a Python saber que este es un valor de tupla. (A diferencia de otros
lenguajes de programación , en Python está bien tener una coma final después del último
elemento en una lista o tupla). Ingrese las siguientes llamadas de función type () en el
shell interactivo para ver la distinción:
>>> type (('hello',))
<class 'tuple'>
>>> type (('hello'))
<class 'str'>
Puede usar tuplas para transmitir a cualquiera que lea su código que
no tiene la intención de que esa secuencia de valores cambie. Si necesita una
secuencia ordenada de valores que nunca cambia, use una tupla. Un segundo beneficio de
usar tuplas en lugar de listas es que, debido a que son inmutables y su
contenido no cambia, Python puede implementar algunas optimizaciones que hacen que el
código que usa tuplas sea un poco más rápido que el código que usa listas.
Conversión de tipos con las funciones list () y tuple ()
Al igual que str (42) devolverá '42', la representación de cadena del
entero 42, las funciones list () y tuple () devolverán las versiones list y tuple
de los valores pasados a ellos. Ingrese lo siguiente en el shell interactivo
y observe que el valor de retorno es de un tipo de datos diferente al valor
pasado:
>>> tupla (['gato', 'perro', 5])
('gato', 'perro', 5)
>>> lista (('gato', 'perro', 5))
['gato', 'perro', 5]
>>> lista ('hola')
['h', 'e', 'l', 'l', 'o']
Convertir una tupla en una lista es útil si necesita una versión mutable de un
valor de tupla.
referencias
Como has visto, las variables almacenan cadenas y valores enteros. Ingrese lo siguiente
en el shell interactivo:
>>> spam = 42
>>> queso = spam
>>> spam = 100
>>> spam
100
>>> queso
42
98 Capítulo 4
Usted asigna 42 a la variable de correo no deseado, y luego copia el valor en correo
no deseado y lo asigna a la variable queso. Cuando luego cambie el valor en spam
a 100, esto no afectará el valor en queso. Esto se debe a que el spam y el queso
son variables diferentes que almacenan valores diferentes.
Pero las listas no funcionan de esta manera. Cuando asigna una lista a una variable, en
realidad está asignando una referencia de lista a la variable. Una referencia es un valor
que apunta a un bit de datos, y una referencia de lista es un valor que apunta a una
lista. Aquí hay un código que hará que esta distinción sea más fácil de entender.
Ingrese esto en el shell interactivo:
u >>> spam = [0, 1, 2, 3, 4, 5]
v >>> cheese = spam
w >>> cheese [1] = '¡Hola!'
>>> spam
[0, '¡Hola!', 2, 3, 4, 5]
>>> queso
[0, '¡Hola!', 2, 3, 4, 5]
Esto puede parecer extraño para ti. El código cambió solo la lista de quesos, pero
parece que tanto la lista de quesos como la de spam han cambiado.
Cuando crea la lista u, le asigna una referencia en la variable de correo no deseado
. Pero la siguiente línea v copia solo la referencia de la lista en spam a cheese, no
el valor de la lista en sí. Esto significa que los valores almacenados en spam y queso ahora se
refieren a la misma lista. Solo hay una lista subyacente porque la lista en sí
nunca se copió realmente. Entonces, cuando modifica el primer elemento de cheese w,
está modificando la misma lista a la que se refiere el spam.
Recuerde que las variables son como cuadros que contienen valores. Las
cifras anteriores de este capítulo muestran que las listas en cuadros no son exactamente precisas
porque las variables de lista en realidad no contienen listas, sino que contienen referencias a
listas. (Estas referencias tendrán números de identificación que Python usa internamente, pero
puede ignorarlas). Usando cuadros como metáfora de las variables, la Figura 4-4 muestra lo que
sucede cuando se asigna una lista a la variable de correo no deseado.

Figura 4-4: spam = [0, 1, 2, 3, 4, 5] almacena una


referencia a una lista, no a la lista real.
Listas 99
Luego, en la Figura 4-5, la referencia en spam se copia en queso. Solo
se creó y almacenó una nueva referencia en cheese, no una nueva lista. Observe cómo ambas
referencias se refieren a la misma lista.
Figura 4-5: spam = cheese copia la referencia, no la lista.
Cuando modifica la lista a la que se refiere queso, la lista a la que se refiere el correo no deseado
también cambia, porque tanto el queso como el correo no deseado se refieren a la misma
lista. Puede
ver esto en la Figura 4-6.
Figura 4-6: queso [1] = '¡Hola!' modifica la lista a la que se refieren ambas
variables.
Las variables contendrán referencias a valores de lista en lugar de valores de lista en
sí. Pero para las cadenas y los valores enteros, las variables simplemente contienen la
cadena o el valor entero. Python usa referencias cuando las variables deben
almacenar valores de tipos de datos mutables, como listas o diccionarios. Para valores
de tipos de datos inmutables como cadenas, enteros o tuplas, las variables de Python
almacenarán el valor en sí.
Aunque las variables de Python técnicamente contienen referencias a
valores de lista o de diccionario , la gente suele decir casualmente que la variable contiene la lista o
el
diccionario.
100 Capítulo 4
Pasar referencias Las
referencias son particularmente importantes para comprender cómo
se pasan los argumentos a las funciones. Cuando se llama a una función, los valores de los
argumentos
se copian a las variables del parámetro. Para las listas (y diccionarios,
que describiré en el próximo capítulo), esto significa que
se utiliza una copia de la referencia para el parámetro. Para ver las consecuencias de esto, abra una
nueva
ventana del editor de archivos , ingrese el siguiente código y guárdelo como passReference.py :
huevos de def (someParameter):
someParameter.append ('Hola')
spam = [1, 2, 3]
huevos (spam)
imprimir (spam)
Tenga en cuenta que cuando se llama a eggs (), no se usa un valor de retorno para asignar un
nuevo valor al spam. En cambio, modifica la lista en su lugar, directamente. Cuando se ejecuta,
este programa produce el siguiente resultado:
[1, 2, 3, 'Hola']
Aunque el spam y someParameter contienen referencias separadas,
ambos se refieren a la misma lista. Es por eso que la llamada al método append ('Hola')
dentro de la función afecta la lista incluso después de que la llamada a la función ha regresado.
Tenga en cuenta este comportamiento: olvidar que Python maneja las variables de lista y
diccionario de esta manera puede generar errores confusos.
Funciones de copia () y copia profunda () del módulo de copia
Aunque pasar referencias suele ser la forma más práctica de manejar
listas y diccionarios, si la función modifica la lista o diccionario que se
pasa, es posible que no desee estos cambios en la lista original o
valor del diccionario Para esto, Python proporciona un módulo denominado copia que proporciona
las funciones copy () y deepcopy (). El primero de ellos, copy.copy (), puede usarse
para hacer una copia duplicada de un valor mutable como una lista o diccionario, no solo una
copia de una referencia. Ingrese lo siguiente en el shell interactivo:
>>> copia de importación
>>> spam = ['A', 'B', 'C', 'D']
>>> cheese = copy.copy (spam)
>>> cheese [1] = 42
>>> spam
['A', 'B', 'C', 'D']
>>> queso
['A', 42, 'C', 'D']
Listas 101
Ahora las variables spam y cheese se refieren a listas separadas, por lo que solo
se modifica la lista en cheese cuando asigna 42 en el índice 1. Como puede ver en la
Figura 4-7, los números de ID de referencia ya no son los mismos para ambos variables
porque las variables se refieren a listas independientes.
Figura 4-7: cheese = copy.copy (spam) crea una segunda lista que puede modificarse
independientemente de la primera.
Si la lista que necesita copiar contiene listas, use la función copy.deepcopy () en
lugar de copy.copy (). La función deepcopy () también copiará estas
listas internas.
Las
listas de resumen son tipos de datos útiles, ya que le permiten escribir código que funciona en un
número de valores modificables en una sola variable. Más adelante en este libro,
verá programas que usan listas para hacer cosas que serían difíciles o imposibles de
hacer sin ellos.
Las listas son mutables, lo que significa que sus contenidos pueden cambiar. Las tuplas y las
cadenas, aunque son parecidas a listas en algunos aspectos, son inmutables y no se pueden
cambiar. Una variable que contiene un valor de tupla o cadena puede sobrescribirse
con un nuevo valor de tupla o cadena, pero esto no es lo mismo que modificar
el valor existente en su lugar, como, por ejemplo, los métodos append () o remove () en
liza.
Las variables no almacenan valores de lista directamente; almacenan referencias a listas.
Esta es una distinción importante al copiar variables o pasar listas como
argumentos en llamadas a funciones. Debido a que el valor que se copia es la
referencia de la lista, tenga en cuenta que cualquier cambio que realice en la lista podría afectar a
otra variable en su programa. Puede usar copy () o deepcopy () si
desea realizar cambios en una lista en una variable sin modificar la
lista original.
102 Capítulo 4
Preguntas de práctica
1. ¿Qué es []?
2. ¿Cómo asignaría el valor 'hola' como tercer valor en una lista almacenada?
en una variable llamada spam? (Suponga que el spam contiene [2, 4, 6, 8, 10]).
Para las siguientes tres preguntas, supongamos que el correo no deseado contiene la lista ['a',
'b', 'c', 'd'].
3. ¿Qué evalúa el spam [int (int ('3' * 2) / 11)]?
4. ¿Qué evalúa el spam [-1]?
5. ¿Qué evalúa el spam [: 2]?
Para las siguientes tres preguntas, digamos que tocino contiene la lista
[3.14, 'cat', 11, 'cat', True].
6. ¿Qué evalúa bacon.index ('cat')?
7. ¿Cómo bacon.append (99) hace que se vea el valor de la lista en tocino?
8. ¿Cómo hace que bacon.remove ('cat') parezca el valor de la lista en tocino?
9. ¿Cuáles son los operadores para la concatenación de listas y la replicación de listas?
10. ¿Cuál es la diferencia entre los métodos de la lista append () e insert ()?
11. ¿Cuáles son dos formas de eliminar valores de una lista?
12. Nombre algunas formas en que los valores de la lista son similares a los valores de cadena.
13. ¿Cuál es la diferencia entre listas y tuplas?
14. ¿Cómo se escribe el valor de tupla que tiene solo el valor entero 42?
15. ¿Cómo puede obtener la forma de tupla de un valor de lista? ¿Cómo puedes obtener la lista?
forma de un valor de tupla?
16. Las variables que "contienen" valores de lista en realidad no contienen listas directamente.
¿Qué contienen en su lugar?
17. ¿Cuál es la diferencia entre copy.copy () y copy.deepcopy ()?
Proyectos de
práctica Para practicar, escriba programas para realizar las siguientes tareas.
Código de coma
Digamos que tiene un valor de lista como este:
spam = ['manzanas', 'bananas', 'tofu', 'gatos']
Escriba una función que tome un valor de lista como argumento y devuelva
una cadena con todos los elementos separados por una coma y un espacio, con e insertada antes del
último elemento. Por ejemplo, pasar la lista de spam anterior a la función devolvería 'manzanas,
plátanos, tofu y gatos'. Pero su función debería poder funcionar con cualquier valor de lista que se le
pase.

Listas 103
Cuadrícula de imagen de caracteres
Digamos que tiene una lista de listas donde cada valor en las listas internas es una cadena de un
carácter
, como esta:
grid = [['.', '.', '.', '.', '.', '.'],
['.', 'O', 'O', '.', '.', '.'],
['O', 'O', 'O', 'O', '.', '.'],
['O', 'O', 'O', 'O', 'O ','. '],
['. ',' O ',' O ',' O ',' O ',' O '],
[' O ',' O ',' O ',' O ', 'O', '.'],
['O', 'O', 'O', 'O', '.', '.'],
['.', 'O', 'O', '. ','. ','. '],
['. ','. ','. ','. ','. ','. ']]
Puede pensar en la cuadrícula [x] [y] como el carácter en las
coordenadas x e y de una "imagen" dibujada con caracteres de texto. El origen (0, 0)
estará en la esquina superior izquierda, las coordenadas x aumentarán hacia la derecha
y las coordenadas y aumentarán hacia abajo.
Copie el valor de cuadrícula anterior y escriba el código que lo usa para imprimir la imagen.
..OO.OO ..
.OOOOOOO.
.OOOOOOO.
..OOOOO ..
... OOO ...
.... O ....
Sugerencia: Necesitará usar un bucle en un bucle para imprimir la grilla [0] [0],
luego la grilla [1] [0], luego la grilla [2] [0], y así sucesivamente, hasta la grilla [ 8] [0]. Esto
finalizará
la primera fila, entonces imprima una nueva línea. Entonces su programa debe imprimir la
cuadrícula [0] [1], luego la cuadrícula [1] [1], luego la cuadrícula [2] [1], y así sucesivamente. Lo
último que imprimirá su
programa es la cuadrícula [8] [5].
Además, recuerde pasar el argumento de palabra clave final a print () si
no desea que se imprima una nueva línea automáticamente después de cada llamada print ().
5
D i Ction A rie SA n D
S tru C turing DA t A
En este capítulo, cubriré el tipo de datos del diccionario
, que proporciona una forma flexible de
acceder y organizar datos. Luego, combina
diccionarios con tu conocimiento de listas de
En el capítulo anterior, aprenderá a crear una estructura de datos
para modelar un tablero de tres en raya.
el tipo de datos del diccionario
Al igual que una lista, un diccionario es una colección de muchos valores. Pero a diferencia de los
índices para
listas, los índices para diccionarios pueden usar muchos tipos de datos diferentes, no solo
enteros. Los índices para los diccionarios se denominan claves , y una clave con su
valor asociado se denomina par clave-valor .
En el código, un diccionario se escribe con llaves, {}. Ingrese lo siguiente en
el shell interactivo:
>>> myCat = {'size': 'fat', 'color': 'grey', 'disposition': 'loud'}
106 Capítulo 5
Esto asigna un diccionario a la variable myCat. Las claves de este diccionario son
'tamaño', 'color' y 'disposición'. Los valores para estas teclas son 'gordo', 'gris'
y 'fuerte', respectivamente. Puede acceder a estos valores a través de sus claves:
>>> myCat ['tamaño']
'gordo'
>>> 'Mi gato tiene' + myCat ['color'] + 'pelaje'.
'Mi gato tiene pelaje gris'.
Los diccionarios aún pueden usar valores enteros como claves, al igual que las listas usan enteros
para los índices, pero no tienen que comenzar en 0 y pueden ser cualquier número.
>>> spam = {12345: 'Combinación de equipaje', 42: 'La respuesta'}
Diccionarios frente a listas
A diferencia de las listas, los elementos de los diccionarios no están ordenados. El primer elemento
en una lista
llamada spam sería spam [0]. Pero no hay "primer" elemento en un diccionario.
Si bien el orden de los elementos es importante para determinar si dos listas son
iguales, no importa en qué orden se escriben los pares clave-valor en un diccionario
. Ingrese lo siguiente en el shell interactivo:
>>> spam = ['gatos', 'perros', 'alces']
>>> bacon = ['perros', 'alces', 'gatos']
>>> spam == tocino
Falso
>>> huevos = { 'nombre': 'Zophie', 'especie': 'gato', 'edad': '8'}
>>> jamón = {'especie': 'gato', 'edad': '8', 'nombre': 'Zophie'}
>>> huevos == jamón
Verdadero
Como los diccionarios no están ordenados, no se pueden dividir como listas.
Intentar acceder a una clave que no existe en un diccionario dará como resultado un
Mensaje de error de KeyError, muy similar al mensaje de error de IndexError de una lista "fuera de
rango"
. Ingrese lo siguiente en el shell interactivo y observe el
mensaje de error que aparece porque no hay una clave de 'color':
>>> spam = {'name': 'Zophie', 'age': 7}
>>> spam ['color']
Traceback (última llamada más reciente):
Archivo "<pyshell # 1>", línea 1, en <module>
spam ['color']
KeyError: 'color'
Aunque los diccionarios no están ordenados, el hecho de que pueda tener
valores arbitrarios para las claves le permite organizar sus datos de manera poderosa.
Digamos que desea que su programa almacene datos sobre los cumpleaños de sus amigos.
Puede usar un diccionario con los nombres como claves y los cumpleaños como valores.
Abra una nueva ventana del editor de archivos e ingrese el siguiente código.
Guárdelo como día de nacimiento.py .
Diccionarios y estructuración de datos 107
u cumpleaños = {'Alice': '1 de abril', 'Bob': '12 de diciembre', 'Carol': '4 de marzo'}
while True:
print ('Ingrese un nombre: (en blanco para salir)')
name = input ()
if name == '':
break
v si nombre en cumpleaños:
w print (cumpleaños [nombre] + 'es el cumpleaños de' + nombre)
más:
print ('No tengo información de cumpleaños para' + nombre)
print ('¿Cuál es su cumpleaños?')
bday = input ()
x cumpleaños [nombre] = bday
print ('Base de datos de cumpleaños actualizada')
Creas un diccionario inicial y lo almacenas en cumpleaños u. Puede ver
si el nombre ingresado existe como una clave en el diccionario con la palabra clave v,
tal como lo hizo para las listas. Si el nombre está en el diccionario, accede al
valor asociado usando corchetes w; si no, puede agregarlo usando la misma
sintaxis de corchetes combinada con el operador de asignación x.
Cuando ejecute este programa, se verá así:
Ingrese un nombre: (en blanco para salir)
Alice
1 de abril es el cumpleaños de Alice
Ingrese un nombre: (en blanco para salir)
Eve
No tengo información de cumpleaños para Eve
¿Cuál es su cumpleaños?
5 de diciembre Se
actualizó la base de datos de cumpleaños.
Ingrese un nombre: (en blanco para salir)
Eve
5 de diciembre es el cumpleaños de Eva
Ingrese un nombre: (en blanco para salir)
Por supuesto, todos los datos que ingrese en este programa se olvidan cuando el
programa finaliza. Aprenderá cómo guardar datos en archivos en el disco duro
en el Capítulo 8.
Los métodos de claves (), valores () e ítems ()
Hay tres métodos de diccionario que devolverán valores similares a una lista de las
claves, valores o claves y valores del diccionario: claves (), valores () y elementos ( )
Los valores devueltos por estos métodos no son listas verdaderas: no se pueden
modificar y no tienen un método append (). Pero estos tipos de datos (dict_keys,
108 Capítulo 5
dict_values y dict_items, respectivamente) se pueden usar para bucles. Para ver
cómo funcionan estos métodos, ingrese lo siguiente en el shell interactivo:
>>> spam = {'color': 'rojo', 'edad': 42}
>>> para v en spam.values ():
print (v)
rojo
42
Aquí, un bucle for itera sobre cada uno de los valores en el diccionario de spam.
Un bucle for también puede iterar sobre las claves o ambas claves y valores:
>>> para k en spam.keys ():
print (k)

edad del color


>>> para i en spam.items ():
print (i)
('color', 'rojo')
('edad', 42)
Usando los métodos keys (), values () y items (), un bucle for puede iterar
sobre las claves, los valores o los pares clave-valor en un diccionario, respectivamente. Observe
que los valores en el valor dict_items devueltos por el método items () son
tuplas de la clave y el valor.
Si desea una lista verdadera de uno de estos métodos, pase su valor de retorno similar
a una lista a la función list (). Ingrese lo siguiente en el shell interactivo:
>>> spam = {'color': 'rojo', 'age': 42}
>>> spam.keys ()
dict_keys (['color', 'age'])
>>> list (spam.keys () )
['color', 'edad']
La línea list (spam.keys ()) toma el valor dict_keys devuelto por las teclas ()
y lo pasa a list (), que luego devuelve un valor de lista de ['color', 'age'].
También puede usar el truco de asignación múltiple en un bucle for para asignar
la clave y el valor a variables separadas. Ingrese lo siguiente en el
shell interactivo:
>>> spam = {'color': 'rojo', 'edad': 42}
>>> para k, v en spam.items ():
print ('Clave:' + k + 'Valor:' + str ( v))
Clave: edad Valor: 42
Clave: color Valor: rojo
Diccionarios y estructuración de datos 109
Comprobando si existe una clave o un valor en un diccionario
Recuerde del capítulo anterior que los operadores in y no en los operadores pueden verificar
si existe un valor en una lista. También puede usar estos operadores para ver si
existe una determinada clave o valor en un diccionario. Ingrese lo siguiente en el
shell interactivo:
>>> spam = {'name': 'Zophie', 'age': 7}
>>> 'name' en spam.keys ()
True
>>> 'Zophie' en spam.values ()
True
>>> ' color 'en spam.keys ()
Falso
>>> ' color 'no en spam.keys ()
Verdadero
>>> ' color 'en spam
Falso
En el ejemplo anterior, observe que 'color' en spam es esencialmente una
versión más corta de escribir 'color' en spam.keys (). Este es siempre el caso: si
alguna vez desea verificar si un valor es (o no) una clave en el diccionario,
simplemente puede usar la palabra clave in (o no in) con el valor del diccionario en sí.
El método get ()
Es tedioso comprobar si existe una clave en un diccionario antes de acceder
al valor de esa clave. Afortunadamente, los diccionarios tienen un método get () que toma dos
argumentos: la clave del valor a recuperar y un valor alternativo a devolver si
esa clave no existe.
Ingrese lo siguiente en el shell interactivo:
>>> picnicItems = {'manzanas': 5, 'tazas': 2}
>>> 'Estoy trayendo' + str (picnicItems.get ('tazas', 0)) + 'tazas'.
'Estoy trayendo 2 tazas'.
>>> 'Estoy trayendo' + str (picnicItems.get ('eggs', 0)) + 'eggs'.
'Estoy trayendo 0 huevos'.
Debido a que no hay una clave 'eggs' en el diccionario picnicItems, el
método get () devuelve el valor predeterminado 0. Sin usar get (), el código
habría causado un mensaje de error, como en el siguiente ejemplo:
>>> picnicItems = {'manzanas': 5, 'tazas': 2}
>>> 'Estoy trayendo' + str (picnicItems ['huevos']) + 'huevos'.
Traceback (última llamada más reciente):
Archivo "<pyshell # 34>", línea 1, en <module>
'Estoy trayendo' + str (picnicItems ['eggs']) + 'eggs.'
KeyError: 'huevos'
110 Capítulo 5
El método setdefault ()
A menudo tendrá que establecer un valor en un diccionario para una determinada clave solo si esa
clave aún no tiene un valor. El código se parece a esto:
spam = {'name': 'Pooka', 'age': 5}
si 'color' no está en spam:
spam ['color'] = 'black'
El método setdefault () ofrece una manera de hacer esto en una línea de código. El
primer argumento pasado al método es la clave para verificar, y el segundo
argumento es el valor a establecer en esa clave si la clave no existe. Si la clave
existe, el método setdefault () devuelve el valor de la clave. Ingrese lo siguiente
en el shell interactivo:
>>> spam = {'name': 'Pooka', 'age': 5}
>>> spam.setdefault ('color', 'black')
'black'
>> > spam
{'color': 'negro', 'edad': 5, 'nombre': 'Pooka'}
>>> spam.setdefault ('color', 'blanco')
'negro'
>>> spam
{'color ':' negro ',' edad ': 5,' nombre ':' Pooka '}
La primera vez que se llama a setdefault (), el diccionario en spam cambia
a {'color': 'black', 'age': 5, 'name': 'Pooka'}. El método devuelve el
valor 'negro' porque ahora es el valor establecido para la clave 'color'. Cuando se
llama a spam.setdefault ('color', 'blanco') a continuación, el valor de esa clave no se cambia a
'blanco' porque el spam ya tiene una clave llamada 'color'.
El método setdefault () es un buen acceso directo para garantizar que exista una clave.
Aquí hay un breve programa que cuenta el número de ocurrencias de cada letra
en una cadena. Abra la ventana del editor de archivos e ingrese el siguiente código,
guardándolo como characterCount.py :
message = 'Era un día frío y brillante en abril, y los relojes daban las trece'.
cuenta = {}
para el carácter en el mensaje:
count.setdefault (character, 0)
count [character] = count [character] + 1
imprimir (contar)
El programa recorre cada carácter en la cadena de la variable del mensaje,
contando con qué frecuencia aparece cada carácter. La llamada al método setdefault ()
garantiza que la clave esté en el diccionario de recuento (con un valor predeterminado de 0)
Diccionarios y estructuración de datos 111
para que el programa no arroje un error KeyError cuando se ejecuta count [character] =
count [character] + 1. Cuando ejecuta este programa, la salida
se verá así:
{'': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, 'a': 4, 'c': 3, 'b': 1, 'e ': 5,' d ': 3,' g ': 2,' i ':
6,' h ': 3,' k ': 2,' l ': 3,' o ': 2,' n ': 4, 'p': 1, 's': 3, 'r': 5, 't': 6, 'w': 2, 'y': 1}
En la salida, puede ver que la letra minúscula c aparece 3 veces,
el carácter de espacio aparece 13 veces y la letra mayúscula A aparece
1 vez. Este programa funcionará sin importar qué cadena esté dentro de la variable del mensaje
, ¡incluso si la cadena tiene millones de caracteres de largo!
Impresión bonita
Si importa el módulo pprint a sus programas, tendrá acceso a
las funciones pprint () y pformat () que "imprimirán bastante" los
valores de un diccionario . Esto es útil cuando desea una visualización más limpia de los elementos
en un
diccionario que la que proporciona print (). Modifique el programa characterCount.py anterior y
guárdelo como prettyCharacterCount.py .

import pprint
message = 'Era un día frío y brillante en abril, y los relojes daban las
trece'.
cuenta = {}
para el carácter en el mensaje:
count.setdefault (character, 0)
count [character] = count [character] + 1
pprint.pprint (cuenta)
Esta vez, cuando se ejecuta el programa, la salida se ve mucho más limpia,
con las teclas ordenadas.
{'': 13,
',': 1,
'.': 1,
'A': 1,
'I': 1,
'a': 4,
'b': 1,
'c': 3,
'd ': 3,
' e ': 5,
' g ': 2,
' h ': 3,
' i ': 6,
112 Capítulo 5
'k': 2,
'l': 3,
'n': 4,
'o': 2,
'p': 1,
'r': 5,
's': 3,
't': 6,
'w ': 2,
' y ': 1}
La función pprint.pprint () es especialmente útil cuando el diccionario
contiene listas anidadas o diccionarios.
Si desea obtener el texto prettificado como un valor de cadena en lugar de
mostrarlo en la pantalla, llame a pprint.pformat () en su lugar. Estas dos líneas son
equivalentes entre sí:
pprint.pprint (someDictionaryValue)
print (pprint.pformat (someDictionaryValue))
Uso de estructuras de datos para modelar cosas del mundo real
Incluso antes de Internet, era posible jugar una partida de ajedrez con alguien
del otro lado del mundo. Cada jugador establecería un tablero de ajedrez en
su casa y luego se turnaría para enviarse una tarjeta postal describiendo
cada movimiento. Para hacer esto, los jugadores necesitaban una manera de describir
inequívocamente
el estado del tablero y sus movimientos.
En la notación algebraica de ajedrez, los espacios en el tablero de ajedrez se identifican mediante
una coordenada de números y letras, como en la Figura 5-1.
ab
1
2
3
4
5
6
7
8
cdefgh
a1
a2
a3
a4
b1
b2
b3
b4
c1
c2
c3
c4
d1
d2
d3
d4
g5
Figura 5-1: Las coordenadas de
un tablero de ajedrez en notación algebraica de ajedrez
Las piezas de ajedrez se identifican con letras: K para rey, Q para reina, R para
torre, B para alfil y N para caballero. Al describir un movimiento, se usa la letra de la
pieza y las coordenadas de su destino. Un par de estos movimientos describe
Diccionarios y estructuración de datos 113
qué sucede en un solo turno (con el blanco yendo primero); por ejemplo, la
notación 2. Cf3 Cc6 indica que las blancas movieron a un caballero a f3 y las negras
movieron a un caballero a c6 en el segundo turno del juego.
Hay un poco más de notación algebraica que esto, pero el punto es que
puedes usarlo para describir inequívocamente un juego de ajedrez sin necesidad
de estar frente a un tablero de ajedrez. ¡Tu oponente puede incluso estar del otro lado
del mundo! De hecho, ni siquiera necesita un juego de ajedrez físico si tiene
buena memoria: puede leer los movimientos de ajedrez enviados por correo y actualizar los
tableros
que tiene en su imaginación.
Las computadoras tienen buenos recuerdos. Un programa en una computadora moderna
puede almacenar fácilmente miles de millones de cadenas como '2. Cf3 Cc6 '. Así es como las
computadoras pueden
jugar al ajedrez sin tener un tablero de ajedrez físico. Modelan datos para representar
un tablero de ajedrez, y puede escribir código para trabajar con este modelo.
Aquí es donde pueden aparecer las listas y los diccionarios. Puede usarlos para
modelar cosas del mundo real, como tableros de ajedrez. Para el primer ejemplo, usarás
un juego un poco más simple que el ajedrez: tic-tac-toe.
Un tablero de tres en raya
Un tablero de tres en raya se parece a un gran
símbolo hash (#) con nueve ranuras que pueden
contener una X , una O o un espacio en blanco. Para representar
el tablero con un diccionario, puede
asignar a cada ranura una clave de valor de cadena, como se muestra
en la Figura 5-2.
Puede usar valores de cadena para representar
lo que hay en cada ranura en el tablero: 'X', 'O' o
'' (un carácter de espacio). Por lo tanto,
deberá almacenar nueve cadenas. Puede usar una dicción
de valores para esto. El valor de la cadena con
la tecla 'top-R' puede representar la
esquina superior derecha , el valor de la cadena con la tecla 'low-L'
puede representar la esquina inferior izquierda, el
valor de la cadena con la tecla 'mid-M' puede representa
el medio, y así sucesivamente.
Este diccionario es una estructura de datos que representa un tablero de tres en raya.
Almacene este tablero como un diccionario en una variable llamada theBoard. Abra una
nueva ventana del editor de archivos e ingrese el siguiente código fuente, guardándolo como
ticTacToe.py :
theBoard = {'top-L': '', 'top-M': '', 'top-R': '',
'mid-L': '', 'mid-M': '', 'mid -R ':' ',
' low-L ':' ',' low-M ':' ',' low-R ':' '}
La estructura de datos almacenada en la variable theBoard representa el tablero de tic-tac
toe en la Figura 5-3.
'bajo-L' 'bajo-M' 'bajo-R'
'mid-L' 'mid-M' 'mid-R'
'top-L' 'top-M' 'top-R'
Figura 5-2: Las ranuras de un tablero de tic-tac
toe con sus teclas correspondientes
114 Capítulo 5
Figura 5-3: Un tablero vacío de tres en raya
Dado que el valor de cada clave en el tablero es una cadena de espacio simple, este
diccionario representa un tablero completamente claro. Si el jugador X fue primero y
eligió el espacio intermedio, podría representar ese tablero con este diccionario:
theBoard = {'top-L': '', 'top-M': '', 'top-R': '',
'mid-L': '', 'mid-M': 'X', ' mid-R ':' ',
' low-L ':' ',' low-M ':' ',' low-R ':' '}
La estructura de datos en el tablero ahora representa el tablero de tres en raya en la
figura 5-4.
Figura 5-4: el primer movimiento
Un tablero donde el jugador O ha ganado colocando O s en la parte superior podría
verse así:
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O',
'mid-L': 'X', 'mid-M': ' X ',' mid-R ':' ',
' low-L ':' ',' low-M ':' ',' low-R ':' X '}
La estructura de datos en el tablero ahora representa el tablero de tres en raya en la
figura 5-5.
Diccionarios y estructuración de datos 115
Figura 5-5: El jugador O gana.
Por supuesto, el jugador solo ve lo que se imprime en la pantalla, no el
contenido de las variables. Creemos una función para imprimir el diccionario de pizarra
en la pantalla. Haga la siguiente adición a ticTacToe.py (el nuevo código está en
negrita):
theBoard = {'top-L': '', 'top-M': '', 'top-R': '',
'mid-L': '', 'mid-M': '', 'mid -R ':' ',
' low-L ':' ',' low-M ':' ',' low-R ':' '}
def printBoard (tablero):
print (tablero [' top-L '] + '|' + tablero ['top-M'] + '|' + tablero ['top-R'])
print ('- + - + -')
print (tablero ['mid-L'] + '| '+ tablero [' mid-M '] +' | '+ tablero [' mid-R '])
print (' - + - + - ')
print (tablero [' low-L '] +' | '+ tablero ['low-M'] + '|' + tablero ['low-R'])
printBoard (theBoard)
Cuando ejecute este programa, printBoard () imprimirá un tablero de fichas en blanco
.
El | El |
-+-+-
| El |
-+-+-
| El |
La función printBoard () puede manejar cualquier estructura de datos tic-tac-toe que le
pase. Intente cambiar el código a lo siguiente:
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O', 'mid-L': 'X', 'mid-M':
' X ',' mid-R ':' ',' low-L ':' ',' low-M ':' ',' low-R ':' X '}
def printBoard (tablero):
print (tablero ['top-L'] + '|' + tablero ['top-M'] + '|' + tablero ['top-R'])
print ('- + - + - ')
print (tablero [' mid-L '] +' | '+ tablero [' mid-M '] +' | '+ tablero [' mid-R '])
print (' - + - + - ')
print (tablero ['bajo-L'] + '|' + tablero ['bajo-M'] + '|' + tablero ['bajo-R'])
printBoard (theBoard)
116 Capítulo 5
Ahora, cuando ejecute este programa, la nueva placa se imprimirá en
la pantalla.
O|O|O
-+-+-
X|X|
-+-+-
||X
Debido a que creó una estructura de datos para representar un tablero
de tres en raya y escribió código en printBoard () para interpretar esa estructura de datos, ahora
tiene un programa que "modela" el tablero de tres en raya . Podría haber organizado
su estructura de datos de manera diferente (por ejemplo, usando teclas como 'SUPERIOR-
IZQUIERDA' en
lugar de 'superior-L'), pero siempre que el código funcione con sus estructuras de datos,
tendrá un programa que funcione correctamente .
Por ejemplo, la función printBoard () espera que la estructura de datos tic-tac-toe
sea un diccionario con claves para las nueve ranuras. Si falta el diccionario que aprobó
, por ejemplo, la tecla 'mid-L', su programa ya no funcionaría.
O|O|O
-+-+-
Rastreo (última llamada última):
Archivo "ticTacToe.py", línea 10, en <module>
printBoard (theBoard)
Archivo "ticTacToe.py", línea 6, en printBoard
print ( placa ['mid-L'] + '|' + placa ['mid-M'] + '|' + placa ['mid-R'])
KeyError: 'mid-L'
Ahora agreguemos un código que permita a los jugadores ingresar sus movimientos. Modifique
el programa ticTacToe.py para que se vea así:
theBoard = {'top-L': '', 'top-M': '', 'top-R': '', 'mid-L': '', 'mid-M': '
', 'mid -R ':' ',' low-L ':' ',' low-M ':' ',' low-R ':' '}
def printBoard (tablero):
print (tablero ['top-L'] + '|' + tablero ['top-M'] + '|' + tablero ['top-R'])
print ('- + - + - ')
print (tablero [' mid-L '] +' | '+ tablero [' mid-M '] +' | '+ tablero [' mid-R '])
print (' - + - + - ')
print (tablero ['bajo-L'] + '|' + tablero ['bajo-M'] + '|' + tablero ['bajo-R'])
turn = 'X'
para i en el rango (9):
u printBoard (theBoard)
print ('Activar para' + activar + '. ¿Mover en qué espacio?')
v move = input ()
w theBoard [move] = turn
x if turn == 'X':
turn = 'O'
else:
turn = 'X'
printBoard (theBoard)
Diccionarios y estructuración de datos 117
El nuevo código imprime el tablero al comienzo de cada nuevo turno u, obtiene
el movimiento del jugador activo v, actualiza el tablero del juego en consecuencia w, y
luego intercambia el jugador activo x antes de pasar al siguiente turno.
Cuando ejecute este programa, se verá más o menos así:
El | El |
-+-+-
| El |
-+-+-
| El |
Gira hacia X. ¿Mover en qué espacio?
mediados de M
| El |
-+-+-
|X|
-+-+-
| El |
Gire para O. Mover en qué espacio?
bajo-L
| El |
-+-+-
|X|
-+-+-
O | El |
- cortar -
O|O|X
-+-+-
X|X|O
-+-+-
O||X
Gira para X. ¿Mover en qué espacio?
bajo-M
O|O|X
-+-+-
X|X|O
-+-+-
O|X|X
Este no es un juego completo de tres en raya, por ejemplo, nunca comprueba
si un jugador ha ganado, pero es suficiente para ver cómo se pueden usar las estructuras de datos
en los programas.
nota Si tiene curiosidad, el código fuente de un programa completo de tres en raya se describe en
los
recursos disponibles en http://nostarch.com/automatestuff/ .
Diccionarios y listas anidados El
modelado de un tablero de tres en raya era bastante simple: el tablero solo necesitaba un
único valor de diccionario con nueve pares de valores clave. A medida que modela cosas más
complicadas
, es posible que necesite diccionarios y listas que contengan
118 Capítulo 5
otros diccionarios y listas Las listas son útiles para contener una serie ordenada
de valores, y los diccionarios son útiles para asociar claves con valores. Por
ejemplo, aquí hay un programa que usa un diccionario que contiene otros diccionarios
para ver quién lleva qué a un picnic. La función totalBrought ()
puede leer esta estructura de datos y calcular el número total de un
artículo que traen todos los invitados.
allGuests = {'Alice': {'manzanas': 5, 'pretzels': 12},
'Bob': {'sandwiches de jamón': 3, 'manzanas': 2},
'Carol': {'tazas': 3 , 'tartas de manzana': 1}}
def totalBrought (invitados, elemento):
numBrought = 0
u para k, v en invitados.items ():
v numBrought = numBrought + v.get (item, 0)
retorno num
print ('Número de cosas que se traen:')
print ('- Manzanas' + str (totalBrought (allGuests, 'apples')))
print ('- Cups' + str (totalBrought (allGuests, 'cups')))
print ('- Cakes' + str (totalBrought (allGuests, 'cakes')))
print ('- Ham Sandwiches' + str (totalBrought (allGuests, 'ham sandwiches')))
print ('- Apple Pies' + str (totalBrought (allGuests, 'tartas de manzana')))
Dentro de la función totalBrought (), el bucle for itera sobre los
pares clave- valor en los invitados u. Dentro del bucle, la cadena del nombre del invitado se
asigna a k, y el diccionario de artículos de picnic que traen se asigna
a v. Si el parámetro del artículo existe como una clave en este diccionario, se
agrega su valor (la cantidad) to numBrought v. Si no existe como una clave, el método get ()
devuelve 0 para agregarse a numBrought.
El resultado de este programa se ve así:
Cantidad de cosas que se traen:
- Manzanas 7
- Tazas 3
- Tartas 0
- Sandwiches de jamón 3
- Tartas de manzana 1
Esto puede parecer algo tan simple de modelar que no
necesitaría molestarse en escribir un programa para hacerlo. Pero
tenga en cuenta que esta misma función totalBrought () podría manejar fácilmente un diccionario
que contiene miles
de invitados, cada uno con miles de artículos de picnic diferentes. ¡Entonces
tener esta información en una estructura de datos junto con la función totalBrought ()
le ahorraría mucho tiempo!
Puede modelar cosas con estructuras de datos de la forma que desee,
siempre que el resto del código de su programa pueda funcionar correctamente con el modelo de
datos
. Cuando comiences a programar, no te preocupes tanto por
Diccionarios y estructuración de datos 119
la forma "correcta" de modelar datos. A medida que gane más experiencia, puede llegar
a modelos más eficientes, pero lo importante es que el modelo de datos
funciona para las necesidades de su programa.
Resumen
Aprendiste todo sobre los diccionarios en este capítulo. Las listas y los diccionarios
son valores que pueden contener múltiples valores, incluidas otras listas y diccionarios
. Los diccionarios son útiles porque puede asignar un elemento (la clave)
a otro (el valor), a diferencia de las listas, que simplemente contienen una serie
de valores en orden. Se accede a los valores dentro de un diccionario usando
corchetes al igual que con las listas. En lugar de un índice entero, los diccionarios pueden tener
claves de una variedad de tipos de datos: enteros, flotantes, cadenas o tuplas. Al organizar
los valores de un programa en estructuras de datos, puede crear representaciones
de objetos del mundo real. Viste un ejemplo de esto con un tablero de tres en raya.
Preguntas de práctica
1. ¿Cómo se ve el código de un diccionario vacío?
2. ¿Cómo se ve un valor de diccionario con una clave 'foo' y un valor 42?
3. ¿Cuál es la principal diferencia entre un diccionario y una lista?
4. ¿Qué sucede si intentas acceder al spam ['foo'] si el spam es {'bar': 100}?
5. Si un diccionario se almacena en spam, ¿cuál es la diferencia entre
expresiones 'cat' en spam y 'cat' en spam.keys ()?
6. Si un diccionario se almacena en spam, ¿cuál es la diferencia entre
expresiones 'cat' en spam y 'cat' en spam.values ()?
7. ¿Qué es un acceso directo para el siguiente código?
si 'color' no está en spam:
spam ['color'] = 'negro'
8. ¿Qué módulo y función se pueden usar para "imprimir bastante" los valores del diccionario
?
Proyectos de
práctica Para practicar, escriba programas para realizar las siguientes tareas.
Fantasy Game Inventory
Estás creando un videojuego de fantasía. La estructura de datos para modelar el
inventario del jugador será un diccionario donde las claves son valores de cadena que
describen el artículo en el inventario y el valor es un valor entero que detalla
cuántos de ese artículo tiene el jugador. Por ejemplo, el valor del diccionario
{'cuerda': 1, 'antorcha': 6, 'moneda de oro': 42, 'daga': 1, 'flecha': 12} significa que el
jugador tiene 1 cuerda, 6 antorchas, 42 de oro monedas, y así sucesivamente.
120 Capítulo 5
Escriba una función llamada displayInventory () que tome cualquier "inventario" posible
y lo muestre de la siguiente manera:
Inventario:
12 flechas
42 monedas de oro
1 cuerda
6 antorcha
1 daga
Número total de artículos: 62
Sugerencia: puede usar un bucle for para recorrer todas las teclas de un diccionario.
# Inventory.py
stuff = {'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}
def displayInventory (inventario):
print ("Inventario:")
item_total = 0
para k, v en Inventory.items ():
# LLENE ESTA PARTE EN
print ("Número total de artículos:" + str (item_total))
displayInventory (cosas)
Función List to Dictionary para Fantasy Game Inventory
Imagine que el botín de un dragón vencido se representa como una lista de cadenas
como esta:
dragonLoot = ['moneda de oro', 'daga', 'moneda de oro', 'moneda de oro', 'rubí']
Escriba una función llamada addToInventory (Inventory, AddedItems), donde el
parámetro de inventario es un diccionario que representa el inventario del jugador (como
en el proyecto anterior) y el parámetro AddedItems es una lista como dragonLoot.
La función addToInventory () debería devolver un diccionario que represente el
inventario actualizado. Tenga en cuenta que la lista de Elementos agregados puede contener
múltiplos del
mismo elemento. Su código podría verse más o menos así:
def addToInventory (inventario, addItems):
# su código va aquí
inv = {'moneda de oro': 42, 'cuerda': 1}
dragonLoot = ['moneda de oro', 'daga', 'moneda de oro', 'moneda de oro', 'rubí']
inv = addToInventory (inv, dragonLoot)
displayInventory (inv)
Diccionarios y estructuración de datos 121
El programa anterior (con su función displayInventory () del
proyecto anterior) generaría lo siguiente:
Inventario:
45 monedas de oro
1 cuerda
1 rubí
1 daga
Número total de artículos: 48
6
m A ni P ul A ting S tring S
El texto es una de las formas más comunes
de datos que manejarán sus programas. Tú
ya sabe cómo concatenar dos valores de cadena
junto con el operador +, pero usted
puede hacer mucho más que eso. Puede extraer
cadenas parciales de valores de cadena, agregar o quitar espacios, convertir letras en minúsculas
o mayúsculas y verificar que las cadenas estén formateadas correctamente. Incluso puede
escribir código Python para acceder al portapapeles para copiar y pegar texto.
En este capítulo, aprenderá todo esto y más. Luego, trabajará en
dos proyectos de programación diferentes: un administrador de contraseñas simple y un programa
para automatizar la tarea aburrida de formatear fragmentos de texto.
trabajar con cadenas
Veamos algunas de las formas en que Python le permite escribir, imprimir y acceder a cadenas
en su código.
124 Capítulo 6
Literales de
cadena Escribir valores de cadena en código Python es bastante sencillo: comienzan
y terminan con una comilla simple. Pero entonces, ¿cómo puedes usar una cita dentro de una
cadena? Escribiendo 'Ese es el gato de Alice'. no funcionará, porque Python piensa que
la cadena termina después de Alice, y el resto (s cat. ') es un código Python no válido.
Afortunadamente, hay varias formas de escribir cadenas.
Comillas dobles Las
cadenas pueden comenzar y terminar con comillas dobles, tal como lo hacen con
comillas simples . Una ventaja de usar comillas dobles es que la cadena puede tener un
carácter de comilla simple. Ingrese lo siguiente en el shell interactivo:
>>> spam = "Ese es el gato de Alice".
Como la cadena comienza con una comilla doble, Python sabe que la
comilla simple es parte de la cadena y no marca el final de la cadena.
Sin embargo, si necesita usar comillas simples y comillas dobles en la
cadena, deberá usar caracteres de escape.
Caracteres de escape
Un personaje de escape le permite usar caracteres que de otro modo serían imposibles de
poner en una cadena. Un carácter de escape consiste en una barra invertida (\) seguida
del carácter que desea agregar a la cadena. (A pesar de constar de dos
caracteres, comúnmente se conoce como un carácter de escape singular). Por
ejemplo, el carácter de escape para una comilla simple es \ '. Puede usar esto
dentro de una cadena que comienza y termina con comillas simples. Para ver cómo funcionan los
caracteres de escape
, ingrese lo siguiente en el shell interactivo:
>>> spam = 'Saluda a la madre de Bob'.
Python sabe que dado que la comilla simple en Bob \ 's tiene una barra diagonal inversa, no
es una comilla simple destinada a finalizar el valor de la cadena. Los caracteres de escape
\ 'y \ "le permiten poner comillas simples y comillas dobles dentro de sus cadenas,
respectivamente.
La Tabla 6-1 enumera los caracteres de escape que puede usar.
tabla 6-1: Caracteres de escape Carácter de
escape Se imprime como
\ ' Comilla simple
\ " Comilla doble
\ t Tab
\ n Nueva línea (salto de línea) \\ Barra invertida
Cuerdas de manipulación 125
Ingrese lo siguiente en el shell interactivo:
>>> print ("¡Hola! \ n¿Cómo estás? \ nEstoy bien".)
¡Hola!
¿Cómo estás?
Estoy bien.
Cadenas sin formato
Puede colocar una r antes de las comillas iniciales de una cadena para convertirla
en una cadena sin formato. Una cadena sin procesar ignora por completo todos los caracteres de
escape e
imprime cualquier barra diagonal inversa que aparezca en la cadena. Por ejemplo, escriba lo
siguiente en el shell interactivo:
>>> print (r'Ese es el gato de Carol. ')
Ese es el gato de Carol.
Como se trata de una cadena sin formato, Python considera la barra invertida como parte de
la cadena y no como el comienzo de un carácter de escape. Las cadenas sin formato son útiles
si está escribiendo valores de cadena que contienen muchas barras invertidas, como las
cadenas utilizadas para las expresiones regulares descritas en el próximo capítulo.
Cadenas de líneas múltiples con comillas triples
Si bien puede usar el carácter de escape \ n para poner una nueva línea en una cadena, a
menudo es más fácil usar cadenas de líneas múltiples. Una cadena multilínea en Python comienza
y termina con tres comillas simples o tres comillas dobles. Las comillas,
pestañas o líneas nuevas entre las "comillas triples" se consideran parte de la
cadena. Las reglas de sangría de Python para bloques no se aplican a líneas dentro de una
cadena multilínea.
Abra el editor de archivos y escriba lo siguiente:
print ('' 'Querida Alice,
El gato de Eve ha sido arrestado por secuestro, robo de gato y extorsión.
Sinceramente,
Bob '' ')
Guarde este programa como catnapping.py y ejecútelo. La salida se verá
así:
Querida Alice,
El gato de Eve ha sido arrestado por secuestro, robo de gato y extorsión.
Sinceramente
Bob
126 Capítulo 6
Tenga en cuenta que el carácter de comillas simples en Eve no necesita
escapar. Escapar de comillas simples y dobles es opcional en cadenas multilínea.
La siguiente llamada print () imprimiría texto idéntico pero no usa una cadena de varias
líneas:
print ('Querida Alice, \ n \ nEl gato de Eve ha sido arrestado por secuestro, robo de gato
y extorsión. \ n \ nSinceramente, \ nBob')
Comentarios multilínea
Mientras que el carácter hash (#) marca el comienzo de un comentario para el
resto de la línea, a menudo se usa una cadena multilínea para comentarios que abarcan varias
líneas. El siguiente es un código Python perfectamente válido:
"" "Este es un programa de prueba de Python.
Escrito por Al Sweigart al@inventwithpython.com
Este programa fue diseñado para Python 3, no Python 2.
"" "
def spam ():
"" "Este es un comentario de varias líneas para ayudar a
explicar lo que hace la función spam ()." ""
print ('¡Hola!')
Cadenas de indexación y segmentación Las cadenas
utilizan índices y sectores de la misma manera que las listas. Puedes pensar en la
cadena '¡Hola mundo!' como una lista y cada carácter en la cadena como un elemento
con un índice correspondiente.
' Hola Mundo ! '
0 1 2 3 4 5 6 7 8 9 10 11
El espacio y el signo de exclamación están incluidos en el recuento de caracteres,
así que '¡Hola, mundo!' tiene 12 caracteres de largo, desde H en el índice 0 hasta! en el índice 11.
Ingrese lo siguiente en el shell interactivo:
>>> spam = '¡Hola mundo!'
>>> spam [0]
'H'
>>> spam [4]
'o'
>>> spam [-1]
'!'
>>> spam [0: 5]
'Hola'
Manipulación de cuerdas 127
>>> spam [: 5]
'Hola'
>>> spam [6:]
'¡mundo!'
Si especifica un índice, obtendrá el carácter en esa posición en la
cadena. Si especifica un rango de un índice a otro,
se incluye el índice inicial y no el índice final. Por eso, si el spam es '¡Hola mundo!', El
spam [0: 5] es 'Hola'. La subcadena que obtiene del correo no deseado [0: 5] incluirá todo
, desde correo no deseado [0] al correo no deseado [4], dejando el espacio en el índice 5.
Tenga en cuenta que cortar una cadena no modifica la cadena original. Puede
capturar un segmento de una variable en una variable separada. Intente escribir lo
siguiente en el shell interactivo:
>>> spam = '¡Hola mundo!'
>>> fizz = spam [0: 5]
>>> fizz
'Hola'
Al cortar y almacenar la subcadena resultante en otra variable, puede
tener a mano la cadena completa y la subcadena para un acceso rápido y fácil.
Los operadores in y not in con cadenas
Los operadores in y not in se pueden usar con cadenas al igual que con los valores de lista.
Una expresión con dos cadenas unidas usando in o not in evaluará a
Boolean True o False. Ingrese lo siguiente en el shell interactivo:
>>> 'Hola' en 'Hola mundo'
Verdadero
>>> 'Hola' en 'Hola'
Verdadero
>>> 'HOLA' en 'Hola mundo'
Falso
>>> '' en 'spam'
Verdadero
>>> 'gatos 'no en' gatos y perros '
Falso
Estas expresiones prueban si la primera cadena (la cadena exacta, distingue entre mayúsculas y
minúsculas) puede encontrarse dentro de la segunda cadena.
Métodos de cadena útiles
Varios métodos de cadena analizan cadenas o crean valores de cadena transformados.
Esta sección describe los métodos que usará con más frecuencia.
128 Capítulo 6
La parte superior (), inferior (), isupper (), y islower () métodos de cadena
La parte superior () e inferior métodos de cadena () Devuelve una nueva cadena donde todas las
letras de la cadena original han sido convertidos a mayúsculas o minúsculas
caso , respectivamente. Los caracteres que no son letras en la cadena permanecen sin cambios.
Ingrese lo siguiente en el shell interactivo:
>>> spam = '¡Hola mundo!'
>>> spam = spam.upper ()
>>> spam
'¡HOLA MUNDO!'
>>> spam = spam.lower ()
>>> spam
'¡hola mundo!'
Tenga en cuenta que estos métodos no cambian la cadena en sí, sino que devuelven
nuevos valores de cadena. Si desea cambiar la cadena original, debe
llamar a upper () o lower () en la cadena y luego asignar la nueva cadena a la
variable donde se almacenó el original. Es por eso que debe usar spam =
spam.upper () para cambiar la cadena en spam en lugar de simplemente spam.upper ().
(Esto es como si un huevo variable contiene el valor 10. Escribir huevos + 3
no cambia el valor de los huevos, pero huevos = huevos + 3 sí).
Los métodos upper () y lower () son útiles si necesita hacer una
comparación entre mayúsculas y minúsculas. Las cadenas 'great' y 'GREat' no son iguales
entre sí. Pero en el siguiente programa pequeño, no importa si
el usuario escribe Great, GREAT o grEAT, porque la cadena se convierte primero a
minúsculas.
print ('¿Cómo estás?')
feeling = input ()
if feeling.lower () == 'great':
print ('Me siento genial también')
else:
print ('Espero que el resto de tu día sea bueno . ')
Cuando ejecutas este programa, se muestra la pregunta, y al ingresar una
variación en genial, como GREat, aún obtendrás el resultado que también me parece genial.
Agregar código a su programa para manejar variaciones o errores en la
entrada del usuario , como mayúsculas inconsistentes, hará que sus programas sean más fáciles
de usar y menos propensos a fallar.
¿Cómo estás?
GENIAL
Me siento genial también.
Los métodos isupper () e islower () devolverán un valor Boolean True
si la cadena tiene al menos una letra y todas las letras son mayúsculas o
Manipulación de cuerdas 129
minúsculas, respectivamente. De lo contrario, el método devuelve False. Ingrese lo
siguiente en el shell interactivo y observe lo que devuelve cada llamada a método
:
>>> spam = '¡Hola mundo!'
>>> spam.islower ()
Falso
>>> spam.isupper ()
Falso
>>> 'HELLO'.isupper ()
Verdadero
>>> ' abc12345'.islower ()
Verdadero
>>> '12345'.islower ()
Falso
>>> '12345'.isupper ()
Falso
Dado que los métodos de cadena superior () e inferior () devuelven cadenas,
también puede llamar a los métodos de cadena en esos valores de cadena devueltos. Las
expresiones
que hacen esto se verán como una cadena de llamadas a métodos. Ingrese lo siguiente en el
shell interactivo:
>>> 'Hello'.upper ()
' HELLO '
>>> ' Hello'.upper (). Lower ()
'hello'
>>> 'Hello'.upper (). Lower (). Upper ()
' HELLO '
>>> ' HELLO'.lower ()
'hello'
>>> 'HELLO'.lower (). Islower ()
True
Los métodos de cadena isX
Junto con islower () e isupper (), hay varios métodos de cadena que
tienen nombres que comienzan con la palabra es . Estos métodos devuelven un
valor booleano que describe la naturaleza de la cadena. Aquí hay algunos métodos comunes
de cadena X :

• isalpha () devuelve True si la cadena consta solo de letras y no está en blanco. • isalnum ()
devuelve True si la cadena consta solo de letras y números

y no está en blanco
• isdecimal () devuelve True si la cadena consta solo de caracteres numéricos
y no está en blanco
130 Capítulo 6
• isspace () devuelve True si la cadena consta solo de espacios, tabuladores y líneas nuevas y no está
en blanco.
• istitle () devuelve True si la cadena consta solo de palabras que comienzan con una letra
mayúscula seguida de letras minúsculas.
Ingrese lo siguiente en el shell interactivo:
>>> 'hello'.isalpha ()
Verdadero
>>> ' hello123'.isalpha ()
Falso
>>> 'hello123'.isalnum ()
Verdadero
>>> ' hello'.isalnum ()
Verdadero
>>> '123' .isdecimal ()
Verdadero
>>> '' .isspace ()
Verdadero
>>> 'Este es el caso del título' .istitle ()
Verdadero
>>> 'Este es el caso del título 123'.istitle ()
Verdadero
>>> ' Esto es not Title Case'.istitle ()
False
>>> 'This NOT NOT Title Case Either'.istitle ()
False
Los métodos de cadena is X son útiles cuando necesita validar la
entrada del usuario . Por ejemplo, el siguiente programa pide repetidamente a los usuarios su
edad y una contraseña hasta que proporcionen una entrada válida. Abra una nueva
ventana del editor de archivos e ingrese este programa, guardándolo como validateInput.py :
while True:
print ('Ingrese su edad:')
age = input ()
if age.isdecimal ():
break
print ('Ingrese un número para su edad')
while True:
print ('Seleccione una nueva contraseña (solo letras y números):')
password = input ()
if password.isalnum ():
break
print ('Las contraseñas solo pueden tener letras y números')
En el primer ciclo while, le pedimos al usuario su edad y almacenamos su
entrada en edad. Si la edad es un valor válido (decimal), salimos de este primer
ciclo while y pasamos al segundo, que solicita una contraseña. De lo contrario,
informamos al usuario que necesita ingresar un número y nuevamente le pedimos que lo haga.
Manipulación de cuerdas 131
Ingrese su edad. En el segundo ciclo while, pedimos una contraseña, almacenamos la
entrada del usuario en la contraseña y salimos del ciclo si la entrada es
alfanumérica. Si no fue así, no estamos satisfechos, por lo que le decimos al usuario que la
contraseña debe
ser alfanumérica y nuevamente le pedimos que ingrese una contraseña.
Cuando se ejecuta, la salida del programa se ve así:
Ingrese su edad:
cuarenta y dos
Ingrese un número para su edad.
Ingrese su edad:
42
Seleccione una nueva contraseña (solo letras y números):
secr3t!
Las contraseñas solo pueden tener letras y números.
Seleccione una nueva contraseña (solo letras y números):
secr3t
Llamando a isdecimal () e isalnum () en las variables, podemos probar si
los valores almacenados en esas variables son decimales o no, alfanuméricos o
no. ¡Aquí, estas pruebas nos ayudan a rechazar la entrada cuarenta y dos y aceptar 42, y
rechazar secr3t! y aceptar secr3t.
Los métodos de cadena comienza con () y termina con () Los métodos
comienza con () y termina con () devuelven Verdadero si el valor de cadena al que
se llama comienza o termina (respectivamente) con la cadena pasada al
método; de lo contrario, devuelven False. Ingrese lo siguiente en el
shell interactivo:
>>> '¡Hola mundo!'. Comienza con ('Hola')
Verdadero
>>> '¡Hola mundo!'. Termina con ('mundo!')
Verdadero
>>> 'abc123'.startswith (' abcdef ')
Falso
>>> 'abc123'.endswith ('12')
Falso
>>> '¡Hola mundo!'. comienza con ('¡Hola mundo!')
Verdadero
>>> '¡Hola mundo!'. termina con ('¡Hola mundo!')
Verdadero
Estos métodos son alternativas útiles al operador == igual si solo
necesita verificar si la primera o la última parte de la cadena, en lugar de
la totalidad, es igual a otra cadena.
Los métodos de cadena join () y split ()
El método join () es útil cuando tiene una lista de cadenas que deben
unirse en un solo valor de cadena. El método join () se llama en un
132 Capítulo 6
cadena, se le pasa una lista de cadenas y devuelve una cadena. La cadena devuelta
es la concatenación de cada cadena en la lista pasada. Por ejemplo, ingrese
lo siguiente en el shell interactivo:
>>> ',' .join (['gatos', 'ratas', 'murciélagos'])
'gatos, ratas, murciélagos'
>>> '' .join (['Mi', 'nombre', 'es' , 'Simon'])
'Mi nombre es Simon'
>>> 'ABC'.join ([' My ',' name ',' is ',' Simon '])
' MyABCnameABCisABCSimon '
Observe que la cadena join () invoca se inserta entre cada cadena
del argumento de la lista. Por ejemplo, cuando se llama a join (['gatos', 'ratas', 'murciélagos'])
en la cadena ',', la cadena devuelta es 'gatos, ratas, murciélagos'.
Recuerde que join () se llama en un valor de cadena y se le pasa un
valor de lista . (Es fácil llamarlo accidentalmente al revés). El
método split () hace lo contrario: se llama a un valor de cadena y devuelve una lista de
cadenas. Ingrese lo siguiente en el shell interactivo:
>>> 'Mi nombre es Simon'.split ()
[' Mi ',' nombre ',' es ',' Simon ']
De manera predeterminada, la cadena 'Mi nombre es Simon' se divide dondequiera que se
encuentren caracteres de espacio en blanco
, como el espacio, la pestaña o los caracteres de nueva línea. Estos
caracteres de espacio en blanco no se incluyen en las cadenas de la lista devuelta. Puede
pasar una cadena delimitadora al método split () para especificar una cadena diferente sobre la que
dividir. Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> 'MyABCnameABCisABCSimon'.split (' ABC ')
[' My ',' name ',' is ',' Simon ']
>>> ' My name is Simon'.split ('m')
['My na ',' e es Si ',' en ']
Un uso común de split () es dividir una cadena multilínea a lo largo de los caracteres de nueva línea
. Ingrese lo siguiente en el shell interactivo:
>>> spam = '' 'Querida Alice,
¿Cómo has estado? Estoy bien.
Hay un recipiente en el refrigerador
que está etiquetado como "Experimento de leche".
Por favor no lo bebas.
Atentamente,
Bob '' '
>>> spam.split (' \ n ')
[' Querida Alice ',' ¿Cómo has estado? Estoy bien ',' Hay un recipiente en el
refrigerador ',' que está etiquetado como 'Experimento de leche'. ',' ',' Por favor, no lo beban ',
' Atentamente ',' Bob ']
Manipulación de cuerdas 133
Al pasar split (), el argumento '\ n' nos permite dividir la cadena de
varias líneas almacenada en el correo no deseado a lo largo de las nuevas líneas y devolver una lista
en la que cada elemento corresponde
a una línea de la cadena.
Justificación del texto con rjust (), ljust () y center ()
Los métodos de cadena rjust () y ljust () devuelven una versión acolchada de la
cadena a la que se llama, con espacios insertados para justificar el texto. El primer
argumento para ambos métodos es una longitud entera para la cadena justificada.
Ingrese lo siguiente en el shell interactivo:
>>> 'Hello'.rjust (10)
' Hello '
>>> ' Hello'.rjust (20)
'Hello'
>>> 'Hello World'.rjust (20)
' Hello World '
>>> ' Hello ' .ljust (10)
'Hola'
'Hello'.rjust (10) dice que queremos justificar a la derecha' Hello 'en una cadena de
longitud total 10.' Hello 'tiene cinco caracteres, por lo que se agregarán cinco espacios a su
izquierda, dándonos una cadena de 10 los caracteres con 'Hola' se justifican correctamente.
Un segundo argumento opcional para rjust () y ljust () especificará un
carácter de relleno que no sea un carácter de espacio. Ingrese lo siguiente en el
shell interactivo:
>>> 'Hola'.rjust (20,' * ')
' *************** Hola '
>>> ' Hola'.ljust (20, '-')
'Hola --------------- '
El método de cadena center () funciona como ljust () y rjust () pero centra
el texto en lugar de justificarlo hacia la izquierda o la derecha. Ingrese lo siguiente
en el shell interactivo:
>>> 'Hello'.center (20)
' Hello '
>>> ' Hello'.center (20, '=')
'======= Hello ========'
Estos métodos son especialmente útiles cuando necesita imprimir
datos tabulares que tengan el espaciado correcto. Abra una nueva ventana del editor de archivos e
ingrese
el siguiente código, guardándolo como picnicTable.py :
def printPicnic (itemsDict, leftWidth, rightWidth):
print ('PICNIC ITEMS'.center (leftWidth + rightWidth,' - '))
para k, v en itemsDict.items ():
print (k.ljust (leftWidth,'. ' ) + str (v) .rjust (rightWidth))
134 Capítulo 6
picnicItems = {'sandwiches': 4, 'apples': 12, 'cups': 4, 'cookies': 8000}
printPicnic (picnicItems, 12, 5)
printPicnic (picnicItems, 20, 6)
En este programa, definimos un método printPicnic () que tomará
un diccionario de información y usará center (), ljust () y rjust () para mostrar
esa información en un formato de tabla perfectamente alineado.
El diccionario que pasaremos a printPicnic () es picnicItems. En
picnicItems, tenemos 4 sándwiches, 12 manzanas, 4 tazas y 8000 galletas.
Queremos organizar esta información en dos columnas, con el nombre
del artículo a la izquierda y la cantidad a la derecha.
Para hacer esto, decidimos qué ancho queremos que sean las columnas izquierda y derecha
. Junto con nuestro diccionario, pasaremos estos valores a printPicnic ().
printPicnic () toma un diccionario, un leftWidth para la columna izquierda de una
tabla y un rightWidth para la columna derecha. Imprime un título, PICNIC ITEMS,
centrado sobre la mesa. Luego, recorre el diccionario, imprimiendo
cada par clave-valor en una línea con la clave justificada a la izquierda y rellenada
por puntos, y el valor justificado a la derecha y rellenado por espacios.
Después de definir printPicnic (), definimos el diccionario picnicItems y
llamamos a printPicnic () dos veces, pasando diferentes anchos para las columnas de la
tabla izquierda y derecha
.
Cuando ejecuta este programa, los elementos de picnic se muestran dos veces.
La primera vez que la columna izquierda tiene 12 caracteres de ancho y la columna derecha
tiene 5 caracteres de ancho. La segunda vez tienen 20 y 6 caracteres de ancho,
respectivamente.
--- ARTÍCULOS DE PICNIC--
sándwiches ... 4
manzanas ...... 12
tazas ........ 4
galletas ..... 8000
------- ARTÍCULOS DE PICNIC ----- -
sándwiches .......... 4
manzanas .............. 12
tazas ................ 4
galletas. ............ 8000
El uso de rjust (), ljust () y center () le permite asegurarse de que las cadenas estén
perfectamente alineadas, incluso si no está seguro de cuántos caracteres tienen sus
cadenas.
Eliminación
de espacios en blanco con strip (), rstrip () y lstrip () A veces es posible que desee quitar los
espacios en blanco (espacio, tabulación
y nueva línea) del lado izquierdo, derecho o ambos lados de una cadena. El
método de cadena strip () devolverá una nueva cadena sin espacios en blanco
Cuerdas de manipulación 135
personajes al principio o al final. Los métodos lstrip () y rstrip ()
eliminarán los espacios en blanco de los extremos izquierdo y derecho, respectivamente.
Ingrese lo siguiente en el shell interactivo:
>>> spam = 'Hola Mundo'
>>> spam.strip ()
'Hola Mundo'
>>> spam.lstrip ()
'Hola Mundo'
>>> spam.rstrip ()
'Hola Mundo'
Opcionalmente, un argumento de cadena especificará qué caracteres en los extremos se
deben quitar. Ingrese lo siguiente en el shell interactivo:
>>> spam = 'SpamSpamBaconSpamEggsSpamSpam'
>>> spam.strip ('ampS')
'BaconSpamEggs'
Al pasar strip (), el argumento 'ampS' le indicará que elimine las ocurrencias de a, m,
p y S mayúscula desde los extremos de la cadena almacenada en el correo no deseado. El orden de
los
caracteres en la cadena pasada a strip () no importa: strip ('ampS') hará
lo mismo que strip ('mapS') o strip ('Spam').
Copiar y pegar cadenas con el módulo pyperclip
El módulo pyperclip tiene funciones copiar () y pegar () que pueden enviar
y recibir texto desde el portapapeles de su computadora. Enviar la salida de
su programa al portapapeles facilitará pegarlo en un correo electrónico,
procesador de textos u otro software.
Pyperclip no viene con Python. Para instalarlo, siga las instrucciones
para instalar módulos de terceros en el Apéndice A. Después de instalar el
módulo pyperclip, ingrese lo siguiente en el shell interactivo:
>>> import pyperclip
>>> pyperclip.copy ('¡Hola mundo!')
>>> pyperclip.paste ()
'¡Hola mundo!'
Por supuesto, si algo fuera de su programa cambia el
contenido del portapapeles , la función pegar () lo devolverá. Por ejemplo, si copio esta
oración en el portapapeles y luego llamo pegar (), se vería así:
>>> pyperclip.paste ()
'Por ejemplo, si copio esta oración en el portapapeles y luego llamo
pegar (), se vería así:'
136 Capítulo 6
Proyecto: Bloqueo de contraseña
Probablemente tenga cuentas en muchos sitios web diferentes. Es un mal hábito
usar la misma contraseña para cada uno de ellos porque si alguno de esos sitios tiene
una violación de seguridad, los piratas informáticos aprenderán la contraseña de todas sus otras
cuentas. Es mejor usar un software de administrador de contraseñas en su computadora que
use una contraseña maestra para desbloquear el administrador de contraseñas. Luego puede
copiar cualquier contraseña de la cuenta en el portapapeles y pegarla en el campo Contraseña del
sitio web
.
El programa administrador de contraseñas que creará en este ejemplo no es
seguro, pero ofrece una demostración básica de cómo funcionan dichos programas.
Paso 1: Diseño del programa y estructuras de datos
Desea poder ejecutar este programa con un argumento de línea de comando
que sea el nombre de la cuenta, por ejemplo, correo electrónico o blog . La
contraseña de esa cuenta se copiará en el portapapeles para que el usuario pueda pegarla en
un campo Contraseña. De esta manera, el usuario puede tener contraseñas largas y complicadas
sin tener que memorizarlas.
Abra una nueva ventana del editor de archivos y guarde el programa como pw.py. ¡Necesitas
comenzar el programa con un #! ( shebang ) (vea el Apéndice B) y
también debe escribir un comentario que describa brevemente el programa. Como desea
asociar el nombre de cada cuenta con su contraseña, puede almacenarlos como
EL PROYECTO DEL CAPÍTULO
Este es el primer "proyecto de capítulo" del libro. De aquí en adelante, cada capítulo tendrá
proyectos que demuestren los conceptos cubiertos en el capítulo. Los proyectos
están escritos en un estilo que lo lleva de una ventana de editor de archivos en blanco a un
programa
completo y funcional. Al igual que con los ejemplos de shell interactivos, no solo
lea las secciones del proyecto, ¡sígalo en su computadora!
ejecutando Py t hon SCr iP t S ou t SiDe of iDl e
Hasta ahora, ha estado ejecutando sus scripts Python utilizando el shell interactivo y
el editor de archivos en IDLE. Sin embargo, no querrá pasar por el inconveniente
de abrir IDLE y el script de Python cada vez que desee ejecutar un script.
Afortunadamente, hay atajos que puede configurar para facilitar la ejecución de scripts de Python
. Los pasos son ligeramente diferentes para Windows, OS X y Linux, pero
cada uno se describe en el Apéndice B. Diríjase al Apéndice B para aprender cómo ejecutar sus
scripts Python convenientemente y poder pasarles argumentos de línea de comando
. (No podrá pasar argumentos de línea de comandos a sus programas
usando IDLE).
Cuerdas de manipulación 137
cadenas en un diccionario. El diccionario será la estructura de datos que organiza
sus datos de cuenta y contraseña. Haga que su programa tenga el siguiente aspecto
:
#! python3
# pw.py: un programa de bloqueo de contraseña inseguro.
CONTRASEÑAS = {'correo electrónico': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6',
'blog': 'VmALvQyKAxiVH5G8v01if1MLZF3sdt',
'equipaje': '12345'}
Paso 2: manejar los argumentos de
la línea de comandos Los argumentos de la línea de comandos se almacenarán en la variable
sys.argv. (Consulte el
Apéndice B para obtener más información sobre cómo usar los argumentos de la línea de comandos
en
sus programas). El primer elemento de la lista sys.argv siempre debe ser una cadena que
contenga el nombre de archivo del programa ('pw.py'), y el segundo elemento debe
ser el primer argumento de línea de comando. Para este programa, este argumento es
el nombre de la cuenta cuya contraseña desea. Dado que el
argumento de la línea de comandos es obligatorio, muestra un mensaje de uso al usuario si olvida
agregarlo (es decir, si la lista sys.argv tiene menos de dos valores). Haga que
su programa tenga el siguiente aspecto:
#! python3
# pw.py: un programa de bloqueo de contraseña inseguro.
CONTRASEÑAS = {'correo electrónico': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6',
'blog': 'VmALvQyKAxiVH5G8v01if1MLZF3sdt',
'equipaje': '12345'}
import sys
if len (sys.argv) <2:
print ('Uso: python pw.py [cuenta] - copiar contraseña de la cuenta')
sys.exit ()
account = sys.argv [1] # primera línea de comando arg es el nombre de la cuenta
Paso 3: Copie la contraseña correcta
Ahora que el nombre de la cuenta se almacena como una cadena en la cuenta variable,
debe ver si existe en el diccionario CONTRASEÑAS como una clave. Si es así,
desea copiar el valor de la clave en el portapapeles usando pyperclip.copy (). (Dado
que está utilizando el módulo pyperclip, debe importarlo). Tenga en cuenta que en
realidad no necesita la variable de cuenta; puede usar sys.argv [1] en todas partes
donde se usa la cuenta en este programa. Pero una cuenta con nombre variable es mucho
más legible que algo críptico como sys.argv [1].
Haga que su programa tenga el siguiente aspecto:
#! python3
# pw.py: un programa de bloqueo de contraseña inseguro.
138 Capítulo 6
CONTRASEÑAS = {'correo electrónico': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6',
'blog': 'VmALvQyKAxiVH5G8v01if1MLZF3sdt',
'equipaje': '12345'}
import sys , pyperclip
if len (sys.argv) <2:
print ('Uso: py pw.py [cuenta] - copiar contraseña de la cuenta')
sys.exit ()
account = sys.argv [1] # primera línea de comando arg es el nombre de la cuenta
si cuenta en CONTRASEÑAS:
pyperclip.copy (CONTRASEÑAS [cuenta])
print ('Contraseña para' + cuenta + 'copiada al portapapeles.')
más:
print ('No hay una cuenta llamada' + cuenta)
Este nuevo código busca en el diccionario CONTRASEÑAS el nombre de la cuenta.
Si el nombre de la cuenta es una clave en el diccionario, obtenemos el valor correspondiente
a esa clave, lo copiamos al portapapeles e imprimimos un mensaje que dice que
copiamos el valor. De lo contrario, imprimimos un mensaje que dice que no hay una cuenta
con ese nombre.
Ese es el guión completo. Usando las instrucciones en el Apéndice B para
iniciar fácilmente los programas de línea de comandos, ahora tiene una forma rápida de copiar las
contraseñas de su cuenta en el portapapeles. Tendrá que modificar el
valor del diccionario CONTRASEÑAS en la fuente cada vez que desee actualizar el
programa con una nueva contraseña.
Por supuesto, probablemente no desee mantener todas sus contraseñas en un
lugar donde cualquiera pueda copiarlas fácilmente. Pero puede modificar este programa
y usarlo para copiar rápidamente texto normal al portapapeles. Supongamos que está
enviando varios correos electrónicos que tienen muchos de los mismos párrafos
comunes en común. Puede poner cada párrafo como un valor en el diccionario CONTRASEÑAS
(probablemente desee cambiar el nombre del diccionario en este punto), y
luego tendría una forma de seleccionar y copiar rápidamente una de las muchas piezas de
texto estándar
en el portapapeles.
En Windows, puede crear un archivo por lotes para ejecutar este programa con la
ventana Ejecutar win-r. (Para obtener más información sobre los archivos por lotes, consulte el
Apéndice B.) Escriba lo
siguiente en el editor de archivos y guarde el archivo como pw.bat en la carpeta C: \ Windows:
@ py.exe C: \ Python34 \ pw.py% *
@pause
Con este archivo por lotes creado, ejecutar el programa seguro con contraseña en
Windows es solo cuestión de presionar win-r y escribir pw <nombre de cuenta>.
Cuerdas de manipulación 139
Proyecto: Agregar viñetas al marcado wiki
Al editar un artículo de Wikipedia, puede crear una lista con viñetas colocando
cada elemento de la lista en su propia línea y colocando una estrella al frente. Pero supongamos que
tiene
una lista realmente grande a la que desea agregar viñetas. Podrías escribir
esas estrellas al comienzo de cada línea, una por una. O podría automatizar
esta tarea con un breve script de Python.
El script bulletPointAdder.py obtendrá el texto del portapapeles, agregará
una estrella y un espacio al comienzo de cada línea y luego pegará este nuevo
texto en el portapapeles. Por ejemplo, si copié el siguiente texto (para el
artículo de Wikipedia "Lista de listas de listas") en el portapapeles:
Listas de animales
Listas de vida del acuario
Listas de biólogos por autor abreviatura
Listas de cultivares
y luego ejecutó el programa bulletPointAdder.py , el portapapeles contendría
lo siguiente:
* Listas de animales
* Listas de vida del acuario
* Listas de biólogos por abreviatura del autor
* Listas de cultivares
Este texto con el prefijo de estrella está listo para ser pegado en un artículo de Wikipedia como una
lista con viñetas.
Paso 1: Copie y pegue desde el Portapapeles
Desea que el programa bulletPointAdder.py haga lo siguiente:
1. Pegue el texto del portapapeles
2. Haga algo
3. Copie el nuevo texto al portapapeles
El segundo paso es un poco complicado, pero los pasos 1 y 3 son bastante sencillos
: solo involucran las funciones pyperclip.copy () y pyperclip.paste ()
. Por ahora, solo escriba la parte del programa que cubre los pasos 1
y 3. Ingrese lo siguiente, guardando el programa como bulletPointAdder.py :
#! python3
# bulletPointAdder.py - Agrega viñetas de Wikipedia al número inicial
de cada línea de texto en el portapapeles.
importar
texto de pyperclip = pyperclip.paste ()
140 Capítulo 6
# TODO: separe las líneas y agregue estrellas.
pyperclip.copy (texto)
El comentario TODO es un recordatorio de que debes completar esta parte del
programa eventualmente. El siguiente paso es implementar esa parte
del programa.
Paso 2: separe las líneas de texto y agregue la estrella
La llamada a pyperclip.paste () devuelve todo el texto en el portapapeles como una gran
cadena. Si utilizamos el ejemplo "Lista de listas de listas", la cadena almacenada en el
texto se vería así:
'Listas de animales \ nListas de vida del acuario \ nListas de biólogos por abreviatura del autor
\ nListas de cultivares'
Los \ n caracteres de nueva línea en esta cadena hacen que se muestre con
varias líneas cuando se imprime o pega desde el portapapeles. Hay
muchas "líneas" en este valor de cadena. Desea agregar una estrella al comienzo de
cada una de estas líneas.
Puede escribir código que busque cada \ n carácter de nueva línea en la
cadena y luego agregue la estrella justo después de eso. Pero sería más fácil usar el
método split () para devolver una lista de cadenas, una para cada línea en la cadena original
, y luego agregar la estrella al frente de cada cadena en la lista.
Haga que su programa tenga el siguiente aspecto:
#! python3
# bulletPointAdder.py - Agrega viñetas de Wikipedia al número inicial
de cada línea de texto en el portapapeles.
importar
texto de pyperclip = pyperclip.paste ()
# Separar líneas y agregar estrellas.
lines = text.split ('\ n')
para i in range (len (lines)): # recorre todos los índices en la lista "lines"
lines [i] = '*' + lines [i] # add star to cada cadena en la lista de "líneas"
pyperclip.copy (texto)
Dividimos el texto a lo largo de sus nuevas líneas para obtener una lista en la que cada elemento es
una
línea del texto. Almacenamos la lista en líneas y luego recorremos los elementos en
líneas. Para cada línea, agregamos una estrella y un espacio al comienzo de la línea. Ahora
cada cadena en líneas comienza con una estrella.
Cuerdas de manipulación 141
Paso 3: Unir las líneas modificadas
La lista de líneas ahora contiene líneas modificadas que comienzan con estrellas. Pero
pyperclip.copy () espera un único valor de cadena, no una lista de valores de cadena.
Para hacer este valor de cadena única, pase líneas al método join () para obtener una
cadena única unida de las cadenas de la lista. Haga que su programa tenga el siguiente aspecto
:
#! python3
# bulletPointAdder.py - Agrega viñetas de Wikipedia al número inicial
de cada línea de texto en el portapapeles.
importar
texto de pyperclip = pyperclip.paste ()
# Separar líneas y agregar estrellas.
lines = text.split ('\ n')
para i en el rango (len (lines)): # recorre todos los índices para la lista de "líneas"
líneas [i] = '*' + líneas [i] # agrega estrella a cada cadena en el
texto de la lista "líneas" = '\ n'.join (líneas)
pyperclip.copy (texto)
Cuando se ejecuta este programa, reemplaza el texto en el portapapeles con
texto que tiene estrellas al comienzo de cada línea. Ahora el programa está completo y
puede intentar ejecutarlo con el texto copiado en el portapapeles.
Incluso si no necesita automatizar esta tarea específica, es posible que desee
automatizar algún otro tipo de manipulación de texto, como eliminar
espacios finales del final de las líneas o convertir texto en mayúsculas o minúsculas.
Sean cuales sean sus necesidades, puede usar el portapapeles para entrada y salida.
El
texto de resumen es una forma común de datos, y Python viene con muchos
métodos útiles de cadena para procesar el texto almacenado en valores de cadena. Hará uso de
métodos de indexación, segmentación y cadena en casi todos los programas de Python que
escriba.
Los programas que está escribiendo ahora no parecen demasiado sofisticados,
no tienen interfaces gráficas de usuario con imágenes y texto colorido. Hasta ahora,
está mostrando texto con print () y permitiendo que el usuario ingrese texto con input ().
Sin embargo, el usuario puede ingresar rápidamente grandes cantidades de texto a través del
portapapeles
. Esta capacidad proporciona una vía útil para escribir programas que manipulan
cantidades masivas de texto. Es posible que estos programas basados en texto no tengan
ventanas o gráficos llamativos, pero pueden hacer mucho trabajo útil rápidamente.
Otra forma de manipular grandes cantidades de texto es leer y escribir
archivos directamente desde el disco duro. Aprenderá cómo hacer esto con Python en
el próximo capítulo.
142 Capítulo 6
¡Eso casi cubre todos los conceptos básicos de la programación de Python!
Continuará aprendiendo nuevos conceptos en el resto de este libro,
pero ahora sabe lo suficiente como para comenzar a escribir algunos programas útiles que pueden
automatizar tareas. Es posible que no piense que tiene suficiente conocimiento de Python para
hacer cosas como descargar páginas web, actualizar hojas de cálculo o enviar
mensajes de texto , ¡pero ahí es donde entran los módulos de Python! Estos módulos, escritos
por otros programadores, proporcionan funciones que le facilitan
hacer todas estas cosas. Entonces, aprendamos cómo escribir programas reales para realizar tareas
automatizadas útiles
.
Preguntas de práctica
1. ¿Qué son los personajes de escape?
2. ¿Qué representan los caracteres de escape \ n y \ t?
3. ¿Cómo puedes poner un carácter \ barra diagonal inversa en una cadena?
4. El valor de la cadena "Howl's Moving Castle" es una cadena válida. Porque no lo es
¿Es un problema que el carácter de comillas simples en la palabra Howl's no se haya
escapado?
5. Si no desea poner \ n en su cadena, ¿cómo puede escribir una cadena
con líneas nuevas?
6. ¿Qué evalúan las siguientes expresiones?
• '¡Hola mundo!' [1] • '¡Hola mundo!' [0: 5] • '¡Hola mundo!' [: 5] • '¡Hola mundo!' [3:]

7. ¿Qué evalúan las siguientes expresiones?


• 'Hello'.upper () • ' Hello'.upper (). Isupper () • 'Hello'.upper (). Lower ()

8. ¿Qué evalúan las siguientes expresiones?


• 'Recuerda, recuerda, el cinco de noviembre.'. Split () • '-'. Join ('Solo puede haber uno.'. Split
())
9. ¿Qué métodos de cadena puedes usar para justificar a la derecha, justificar a la izquierda y
centrar
una cadena?
10. ¿Cómo puedes recortar los espacios en blanco desde el principio o el final de
una cadena?
Cuerdas de manipulación 143
Proyecto de
práctica Para practicar, escriba un programa que haga lo siguiente.
Impresora de tablas
Escriba una función llamada printTable () que tome una lista de listas de cadenas
y la muestre en una tabla bien organizada con cada columna justificada a la derecha.
Suponga que todas las listas internas contendrán el mismo número de cadenas.
Por ejemplo, el valor podría verse así:
tableData = [['' manzanas ',' naranjas ',' cerezas ',' plátano '],
[' Alice ',' Bob ',' Carol ',' David '],
[' perros ',' gatos ',' alces ', 'ganso']]
Su función printTable () imprimiría lo siguiente:
manzanas Alice perros
naranjas Bob gatos
cerezas Carol alce
plátano David ganso
Sugerencia: Su código primero tendrá que encontrar la cadena más larga en cada una de las
listas internas para que toda la columna pueda ser lo suficientemente ancha como para caber en
todas las cadenas.
Puede almacenar el ancho máximo de cada columna como una lista de enteros. La función
printTable () puede comenzar con colWidths = [0] * len (tableData), que
creará una lista que contiene el mismo número de valores 0 que el número
de listas internas en tableData. De esa manera, colWidths [0] puede almacenar el ancho de la
cadena más larga en tableData [0], colWidths [1] puede almacenar el ancho de la
cadena más larga en tableData [1], y así sucesivamente. A continuación, puede encontrar el valor
más grande en
la lista colWidths para averiguar qué ancho entero pasar al método de cadena rjust ()
.
Parte II
A utom A tingt AS k S
7
P A tternm A t C hingwith
expresiones regulares
Puede estar familiarizado con la búsqueda de texto
presionando ctrl-F y escribiendo las palabras
estas buscando. Las expresiones regulares van un
paso más allá: te permiten especificar un patrón
de texto a buscar. Es posible que no conozca el
número de teléfono exacto de una empresa , pero si vive en los Estados Unidos
o Canadá, sabrá que serán tres dígitos, seguidos de
un guión y luego cuatro dígitos más (y, opcionalmente, un código de área de tres dígitos
en el comienzo). Así es como usted, como humano, conoce un número de teléfono cuando lo
ve: 415-555-1234 es un número de teléfono, pero 4,155,551,234 no lo es.
Las expresiones regulares son útiles, pero no muchos no programadores las
conocen a pesar de que la mayoría de los editores de texto y
procesadores de texto modernos , como Microsoft Word u OpenOffice, tienen
funciones de buscar y buscar y reemplazar que pueden buscar en base a expresiones
regulares. Las expresiones regulares
ahorran mucho tiempo, no solo para los usuarios de software sino también para
148 Capítulo 7
programadores De hecho, el escritor tecnológico Cory Doctorow argumenta que incluso antes de
enseñar programación, deberíamos enseñar expresiones regulares:
“ Saber [expresiones regulares] puede significar la diferencia entre
resolver un problema en 3 pasos y resolverlo en 3,000 pasos. Cuando
eres un nerd, olvidas que los problemas que resuelves con un par de
pulsaciones de teclas pueden llevar días de trabajo tedioso y propenso a errores para otras personas
”. 1
En este capítulo, comenzará escribiendo un programa para encontrar patrones de texto
sin usar expresiones regulares y luego verá cómo usar expresiones regulares
para hacer que el código sea mucho menos hinchado. Le mostraré coincidencias básicas con
expresiones regulares y luego pasaré a algunas características más potentes,
como la sustitución de cadenas y la creación de sus propias clases de caracteres. Finalmente,
al final del capítulo, escribirá un programa que puede extraer automáticamente
números de teléfono y direcciones de correo electrónico de un bloque de texto.
encontrar patrones de texto sin expresiones regulares
Digamos que desea encontrar un número de teléfono en una cadena. Conoces el patrón:
tres números, un guión, tres números, un guión y cuatro números.
Aquí hay un ejemplo: 415-555-4242.
Usemos una función llamada isPhoneNumber () para verificar si una cadena
coincide con este patrón, devolviendo Verdadero o Falso. Abra una nueva ventana del editor de
archivos
e ingrese el siguiente código; luego guarde el archivo como isPhoneNumber.py:
def isPhoneNumber (texto):
u if len (texto)! = 12:
devuelve False
para i en el rango (0, 3):
v si no es texto [i] .isdecimal ():
return False
w if text [3]! = '-':
devuelve False
para i en el rango (4, 7):
x si no es texto [i] .isdecimal ():
return False
y if text [7]! = '-':
devuelve False
para i en el rango (8, 12):
z si no es texto [i] .isdecimal ():
return False
{return True
print ('415-555-4242 es un número de teléfono:')
print (isPhoneNumber ('415-555-4242'))
print ('Moshi moshi es un número de teléfono:')
print (isPhoneNumber ('Moshi moshi'))
1. Cory Doctorow, "Esto es lo que las TIC realmente deberían enseñar a los niños: cómo hacer
expresiones regulares" ,
Guardian , 4 de diciembre de 2012, http://www.theguardian.com/technology/2012/dec/04/ict-teach-
niños
-expresiones-regulares /.
Coincidencia de patrones con expresiones regulares 149
Cuando se ejecuta este programa, el resultado se ve así:
415-555-4242 es un número de teléfono:
verdadero
Moshi moshi es un número de teléfono:
falso
La función isPhoneNumber () tiene un código que realiza varias verificaciones para ver
si la cadena de texto es un número de teléfono válido. Si alguna de estas comprobaciones
falla, la función devuelve False. Primero, el código verifica que la cadena tenga
exactamente 12 caracteres u. Luego verifica que el código de área (es decir, los primeros
tres caracteres del texto) consista solo en caracteres numéricos v. El resto
de la función verifica que la cadena siga el patrón de un número de teléfono
: el número debe tener el primer guión después del código de área w, tres
caracteres numéricos más x, luego otro guión y, y finalmente cuatro
números más z. Si la ejecución del programa logra superar todas las comprobaciones,
devuelve True {.
Llamar a isPhoneNumber () con el argumento '415-555-4242' devolverá
True. Llamar a isPhoneNumber () con 'Moshi moshi' devolverá False; la primera
prueba falla porque 'Moshi moshi' no tiene 12 caracteres de longitud.
Tendría que agregar aún más código para encontrar este patrón de texto en una
cadena más grande. Reemplace las últimas cuatro llamadas a la función print ()
en isPhoneNumber.py con lo siguiente:
mensaje = 'Llámame al 415-555-1011 mañana. 415-555-9999 es mi oficina.
para i en rango (len (mensaje)):
u fragmento = mensaje [i: i + 12]
v si isPhoneNumber (fragmento):
print ('Número de teléfono encontrado:' + fragmento)
print ('Listo')
Cuando se ejecuta este programa, la salida se verá así:
Número de teléfono encontrado: 415-555-1011
Número de teléfono encontrado: 415-555-9999
Hecho
En cada iteración del ciclo for,
se asigna un nuevo fragmento de 12 caracteres del mensaje a la variable u. Por ejemplo, en la
primera iteración,
i es 0 y se asigna un mensaje al fragmento [0:12] (es decir, la cadena 'Llámame a las 4').
En la siguiente iteración, i es 1, y al fragmento se le asigna el mensaje [1:13] (la cadena
'all me at 41').
Pasa el fragmento a isPhoneNumber () para ver si coincide con el patrón de número de teléfono
v, y si es así, imprime el fragmento.
Continúe recorriendo el mensaje y, eventualmente, los 12 caracteres
en pedazos serán un número de teléfono. El bucle recorre toda la cadena,
prueba cada pieza de 12 caracteres e imprime cualquier fragmento que encuentre que satisfaga
isPhoneNumber (). Una vez que terminamos de leer el mensaje, imprimimos Listo.
150 Capítulo 7
Si bien la cadena en el mensaje es corta en este ejemplo, podría tener millones
de caracteres y el programa aún se ejecutaría en menos de un segundo. Un
programa similar que encuentre números de teléfono usando expresiones regulares
también se ejecutaría en menos de un segundo, pero las expresiones regulares hacen que sea más
rápido
escribir estos programas.
encontrar patrones de texto con expresiones regulares
El programa anterior de búsqueda de números de teléfono funciona, pero usa mucho
código para hacer algo limitado: la función isPhoneNumber () tiene 17 líneas pero
solo puede encontrar un patrón de números de teléfono. ¿Qué pasa con un número de teléfono
formateado como 415.555.4242 o (415) 555-4242? ¿Qué pasa si el número de teléfono
tiene una extensión, como 415-555-4242 x99? La función isPhoneNumber ()
no podría validarlos. Podría agregar aún más código para estos
patrones adicionales, pero hay una manera más fácil.
Las expresiones regulares, llamadas expresiones regulares para abreviar, son descripciones de un
patrón de texto. Por ejemplo, a \ d en una expresión regular representa un carácter de dígito
, es decir, cualquier número único de 0 a 9. La expresión regular \ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d
es utilizado
por Python para coincidir con el mismo texto que la función isPhoneNumber () anterior:
una cadena de tres números, un guión, tres números más, otro guión
y cuatro números. Cualquier otra cadena no coincidiría con la \ d \ d \ d- \ d \ d \ d- \ d \ d
\ d \ d regex.
Pero las expresiones regulares pueden ser mucho más sofisticadas. Por ejemplo,
agregar un 3 entre llaves ({3}) después de un patrón es como decir: "Haga coincidir este
patrón tres veces". Entonces, la expresión regular un poco más corta \ d {3} - \ d {3} - \ d {4 }
también
coincide con el formato de número de teléfono correcto.
Crear objetos
regex Todas las funciones regex en Python están en el módulo re. Ingrese lo siguiente
en el shell interactivo para importar este módulo:
>>> importar re
note La mayoría de los ejemplos que siguen en este capítulo requerirán el módulo re, así que
recuerde
importarlo al comienzo de cualquier script que escriba o cada vez que reinicie IDLE.
De lo contrario, obtendrá un NameError: el nombre 're' no está definido como mensaje de error.
Pasar un valor de cadena que representa su expresión regular a re.compile ()
devuelve un objeto de patrón Regex (o simplemente, un objeto Regex).
Para crear un objeto Regex que coincida con el patrón del número de teléfono, ingrese
lo siguiente en el shell interactivo. (Recuerde que \ d significa "un
carácter de dígito " y \ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d es la expresión regular para el
patrón de número de teléfono correcto).
Coincidencia de patrones con expresiones regulares 151
>>> phoneNumRegex = re.compile (r '\ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d')
Ahora la variable phoneNumRegex contiene un objeto Regex.
Coincidencia de objetos
Regex El método search () de un objeto Regex busca en la cadena que se le pasa para encontrar
coincidencias con la expresión regular. El método search () no devolverá None si el patrón regex
no se encuentra en la cadena. Si se encuentra el patrón , el método search ()
devuelve un objeto Match. Los objetos de coincidencia tienen un método group () que devolverá
el texto coincidente real de la cadena buscada. (Explicaré los grupos en
breve.) Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> phoneNumRegex = re.compile (r '\ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d')
>>> mo = phoneNumRegex.search ('Mi número es 415- 555-4242. ')
>>> print (' Número de teléfono encontrado: '+ mo.group ())
Número de teléfono encontrado: 415-555-4242
El nombre de la variable mo es solo un nombre genérico para usar en objetos Match.
Este ejemplo puede parecer complicado al principio, pero es mucho más corto que
el programa isPhoneNumber.py anterior y hace lo mismo.
Aquí, pasamos nuestro patrón deseado a re.compile () y almacenamos el
objeto Regex resultante en phoneNumRegex. Luego llamamos a search () en phoneNumRegex y
pasamos
search () la cadena que queremos buscar para una coincidencia. El resultado de la búsqueda
se almacena en la variable mo. En este ejemplo, sabemos que nuestro patrón
se encontrará en la cadena, por lo que sabemos que se devolverá un objeto Match.
Sabiendo que mo contiene un objeto Match y no el valor nulo None, podemos
llamar a group () en mo para devolver la coincidencia. Escribir mo.group () dentro de
nuestra declaración de impresión
muestra la coincidencia completa, 415-555-4242.
PA SSing r Aw S tringS to r e.ComPil e ()
Recuerde que los caracteres de escape en Python usan la barra invertida (\). El
valor de cadena '\ n' representa un solo carácter de nueva línea, no una barra invertida seguida de
una
n minúscula. Debe ingresar el carácter de escape \\ para imprimir una
barra diagonal inversa . Entonces '\\ n' es la cadena que representa una barra invertida seguida de
una
n minúscula . Sin embargo, al poner una r antes de la primera cita del valor de la cadena,
puede marcar la cadena como una cadena sin procesar, que no escapa a los caracteres.
Dado que las expresiones regulares frecuentemente usan barras invertidas en ellas, es conveniente
pasar cadenas sin procesar a la función re.compile () en lugar de escribir
barras invertidas adicionales . Escribir r '\ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d' es mucho más fácil que
escribir
'\\ d \\ d \\ d - \\ d \\ d \\ d - \\ d \\ d \\ d \\ d '.
152 Capítulo 7
Revisión de la coincidencia de expresiones regulares
Si bien hay varios pasos para usar expresiones regulares en Python, cada
paso es bastante simple.
1. Importe el módulo regex con import re.
2. Cree un objeto Regex con la función re.compile (). (Recuerde usar un
cadena sin procesar.)
3. Pase la cadena que desea buscar en el método search () del objeto Regex.
Esto devuelve un objeto Match.
4. Llame al método group () del objeto Match para devolver una cadena del valor real
texto coincidente
note Si bien lo aliento a que ingrese el código de ejemplo en el shell interactivo, también debe
utilizar probadores de expresiones regulares basados en la web, que pueden mostrarle exactamente
cómo una expresión regular coincide con un texto que ingresa. Recomiendo el probador en http: //
regexpal.com/ .
más Coincidencia de patrones con expresiones regulares
Ahora que conoce los pasos básicos para crear y encontrar
objetos de expresión regular con Python, está listo para probar algunas de sus capacidades más
potentes
de coincidencia de patrones.
Agrupación con paréntesis
Digamos que desea separar el código de área del resto del número de teléfono.
Agregar paréntesis creará grupos en la expresión regular: (\ d \ d \ d) - (\ d \ d \ d- \ d \ d \ d \ d).
Luego puede usar el método de coincidencia de objetos group () para obtener el texto coincidente
de un solo grupo.
El primer conjunto de paréntesis en una cadena de expresiones regulares será el grupo 1. El
segundo conjunto será el grupo 2. Al pasar el entero 1 o 2 al
método de objeto de coincidencia group () , puede tomar diferentes partes del texto
coincidente. Pasar 0
o nada al método group () devolverá todo el texto coincidente. Ingrese
lo siguiente en el shell interactivo:
>>> phoneNumRegex = re.compile (r '(\ d \ d \ d) - (\ d \ d \ d- \ d \ d \ d \ d)')
>>> mo = phoneNumRegex.search ('Mi número es 415-555-4242. ')
>>> mo.group (1)
' 415 '
>>> mo.group (2)
' 555-4242 '
>>> mo.group (0)
' 415-555- 4242 '
>>> mo.group ()
' 415-555-4242 '
Coincidencia de patrones con expresiones regulares 153
Si desea recuperar todos los grupos a la vez, use el método groups ()
: observe la forma plural del nombre.
>>> mo.groups ()
('415', '555-4242')
>>> areaCode, mainNumber = mo.groups ()
>>> print (areaCode)
415
>>> print (mainNumber)
555-4242
Como mo.groups () devuelve una tupla de valores múltiples, puede usar el
truco de asignación múltiple para asignar cada valor a una variable separada, como en
la línea areaCode, mainNumber = mo.groups () anterior.
Los paréntesis tienen un significado especial en las expresiones regulares, pero ¿qué
haces si necesitas un paréntesis en tu texto? Por ejemplo, tal vez
los números de teléfono con los que intenta hacer coincidir tengan el código de área configurado
entre paréntesis
. En este caso, debe escapar de los caracteres (y) con una barra diagonal inversa
. Ingrese lo siguiente en el shell interactivo:
>>> phoneNumRegex = re.compile (r '(\ (\ d \ d \ d \)) (\ d \ d \ d- \ d \ d \ d \ d)')
>>> mo = phoneNumRegex.search ('Mi número de teléfono es (415) 555-4242.')
>>> mo.group (1)
'(415)'
>>> mo.group (2)
'555-4242'
Los caracteres de escape \ (y \) en la cadena sin formato pasada a re.compile ()
coincidirán con los caracteres de paréntesis reales.
Coincidencia de varios grupos con la tubería
El | El personaje se llama tubería . Puede usarlo en cualquier lugar que desee para coincidir con
una
de las muchas expresiones. Por ejemplo, la expresión regular r'Batman | Tina Fey '
coincidirá con' Batman 'o' Tina Fey '.
Cuando aparecen tanto Batman como Tina Fey en la cadena buscada, la primera
aparición de texto coincidente se devolverá como el objeto Match. Ingrese lo
siguiente en el shell interactivo:
>>> heroRegex = re.compile (r'Batman | Tina Fey ')
>>> mo1 = heroRegex.search (' Batman y Tina Fey. ')
>>> mo1.group ()
' Batman '
>>> mo2 = heroRegex.search ('Tina Fey y Batman.')
>>> mo2.group ()
'Tina Fey'
nota Puede encontrar todas las ocurrencias coincidentes con el método findall () que se describe
en
“El método findall ()” en la página 157.
154 Capítulo 7
También puede usar la tubería para que coincida con uno de varios patrones como parte de
su expresión regular. Por ejemplo, supongamos que desea hacer coincidir cualquiera de las cadenas
'Batman',
'Batmobile', 'Batcopter' y 'Batbat'. Dado que todas estas cadenas comienzan con Bat,
sería bueno si pudiera especificar ese prefijo solo una vez. Esto se puede hacer
con paréntesis. Ingrese lo siguiente en el shell interactivo:
>>> batRegex = re.compile (r'Bat (man | mobile | copter | bat) ')
>>> mo = batRegex.search (' Batmobile perdió una rueda ')
>>> mo.group ()
' Batmobile '
>>> mo.group (1)
'móvil'
La llamada al método mo.group () devuelve el texto coincidente completo 'Batmobile',
mientras que mo.group (1) devuelve solo la parte del texto coincidente dentro del primer
grupo de paréntesis, 'mobile'. Al utilizar el carácter de la tubería y los análisis de agrupación
, puede especificar varios patrones alternativos con los que desea que coincida su expresión regular
.
Si necesita hacer coincidir un carácter de tubería real, escape con una barra diagonal inversa
, como \ |.
Emparejamiento opcional con el signo de interrogación
A veces hay un patrón que desea emparejar solo opcionalmente. Es
decir, la expresión regular debería encontrar una coincidencia independientemente de si ese
fragmento de texto está allí o no.
Los ? el carácter marca el grupo que lo precede como una parte opcional del
patrón. Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> batRegex = re.compile (r'Bat (wo)? man ')
>>> mo1 = batRegex.search (' Las aventuras de Batman ')
>>> mo1.group ()
' Batman '
>>> mo2 = batRegex.search ('Las aventuras de Batwoman')
>>> mo2.group ()
'Batwoman'
El (wo)? parte de la expresión regular significa que el patrón wo es
un grupo opcional. La expresión regular coincidirá con el texto que tiene cero instancias o
una instancia de wo . Es por eso que la expresión regular coincide con 'Batwoman' y
'Batman'.
Utilizando el ejemplo de número de teléfono anterior, puede hacer que la expresión regular busque
números de teléfono que tengan o no un código de área. Ingrese lo siguiente
en el shell interactivo:
>>> phoneRegex = re.compile (r '(\ d \ d \ d -)? \ d \ d \ d- \ d \ d \ d \ d')
>>> mo1 = phoneRegex.search ('Mi número es 415-555-4242 ')
>>> mo1.group ()
' 415-555-4242 '
Coincidencia de patrones con expresiones regulares 155
>>> mo2 = phoneRegex.search ('Mi número es 555-4242')
>>> mo2.group ()
'555-4242'
Puedes pensar en el? como diciendo: "Haga coincidir cero o uno del grupo anterior a
este signo de interrogación".
Si necesita hacer coincidir un carácter de signo de interrogación real, escape con \ ?.
Hacer coincidir cero o más con la estrella
El * (llamado estrella o asterisco ) significa "hacer coincidir cero o más": el grupo
que precede a la estrella puede aparecer cualquier número de veces en el texto. Puede estar
completamente ausente o repetirse una y otra vez. Veamos el ejemplo de Batman
nuevamente.
>>> batRegex = re.compile (r'Bat (wo) * man ')
>>> mo1 = batRegex.search (' Las aventuras de Batman ')
>>> mo1.group ()
' Batman '
>>> mo2 = batRegex.search ('Las aventuras de Batwoman')
>>> mo2.group ()
'Batwoman'
>>> mo3 = batRegex.search ('Las aventuras de Batwowowowoman')
>>> mo3.group ()
'Batwowowowoman'
Para 'Batman', la parte (wo) * de la expresión regular coincide con cero instancias de wo
en la cadena; para 'Batwoman', el (wo) * coincide con una instancia de wo; y para
'Batwowowowoman', (wo) * coincide con cuatro instancias de wo.
Si necesita hacer coincidir un carácter de estrella real, prefije la estrella en la
expresión regular con una barra invertida, \ *.
Hacer coincidir uno o más con el signo más
Mientras * significa "hacer coincidir cero o más", el + (o más ) significa "hacer coincidir uno o
más". A diferencia de la estrella, que no requiere que su grupo aparezca en la
cadena coincidente, el grupo antes de un plus debe aparecer al menos una vez . No es
opcional Ingrese lo siguiente en el shell interactivo y compárelo
con las expresiones regulares de estrellas en la sección anterior:
>>> batRegex = re.compile (r'Bat (wo) + man ')
>>> mo1 = batRegex.search (' Las aventuras de Batwoman ')
>>> mo1.group ()
' Batwoman '
>>> mo2 = batRegex.search ('Las aventuras de Batwowowowoman')
>>> mo2.group ()
'Batwowowowoman'
156 Capítulo 7
>>> mo3 = batRegex.search ('Las aventuras de Batman')
>>> mo3 == Ninguno
verdadero
La expresión regular Bat (wo) + man no coincidirá con la cadena 'The Adventures of
Batman' porque el signo más requiere al menos un wo.
Si necesita hacer coincidir un carácter de signo más real, prefije el signo más
con una barra invertida para escapar: \ +.
Coincidencia de repeticiones específicas con corchetes
Si tiene un grupo que desea repetir un número específico de veces, siga
el grupo en su expresión regular con un número entre llaves. Por ejemplo,
la expresión regular (Ha) {3} coincidirá con la cadena 'HaHaHa', pero no coincidirá con 'HaHa',
ya que este último solo tiene dos repeticiones del grupo (Ha).
En lugar de un número, puede especificar un rango escribiendo un mínimo,
una coma y un máximo entre los corchetes. Por ejemplo, la
expresión regular (Ha) {3,5} coincidirá con 'HaHaHa', 'HaHaHaHa' y 'HaHaHaHaHa'.
También puede omitir el primer o segundo número entre llaves
para dejar el mínimo o el máximo sin límites. Por ejemplo, (Ha) {3,}
coincidirá con tres o más instancias del grupo (Ha), mientras que (Ha) {, 5} coincidirá con
cero a cinco instancias. Los corchetes pueden ayudar a que sus expresiones regulares sean
más cortas. Estas dos expresiones regulares coinciden con patrones idénticos:
(Ha) {3}
(Ha) (Ha) (Ha)
Y estas dos expresiones regulares también coinciden con patrones idénticos:
(Ha) {3,5}
((Ha) (Ha) (Ha)) | ((Ha) (Ha) (Ha) (Ha)) | ((Ha) (Ha) (Ha) (Ha) (Ha ))
Ingrese lo siguiente en el shell interactivo:
>>> haRegex = re.compile (r '(Ha) {3}')
>>> mo1 = haRegex.search ('HaHaHa')
>>> mo1.group ()
'HaHaHa'
>>> mo2 = haRegex.search ('Ha')
>>> mo2 == Ninguno
Verdadero
Aquí, (Ha) {3} coincide con 'HaHaHa' pero no con 'Ha'. Como no coincide con 'Ha',
search () devuelve None.
correspondencia codiciosa y no codiciosa
Dado que (Ha) {3,5} puede coincidir con tres, cuatro o cinco instancias de Ha en la cadena
'HaHaHaHaHa', puede preguntarse por qué la llamada del objeto Match al grupo () en el
Coincidencia de patrones con expresiones regulares 157
El ejemplo anterior de soporte rizado devuelve 'HaHaHaHaHa' en lugar de las
posibilidades más cortas . Después de todo, 'HaHaHa' y 'HaHaHaHa' también son coincidencias
válidas de la
expresión regular (Ha) {3,5}.
Las expresiones regulares de Python son codiciosas por defecto, lo que significa que en
situaciones ambiguas coincidirán con la cadena más larga posible. La versión no
codiciosa de los corchetes, que coincide con la cadena más corta
posible, tiene el corchete de cierre seguido de un signo de interrogación.
Ingrese lo siguiente en el shell interactivo y observe la diferencia
entre las formas codiciosas y no codiciosas de las llaves que
buscan la misma cadena:
>>> greedyHaRegex = re.compile (r '(Ha) {3,5}')
>>> mo1 = greedyHaRegex.search ('HaHaHaHaHa')
>>> mo1.group ()
'HaHaHaHaHa'
>>> nongreedyHaRegex = re.compile (r '(Ha) {3,5}?')
>>> mo2 = nongreedyHaRegex.search ('HaHaHaHaHa')
>>> mo2.group ()
'HaHaHa'
Tenga en cuenta que el signo de interrogación puede tener dos significados en expresiones
regulares
: declarar una coincidencia que no sea de mala educación o marcar un grupo opcional. Estos
significados no tienen ninguna relación.
el método findall ()
Además del método search (), los objetos Regex también tienen un
método findall () . Mientras que search () devolverá un objeto Match del primer texto coincidente
en la cadena buscada, el método findall () devolverá las cadenas de cada coincidencia en la cadena
buscada. Para ver cómo search () devuelve un objeto Match solo en la primera instancia de texto
coincidente, ingrese lo siguiente en el shell interactivo:

>>> phoneNumRegex = re.compile (r '\ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d')


>>> mo = phoneNumRegex.search ('Cell: 415-555 -9999 Trabajo: 212-555-0000 ')
>>> mo.group ()
' 415-555-9999 '
Por otro lado, findall () no devolverá un objeto Match sino una lista de
cadenas , siempre que no haya grupos en la expresión regular . Cada cadena de
la lista es una parte del texto buscado que coincide con la expresión regular.
Ingrese lo siguiente en el shell interactivo:
>>> phoneNumRegex = re.compile (r '\ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d') # no tiene grupos
>>> phoneNumRegex.findall ('Cell: 415 -555-9999 Trabajo: 212-555-0000 ')
[' 415-555-9999 ',' 212-555-0000 ']
Si hay son grupos en la expresión regular, a continuación, findall () devuelve
una lista de tuplas. Cada tupla representa una coincidencia encontrada, y sus elementos son los
158 Capítulo 7
cadenas coincidentes para cada grupo en la expresión regular. Para ver findall () en acción, ingrese
lo siguiente en el shell interactivo (observe que la expresión regular que se
está compilando ahora tiene grupos entre paréntesis):
>>> phoneNumRegex = re.compile (r '(\ d \ d \ d) - (\ d \ d \ d) - (\ d \ d \ d \ d)') # tiene grupos
>>> phoneNumRegex.findall ('Celda: 415-555-9999 Trabajo: 212-555-0000')
[('415', '555', '1122'), ('212', '555', '0000')]
Para resumir lo que devuelve el método findall (), recuerde lo
siguiente:
1. Cuando se llama en una expresión regular sin grupos, como \ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d,
el método findall () devuelve una lista de coincidencias de cadenas, como ['415-555-
9999', '212-555-0000'].
2. Cuando se llama a una expresión regular que tiene grupos, como (\ d \ d \ d) - (\ d \ d \ d) - (\ d \
d \ d \ d), el método findall () devuelve una lista de tuplas de cadenas (una cadena
para cada grupo), como [('415', '555', '1122'), ('212', '555', '0000')].
Clases de caracteres
En el ejemplo anterior de expresiones regulares de números de teléfono, aprendió que \ d podría
significar cualquier dígito numérico. Es decir, \ d es la abreviatura de la
expresión regular (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9). Hay muchas clases de caracteres abreviados ,
como se
muestra en la Tabla 7-1.
Tabla 7-1: Códigos abreviados para clases de caracteres comunes Clase de
caracteres abreviados Representa
\ d Cualquier dígito numérico del 0 al 9.
\ D Cualquier carácter que no sea un dígito numérico del 0 al 9.
\ w Cualquier letra, dígito numérico o subrayar el carácter
(Piense en esto como caracteres coincidentes de "palabras").
\ W Cualquier carácter que no sea una letra, un dígito numérico o el
subrayar el carácter
\ s Cualquier espacio, tabulación o carácter de nueva línea. (Piense en esto como
caracteres de "espacio" coincidentes.)
\ S Cualquier carácter que no sea un espacio, tabulación o nueva línea.
Las clases de caracteres son buenas para acortar expresiones regulares. La
clase de carácter [0-5] coincidirá solo con los números del 0 al 5; esto es mucho más corto
que escribir (0 | 1 | 2 | 3 | 4 | 5).
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> xmasRegex = re.compile (r '\ d + \ s \ w +')
>>> xmasRegex.findall ('12 bateristas, 11 gaiteros, 10 señores, 9 damas, 8 criadas, 7
cisnes, 6 gansos, 5 anillos , 4 pájaros, 3 gallinas, 2 palomas, 1 perdiz ')
['12 tambores', '11 gaiteros ', '10 señores', '9 damas', '8 mucamas', '7 cisnes', '6
gansos', '5 anillos', '4 pájaros', '3 gallinas', '2 palomas', '1 perdiz']
Coincidencia de patrones con expresiones regulares 159
La expresión regular \ d + \ s \ w + coincidirá con el texto que tiene uno o más
dígitos numéricos (\ d +), seguido de un carácter de espacio en blanco (\ s), seguido de
una o más letras / dígitos / caracteres de subrayado (\ w +). El método findall ()
devuelve todas las cadenas coincidentes del patrón regex en una lista.
crear sus propias clases de caracteres
Hay momentos en los que desea hacer coincidir un conjunto de caracteres, pero las
clases de caracteres abreviados (\ d, \ w, \ s, etc.) son demasiado amplias. Puedes definir
tu propia clase de personaje usando corchetes. Por ejemplo, la
clase de caracteres [aeiouAEIOU] coincidirá con cualquier vocal, tanto en minúsculas como en
mayúsculas. Ingrese
lo siguiente en el shell interactivo:
>>> vocalelRegex = re.compile (r '[aeiouAEIOU]')
>>> vocalelRegex.findall ('RoboCop come comida para bebés. ALIMENTOS PARA BEBÉ')
['o', 'o', 'o', 'e' , 'a', 'a', 'o', 'o', 'A', 'O', 'O']
También puede incluir rangos de letras o números usando un guión.
Por ejemplo, la clase de caracteres [a-zA-Z0-9] coincidirá con todas las letras minúsculas,
mayúsculas y números.
Tenga en cuenta que dentro de los corchetes, los
símbolos de expresión regular normales no se interpretan como tales. Esto significa que no necesita
escapar de
los caracteres., *,? O () con una barra invertida anterior. Por ejemplo, la
clase de caracteres [0-5.] Coincidirá con los dígitos del 0 al 5 y un punto. No necesita
escribirlo como [0-5 \.].
Al colocar un carácter de intercalación (^) justo después del
paréntesis de apertura de la clase de caracteres , puede crear una clase de caracteres negativa . Una
clase de caracteres negativa
coincidirá con todos los caracteres que no están en la clase de caracteres. Por ejemplo,
ingrese lo siguiente en el shell interactivo:
>>> consonantRegex = re.compile (r '[^ aeiouAEIOU]')
>>> consonantRegex.findall ('RoboCop come comida para bebés. ALIMENTOS PARA
BEBÉ')
['R', 'b', 'c', 'p ',' ',' t ',' s ',' ',' b ',' b ',' y ',' ',' f ',' d ','. ','
',' B ', 'B', 'Y', '', 'F', 'D', '.']
Ahora, en lugar de hacer coincidir cada vocal, estamos haciendo coincidir cada personaje
que no sea vocal.
los caracteres de intercalación y signo de dólar
También puede usar el símbolo de intercalación (^) al comienzo de una expresión regular para
indicar que
debe haber una coincidencia al comienzo del texto buscado. Del mismo modo, puede
poner un signo de dólar ($) al final de la expresión regular para indicar que la cadena
debe terminar con este patrón de expresión regular. Y puede usar ^ y $ juntos para indicar que toda
la cadena debe coincidir con la expresión regular, es decir, no es suficiente que se
haga una coincidencia en algún subconjunto de la cadena.

160 Capítulo 7
Por ejemplo, la cadena de expresión regular r '^ Hello' coincide con las cadenas
que comienzan con 'Hello'. Ingrese lo siguiente en el shell interactivo:
>>> beginWithHello = re.compile (r '^ Hola')
>>> comienzaWithHello.search ('¡Hola mundo!')
<_sre.SRE_Match objeto; span = (0, 5), match = 'Hola'>
>>> comienza con Hola.search ('Dijo hola') == Ninguno
Verdadero
La cadena de expresión regular r '\ d $' coincide con las cadenas que terminan con un
carácter numérico del 0 al 9. Ingrese lo siguiente en el shell interactivo:
>>> endsWithNumber = re.compile (r '\ d $')
>>> endsWithNumber.search ('Su número es 42')
<_sre.SRE_Match objeto; span = (16, 17), match = '2'>
>>> endsWithNumber.search ('Su número es cuarenta y dos') == Ninguno
Verdadero
La cadena de expresión regular r '^ \ d + $' coincide con cadenas que comienzan
y terminan con uno o más caracteres numéricos. Ingrese lo siguiente en el
shell interactivo:
>>> wholeStringIsNum = re.compile (r '^ \ d + $')
>>> wholeStringIsNum.search ('1234567890')
<_sre.SRE_Match objeto; span = (0, 10), match = '1234567890'>
>>> wholeStringIsNum.search ('12345xyz67890') == Ninguno
verdadero
>>> wholeStringIsNum.search ('12 34567890 ') == Ninguno
verdadero
Las últimas dos llamadas a search () en el ejemplo de shell interactivo anterior
demuestran cómo la cadena completa debe coincidir con la expresión regular si se usan ^ y $.
Siempre confundo los significados de estos dos símbolos, por lo que utilizo el mnemotécnico
“Las zanahorias cuestan dólares” para recordarme que el símbolo de intercalación es lo primero y
el signo de dólar lo último.
el carácter comodín
. (o punto ) en una expresión regular se llama comodín y
coincidirá con cualquier carácter excepto una nueva línea. Por ejemplo, ingrese lo siguiente
en el shell interactivo:
>>> atRegex = re.compile (r'.at ')
>>> atRegex.findall (' El gato del sombrero se sentó en la alfombra plana ')
[' cat ',' hat ',' sat ',' lat ',' mat ']
Coincidencia de patrones con expresiones regulares 161
Recuerde que el carácter de punto coincidirá con un solo carácter, por lo
que la coincidencia para el texto plano en el ejemplo anterior coincidió solo con lat.
Para hacer coincidir un punto real, escapa del punto con una barra invertida: \ ..
Combinando todo con Dot-Star
A veces querrás combinar todo y cualquier cosa. Por ejemplo,
supongamos que desea hacer coincidir la cadena 'Nombre:', seguido de todos y cada uno de los
textos,
seguido de 'Apellido:' y luego seguido de todo. Puede
usar la estrella de puntos (. *) Para representar ese "cualquier cosa". Recuerde que el
carácter de punto significa "cualquier carácter único excepto la nueva línea", y el
carácter de estrella significa "cero o más del carácter anterior".
Ingrese lo siguiente en el shell interactivo:
>>> nameRegex = re.compile (r'Primer nombre: (. *) Apellido: (. *) ')
>>> mo = nameRegex.search (' Nombre: Al Apellido: Sweigart ')
>>> mo.group (1)
'Al'
>>> mo.group (2)
'Sweigart'
El dot-star usa el modo codicioso : siempre intentará hacer coincidir la mayor cantidad de texto
posible. Para hacer coincidir todos y cada uno de los textos de una manera no codiciosa , use el
punto, la estrella
y el signo de interrogación (. *?). Al igual que con los corchetes, el signo de interrogación le dice a
Python que coincida de una manera no codiciosa.
Ingrese lo siguiente en el shell interactivo para ver la diferencia
entre las versiones codiciosas y no codiciosas:
>>> nongreedyRegex = re.compile (r '<. *?>')
>>> mo = nongreedyRegex.search ('<Para servir al hombre> para la cena.>')
>>> mo.group ()
'<A servir al hombre> '
>>> greedyRegex = re.compile (r '<. *>')
>>> mo = greedyRegex.search ('<Para servir al hombre> para la cena.>')
>>> mo.group ()
'<Para servir hombre> para cenar.> '
Ambas expresiones regulares se traducen aproximadamente como "Emparejar un corchete angular
de apertura,
seguido de cualquier cosa, seguido de un corchete angular de cierre". Pero la cadena
'<To serve man> for dinner.>' Tiene dos posibles coincidencias para el
corchete angular de cierre . En la versión sin expresiones de la expresión regular, Python coincide
con la
cadena más corta posible: '<To serve man>'. En la versión codiciosa, Python coincide con la
cadena más larga posible: '<To serve man> for dinner.>'.
162 Capítulo 7
Coincidencia de nuevas líneas con el carácter de
punto La estrella de puntos coincidirá con todo excepto una nueva línea. Al pasar re.DOTALL
como
el segundo argumento para re.compile (), puede hacer que el carácter de punto coincida con
todos los caracteres, incluido el carácter de nueva línea.
Ingrese lo siguiente en el shell interactivo:
>>> noNewlineRegex = re.compile ('. *')
>>> noNewlineRegex.search ('Servir a la confianza pública. \ nProteger a los inocentes.
\ nDetener la ley.'). group ()
'Servir a la confianza pública'.
>>> newlineRegex = re.compile ('. *', re.DOTALL)
>>> newlineRegex.search ('Servir a la confianza pública. \ nProteger a los inocentes.
\ nDetener la ley.'). group ()
'Servir a confianza pública. \ nProtege a los inocentes. \ nDetiene la ley.
El regex noNewlineRegex, que no tenía re.DOTALL pasado a la
llamada re.compile () que lo creó, coincidirá con todo solo hasta el primer
carácter de nueva línea, mientras que newlineRegex, que sí tuvo re.DOTALL pasado a
re.compile ( ), coincide con todo. Esta es la razón por la cual la llamada newlineRegex.search ()
coincide con la cadena completa, incluidos sus caracteres de nueva línea.
revisión de los símbolos regex
Este capítulo abarcó mucha notación, así que aquí hay una revisión rápida de lo
que aprendió:

• El? coincide con cero o uno del grupo anterior. • El * coincide con cero o más del grupo
anterior. • El + coincide con uno o más del grupo anterior. • {n} coincide exactamente con n del
grupo anterior. • La {n,} coincide n o más del grupo anterior. • {, m} coincide con 0 am del grupo
anterior. • {n, m} coincide con al menos ny como máximo m del grupo anterior. • {n, m}? o *? o
+? realiza un partido no codicioso del grupo anterior. • ^ spam significa que la cadena debe
comenzar con spam . • spam $ significa que la cadena debe terminar con spam . • El. coincide con
cualquier carácter, excepto los caracteres de nueva línea. • \ d, \ w y \ s coinciden con un dígito,
palabra o carácter de espacio, respectivamente. • \ D, \ W y \ S coinciden con cualquier cosa,
excepto un dígito, palabra o carácter de espacio,
respectivamente.
• [abc] coincide con cualquier carácter entre los corchetes (como a , b o c ). • [^ abc] coincide con
cualquier carácter que no esté entre corchetes.

Coincidencia de patrones con expresiones regulares 163


coincidencia entre mayúsculas y minúsculas
Normalmente, las expresiones regulares hacen coincidir el texto con la carcasa exacta que
especifique.
Por ejemplo, las siguientes expresiones regulares coinciden con cadenas completamente diferentes:
>>> regex1 = re.compile ('RoboCop')
>>> regex2 = re.compile ('ROBOCOP')
>>> regex3 = re.compile ('robOcop')
>>> regex4 = re.compile ('RobocOp ')
Pero a veces solo le importa emparejar las letras sin preocuparse
de si son mayúsculas o minúsculas. Para hacer que su expresión regular no distinga entre
mayúsculas y minúsculas
, puede pasar re.IGNORECASE o re.I como segundo argumento para re.compile ().
Ingrese lo siguiente en el shell interactivo:
>>> robocop = re.compile (r'robocop ', re.I)
>>> robocop.search (' RoboCop es parte hombre, parte máquina, todo policía '). grupo ()
' RoboCop '
>>> robocop.search ('ROBOCOP protege a los inocentes'). group ()
'ROBOCOP'
>>> robocop.search ('Al, ¿por qué tu libro de programación habla tanto de robocop?'). group
()
'robocop'
Sustitución de cadenas con el método sub ()
Las expresiones regulares no solo pueden encontrar patrones de texto, sino que también pueden
sustituir
texto nuevo en lugar de esos patrones. El método sub () para objetos Regex recibe
dos argumentos. El primer argumento es una cadena para reemplazar cualquier coincidencia.
El segundo es la cadena para la expresión regular. El método sub () devuelve
una cadena con las sustituciones aplicadas.
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> namesRegex = re.compile (r'Agent \ w + ')
>>> namesRegex.sub (' CENSURADO ',' El Agente Alice le dio los documentos secretos al
Agente Bob. ')
' CENSURADO le dio los documentos secretos a CENSURADO '.
A veces es posible que necesite usar el texto coincidente como parte de la
sustitución. En el primer argumento de sub (), puede escribir \ 1, \ 2, \ 3, y así sucesivamente
, para significar "Ingrese el texto del grupo 1, 2, 3, y así sucesivamente, en la sustitución".
Por ejemplo, supongamos que desea censurar los nombres de los agentes secretos
mostrando solo las primeras letras de sus nombres. Para hacer esto, puede usar el
Agente regex (\ w) \ w * y pasar r '\ 1 ****' como primer argumento para sub (). El \ 1
en esa cadena será reemplazado por cualquier texto que coincida con el grupo 1
, es decir, el grupo (\ w) de la expresión regular.
164 Capítulo 7
>>> agentNamesRegex = re.compile (r'Agent (\ w) \ w * ')
>>> agentNamesRegex.sub (r' \ 1 **** ',' el agente Alice le dijo al agente Carol que el agente
Eve conocía al agente Bob era un agente doble. ')
A **** le dijo a C **** que E **** sabía que B **** era un agente doble'.
administrar expresiones
regulares complejas Las expresiones regulares están bien si el patrón de texto que necesita para
coincidir es simple.
Pero hacer coincidir patrones de texto complicados puede requerir
expresiones regulares largas y complicadas . Puede mitigar esto diciéndole a la función re.compile
()
que ignore los espacios en blanco y los comentarios dentro de la cadena de expresión regular.
Este "modo detallado" se puede habilitar pasando la variable re.VERBOSE como
segundo argumento para re.compile ().
Ahora, en lugar de una expresión regular difícil de leer como esta:
phoneRegex = re.compile (r '((\ d {3} | \ (\ d {3} \))? (\ s | - | \.)? \ d {3} (\ s | - | \. ) \ d {4}
(\ s * (ext | x | ext.) \ s * \ d {2,5})?) ')
puede extender la expresión regular en varias líneas con comentarios
como este:
phoneRegex = re.compile (r '' '(
(\ d {3} | \ (\ d {3} \))? # código de área
(\ s | - | \.)? # separator
\ d {3} # primeros 3 dígitos
(\ s | - | \.) # separador
\ d {4} # últimos 4 dígitos
(\ s * (ext | x | ext.) \ s * \ d {2,5})? # extensión
) '' ', re.VERBOSE)
Observe cómo el ejemplo anterior usa la sintaxis de comillas triples ('' ') para
crear una cadena multilínea para que pueda extender la definición de expresión regular
en muchas líneas, haciéndola mucho más legible.
Las reglas de comentario dentro de la cadena de expresión regular son las mismas que
las del código Python normal:
se ignora el símbolo # y todo lo que se encuentra al final de la línea. Además, los espacios
adicionales dentro de la cadena multilínea para la
expresión regular no se consideran parte del patrón de texto que debe coincidir.
Esto le permite organizar la expresión regular para que sea más fácil de leer.
combinando re.ignorecASe, re.dotAll y re.VerBoSe
¿Qué sucede si desea usar re.VERBOSE para escribir comentarios en su
expresión regular pero también quiere usar re.IGNORECASE para ignorar las
mayúsculas? Desafortunadamente,
la función re.compile () toma solo un valor único como segundo argumento. Puede
sortear esta limitación combinando las variables re.IGNORECASE, re.DOTALL y
re.VERBOSE utilizando el carácter de barra vertical (|), que en este contexto se
conoce como bit a bit u operador.
Coincidencia de patrones con expresiones regulares 165
Entonces, si desea una expresión regular que no distinga entre mayúsculas y minúsculas e incluya
nuevas líneas para que coincida con el carácter de punto, formaría su llamada re.compile () de
esta manera:
>>> someRegexValue = re.compile ('foo', re.IGNORECASE | re.DOTALL)
Las tres opciones para el segundo argumento se verán así:
>>> someRegexValue = re.compile ('foo', re.IGNORECASE | re.DOTALL | re.VERBOSE)
Esta sintaxis es un poco anticuada y se origina en las primeras versiones
de Python. Los detalles de los operadores bit a bit están más allá del alcance de este
libro, pero consulte los recursos en http://nostarch.com/automatestuff/ para
obtener más información. También puede pasar otras opciones para el segundo argumento;
son poco comunes, pero también puede leer más sobre ellos en los recursos.
Proyecto: Extractor de número de teléfono y dirección de correo electrónico
Digamos que tiene la aburrida tarea de encontrar cada número de teléfono y
dirección de correo electrónico en una página web o documento largo. Si te desplazas manualmente
por
la página, podrías terminar buscando mucho tiempo. Pero si tuviera un programa
que pudiera buscar números de teléfono y
direcciones de correo electrónico en el portapapeles , simplemente podría presionar ctrl-A para
seleccionar todo el texto, presionar
ctrl-c para copiarlo en el portapapeles y luego ejecutar su programa Podría
reemplazar el texto en el portapapeles con solo los números de teléfono y las direcciones de correo
electrónico que encuentre.
Cada vez que aborda un nuevo proyecto, puede ser tentador sumergirse directamente
en el código escrito. Pero la mayoría de las veces, es mejor dar un paso atrás y
considerar el panorama general. Recomiendo primero elaborar un plan de alto nivel
para lo que su programa necesita hacer. No piense en el código real
todavía; puede preocuparse por eso más tarde. En este momento, se adhieren a trazos amplios.
Por ejemplo, su extractor de teléfono y dirección de correo electrónico deberá hacer
lo siguiente:

• Sacar el texto del portapapeles. • Encuentra todos los números de teléfono y direcciones de correo
electrónico en el texto. • Péguelos en el portapapeles.

Ahora puede comenzar a pensar cómo podría funcionar esto en el código. El


código deberá hacer lo siguiente:

• Use el módulo pyperclip para copiar y pegar cadenas. • Cree dos expresiones regulares, una para
hacer coincidir los números de teléfono y la otra para

Direcciones de correo electrónico coincidentes.


• Encuentra todas las coincidencias, no solo la primera coincidencia, de ambas expresiones
regulares. • Formatee cuidadosamente las cadenas coincidentes en una sola cadena para
pegar. • Mostrar algún tipo de mensaje si no se encontraron coincidencias en el texto.

166 Capítulo 7
Esta lista es como una hoja de ruta para el proyecto. A medida que escribe el código,
puede concentrarse en cada uno de estos pasos por separado. Cada paso es bastante manejable
y se expresa en términos de cosas que ya sabes cómo hacer en Python.
Paso 1: Cree una expresión regular para números de teléfono
Primero, debe crear una expresión regular para buscar números de teléfono.
Cree un nuevo archivo, ingrese lo siguiente y guárdelo como phoneAndEmail.py:
#! python3
# phoneAndEmail.py - Encuentra números de teléfono y direcciones de correo electrónico en el
portapapeles.
importar pyperclip, re
phoneRegex = re.compile (r '' '(
(\ d {3} | \ (\ d {3} \))? # código de área
(\ s | - | \.)? # separador
(\ d {3} ) # primeros 3 dígitos
(\ s | - | \.) # separador
(\ d {4}) # últimos 4 dígitos
(\ s * (ext | x | ext.) \ s * (\ d {2,5} ))? # extensión
) '' ', re.VERBOSE)
# TODO: Crea una expresión regular de correo electrónico.
# TODO: Encuentra coincidencias en el texto del portapapeles.
# TODO: copia los resultados al portapapeles.
Los comentarios TODO son solo un esqueleto para el programa. Serán
reemplazados a medida que escriba el código real.
El número de teléfono comienza con un código de área opcional , por lo que al
grupo de códigos de área le sigue un signo de interrogación. Como el código de área puede tener
solo
tres dígitos (es decir, \ d {3}) o tres dígitos entre paréntesis (es decir, \ (\ d {3} \)),
debe tener una tubería que una esas partes. Puede agregar el
código de área # de comentario regex a esta parte de la cadena multilínea para ayudarlo a recordar
qué
(\ d {3} | \ (\ d {3} \))? Se supone que coincide.
El carácter separador del número de teléfono puede ser un espacio (\ s), guión (-)
o punto (.), Por lo que estas partes también deben estar unidas por tuberías. Las siguientes
partes de la expresión regular son sencillas: tres dígitos, seguidos
de otro separador, seguido de cuatro dígitos. La última parte es una
extensión opcional compuesta por cualquier número de espacios seguidos de ext, x o ext.,
Seguidos de dos a cinco dígitos.
Paso 2: Cree una expresión regular para direcciones de correo electrónico
También necesitará una expresión regular que pueda coincidir con las direcciones de correo
electrónico.
Haga que su programa tenga el siguiente aspecto:
#! python3
# phoneAndEmail.py - Encuentra números de teléfono y direcciones de correo electrónico en el
portapapeles.
Coincidencia de patrones con expresiones regulares 167
importar pyperclip, re
phoneRegex = re.compile (r '' '(
- snip -
# Crear regex de correo electrónico.
emailRegex = re.compile (r '' '(
u [a-zA-Z0-9 ._% + -] + # nombre de usuario
v @ # @ símbolo
w [a-zA-Z0-9 .-] + # nombre de dominio
(\. [a-zA-Z] {2,4}) # punto-algo
) '' ', re.VERBOSE)
# TODO: Encuentra coincidencias en el texto del portapapeles.
# TODO: copia los resultados al portapapeles.
La parte del nombre de usuario de la dirección de correo electrónico u es uno o más caracteres
que pueden ser cualquiera de los siguientes: letras minúsculas y mayúsculas, números,
un punto, un guión bajo, un signo de porcentaje, un signo más o un guión. Puede poner
todo esto en una clase de caracteres: [a-zA-Z0-9 ._% + -].
El dominio y el nombre de usuario están separados por un símbolo @ v. El
nombre de dominio w tiene una clase de caracteres ligeramente menos permisiva con solo
letras, números, puntos y guiones: [a-zA-Z0-9.-]. Y el último será
la parte "punto-com" (técnicamente conocida como el dominio de nivel superior ),
que realmente puede
ser punto-cualquier cosa. Esto es entre dos y cuatro caracteres.
El formato para las direcciones de correo electrónico tiene muchas reglas extrañas. Esta
expresión regular no coincidirá con todas las direcciones de correo electrónico válidas posibles,
pero coincidirá con
casi cualquier dirección de correo electrónico típica que encuentre.
Paso 3: Buscar todas las coincidencias en el texto del portapapeles
Ahora que ha especificado las expresiones regulares para los números de teléfono
y las direcciones de correo electrónico, puede dejar que el módulo de Python haga el trabajo duro
de
encontrar todas las coincidencias en el portapapeles. La función pyperclip.paste ()
obtendrá un valor de cadena del texto en el portapapeles y el método regex findall ()
devolverá una lista de tuplas.
Haga que su programa tenga el siguiente aspecto:
#! python3
# phoneAndEmail.py - Encuentra números de teléfono y direcciones de correo electrónico en el
portapapeles.
importar pyperclip, re
phoneRegex = re.compile (r '' '(
- snip -
# Encuentra coincidencias en el texto del portapapeles.
texto = str (pyperclip.paste ())
168 Capítulo 7
u coincide = []
v para grupos en phoneRegex.findall (texto):
phoneNum = '-'. join ([grupos [1], grupos [3], grupos [5]])
if groups [8]! = '':
phoneNum + = 'x' + groups [8]
coincide con .append ( número de teléfono)
w para grupos en emailRegex.findall (texto):
coincidencias.append (grupos [0])
# TODO: copia los resultados al portapapeles.
Hay una tupla para cada coincidencia, y cada tupla contiene cadenas para
cada grupo en la expresión regular. Recuerde que el grupo 0 coincide con la
expresión regular completa, por lo que el grupo en el índice 0 de la tupla es el que le
interesa.
Como puede ver en u, almacenará las coincidencias en una variable de lista denominada
coincidencias. Comienza como una lista vacía y un par de bucles. Para las
direcciones de correo electrónico, agregue el grupo 0 de cada coincidencia w. Para los
números de teléfono coincidentes , no solo desea agregar el grupo 0. Si bien el
programa detecta números de teléfono en varios formatos, desea que el número de teléfono
adjunto esté en un único formato estándar. La variable phoneNum contiene una cadena construida a
partir de los grupos 1, 3, 5 y 8 del texto coincidente v. (Estos grupos son el código de área, los
primeros tres dígitos, los últimos cuatro dígitos y la extensión).

Paso 4: unir las coincidencias en una cadena para el portapapeles


Ahora que tiene las direcciones de correo electrónico y los números de teléfono como una lista de
cadenas
en las coincidencias, desea ponerlas en el portapapeles. La función pyperclip.copy ()
toma solo un valor de cadena único, no una lista de cadenas, por lo que llama al método join ()
en las coincidencias.
Para que sea más fácil ver que el programa está funcionando, imprimamos cualquier
coincidencia que encuentre en el terminal. Y si no se encontraron números de teléfono o direcciones
de correo
electrónico, el programa debería decirle esto al usuario.
Haga que su programa tenga el siguiente aspecto:
#! python3
# phoneAndEmail.py - Encuentra números de teléfono y direcciones de correo electrónico en el
portapapeles.
- recorte -
para grupos en emailRegex.findall (texto):
coincidencias.append (grupos [0])
# Copie los resultados al portapapeles.
if len (coincidencias)> 0:
pyperclip.copy ('\ n'.join (coincidencias))
print (' Copiado al portapapeles: ')
print (' \ n'.join (coincidencias))
else:
print ('Sin teléfono números o direcciones de correo electrónico encontrados. ')
Coincidencia de patrones con expresiones regulares 169
Ejecución del programa
Por ejemplo, abra su navegador web en la página de contacto de No Starch Press
en http://www.nostarch.com/contactus.htm , presione ctrl-A para seleccionar todo el texto de
la página y presione ctrl- c para copiarlo en el portapapeles. Cuando ejecutas este
programa, la salida se verá así:
Copiado al portapapeles:
800-420-7240
415-863-9900
415-863-9950
info@nostarch.com
media@nostarch.com
academic@nostarch.com
help@nostarch.com
Ideas para programas similares La
identificación de patrones de texto (y posiblemente su sustitución por el método sub ()
) tiene muchas aplicaciones potenciales diferentes.

• Busque las URL de sitios web que comienzan con http: // o https: // . • Limpie las fechas en
diferentes formatos de fecha (como 14/03/2015, 14/03/2015,

y 2015/3/14) al reemplazarlos con fechas en un único formato estándar.


• Eliminar información confidencial como el Seguro Social o la tarjeta de crédito
números.
• Encuentra errores tipográficos comunes como espacios múltiples entre palabras, acciden-

Cuenta palabras repetidas accidentalmente o múltiples signos de exclamación al


final de las oraciones. Esos son molestos!
Resumen
Si bien una computadora puede buscar texto rápidamente, se le debe decir exactamente qué
buscar. Las expresiones regulares le permiten especificar los patrones precisos de los
caracteres que está buscando. De hecho, algunas aplicaciones de procesamiento de texto y
hojas de cálculo proporcionan funciones de búsqueda y reemplazo que le permiten buscar
usando expresiones regulares.
El módulo re que viene con Python le permite compilar objetos Regex.
Estos valores tienen varios métodos: buscar () para encontrar una sola coincidencia, findall ()
para encontrar todas las instancias coincidentes y sub () para hacer una sustitución de buscar y
reemplazar
texto.
La sintaxis de las expresiones regulares tiene un poco más de lo que se describe en
este capítulo. Puede encontrar más información en la documentación oficial de Python
en http://docs.python.org/3/library/re.html . El sitio web tutorial http: // www
.regular-expressions.info / también es un recurso útil.
Ahora que tiene experiencia en la manipulación y combinación de cadenas, es
hora de profundizar en cómo leer y escribir en archivos en el disco duro de su computadora
.
170 Capítulo 7
Preguntas de práctica
1. ¿Cuál es la función que crea los objetos Regex?
2. ¿Por qué las cadenas sin formato se usan a menudo al crear objetos Regex?
3. ¿Qué devuelve el método search ()?
4. ¿Cómo se obtienen las cadenas reales que coinciden con el patrón de una coincidencia?
¿objeto?
5. En la expresión regular creada a partir de r '(\ d \ d \ d) - (\ d \ d \ d- \ d \ d \ d \ d)', ¿qué hace
cubierta del grupo 0? ¿Grupo 1? ¿Grupo 2?
6. Los paréntesis y los puntos tienen significados específicos en la expresión regular.
sintaxis. ¿Cómo especificaría que desea que una expresión regular coincida con paréntesis y
caracteres de punto reales
?
7. El método findall () devuelve una lista de cadenas o una lista de tuplas de
cadenas. ¿Qué lo hace regresar uno u otro?
8. ¿Qué significa el | ¿Qué significan los caracteres en expresiones regulares?
9. ¿Qué dos cosas hace el? ¿Qué significan los caracteres en expresiones regulares?
10. ¿Cuál es la diferencia entre los caracteres + y * en regular
expresiones?
11. ¿Cuál es la diferencia entre {3} y {3,5} en expresiones regulares?
12. ¿Qué significan las clases de caracteres abreviados \ d, \ w y \ s en forma regular
expresiones?
13. ¿Qué significan las clases de caracteres abreviados \ D, \ W y \ S en forma regular
expresiones?
14. ¿Cómo se hace una expresión regular que no distingue entre mayúsculas y minúsculas?
15. ¿Qué hace el. personaje normalmente coincide? ¿Qué coincide si
re.DOTALL se pasa como el segundo argumento para re.compile ()?
16. ¿Cuál es la diferencia entre. * Y. * ??
17. ¿Cuál es la sintaxis de la clase de caracteres para que coincida con todos los números y
minúsculas?
¿letras?
18. Si numRegex = re.compile (r '\ d +'), ¿qué será numRegex.sub ('X', '12 bateristas,
¿11 gaiteros, cinco anillos, 3 gallinas) regresan?
19. ¿Qué significa pasar re.VERBOSE como segundo argumento para re.compile ()
te permite hacer?
20. ¿Cómo escribirías una expresión regular que coincida con un número con comas para
cada tres dígitos? Debe coincidir con lo siguiente:
• '42' • '1,234' • '6,368,745' pero no con lo siguiente: • '12, 34,567 '(que solo tiene dos dígitos entre
las comas) • ' 1234 '(que carece de comas)

Coincidencia de patrones con expresiones regulares 171


21. ¿Cómo escribirías una expresión regular que coincida con el nombre completo de alguien
cuyo apellido es Nakamoto? Puede suponer que el primer nombre que
viene antes siempre será una palabra que comience con una letra mayúscula.
La expresión regular debe coincidir con lo siguiente:
• 'Satoshi Nakamoto' • 'Alice Nakamoto' • 'RoboCop Nakamoto' pero no lo siguiente: • 'satoshi
Nakamoto' (donde el nombre no está en mayúscula) • 'Sr. Nakamoto '(donde la palabra anterior
tiene un carácter que no es letra) • ' Nakamoto '(que no tiene nombre) • ' Satoshi nakamoto '(donde
Nakamoto no está en mayúscula)

22. ¿Cómo escribirías una expresión regular que coincida con una oración donde la primera
palabra sea Alice , Bob o Carol ; la segunda palabra es comer , mascotas o
tirar ; la tercera palabra es manzanas , gatos o pelotas de béisbol ; y la oración termina
con un punto? Esta expresión regular no debe ser sensible a mayúsculas y minúsculas. Debe
coincidir con lo
siguiente:
• 'Alice come manzanas'. • 'Bob acaricia gatos'. • "Carol tira pelotas de béisbol". • 'Alicia tira
manzanas'. • 'BOB COME GATOS'. pero no lo siguiente: • 'RoboCop come manzanas'. • 'ALICE
LANZA FÚTBOL'. • "Carol come 7 gatos".
Proyectos de
práctica Para practicar, escriba programas para realizar las siguientes tareas.
Detección de contraseña
segura Escriba una función que use expresiones regulares para asegurarse de que la
cadena de contraseña que se pasa es segura . Una contraseña segura se define como una que tiene al
menos ocho caracteres de longitud, contiene caracteres en mayúsculas y minúsculas
y tiene al menos un dígito. Es posible que necesite probar la cadena contra múltiples
patrones de expresiones regulares para validar su fuerza.
Versión de expresión regular de strip ()
Escribe una función que toma una cadena y hace lo mismo que el
método de cadena strip () . Si no se pasa ningún otro argumento que no sea la cadena para
eliminar, los caracteres de espacio en blanco se eliminarán desde el principio y el
final de la cadena. De lo contrario, los caracteres especificados en el segundo argumento
de la función se eliminarán de la cadena.
8
r e ADing A y D
archivo de escritura S
Las variables son una buena manera de almacenar datos mientras
su programa se está ejecutando, pero si lo desea
sus datos persistirán incluso después de que su programa
haya finalizado, debe guardarlos en un archivo. Tú
puede pensar en el contenido de un archivo como un valor de cadena único,
potencialmente de un tamaño de gigabytes. En este capítulo,
aprenderá a usar Python para crear, leer y guardar archivos
en el disco duro.
archivos y rutas de archivo
Un archivo tiene dos propiedades clave: un nombre de archivo (generalmente escrito como una
palabra) y
una ruta. La ruta especifica la ubicación de un archivo en la computadora. Por ejemplo,
hay un archivo en mi computadora portátil con Windows 7 con el nombre de archivo projects.docx
en la
ruta C: \ Users \ asweigart \ Documents. La parte del nombre del archivo después del último
período se denomina extensión del archivo y le indica el tipo de archivo. project.docx es un
documento de Word, y los usuarios , asweigart y documentos se refieren a carpetas (también
174 Capítulo 8
llamados directorios). Las carpetas pueden contener archivos
y otras carpetas. Por ejemplo, project.docx está en la carpeta Documentos , que está dentro
de la carpeta asweigart , que está dentro de la carpeta Usuarios . La Figura 8-1 muestra
esta organización de carpetas .

La parte C: \ de la ruta es la carpeta raíz , que contiene todas las demás carpetas. En Windows, la
carpeta raíz se denomina C: \ y también se llama la unidad C: . En OS X y Linux, la carpeta raíz
es / . En este libro, usaré la carpeta raíz estilo Windows , C: \ . Si está ingresando los ejemplos de
shell interactivos en OS X o Linux, ingrese / en su lugar.

Los volúmenes adicionales , como una unidad de DVD o una unidad de memoria USB, aparecerán
de manera
diferente en los diferentes sistemas operativos. En Windows, aparecen como nuevas
unidades raíz con letras, como D: \ o E: \ . En OS X, aparecen como carpetas nuevas
en la carpeta / Volumes . En Linux, aparecen como carpetas nuevas en la carpeta
/ mnt ("montaje"). También tenga en cuenta que si bien los nombres de carpetas y nombres de
archivos no distinguen entre
mayúsculas y minúsculas en Windows y OS X, sí distinguen entre mayúsculas y minúsculas en
Linux.
Barra diagonal inversa en Windows y barra diagonal directa en OS X y Linux
En Windows, las rutas se escriben utilizando barras diagonales inversas ( \ ) como separador
entre los nombres de las carpetas. OS X y Linux, sin embargo, utilizan la barra diagonal ( / )
como separador de ruta. Si desea que sus programas funcionen en todos los sistemas operativos
, tendrá que escribir sus scripts de Python para manejar ambos casos.
Afortunadamente, esto es simple de hacer con la función os.path.join (). Si le
pasa los valores de cadena de archivos individuales y nombres de carpetas en su ruta,
os.path.join () devolverá una cadena con una ruta de archivo utilizando los separadores de ruta
correctos
. Ingrese lo siguiente en el shell interactivo:
>>> import os
>>> os.path.join ('usr', 'bin', 'spam')
'usr \\ bin \\ spam'
Estoy ejecutando estos ejemplos de shell interactivos en Windows, por lo que os.path
.join ('usr', 'bin', 'spam') devolvió 'usr \\ bin \\ spam'. (Observe que las
barras diagonales inversas se duplican porque cada barra diagonal inversa debe escapar por otro
carácter de barra diagonal inversa). Si hubiera llamado a esta función en OS X o Linux, la
cadena habría sido 'usr / bin / spam'.
La función os.path.join () es útil si necesita crear cadenas para
nombres de archivo. Estas cadenas se pasarán a varias de las funciones relacionadas con archivos
introducidas en este capítulo. Por ejemplo, el siguiente ejemplo une
nombres de una lista de nombres de archivo al final del nombre de una carpeta:
>>> myFiles = ['accounts.txt', 'details.csv', 'invite.docx']
>>> para el nombre de archivo en myFiles:
Los usuarios
C:\
asweigart
Documentos
proyecto.docx
Figura 8-1: Un archivo en una jerarquía de
carpetas
Lectura y escritura de archivos 175
print (os.path.join ('C: \\ Users \\ asweigart', nombre de archivo))
C: \ Users \ asweigart \ accounts.txt
C: \ Users \ asweigart \ details.csv
C: \ Users \ asweigart \ invite .docx
El directorio de trabajo actual
Cada programa que se ejecuta en su computadora tiene un directorio de trabajo actual ,
o cwd. Se
supone que cualquier nombre de archivo o ruta que no comience con la carpeta raíz se encuentra en
el directorio de trabajo actual. Puede obtener el
directorio de trabajo actual como un valor de cadena con la función os.getcwd () y cambiarlo
con os.chdir (). Ingrese lo siguiente en el shell interactivo:
>>> import os
>>> os.getcwd ()
'C: \\ Python34'
>>> os.chdir ('C: \\ Windows \\ System32')
>>> os.getcwd ()
'C: \ \ Windows \\ System32 '
Aquí, el directorio de trabajo actual se establece en C: \ Python34, por lo que el
nombre del archivo project.docx se refiere a C: \ Python34 \ project.docx . Cuando cambiamos el
directorio de trabajo actual a C: \ Windows , project.docx se interpreta como C: \
Windows \ project.docx .
Python mostrará un error si intenta cambiar a un directorio que
no existe.
>>> os.chdir ('C: \\ ThisFolderDoesNotExist')
Traceback (última llamada más reciente):
Archivo "<pyshell # 18>", línea 1, en <module>
os.chdir ('C: \\ ThisFolderDoesNotExist' )
FileNotFoundError: [WinError 2] El sistema no puede encontrar el archivo especificado:
'C: \\ ThisFolderDoesNotExist'
note Aunque carpeta es el nombre más moderno para directorio, tenga en cuenta que el directorio
de trabajo actual (o simplemente el directorio de trabajo ) es el término estándar, no la carpeta
de trabajo actual .
Rutas absolutas frente a rutas relativas
Hay dos formas de especificar una ruta de archivo.

• Una ruta absoluta , que siempre comienza con la carpeta raíz • Una ruta relativa , que es relativa
al funcionamiento actual del programa

directorio
También están las carpetas punto (.) Y punto-punto (..). Estas no son
carpetas reales sino nombres especiales que se pueden usar en una ruta. Un solo punto ("punto")
para el nombre de una carpeta es la abreviatura de "este directorio". Dos puntos ("punto-punto")
significa "la carpeta principal".
176 Capítulo 8
La Figura 8-2 es un ejemplo de algunas carpetas y archivos. Cuando el
directorio de trabajo actual está configurado en C: \ bacon , las rutas relativas para las otras
carpetas
y archivos se configuran como están en la figura.
tocino
C:\
efervescencia
spam.txt
spam.txt
huevos
spam.txt
spam.txt
Directorio de
trabajo actual
Caminos relativos
.\
.. \
.\efervescencia
. \ fizz \ spam.txt
. \ spam.txt
..\huevos
.. \ eggs \ spam.txt
.. \ spam.txt
Caminos absolutos
C: \ tocino
C:\
C: \ tocino \ fizz
C: \ bacon \ fizz \ spam.txt
C: \ bacon \ spam.txt
C: \ eggs
C: \ eggs \ spam.txt
C: \ spam.txt
Figura 8-2: Las rutas relativas para carpetas y archivos en el directorio de trabajo C: \ bacon
El . \ Al comienzo de una ruta relativa es opcional. Por ejemplo ,. \ Spam.txt y spam.txt se refieren
al mismo archivo.
Crear nuevas carpetas con os.makedirs ()
Sus programas pueden crear nuevas carpetas (directorios) con la función os.makedirs ()
. Ingrese lo siguiente en el shell interactivo:
>>> import os
>>> os.makedirs ('C: \\ delicious \\ walnut \\ waffles')
Esto creará no solo la carpeta C: \ delicious sino también una carpeta de nueces dentro de C: \
delicious y una carpeta de waffles dentro de C: \ delicious \ walnut. Es decir, os.makedirs () creará
las carpetas intermedias necesarias para garantizar que exista la ruta completa. La Figura 8-3
muestra esta jerarquía de carpetas.

delicioso
C:\
nuez
gofres
Figura 8-3: El resultado de
os.makedirs ('C: \\ delicious
\\ walnut \\ waffles')
Lectura y escritura de archivos 177
el módulo os.path
El módulo os.path contiene muchas funciones útiles relacionadas con los nombres de archivo
y las rutas de archivo. Por ejemplo, ya usó os.path.join () para crear
rutas de una manera que funcione en cualquier sistema operativo. Dado que os.path es un
módulo dentro del módulo os, puede importarlo simplemente ejecutando import
os. Siempre que sus programas necesiten trabajar con archivos, carpetas o rutas de archivos,
puede consultar los ejemplos breves de esta sección. La documentación completa
del módulo os.path se encuentra en el sitio web de Python en http://docs.python.org/3/
library / os.path.html .
note La mayoría de los ejemplos que siguen en esta sección requerirán el módulo os, así que
recuerde
importarlo al comienzo de cualquier script que escriba y cada vez que reinicie
IDLE. De lo contrario, obtendrá un NameError: el nombre 'os' no está definido como mensaje de
error.
Manejo de rutas absolutas y relativas
El módulo os.path proporciona funciones para devolver la ruta absoluta de una
ruta relativa y para verificar si una ruta determinada es una ruta absoluta.
• Llamar a os.path.abspath ( ruta ) devolverá una cadena de la ruta absoluta del argumento. Esta es
una manera fácil de convertir una ruta relativa en una absoluta.
• Llamar a os.path.isabs ( ruta ) devolverá True si el argumento es una ruta absoluta y False si es
una ruta relativa.
• Llamar a os.path.relpath ( ruta , inicio ) devolverá una cadena de una ruta relativa desde la ruta
de inicio a la ruta . Si no se proporciona el inicio , el directorio de trabajo actual se usa como la ruta
de inicio.
Pruebe estas funciones en el shell interactivo:
>>> os.path.abspath ('.')
'C: \\ Python34'
>>> os.path.abspath ('. \\ Scripts')
'C: \\ Python34 \\ Scripts'
>>> os .path.isabs ('.')
Falso
>>> os.path.isabs (os.path.abspath ('.'))
Verdadero
Dado que C: \ Python34 era el directorio de trabajo cuando se llamó a os.path.abspath ()
, la carpeta "punto único" representa la ruta absoluta 'C: \\ Python34'.
nota Dado que su sistema probablemente tenga diferentes archivos y carpetas que el mío, no
podrá seguir todos los ejemplos de este capítulo exactamente. Aún así, intente seguir usando
carpetas que existen en su computadora.
178 Capítulo 8
Ingrese las siguientes llamadas a os.path.relpath () en el shell interactivo:
>>> os.path.relpath ('C: \\ Windows', 'C: \\')
'Windows'
>>> os.path.relpath ('C: \\ Windows', 'C: \\ spam \\ eggs ')
' .. \\ .. \\ Windows '
>>> os.getcwd ()
' C: \\ Python34 '
Llamar a os.path.dirname ( ruta ) devolverá una cadena de todo lo que viene
antes de la última barra en el argumento de la ruta. Llamar a os.path.basename ( ruta )
devolverá una cadena de todo lo que viene después de la última barra en el argumento de la ruta
. El nombre del directorio y el nombre base de una ruta se describen en la Figura 8-4.
C: \ Windows \ System32 \ calc.exe
Nombre de Dir Nombre de la base
Figura 8-4: El nombre de la base sigue a la última barra
en una ruta y es el mismo que el nombre del archivo. El nombre del directorio
lo es todo antes de la última barra.
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> ruta = 'C: \\ Windows \\ System32 \\ calc.exe'
>>> os.path.basename (ruta)
'calc.exe'
>>> os.path.dirname (ruta)
'C: \\ Windows \\ System32 '
Si necesita el nombre de directorio y el nombre base de una ruta juntos, puede llamar a
os.path.split () para obtener un valor de tupla con estas dos cadenas, de esta manera:
>>> calcFilePath = 'C: \\ Windows \\ System32 \\ calc.exe'
>>> os.path.split (calcFilePath)
('C: \\ Windows \\ System32', 'calc.exe')
Observe que puede crear la misma tupla llamando a os.path.dirname ()
y os.path.basename () y colocando sus valores de retorno en una tupla.
>>> (os.path.dirname (calcFilePath), os.path.basename (calcFilePath))
('C: \\ Windows \\ System32', 'calc.exe')
Pero os.path.split () es un buen acceso directo si necesita ambos valores.
Además, tenga en cuenta que os.path.split () no toma una ruta de archivo y devuelve una lista
de cadenas de cada carpeta. Para eso, use el método de cadena split () y divida
la cadena en os.sep. Recuerde que la variable os.sep está configurada en la
barra diagonal de separación de carpetas correcta para la computadora que ejecuta el programa.
Lectura y escritura de archivos 179
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> calcFilePath.split (os.path.sep)
['C:', 'Windows', 'System32', 'calc.exe']
En los sistemas OS X y Linux, habrá una cadena en blanco al comienzo de
la lista devuelta:
>>> '/usr/bin'.split(os.path.sep)
[' ',' usr ',' bin ']
El método de cadena split () funcionará para devolver una lista de cada parte de la
ruta. Funcionará en cualquier sistema operativo si lo pasa os.path.sep.
Búsqueda de tamaños de archivo y contenido de carpeta
Una vez que tenga formas de manejar las rutas de archivo, puede comenzar a recopilar
información sobre archivos y carpetas específicos. El módulo os.path proporciona
funciones para encontrar el tamaño de un archivo en bytes y los archivos y carpetas
dentro de una carpeta determinada.
• Llamar a os.path.getsize (ruta) devolverá el tamaño en bytes del archivo en el argumento
de la ruta .
• Llamar a os.listdir (ruta) devolverá una lista de cadenas de nombre de archivo para cada
archivo en el argumento de la ruta . (Tenga en cuenta que esta función está en el módulo os, no
en os.path).
Esto es lo que obtengo cuando intento estas funciones en el shell interactivo:
>>> os.path.getsize ('C: \\ Windows \\ System32 \\ calc.exe')
776192
>>> os.listdir ('C: \\ Windows \\ System32')
['0409', ' 12520437.cpx ' '12520850.cpx', '5U877.ax', 'aaclient.dll',
- cortar -
'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN',' zh-HK ',' zh-TW ',' zipfldr.dll ']
Como puede ver, el programa calc.exe en mi computadora tiene un
tamaño de 776,192 bytes , y tengo muchos archivos en C: \ Windows \ system32. Si quiero
encontrar el
tamaño total de todos los archivos en este directorio, puedo usar os.path.getsize () y
os.listdir () juntos.
>>> totalSize = 0
>>> para el nombre de archivo en os.listdir ('C: \\ Windows \\ System32'):
totalSize = totalSize + os.path.getsize (os.path.join ('C: \\ Windows \\ System32 ', nombre de
archivo))
>>> imprimir (tamaño total)
1117846456
180 Capítulo 8
A medida que recorro cada nombre de archivo en la carpeta C: \ Windows \ System32, la
variable totalSize se incrementa en el tamaño de cada archivo. Observe cómo cuando
llamo a os.path.getsize (), uso os.path.join () para unir el nombre de la carpeta con el
nombre de archivo actual. El entero que devuelve os.path.getsize () se agrega al
valor de totalSize. Después de recorrer todos los archivos, imprimo totalSize para ver
el tamaño total de la carpeta C: \ Windows \ System32 .
Comprobación de la validez de la ruta
Muchas funciones de Python se bloquearán con un error si les proporciona una
ruta que no existe. El módulo os.path proporciona funciones para verificar
si existe una ruta determinada y si se trata de un archivo o carpeta.
• Llamar a os.path.exists (ruta) devolverá True si el archivo o carpeta mencionado en el argumento
existe y devolverá False si no existe.
• Llamar a os.path.isfile ( ruta ) devolverá True si el argumento de la ruta existe y es un archivo y,
de lo contrario, devolverá False.
• Llamar a os.path.isdir ( ruta ) devolverá True si el argumento de la ruta existe y es una carpeta y,
de lo contrario, devolverá False.
Esto es lo que obtengo cuando intento estas funciones en el shell interactivo:
>>> os.path.exists ('C: \\ Windows')
Verdadero
>>> os.path.exists ('C: \\ some_made_up_folder')
Falso
>>> os.path.isdir ('C: \\ Windows \\ System32 ')
Verdadero
>>> os.path.isfile (' C: \\ Windows \\ System32 ')
Falso
>>> os.path.isdir (' C: \\ Windows \\ System32 \\ calc. exe ')
Falso
>>> os.path.isfile (' C: \\ Windows \\ System32 \\ calc.exe ')
Verdadero
Puede determinar si hay un DVD o unidad flash actualmente
conectado a la computadora verificándolo con la función os.path.exists ()
. Por ejemplo, si quisiera buscar una unidad flash con el volumen
llamado D: \ en mi computadora con Windows, podría hacerlo con lo siguiente:
>>> os.path.exists ('D: \\')
Falso
¡Uy! Parece que olvidé conectar mi unidad flash.
el proceso de lectura / escritura de archivos
Una vez que se sienta cómodo trabajando con carpetas y rutas relativas,
podrá especificar la ubicación de los archivos para leer y escribir. Las funciones
cubiertas en las siguientes secciones se aplicarán a los archivos de texto sin formato. Archivos de
texto sin formato
Lectura y escritura de archivos 181
contiene solo caracteres de texto básicos y no incluye información de fuente, tamaño o color
. Los archivos de texto con la extensión .txt o los archivos de script Python con
la extensión .py son ejemplos de archivos de texto sin formato. Estos se pueden abrir con
el Bloc de notas de Windows o la aplicación TextEdit de OS X. Sus programas
pueden leer fácilmente
el contenido de los archivos de texto sin formato y tratarlos como un valor de cadena normal.
Los archivos binarios son todos los otros tipos de archivos, como documentos de procesamiento de
texto,
PDF, imágenes, hojas de cálculo y programas ejecutables. Si abre un
archivo binario en el Bloc de notas o TextEdit, se verá como una tontería codificada, como en la
Figura 8-5.
Figura 8-5: El programa Windows calc.exe abierto en el Bloc de notas
Dado que cada tipo diferente de archivo binario debe manejarse a su
manera, este libro no se dedicará a leer y escribir archivos binarios en bruto directamente.
Afortunadamente, muchos módulos facilitan el trabajo con archivos binarios:
explorará uno de ellos, el módulo de estantería, más adelante en este capítulo.
Hay tres pasos para leer o escribir archivos en Python.
1. Llame a la función open () para devolver un objeto File.
2. Llame al método read () o write () en el objeto File.
3. Cierre el archivo llamando al método close () en el objeto File.
Abrir archivos con la función open ()
Para abrir un archivo con la función open (), le pasa una ruta de cadena que indica
el archivo que desea abrir; puede ser una ruta absoluta o relativa. La función
open () devuelve un objeto File.
Pruébelo creando un archivo de texto llamado hello.txt usando el Bloc de notas o TextEdit.
Escriba Hello world! como el contenido de este archivo de texto y guárdelo en su
carpeta de inicio de usuario . Luego, si está utilizando Windows, ingrese lo siguiente en el
shell interactivo:
>>> helloFile = open ('C: \\ Users \\ your_home_folder \\ hello.txt')
Si está utilizando OS X, ingrese lo siguiente en el shell interactivo:
>>> helloFile = open ('/ Users / your_home_folder /hello.txt')
182 Capítulo 8
Asegúrese de reemplazar your_home_folder con el nombre de usuario de su computadora.
Por ejemplo, mi nombre de usuario es asweigart , por lo que ingresaría 'C: \\ Users \\ asweigart \\
hello.txt' en Windows.
Ambos comandos abrirán el archivo en modo "lectura de texto sin formato"
o en modo de lectura para abreviar. Cuando se abre un archivo en modo de lectura, Python
solo le permite leer datos del archivo; no puedes escribirlo o modificarlo de ninguna manera. El
modo de lectura es el modo predeterminado para los archivos que abre en Python. Pero si no desea
confiar en los valores predeterminados de Python, puede especificar explícitamente el modo
pasando
el valor de cadena 'r' como un segundo argumento para abrir (). Entonces open ('/ Users / asweigart
/
hello.txt', 'r') y open ('/ Users / asweigart / hello.txt') hacen lo mismo.
La llamada a open () devuelve un objeto File. Un objeto File representa un archivo en
su computadora; es simplemente otro tipo de valor en Python, muy parecido a las
listas y diccionarios con los que ya está familiarizado. En el ejemplo anterior,
almacenó el objeto File en la variable helloFile. Ahora, cada vez que desee
leer o escribir en el archivo, puede hacerlo llamando a métodos en el
objeto File en helloFile.
Lectura del contenido de los archivos
Ahora que tiene un objeto File, puede comenzar a leerlo. Si desea
leer todo el contenido de un archivo como un valor de cadena, use el
método read () del objeto File . Continuemos con el objeto de archivo hello.txt que almacenó en
helloFile.
Ingrese lo siguiente en el shell interactivo:
>>> helloContent = helloFile.read ()
>>> helloContent
'¡Hola, mundo!'
Si piensa en el contenido de un archivo como un único valor de cadena grande, el
método read () devuelve la cadena que está almacenada en el archivo.
Alternativamente, puede usar el método readlines () para obtener una lista de
valores de cadena del archivo, una cadena para cada línea de texto. Por ejemplo, cree un
archivo llamado sonnet29.txt en el mismo directorio que hello.txt y escriba el siguiente
texto en él:
Cuando, en desgracia con la fortuna y los ojos de los hombres,
solo lloro mi estado marginado,
y molesto al cielo sordo con mis gritos sin botas,
y me miro y maldigo mi destino,
Asegúrese de separar las cuatro líneas con saltos de línea. Luego ingrese lo
siguiente en el shell interactivo:
>>> sonnetFile = open ('sonnet29.txt')
>>> sonnetFile.readlines ()
[Cuando, en desgracia con la fortuna y los ojos de los hombres, \ n ',' solo lloro mi
estado marginado, \ n ', y molestar al cielo sordo con mis llantos sin botas, \ n ', y
mirarme a mí mismo y maldecir mi destino']
Lectura y escritura de archivos 183
Tenga en cuenta que cada uno de los valores de cadena termina con un carácter de nueva línea, \ n,
excepto la última línea del archivo. A menudo es más fácil trabajar con una lista de cadenas que
con
un solo valor de cadena grande.
Escribir en archivos
Python le permite escribir contenido en un archivo de forma similar a cómo la función print ()
"escribe" cadenas en la pantalla. Sin
embargo, no puede escribir en un archivo que ha abierto en modo de lectura. En su lugar, debe
abrirlo en el modo "escribir texto sin formato"
o en el modo "agregar texto sin formato", o en modo escribir y agregar modo para abreviar.
El modo de escritura sobrescribirá el archivo existente y comenzará desde cero, al
igual que cuando sobrescribe el valor de una variable con un nuevo valor. Pase 'w' como
segundo argumento para abrir () para abrir el archivo en modo de escritura. El modo Agregar,
por otro lado, agregará texto al final del archivo existente. Puede
pensar en esto como anexar a una lista en una variable, en lugar de sobrescribir la
variable por completo. Pase 'a' como el segundo argumento para abrir () para abrir el
archivo en modo agregar.
Si el nombre de archivo pasado a open () no existe, los
modos de escritura y anexión crearán un nuevo archivo en blanco. Después de leer o escribir un
archivo, llame al
método close () antes de abrir el archivo nuevamente.
Pongamos estos conceptos juntos. Ingrese lo siguiente en el
shell interactivo:
>>> baconFile = abierto ('bacon.txt', 'w')
>>> baconFile.write ('¡Hola mundo! \ n')
13
>>> baconFile.close ()
>>> baconFile = abierto ('bacon .txt ',' a ')
>>> baconFile.write (' El tocino no es un vegetal. ')
25
>>> baconFile.close ()
>>> baconFile = open (' bacon.txt ')
>>> contenido = baconFile.read ()
>>> baconFile.close ()
>>> print (contenido)
¡Hola, mundo!
El tocino no es un vegetal.
Primero, abrimos bacon.txt en modo de escritura. Como todavía no hay un bacon.txt ,
Python crea uno. Llamando a write () en el archivo abierto y pasando a write ()
el argumento de cadena '¡Hola mundo! / n 'escribe la cadena en el archivo y
devuelve el número de caracteres escritos, incluida la nueva línea. Luego
cerramos el archivo.
Para agregar texto al contenido existente del archivo en lugar de reemplazar la
cadena que acabamos de escribir, abrimos el archivo en modo de agregado. Escribimos 'El tocino
no es un vegetal'. al archivo y ciérrelo. Finalmente, para imprimir el contenido del archivo en
la pantalla, abrimos el archivo en su modo de lectura predeterminado, llamamos a read (),
almacenamos el
objeto File resultante en contenido, cerramos el archivo e imprimimos contenido.
184 Capítulo 8
Tenga en cuenta que el método write () no agrega automáticamente un
carácter de nueva línea al final de la cadena como lo hace la función print (). Tendrás
que agregar este personaje tú mismo.
Guardar variables con el módulo de
estantería Puede guardar variables en sus programas Python en archivos de estantería binarios
utilizando
el módulo de estantería . De esta manera, su programa puede restaurar datos a variables
desde el disco duro. El módulo de estantería le permitirá agregar
funciones Guardar y Abrir a su programa. Por ejemplo, si ejecutó un programa e ingresó
algunos ajustes de configuración, podría guardar esos ajustes en un archivo de estantería y
luego hacer que el programa los cargue la próxima vez que se ejecute.
Ingrese lo siguiente en el shell interactivo:
>>> import shelve
>>> shelfFile = shelve.open ('mydata')
>>> cats = ['Zophie', 'Pooka', 'Simon']
>>> shelfFile ['cats'] = cats
>>> shelfFile.close ()
Para leer y escribir datos usando el módulo de estantería, primero importa estantería.
Llame a shelve.open () y pásele un nombre de archivo, y luego almacene el
valor de estante devuelto en una variable. Puede realizar cambios en el valor del estante como si
fuera un
diccionario. Cuando haya terminado, llame a close () en el valor del estante. Aquí, nuestro
valor de estantería se almacena en estantería. Creamos una lista de gatos y escribimos shelfFile
['cats'] =
cats para almacenar la lista en shelfFile como un valor asociado con la clave 'cats'
(como en un diccionario). Luego llamamos a close () en shelfFile.
Después de ejecutar el código anterior en Windows, verá tres archivos nuevos
en el directorio de trabajo actual: mydata.bak , mydata.dat y mydata.dir . En
OS X, solo se creará un único archivo mydata.db.
Estos archivos binarios contienen los datos que almacenó en su estante. El formato
de estos archivos binarios no es importante; solo necesita saber qué hace el
módulo de estantería , no cómo lo hace. El módulo te libera de preocuparte sobre
cómo almacenar los datos de tu programa en un archivo.
Sus programas pueden usar el módulo
de estantería para luego volver a abrir y recuperar los datos de estos archivos de estantería. Los
valores de estante no tienen que abrirse en modo lectura
o escritura; pueden hacer ambos una vez abiertos. Ingrese lo siguiente en el
shell interactivo:
>>> shelfFile = shelve.open ('mydata')
>>> type (shelfFile)
<class 'shelve.DbfilenameShelf'>
>>> shelfFile ['cats']
['Zophie', 'Pooka', 'Simon']
>>> estantería.close ()
Aquí, abrimos los archivos del estante para verificar que nuestros datos se almacenaron
correctamente.
Al ingresar a shelfFile ['cats'], se devuelve la misma lista que almacenamos anteriormente, por lo
que
sabemos que la lista está almacenada correctamente y llamamos a close ().
Lectura y escritura de archivos 185
Al igual que los diccionarios, los valores de estantería tienen métodos de claves () y valores () que
devolverán valores de lista de las claves y valores en la estantería. Dado que estos
métodos devuelven valores similares a listas en lugar de listas verdaderas, debe pasarlos
a la función list () para obtenerlos en forma de lista. Ingrese lo siguiente en el
shell interactivo:
>>> shelfFile = shelve.open ('mydata')
>>> list (shelfFile.keys ())
['cats']
>>> list (shelfFile.values ())
[['' Zophie ',' Pooka ', 'Simon']]
>>> shelfFile.close ()
El texto simple es útil para crear archivos que leerá en un editor de texto
como el Bloc de notas o TextEdit, pero si desea guardar datos de sus programas Python
, use el módulo de estantería.
Guardar variables con la función pprint.pformat ()
Recuerde de "Pretty Printing" en la página 111 que la función pprint.pprint ()
"imprimirá bastante" el contenido de una lista o diccionario en la pantalla,
mientras que pprint.pformat () la función devolverá este mismo texto como una cadena en
lugar de imprimirlo. Esta cadena no solo está formateada para que sea fácil de leer,
sino que también es un código Python sintácticamente correcto. Supongamos que tiene un
diccionario
almacenado en una variable y desea guardar esta variable y su contenido para
su uso futuro. El uso de pprint.pformat () le dará una cadena que puede escribir
en el archivo .py. Este archivo será su propio módulo que puede importar
cuando quiera usar la variable almacenada en él.
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> import pprint
>>> cats = [{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}]
>>> pprint.pformat (gatos)
"[{'' desc ':' gordito ',' nombre ':' Zophie '}, {' desc ':' esponjoso ',' nombre ':' Pooka '}]"
>>> fileObj = open ('myCats.py', 'w')
>>> fileObj.write ('cats =' + pprint.pformat (cats) + '\ n')
83
>>> fileObj.close ()
Aquí, importamos pprint para permitirnos usar pprint.pformat (). Tenemos una lista de
diccionarios, almacenados en una variable de gatos. Para mantener la lista en gatos disponible
incluso
después de cerrar el shell, usamos pprint.pformat () para devolverlo como una cadena. Una vez
que tenemos los datos en gatos como una cadena, es fácil escribir la cadena en un archivo, que
llamaremos myCats.py .
Los módulos que importa una declaración de importación son solo
scripts de Python. Cuando la cadena de pprint.pformat () se guarda en un archivo .py,
el archivo es un módulo que se puede importar como cualquier otro.
186 Capítulo 8
Y dado que los scripts de Python son solo archivos de texto con la
extensión de archivo .py , sus programas de Python pueden incluso generar otros programas de
Python
. Luego puede importar estos archivos en scripts.
>>> import myCats
>>> myCats.cats
[{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}]
>> > myCats.cats [0]
{'nombre': 'Zophie', 'desc': 'gordito'}
>>> myCats.cats [0] ['nombre']
'Zophie'
La ventaja de crear un archivo .py (en lugar de guardar variables con
el módulo de almacenamiento ) es que, dado que es un archivo de texto,
cualquiera que tenga un editor de texto simple puede leer y modificar el contenido del archivo .
Sin embargo, para la mayoría de las aplicaciones, guardar datos utilizando el módulo de
almacenamiento es la
forma preferida de guardar variables en un archivo. Solo los tipos de datos básicos como enteros,
flotantes,
cadenas, listas y diccionarios se pueden escribir en un archivo como texto simple. Los objetos
de archivo
, por ejemplo, no pueden codificarse como texto.
Proyecto: generar archivos de cuestionarios aleatorios
Digamos que usted es un profesor de geografía con 35 estudiantes en su clase y desea
dar un cuestionario emergente sobre las capitales de los estados de EE. Por desgracia, tu clase tiene
algunos huevos malos
y no puedes confiar en que los estudiantes no hagan trampa. Le gustaría aleatorizar el
orden de las preguntas para que cada cuestionario sea único, lo que hace imposible que
nadie pueda responder las respuestas de nadie más. Por supuesto, hacer esto a mano sería
un asunto largo y aburrido. Afortunadamente, sabes algo de Python.
Esto es lo que hace el programa:

• Crea 35 cuestionarios diferentes. • Crea 50 preguntas de opción múltiple para cada cuestionario,
en orden aleatorio. • Proporciona la respuesta correcta y tres respuestas incorrectas al azar para
cada

pregunta, en orden aleatorio.


• Escribe los cuestionarios en 35 archivos de texto. • Escribe las claves de respuesta en 35 archivos
de texto.

Esto significa que el código deberá hacer lo siguiente:

• Almacene los estados y sus capitales en un diccionario. • Llame a open (), write () y close () para
el cuestionario y responda los archivos de texto clave. • Use random.shuffle () para aleatorizar el
orden de las preguntas y

Opciones de opción múltiple.


Lectura y escritura de archivos 187
Paso 1: Almacene los datos de
la prueba en un diccionario El primer paso es crear una secuencia de comandos esqueleto y
completarla con los datos de la prueba.
Cree un archivo llamado randomQuizGenerator.py y haga que se vea así
:
#! python3
# randomQuizGenerator.py - Crea cuestionarios con preguntas y respuestas en
# orden aleatorio, junto con la clave de respuestas.
importas al azar
# Los datos del cuestionario. Las claves son estados y los valores son sus capitales.
v capitales = {'Alabama': 'Montgomery', 'Alaska': 'Juneau', 'Arizona': 'Phoenix',
'Arkansas': 'Little Rock', 'California': 'Sacramento', 'Colorado': 'Denver',
'Connecticut': 'Hartford', 'Delaware': 'Dover', 'Florida': 'Tallahassee',
' Georgia ':' Atlanta ',' Hawaii ':' Honolulu ',' Idaho ':' Boise ',' Illinois ':
' Springfield ',' Indiana ':' Indianápolis ',' Iowa ':' Des Moines ',' Kansas ':
' Topeka ',' Kentucky ':' Frankfort ',' Louisiana ':' Baton Rouge ',' Maine ':
' Augusta ',' Maryland ':' Annapolis ',' Massachusetts ':' Boston ',' Michigan ' :
'Lansing', 'Minnesota': 'San Pablo', 'Mississippi': 'Jackson', 'Missouri':
'Jefferson City', 'Montana': 'Helena', 'Nebraska': 'Lincoln', 'Nevada' :
'Carson City', 'New Hampshire': 'Concord', 'New Jersey': 'Trenton', 'New
Mexico': 'Santa Fe', 'New York': 'Albany', 'North Carolina': 'Raleigh ',
' Dakota del Norte ':' Bismarck ',' Ohio ':' Columbus ',' Oklahoma ':' Oklahoma City ',
' Oregon ':' Salem ',' Pennsylvania ':' Harrisburg ',' Rhode Island ':' Providence ',
' Carolina del Sur ':' Columbia ',' Dakota del Sur ':' Pierre ',' Tennessee ':
' Nashville ',' Texas ':' Austin ',' Uta h ': 'Salt Lake City', 'Vermont':
'Montpelier', 'Virginia': 'Richmond', 'Washington': 'Olympia', 'West
Virginia': 'Charleston', 'Wisconsin': 'Madison', 'Wyoming': 'Cheyenne'}
# Generar 35 archivos de prueba.
w para quizNum en rango (35):
# TODO: Cree el cuestionario y responda los archivos clave.
# TODO: escriba el encabezado de la prueba.
# TODO: baraja el orden de los estados.
# TODO: recorre los 50 estados, haciendo una pregunta para cada uno.
Dado que este programa ordenará aleatoriamente las preguntas y las respuestas,
deberá importar el módulo aleatorio u para utilizar sus funciones. La
variable v de mayúsculas contiene un diccionario con estados de EE. UU. Como claves y sus
mayúsculas como valores. Y dado que desea crear 35 cuestionarios, el código que realmente
genera el cuestionario y los archivos clave de respuestas (marcados con TODO comentarios por
ahora) irá dentro de un bucle for que se repite 35 veces w. (Este número se puede
cambiar para generar cualquier número de archivos de prueba).
188 Capítulo 8
Paso 2: Cree el archivo de cuestionario y baraje el orden de las preguntas
Ahora es el momento de comenzar a completar esos TODOS.
El código en el bucle se repetirá 35 veces, una vez para cada prueba,
por lo que debe preocuparse por una sola prueba a la vez dentro del bucle. Primero
creará el archivo de prueba real. Debe tener un nombre de archivo único y
también debe tener algún tipo de encabezado estándar, con lugares para que el estudiante
complete un nombre, fecha y período de clase. Luego, deberá obtener una lista
de estados en orden aleatorio, que se puede utilizar más adelante para crear las preguntas
y respuestas para el cuestionario.
Agregue las siguientes líneas de código a randomQuizGenerator.py :
#! python3
# randomQuizGenerator.py - Crea cuestionarios con preguntas y respuestas en
# orden aleatorio, junto con la clave de respuestas.
- cortar -
# Generar 35 archivos de prueba.
for quizNum in range (35):
# Cree el cuestionario y responda los archivos clave.
u quizFile = open ('capitalsquiz% s.txt'% (quizNum + 1), 'w')
v answerKeyFile = open ('capitalsquiz_answers% s.txt'% (quizNum + 1), 'w')
# Escriba el encabezado de la prueba.
w quizFile.write ('Nombre: \ n \ nFecha: \ n \ nPeriod: \ n \ n')
quizFile.write (('' * 20) + 'State Capitals Quiz (Form% s)'% (quizNum + 1))
quizFile.write ('\ n \ n')
# Baraja el orden de los estados.
estados = lista (capitals.keys ())
x random.shuffle (estados)
# TODO: recorre los 50 estados, haciendo una pregunta para cada uno.
Los nombres de archivo para las pruebas serán mayúsculas <N> .txt, donde <N> es
un número único para la prueba que viene de quizNum, el contador del bucle for
. La clave de respuesta para capitalsquiz <N> .txt se almacenará en un archivo de texto llamado
capitalsquiz_answers <N> .txt . Cada vez a través del ciclo, el marcador
de posición% s en 'capitalsquiz% s.txt' y 'capitalsquiz_answers% s.txt' se reemplazará por
(quizNum + 1), por lo que la primera prueba y clave de respuesta creada será capitalsquiz1.txt
y capitalsquiz_answers1.txt. Estos archivos se crearán con llamadas a la función open ()
en u y v, con 'w' como segundo argumento para abrirlos en
modo de escritura.
Las declaraciones write () en w crean un encabezado de prueba para que el estudiante complete
. Finalmente, se crea una lista aleatoria de estados de EE. UU. Con la ayuda de la función
random.shuffle () x, que reordena aleatoriamente los valores en cualquier lista
que se le pase.
Lectura y escritura de archivos 189
Paso 3: Cree las opciones de respuesta
Ahora debe generar las opciones de respuesta para cada pregunta, que serán de
opción múltiple de la A a la D. Necesitará crear otro bucle for, este
para generar el contenido para cada uno de los 50 preguntas en el cuestionario. Luego
habrá un tercer bucle for anidado dentro para generar las opciones de opción múltiple
para cada pregunta. Haga que su código tenga el siguiente aspecto:
#! python3
# randomQuizGenerator.py - Crea cuestionarios con preguntas y respuestas en
# orden aleatorio, junto con la clave de respuestas.
- cortar -
# Recorrer los 50 estados, haciendo una pregunta para cada uno.
para questionNum en rango (50):
# Obtenga respuestas correctas e incorrectas.
u correctAnswer = mayúsculas [estados [questionNum]]
v wrongAnswers = list (capitals.values ())
w del wrongAnswers [wrongAnswers.index (correctAnswer)]
x wrongAnswers = random.sample (wrongAnswers, 3)
y answerOptions = wrongAnswers + [correctAnswer ]
z random.shuffle (answerOptions)
# TODO: escriba las opciones de preguntas y respuestas en el archivo de prueba.
# TODO: Escriba la clave de respuesta en un archivo.
La respuesta correcta es fácil de obtener: se almacena como un valor en el
diccionario de mayúsculas u. Este bucle recorrerá los estados en la
lista de estados aleatorios, desde los estados [0] a los estados [49], encontrará cada estado en
mayúsculas y almacenará la capital correspondiente de ese
estado en la respuesta correcta.
La lista de posibles respuestas incorrectas es más complicada. Se puede conseguir por duplicat-
ing todos los valores en las capitales diccionario v, la supresión de la respuesta correcta w,
y seleccionar tres valores aleatorios de esta lista x. La función random.sample ()
facilita esta selección. Su primer argumento es la lista que desea
seleccionar; El segundo argumento es el número de valores que desea
seleccionar. La lista completa de opciones de respuesta es la combinación de estas tres
respuestas incorrectas con las respuestas correctas y. Finalmente, las respuestas deben ser
aleatorizadas
z para que la respuesta correcta no sea siempre la opción D.
Paso 4: Escribir contenido en el
archivo de prueba y clave de respuestas Todo lo que queda es escribir la pregunta en el archivo de
prueba y la respuesta en
el archivo de clave de respuesta. Haga que su código tenga el siguiente aspecto:
#! python3
# randomQuizGenerator.py - Crea cuestionarios con preguntas y respuestas en
# orden aleatorio, junto con la clave de respuestas.
- cortar -
190 Capítulo 8
# Recorrer los 50 estados, haciendo una pregunta para cada uno.
para questionNum en rango (50):
- snip -
# Escriba la pregunta y las opciones de respuesta en el archivo de prueba.
quizFile.write ('% s. ¿Cuál es la capital de% s? \ n'% (questionNum + 1,
states [questionNum]))
u para i en el rango (4):
v quizFile.write ('% s.% s \ n'% ('ABCD' [i], answerOptions [i]))
quizFile.write ('\ n')
# Escriba la clave de respuesta en un archivo.
w answerKeyFile.write ('% s.% s \ n'% (questionNum + 1, 'ABCD' [
answerOptions.index (correctAnswer)]))
quizFile.close ()
answerKeyFile.close ()
Un bucle for que pasa por enteros 0 a 3 escribirá las opciones de respuesta
en la lista de opciones de respuesta u. La expresión 'ABCD' [i] en v trata la cadena
'ABCD' como una matriz y evaluará a 'A', 'B', 'C' y luego 'D' en cada
iteración respectiva a través del bucle.
En la línea final w, la expresión answerOptions.index (correctAnswer)
encontrará el índice entero de la respuesta correcta en las
opciones de respuesta ordenadas al azar , y 'ABCD' [answerOptions.index (correctAnswer)]
evaluará
la letra de la respuesta correcta para ser escrito en el archivo de clave de respuestas.
Después de ejecutar el programa, así es como se
verá su archivo capitalsquiz1.txt , aunque, por supuesto, sus opciones de preguntas y respuestas
pueden ser diferentes
de las que se muestran aquí, dependiendo del resultado de sus llamadas random.shuffle ()
:
Nombre:
Fecha:
Período:
Examen de capitales estatales (formulario 1)
1. ¿Cuál es la capital de Virginia Occidental?
A. Hartford
B. Santa Fe
C. Harrisburg
D. Charleston
2. ¿Cuál es la capital de Colorado?
A. Raleigh
B. Harrisburg
C. Denver
D. Lincoln
- cortar -
Lectura y escritura de archivos 191
El correspondiente archivo de texto capitalsquiz_answers1.txt se verá así:
1. D
2. C
3. A
4. C
- recorte -
Proyecto: multiclipboard
Digamos que tiene la aburrida tarea de llenar muchos formularios en una página web o software
con varios campos de texto. El portapapeles le evita escribir el mismo
texto una y otra vez. Pero solo una cosa puede estar en el portapapeles a la
vez. Si tiene varias piezas de texto diferentes que necesita copiar y
pegar, debe seguir resaltando y copiando las mismas pocas cosas una
y otra vez.
Puede escribir un programa de Python para realizar un seguimiento de varios fragmentos de texto.
Este "multiclipboard" se llamará mcb.pyw (ya que "mcb" es más corto de escribir
que "multiclipboard"). La extensión .pyw significa que Python no mostrará
una ventana de Terminal cuando ejecute este programa. (Consulte el Apéndice B para más
detalles).
El programa guardará cada parte del texto del portapapeles bajo una palabra clave.
Por ejemplo, cuando ejecuta py mcb.pyw save spam, el contenido actual del
portapapeles se guardará con la palabra clave spam . Este texto luego puede cargarse
nuevamente en el portapapeles ejecutando py mcb.pyw spam. Y si el usuario olvida
qué palabras clave tiene, puede ejecutar py mcb.pyw list para copiar una lista de todas las
palabras clave en el portapapeles.
Esto es lo que hace el programa:

• Se marca el argumento de la línea de comando para la palabra clave. • Si el argumento es guardar,


el contenido del portapapeles se guarda en el

palabra clave.
• Si el argumento es una lista, todas las palabras clave se copian en el portapapeles. • De lo
contrario, el texto de la palabra clave se copia en el teclado.

Esto significa que el código deberá hacer lo siguiente:

• Lea los argumentos de la línea de comandos de sys.argv. • Leer y escribir en el


portapapeles. • Guardar y cargar en un archivo de estante.
Si usa Windows, puede ejecutar fácilmente este script desde la ventana Ejecutar ...
creando un archivo por lotes llamado mcb.bat con el siguiente contenido:
@ pyw.exe C: \ Python34 \ mcb.pyw% *
192 Capítulo 8
Paso 1: Comentarios y configuración de estante
Comencemos por hacer un script esqueleto con algunos comentarios y configuración básica.
Haga que su código tenga el siguiente aspecto:
#! python3
# mcb.pyw: guarda y carga fragmentos de texto en el portapapeles.
u # Uso: py.exe mcb.pyw save <keyword> - Guarda el portapapeles en la palabra clave.
# py.exe mcb.pyw <palabra clave>: carga la palabra clave en el portapapeles.
# py.exe mcb.pyw list: carga todas las palabras clave en el portapapeles.
v importar estantería, pyperclip, sys
w mcbShelf = shelve.open ('mcb')
# TODO: guarda el contenido del portapapeles.
# TODO: enumere palabras clave y cargue contenido.
mcbShelf.close ()
Es una práctica común poner información de uso general en los comentarios
en la parte superior del archivo u. Si alguna vez olvida cómo ejecutar su secuencia de comandos,
siempre puede ver estos comentarios como recordatorio. Luego importa sus
módulos v. Copiar y pegar requerirá el módulo pyperclip, y leer
los argumentos de la línea de comandos requerirá el módulo sys. El módulo de
estantería también será útil: cada vez que el usuario quiera guardar una nueva pieza
de texto del portapapeles, lo guardará en un archivo de estantería. Luego, cuando el usuario quiera
pegar el texto nuevamente en su portapapeles, abrirá el archivo de estantería y lo cargará
nuevamente en su programa. El archivo del estante se nombrará con el prefijo mcb w.
Paso 2: Guardar el contenido del portapapeles con una palabra clave
El programa hace diferentes cosas dependiendo de si el usuario desea
guardar texto en una palabra clave, cargar texto en el portapapeles o enumerar todas las
palabras clave existentes . Tratemos con ese primer caso. Haga que su código tenga
el siguiente aspecto
:
#! python3
# mcb.pyw: guarda y carga fragmentos de texto en el portapapeles.
- cortar -
# Guardar contenido del portapapeles.
u if len (sys.argv) == 3 y sys.argv [1] .lower () == 'guardar':
v mcbShelf [sys.argv [2]] = pyperclip.paste ()
elif len (sys.argv) == 2:
w # TODO: Listar palabras clave y cargar contenido.
mcbShelf.close ()
Lectura y escritura de archivos 193
Si el primer argumento de línea de comando (que siempre estará en el índice 1
de la lista sys.argv) es 'guardar' u, el segundo argumento de línea de comando es la
palabra clave para el contenido actual del portapapeles. La palabra clave se usará
como clave para mcbShelf, y el valor será el texto actualmente en el portapapeles
v.
Si solo hay un argumento de línea de comando, asumirá que es
'lista' o una palabra clave para cargar contenido en el portapapeles. Implementará
ese código más tarde. Por ahora, solo ponga un comentario TODO allí w.
Paso 3: Listar palabras clave y cargar el contenido de una palabra clave
Finalmente, implementemos los dos casos restantes: el usuario quiere cargar el
texto del portapapeles desde una palabra clave, o quiere una lista de todas las palabras clave
disponibles
. Haga que su código tenga el siguiente aspecto:
#! python3
# mcb.pyw: guarda y carga fragmentos de texto en el portapapeles.
- cortar -
# Guardar contenido del portapapeles.
if len (sys.argv) == 3 y sys.argv [1] .lower () == 'save':
mcbShelf [sys.argv [2]] = pyperclip.paste ()
elif len (sys.argv) = = 2:
# Listar palabras clave y cargar contenido.
u si sys.argv [1] .lower () == 'lista':
v pyperclip.copy (str (list (mcbShelf.keys ())))
elif sys.argv [1] en mcbShelf:
w pyperclip.copy (mcbShelf [sys.argv [1]])
mcbShelf.close ()
Si solo hay un argumento de línea de comando, primero verifiquemos si
es 'list' u. Si es así, se copiará una representación de cadena de la lista de claves de estantería
en el portapapeles v. El usuario puede pegar esta lista en un editor de texto abierto
para leerla.
De lo contrario, puede asumir que el argumento de la línea de comando es una palabra clave.
Si esta palabra clave existe en el estante mcbShelf como una clave, puede cargar el valor
en el portapapeles w.
¡Y eso es! El lanzamiento de este programa tiene diferentes pasos dependiendo
del sistema operativo que use su computadora. Consulte el Apéndice B para obtener detalles sobre
su sistema operativo.
Recuerde el programa de bloqueo de contraseña que creó en el Capítulo 6 que
almacenó las contraseñas en un diccionario. La actualización de las contraseñas requirió
cambiar el código fuente del programa. Esto no es ideal porque los
usuarios promedio no se sienten cómodos cambiando el código fuente para actualizar su software.
Además, cada vez que modifica el código fuente de un programa, corre el riesgo
de introducir accidentalmente nuevos errores. Al almacenar los datos de un programa
en un lugar diferente al del código, puede hacer que sus programas sean más fáciles de
usar y más resistentes a los errores.
194 Capítulo 8
Los
archivos de resumen están organizados en carpetas (también llamados directorios), y una ruta
describe
la ubicación de un archivo. Cada programa que se ejecuta en su computadora tiene un
directorio de trabajo
actual , que le permite especificar rutas de archivos relativas a la ubicación actual en lugar de
escribir siempre la ruta completa (o absoluta). El
módulo os.path tiene muchas funciones para manipular rutas de archivos.
Sus programas también pueden interactuar directamente con el contenido de los archivos de texto.
La función open () puede abrir estos archivos para leer en su contenido como una
cadena grande (con el método read ()) o como una lista de cadenas (con el
método readlines () ). La función open () puede abrir archivos en modo de escritura o anexión para
crear nuevos archivos de texto o agregarlos a archivos de texto existentes, respectivamente.
En capítulos anteriores, usó el portapapeles como una forma de obtener grandes
cantidades de texto en un programa, en lugar de escribirlo todo. Ahora puede
hacer que sus programas lean archivos directamente desde el disco duro, lo cual es una gran
mejora, ya que los archivos son mucho menos volátiles que el portapapeles.
En el próximo capítulo, aprenderá cómo manejar los archivos ellos mismos,
copiándolos, eliminándolos, renombrándolos, moviéndolos y más.
Preguntas de práctica
1. ¿A qué se refiere un camino relativo?
2. ¿Con qué comienza una ruta absoluta?
3. ¿Qué hacen las funciones os.getcwd () y os.chdir ()?
4. ¿Cuáles son los. y ... carpetas?
5. En C: \ bacon \ eggs \ spam.txt , qué parte es el nombre del directorio y qué parte es
el nombre base?
6. ¿Cuáles son los tres argumentos de "modo" que se pueden pasar a open ()
¿función?
7. ¿Qué sucede si un archivo existente se abre en modo de escritura?
8. ¿Cuál es la diferencia entre los métodos read () y readlines ()?
9. ¿A qué estructura de datos se parece un valor de estante?
Proyectos de
práctica Para practicar, diseñar y escribir los siguientes programas.
Extender el Multiclipboard
Extienda el programa multiclipboard en este capítulo para que tenga un
argumento de línea de comando delete <keyword> que eliminará una palabra clave del estante.
Luego agregue un argumento de línea de comando para eliminar que eliminará todas las palabras
clave.
Lectura y escritura de archivos 195
Liberaciones enojadas
crear un programa enojadas que lee en archivos de texto y permite al usuario añadir
su propio texto en cualquier lugar de la palabra ADJECTIVE , NOMBRE , ADVERBIO ,
o VERBO aparece en el archivo de texto. Por ejemplo, un archivo de texto puede verse así:
El panda ADJETIVO caminó hacia el NOUN y luego VERBO. Un NOUN cercano no se vio
afectado por estos eventos.
El programa encontraría estos sucesos y solicitaría al usuario que los
reemplazara.
Ingrese un adjetivo:
tonto
Ingrese un sustantivo:
candelabro
Ingrese un verbo:
gritó
Ingrese un sustantivo:
camioneta
Luego se crearía el siguiente archivo de texto:
El panda tonto caminó hacia el candelabro y luego gritó. Una camioneta cercana
no se vio afectada por estos eventos.
Los resultados deben imprimirse en la pantalla y guardarse en un nuevo archivo de texto.
Búsqueda de expresiones regulares
Escriba un programa que abra todos los archivos .txt en una carpeta y busque cualquier
línea que coincida con una expresión regular proporcionada por el usuario. Los resultados deben
imprimirse en la pantalla.
9
o rg A nizingfile S
En el capítulo anterior, aprendió
a crear y escribir en archivos nuevos en Python.
Sus programas también pueden organizar archivos preexistentes
en el disco duro. Tal vez has tenido el
experiencia de revisar una carpeta llena de docenas,
cientos o incluso miles de archivos y copiarlos,
renombrarlos, moverlos o comprimirlos a mano.
O considere tareas como estas:
• Hacer copias de todos los archivos PDF (y solo los archivos PDF) en cada sub-
carpeta de una carpeta
• Eliminando los ceros iniciales en los nombres de archivo para cada archivo en una carpeta
de
cientos de archivos llamados spam001.txt, spam002.txt, spam003.txt, etc.
• Comprimir el contenido de varias carpetas en un archivo ZIP (que
podría ser un sistema de respaldo simple)
198 Capítulo 9
Todas estas cosas aburridas solo piden ser automatizadas en Python. Al
programar su computadora para realizar estas tareas, puede transformarla en
un empleado de archivos de trabajo rápido que nunca comete errores.
A medida que comience a trabajar con archivos, puede resultarle útil poder
ver rápidamente cuál es la extensión (.txt, .pdf, .jpg, etc.) de un archivo.
Con OS X y Linux, su buscador de archivos probablemente muestre extensiones
automáticamente. Con Windows, las extensiones de archivo pueden estar ocultas de forma
predeterminada.
Para mostrar extensiones, vaya a Inicio 4 Panel de control 4 Apariencia y
personalización 4 Opciones de carpeta . En la pestaña Ver, en Configuración avanzada
, desmarque la casilla Ocultar extensiones para tipos de archivo conocidos.
el módulo shutil
El módulo shutil (o utilidades de shell) tiene funciones que le permiten copiar, mover,
renombrar y eliminar archivos en sus programas Python. Para usar las funciones shutil
, primero deberá usar import shutil.
Copiar archivos y carpetas
El módulo shutil proporciona funciones para copiar archivos, así como carpetas completas.
Llamar a shutil.copy (origen, destino) copiará el archivo en el
origen de la ruta a la carpeta en el destino de la ruta . (Tanto el origen como el destino son
cadenas). Si el destino es un nombre de archivo, se utilizará como el nuevo nombre del
archivo copiado. Esta función devuelve una cadena de la ruta del archivo copiado.
Ingrese lo siguiente en el shell interactivo para ver cómo funciona shutil.copy ()
:
>>> import shutil, os
>>> os.chdir ('C: \\')
u >>> shutil.copy ('C: \\ spam.txt', 'C: \\ delicious')
'C: \\ delicious \\ spam.txt'
v >>> shutil.copy ('eggs.txt', 'C: \\ delicious \\ eggs2.txt')
'C: \\ delicious \\ eggs2.txt'
La primera llamada a shutil.copy () copia el archivo en C: \ spam.txt a la carpeta
C: \ delicious. El valor de retorno es la ruta del archivo recién copiado. Tenga en cuenta que,
dado que se especificó una carpeta como destino u, el
nombre de archivo spam.txt original se utiliza para el nuevo nombre de archivo del archivo
copiado. La segunda
llamada shutil.copy () v también copia el archivo en C: \ eggs.txt a la carpeta C: \ delicious pero le
da
al archivo copiado el nombre eggs2.txt.
Mientras que shutil.copy () copiará un solo archivo, shutil.copytree ()
copiará una carpeta completa y cada carpeta y archivo que contenga. Call-
shutil.copytree ING ( fuente , destino ) copiará la carpeta en la ruta de
origen, junto con todos sus archivos y subcarpetas, a la carpeta en la ruta
de destino . Los parámetros de origen y destino son ambas cadenas. La
función devuelve una cadena de la ruta de la carpeta copiada.
Organizar archivos 199
Ingrese lo siguiente en el shell interactivo:
>>> import shutil, os
>>> os.chdir ('C: \\')
>>> shutil.copytree ('C: \\ bacon', 'C: \\ bacon_backup')
'C: \\ bacon_backup '
La llamada shutil.copytree () crea una nueva carpeta llamada bacon_backup con
el mismo contenido que la carpeta original de tocino . Ahora ha hecho una copia de seguridad de
su precioso tocino precioso.
Mover y renombrar archivos y carpetas
Llamar a shutil.move (origen, destino) moverá el archivo o carpeta en el
origen de la ruta al destino de la ruta y devolverá una cadena de la ruta absoluta de
la nueva ubicación.
Si el destino apunta a una carpeta, el archivo fuente se mueve al destino
y mantiene su nombre de archivo actual. Por ejemplo, ingrese lo siguiente en el
shell interactivo:
>>> import shutil
>>> shutil.move ('C: \\ bacon.txt', 'C: \\ eggs')
'C: \\ eggs \\ bacon.txt'
Suponiendo que ya exista una carpeta llamada eggs en el directorio C: \ , esta
llamada shutil.move () dice: "Mueva C: \ bacon.txt a la carpeta C: \ eggs ".
Si ya hubiera habido un archivo bacon.txt en C: \ eggs, se habría
sobrescrito. Como es fácil sobrescribir accidentalmente archivos de esta manera,
debe tener cuidado al usar move ().
La ruta de destino también puede especificar un nombre de archivo. En el siguiente
ejemplo, el archivo fuente se mueve y cambia de nombre.
>>> shutil.move ('C: \\ bacon.txt', 'C: \\ eggs \\ new_bacon.txt')
'C: \\ eggs \\ new_bacon.txt'
Esta línea dice: "Mueva C: \ bacon.txt a la carpeta C: \ eggs , y mientras
lo hace, cambie el nombre del archivo bacon.txt a new_bacon.txt".
Los dos ejemplos anteriores funcionaron bajo el supuesto de que había
una carpeta de huevos en el directorio C: \ . Pero si no hay una carpeta de huevos , move ()
cambiará el nombre de bacon.txt a un archivo llamado eggs.
>>> shutil.move ('C: \\ bacon.txt', 'C: \\ eggs')
'C: \\ eggs'
Aquí, move () no puede encontrar una carpeta llamada eggs en el directorio C: \ y, por lo tanto,
supone que el destino debe especificar un nombre de archivo, no una carpeta. Por lo tanto, el
archivo de texto bacon.txt cambia su nombre a huevos (un archivo de texto sin la extensión de
archivo .txt
), ¡probablemente no es lo que quería! Esto puede ser un error difícil de detectar en
200 Capítulo 9
sus programas desde la llamada move () pueden hacer felizmente algo que podría ser
bastante diferente de lo que esperaba. Esta es otra razón más para
tener cuidado al usar move ().
Finalmente, las carpetas que conforman el destino ya deben existir,
o Python lanzará una excepción. Ingrese lo siguiente en el
shell interactivo:
>>> shutil.move ('spam.txt', 'c: \\ does_not_exist \\ eggs \\ ham')
Traceback (última llamada más reciente):
Archivo "C: \ Python34 \ lib \ shutil.py", línea 521, en movimiento
os.rename (src, real_dst)
FileNotFoundError: [WinError 3] El sistema no puede encontrar la ruta especificada:
'spam.txt' -> 'c: \\ does_not_exist \\ eggs \\ ham'
Durante el manejo de la excepción anterior, se produjo otra excepción:
Rastreo (última llamada más reciente):
Archivo "<pyshell # 29>", línea 1, en <module>
shutil.move ('spam.txt', 'c: \\ does_not_exist \\ eggs \\ ham')
Archivo " C: \ Python34 \ lib \ shutil.py ", línea 533, en movimiento
copy2 (src, real_dst)
Archivo" C: \ Python34 \ lib \ shutil.py ", línea 244, en copy2
copyfile (src, dst, follow_symlinks = follow_symlinks)
Archivo "C: \ Python34 \ lib \ shutil.py", línea 108, en copyfile
con open (dst, 'wb') como fdst:
FileNotFoundError: [Errno 2] No existe dicho archivo o directorio: 'c: \\ no_existe \\
huevos \\ jamón '
Python busca huevos y jamón dentro del directorio does_not_exist . No
encuentra el directorio inexistente, por lo que no puede mover spam.txt a la ruta
que especificó.
Eliminación permanente de archivos y carpetas
Puede eliminar un solo archivo o una única carpeta vacía con funciones en el
módulo os, mientras que para eliminar una carpeta y todo su contenido, utilice el
módulo shutil.

• Llamar a os.unlink (ruta) eliminará el archivo en la ruta. • Llamar a os.rmdir ( ruta ) eliminará la
carpeta en la ruta . Esta carpeta debe ser

Vacío de cualquier archivo o carpeta.


• Llamar a shutil.rmtree (ruta) eliminará la carpeta en la ruta y todos los archivos
y las carpetas que contiene también se eliminarán.
¡Tenga cuidado al usar estas funciones en sus programas! A menudo es una
buena idea ejecutar primero su programa con estas llamadas comentadas y
con las llamadas print () agregadas para mostrar los archivos que se eliminarían. Aquí está
Organizar archivos 201
un programa de Python que estaba destinado a eliminar archivos que tienen la
extensión de archivo .txt pero tiene un error tipográfico (resaltado en negrita) que hace que elimine
los archivos .rxt
importar os
para nombre de archivo en os.listdir ():
if filename.endswith ('. r xt'):
os.unlink (filename)
Si tuviera algún archivo importante que terminara con .rxt, se habría
eliminado accidentalmente de forma permanente. En su lugar, primero debería haber ejecutado el
programa de esta manera:
import os
para nombre de archivo en os.listdir ():
if filename.endswith ('. rxt'):
# os.unlink (filename)
print (filename)
Ahora se comenta la llamada os.unlink (), por lo que Python la ignora. En su lugar,
imprimirá el nombre de archivo del archivo que se habría eliminado. La ejecución de
esta versión del programa primero le mostrará que accidentalmente le ha dicho
al programa que elimine los archivos .rxt en lugar de los archivos .txt.
Una vez que esté seguro de que el programa funciona según lo previsto, elimine la línea de
impresión (nombre de archivo) y elimine el comentario de la línea os.unlink (nombre de
archivo). Luego
ejecute el programa nuevamente para eliminar realmente los archivos.
Elimina de forma segura con el módulo send2trash
Dado que la función incorporada shutil.rmtree () de Python elimina irreversiblemente archivos
y carpetas, puede ser peligroso de usar. Una forma mucho mejor de eliminar archivos y
carpetas es con el módulo send2trash de terceros. Puede instalar este módulo
ejecutando pip install send2trash desde una ventana de Terminal. (Consulte el Apéndice
A para obtener una explicación más detallada de cómo instalar módulos de terceros).
Usar send2trash es mucho más seguro que las funciones de eliminación regulares de Python,
ya que enviará carpetas y archivos a la papelera o papelera de reciclaje de su computadora en
lugar de eliminarlos permanentemente. Si un error en su programa elimina
algo con send2trash que no tenía la intención de eliminar, más tarde puede restaurarlo
desde la papelera de reciclaje.
Después de haber instalado send2trash, ingrese lo siguiente en el shell interactivo
:
>>> import send2trash
>>> baconFile = open ('bacon.txt', 'a') # crea el archivo
>>> baconFile.write ('Bacon no es un vegetal.')
25
>>> baconFile.close ( )
>>> send2trash.send2trash ('bacon.txt')
202 Capítulo 9
En general, siempre debe usar la función send2trash.send2trash ()
para eliminar archivos y carpetas. Pero si bien el envío de archivos a la papelera de reciclaje le
permite
recuperarlos más tarde, no liberará espacio en el disco, como eliminarlos permanentemente
. Si desea que su programa libere espacio en disco, use las
funciones os y shutil para eliminar archivos y carpetas. Tenga en cuenta que la función send2trash
()
solo puede enviar archivos a la papelera de reciclaje; no puede extraer archivos de él.
caminar por un árbol de directorios
Supongamos que desea cambiar el nombre de cada archivo en alguna carpeta y también cada
archivo en cada
subcarpeta de esa carpeta. Es decir, desea recorrer el árbol de directorios,
tocando cada archivo a medida que avanza. Escribir un programa para hacer esto podría ser
complicado;
Afortunadamente, Python proporciona una función para manejar este proceso por usted.
Veamos la carpeta C: \ delicious con su contenido, que se muestra en la Figura 9-1.
delicioso
C:\
gatos
catnames.txt
zophie.jpg
nuez
gofres
butter.txt
spam.txt
Figura 9-1: una carpeta de ejemplo que
contiene tres carpetas y cuatro archivos
Aquí hay un programa de ejemplo que usa la función os.walk () en el
árbol de directorios de la Figura 9-1:
importar os
para folderName, subcarpetas, nombres de archivo en os.walk ('C: \\ delicious'):
print ('La carpeta actual es' + folderName)
para subcarpetas en subcarpetas:
print ('SUBFOLDER OF' + folderName + ':' + subfolder)
Organizar archivos 203
para nombre de archivo en nombres de archivo:
print ('FILE INSIDE' + folderName + ':' + filename)

print ('')
La función os.walk () pasa un solo valor de cadena: la ruta de una
carpeta. Puede usar os.walk () en una declaración de bucle for para recorrer un
árbol de directorios , de forma muy similar a cómo puede usar la función range () para recorrer un
rango de
números. A diferencia de range (), la función os.walk () devolverá tres valores en
cada iteración a través del bucle:
1. Una cadena del nombre de la carpeta actual
2. Una lista de cadenas de las carpetas en la carpeta actual
3. Una lista de cadenas de los archivos en la carpeta actual
(Por carpeta actual, me refiero a la carpeta para la iteración actual del
bucle for. Os.walk () no cambia el directorio de trabajo actual del programa
).
Al igual que puede elegir el nombre de la variable i en el código para i en el
rango (10) :, también puede elegir los nombres de las variables para los tres valores
enumerados anteriormente. Usualmente uso los nombres de carpetas, subcarpetas y nombres de
archivos.
Cuando ejecuta este programa, generará lo siguiente:
La carpeta actual es C: \ delicious
SUBFOLDER OF C: \ delicious: cats
SUBFOLDER OF C: \ delicious: walnut
ARCHIVO INTERIOR C: \ delicious: spam.txt
La carpeta actual es C: \ delicious \ cats
ARCHIVO INTERIOR C: \ delicious \ cats: catnames.txt
ARCHIVO INTERIOR C: \ delicious \ cats: zophie.jpg
La carpeta actual es C: \ delicious \ walnut
SUBFOLDER DE C: \ delicious \ walnut: waffles
La carpeta actual es C: \ delicious \ walnut \ waffles
ARCHIVO DENTRO DE C: \ delicious \ walnut \ waffles: butter.txt.
Dado que os.walk () devuelve listas de cadenas para las
variables de subcarpeta y nombre de archivo , puede usar estas listas en sus propios
bucles. Reemplace las
llamadas a la función print () con su propio código personalizado. (O si no necesita uno o
ambos, elimine los bucles for).
compresión de archivos con el módulo zipfile
Es posible que esté familiarizado con los archivos ZIP (con la extensión de archivo .zip), que
pueden contener el contenido comprimido de muchos otros archivos. Comprimir un archivo
reduce su tamaño, lo cual es útil cuando se transfiere a través de Internet. Y
204 Capítulo 9
Dado que un archivo ZIP también puede contener múltiples archivos y
subcarpetas, es una forma práctica de empaquetar varios archivos
en uno. Este archivo único, llamado archivo de almacenamiento, puede
adjuntarse, por ejemplo, a un correo electrónico.
Sus programas Python pueden crear
y abrir (o extraer) archivos ZIP utilizando funciones
en el módulo zipfile. Supongamos que tiene un archivo ZIP
llamado example.zip que tiene el contenido que se muestra
en la Figura 9-2.
Puede descargar este archivo ZIP desde http: //
nostarch.com/automatestuff/ o simplemente seguir
usando un archivo ZIP que ya está en su computadora.
Lectura de archivos ZIP
Para leer el contenido de un archivo ZIP, primero debe crear un objeto ZipFile
(tenga en cuenta las letras mayúsculas Z y F ). Los objetos ZipFile son conceptualmente similares
a los objetos File que vio devueltos por la función open () en el
capítulo anterior : son valores a través de los cuales el programa interactúa con el archivo.
Para crear un objeto ZipFile, llame a la función zipfile.ZipFile (), pasándole una
cadena del nombre de archivo del archivo .zip. Tenga en cuenta que zipfile es el nombre
del módulo Python
, y ZipFile () es el nombre de la función.
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> importar zipfile, os
>>> os.chdir ('C: \\') # mover a la carpeta con example.zip
>>> exampleZip = zipfile.ZipFile ('example.zip')
>>> exampleZip. namelist ()
['spam.txt', 'cats /', 'cats / catnames.txt', 'cats / zophie.jpg']
>>> spamInfo = exampleZip.getinfo ('spam.txt')
>>> spamInfo .file_size
13908
>>> spamInfo.compress_size
3828
u >>> '¡El archivo comprimido es% sx más pequeño!' % (round (spamInfo.file_size /
spamInfo .compress_size, 2)) '¡El archivo comprimido es 3.63x más
pequeño!' >>> ejemploZip.close ()

Un objeto ZipFile tiene un método namelist () que devuelve una lista de cadenas
para todos los archivos y carpetas contenidos en el archivo ZIP. Estas cadenas se pueden
pasar al método ZipFile getinfo () para devolver un objeto ZipInfo sobre ese
archivo en particular. Los objetos ZipInfo tienen sus propios atributos, como file_size
y compress_size en bytes, que contienen enteros del tamaño del archivo original y
el tamaño del archivo comprimido, respectivamente. Mientras que un objeto ZipFile representa un
archivo de archivo completo , un objeto ZipInfo contiene información útil sobre un solo archivo en
el archivo.
El comando en u calcula cuán eficientemente se comprime example.zip
dividiendo el tamaño del archivo original por el tamaño del archivo comprimido e imprime esta
información usando una cadena formateada con% s.
gatos
catnames.txt
zophie.jpg
spam.txt
Figura 9-2: El contenido
del ejemplo .zip
Organizar archivos 205
Extracción de archivos ZIP
El método extractall () para objetos ZipFile extrae todos los archivos y carpetas
de un archivo ZIP en el directorio de trabajo actual.
>>> import zipfile, os
>>> os.chdir ('C: \\') # mover a la carpeta con example.zip
>>> exampleZip = zipfile.ZipFile ('example.zip')
u >>> exampleZip.extractall ()
>>> exampleZip.close ()
Después de ejecutar este código, el contenido de example.zip se extraerá
a C: \ . Opcionalmente, puede pasar un nombre de carpeta a extractall () para que
extraiga los archivos en una carpeta que no sea el directorio de trabajo actual. Si
la carpeta pasada al método extractall () no existe, se creará.
Por ejemplo, si reemplaza la llamada en u con exampleZip.extractall ('C: \\
delicious'), el código extraerá los archivos de example.zip en una carpeta C: \ delicious recién
creada .
El método extract () para objetos ZipFile extraerá un solo archivo del
archivo ZIP. Continúe con el ejemplo de shell interactivo:
>>> exampleZip.extract ('spam.txt')
'C: \\ spam.txt'
>>> exampleZip.extract ('spam.txt', 'C: \\ algunas \\ nuevas \\ carpetas')
' C: \\ some \\ new \\ folder \\ spam.txt '
>>> exampleZip.close ()
La cadena que pasa a extract () debe coincidir con una de las cadenas en la
lista devuelta por namelist (). Opcionalmente, puede pasar un segundo argumento para
extraer () para extraer el archivo en una carpeta que no sea el
directorio de trabajo actual . Si este segundo argumento es una carpeta que aún no existe, Python
creará la carpeta. El valor que extract () devuelve es la ruta absoluta
a la que se extrajo el archivo.
Creación y adición a archivos ZIP
Para crear sus propios archivos ZIP comprimidos, debe abrir el objeto ZipFile
en modo de escritura pasando 'w' como segundo argumento. (Esto es similar a
abrir un archivo de texto en modo de escritura pasando 'w' a la función open ()).
Cuando pasa una ruta al método write () de un objeto ZipFile, Python
comprime el archivo en esa ruta y lo agrega al archivo ZIP. El
primer argumento del método write () es una cadena del nombre de archivo para agregar. El
segundo argumento
es el parámetro del tipo de compresión , que le dice a la computadora qué algoritmo
debe usar para comprimir los archivos; siempre puede establecer este valor en
zipfile.ZIP_DEFLATED. (Esto especifica el algoritmo de compresión desinflado, que
funciona bien en todos los tipos de datos). Ingrese lo siguiente en el shell interactivo:
>>> import zipfile
>>> newZip = zipfile.ZipFile ('new.zip', 'w')
>>> newZip.write ('spam.txt', compress_type = zipfile.ZIP_DEFLATED)
>>> newZip.close ( )
206 Capítulo 9
Este código creará un nuevo archivo ZIP llamado new.zip que tiene el
contenido comprimido de spam.txt .
Tenga en cuenta que, al igual que con la escritura en archivos, el modo de escritura borrará
todos los contenidos existentes de un archivo ZIP. Si desea simplemente agregar archivos a un
archivo ZIP existente , pase 'a' como segundo argumento a zipfile.ZipFile () para abrir
el archivo ZIP en modo de agregado.
Proyecto: renombrar archivos con fechas de estilo americano a fechas de estilo
europeo
Digamos que su jefe le envía por correo electrónico miles de archivos con fechas de estilo
americano
(MM-DD-AAAA) en sus nombres y necesita cambiarles el nombre a
fechas de estilo europeo (DD-MM-AAAA). Esta tarea aburrida podría tomar todo el día para hacer
por
la mano! Escribamos un programa para hacerlo en su lugar.
Esto es lo que hace el programa:
• Busca todos los nombres de archivo en el directorio de trabajo actual para fechas de estilo
americano.
• Cuando se encuentra uno, cambia el nombre del archivo con el mes y el día intercambiados para
que sea de estilo europeo.
Esto significa que el código deberá hacer lo siguiente:
• Cree una expresión regular que pueda identificar el patrón de texto de fechas de estilo
americano. • Llame a os.listdir () para encontrar todos los archivos en el directorio de
trabajo. • Pase sobre cada nombre de archivo, usando la expresión regular para verificar si tiene una
fecha. • Si tiene una fecha, cambie el nombre del archivo con shutil.move ().

Para este proyecto, abra una nueva ventana del editor de archivos y guarde su código como
renameDates.py .
Paso 1: Cree una expresión regular para fechas de estilo americano
La primera parte del programa deberá importar los módulos necesarios
y crear una expresión regular que pueda identificar las fechas MM-DD-AAAA. Los comentarios de
tareas
le recordarán lo que queda por escribir en este programa. Escribiéndolos como
TODO los hace fáciles de encontrar usando la función de búsqueda ctrl-F de IDLE. Haga que
su código tenga
el siguiente aspecto:
#! python3
# renameDates.py - Renombra los nombres de archivo con el formato de fecha estadounidense
MM-DD-AAAA
# a DD-MM-AAAA europeo.
importa shutil, os, re
# Cree una expresión regular que coincida con los archivos con el formato de fecha
estadounidense.
v datePattern = re.compile (r "" "^ (. *?) # todo el texto anterior a la fecha
((0 | 1)? \ D) - # uno o dos dígitos para el mes
Organizar archivos 207
((0 | 1 | 2 | 3)? \ D) - # uno o dos dígitos para el día
((19 | 20) \ d \ d) # cuatro dígitos para el año
(. *?) $ # Todo el texto después la fecha
w "" ", re.VERBOSE)
# TODO: recorre los archivos en el directorio de trabajo.
# TODO: salta archivos sin fecha.
# TODO: Obtenga las diferentes partes del nombre del archivo.
# TODO: forma el nombre de archivo de estilo europeo.
# TODO: Obtenga las rutas completas y absolutas del archivo.
# TODO: cambie el nombre de los archivos.
En este capítulo, sabrá que la función shutil.move () se puede usar
para cambiar el nombre de los archivos: sus argumentos son el nombre del archivo a renombrar y el
nuevo nombre de archivo. Debido a que esta función existe en el módulo shutil, debe
importar ese módulo u.
Pero antes de renombrar los archivos, debe identificar qué archivos desea
renombrar. Los nombres de archivo con fechas como spam4-4-1984.txt y 01-03-2014eggs.zip deben
renombrarse, mientras que los nombres de archivo sin fechas como littlebrother.epub pueden
ignorarse.
Puede usar una expresión regular para identificar este patrón. Después de importar
el módulo re en la parte superior, llame a re.compile () para crear un objeto Regex v.
Pasar re.VERBOSE para el segundo argumento w permitirá espacios en blanco y
comentarios en la cadena de expresiones regulares para que sea más legible.
La cadena de expresión regular comienza con ^ (. *?) Para que coincida con cualquier texto
al comienzo del nombre de archivo que pueda aparecer antes de la fecha. El grupo
((0 | 1)? \ D) coincide con el mes. El primer dígito puede ser 0 o 1,
por lo que la expresión regular coincide con 12 para diciembre pero también con 02 para
febrero. Este dígito
también es opcional para que el mes pueda ser 04 o 4 para abril. El grupo para
el día es ((0 | 1 | 2 | 3)? \ D) y sigue una lógica similar; 3, 03 y 31 son
números válidos para días. (Sí, esta expresión regular aceptará algunas fechas no válidas, como el
31 de abril de
2014, el 29 de febrero de 2013 y el 15 de febrero de 2014. Las fechas tienen muchos casos
especiales espinosos que
pueden ser fáciles de pasar por alto. Pero por simplicidad, la expresión regular en este programa
funciona lo suficientemente bien
).
Si bien 1885 es un año válido, puede buscar años en el siglo XX o XXI
. Esto evitará que su programa coincida accidentalmente con nombres de
archivos sin fecha con un formato similar a la fecha, como 10-10-1000.txt.
La parte (. *?) $ De la expresión regular coincidirá con cualquier texto que venga después de la
fecha.
Paso 2: Identifique las partes de fecha de los nombres de archivo
A continuación, el programa tendrá que recorrer la lista de cadenas de nombre de archivo devueltas
de os.listdir () y compararlas con la expresión regular. Cualquier archivo que no
208 Capítulo 9
tener una fecha en ellos debe ser omitido. Para los nombres de archivo que tienen una fecha, el
texto coincidente se almacenará en varias variables. Complete los primeros tres TODO en
su programa con el siguiente código:
#! python3
# renameDates.py - Renombra los nombres de archivo con el formato de fecha estadounidense
MM-DD-AAAA
# a DD-MM-AAAA europeo.
- cortar -
# Recorrer los archivos en el directorio de trabajo.
para amerFilename en os.listdir ('.'):
mo = datePattern.search (amerFilename)
# Saltar archivos sin fecha.
u if mo == Ninguno:
v continuar
w # Obtener las diferentes partes del nombre del archivo.
beforePart = mo.group (1)
monthPart = mo.group (2)
dayPart = mo.group (4)
yearPart = mo.group (6)
afterPart = mo.group (8)
- cortar -
Si el objeto Match devuelto por el método search () es None u, entonces
el nombre del archivo en amerFilename no coincide con la expresión regular. La
instrucción continue v omitirá el resto del ciclo y pasará al siguiente
nombre de archivo.
De lo contrario, las diversas cadenas que coinciden en los
grupos de expresiones regulares se almacenan en variables denominadas beforePart, monthPart,
dayPart, yearPart
y afterPart w. Las cadenas de estas variables se utilizarán para formar el
nombre de archivo de estilo europeo en el siguiente paso.
Para mantener los números de grupo rectos, intente leer la expresión regular desde el
principio y cuente cada vez que encuentre un paréntesis inicial
. Sin pensar en el código, simplemente escriba un esquema de la expresión regular
. Esto puede ayudarlo a visualizar los grupos. Por ejemplo:
datePattern = re.compile (r "" "^ ( 1 ) # todo el texto antes de la fecha
( 2 ( 3 )) - # uno o dos dígitos para el mes
( 4 ( 5 )) - # uno o dos dígitos para el día
( 6 ( 7 )) # cuatro dígitos para el año
( 8 ) $ # todo el texto después de la fecha
"" ", re.VERBOSE)
Aquí, los números del 1 al 8 representan los grupos en la
expresión regular que escribió. Haciendo un resumen de la expresión regular, con
sólo los paréntesis y los números de grupo, le puede dar una comprensión más clara
ing de la expresión regular antes de seguir adelante con el resto del programa.
Organizar archivos 209
Paso 3: forme el nuevo nombre de archivo y cambie el nombre de los archivos
Como paso final, concatene las cadenas en las variables hechas en el
paso anterior con la fecha de estilo europeo: la fecha es anterior al mes.
Complete los tres TODO restantes en su programa con el siguiente código:
#! python3
# renameDates.py - Renombra los nombres de archivo con el formato de fecha estadounidense
MM-DD-AAAA
# a DD-MM-AAAA europeo.
- cortar -
# Forma el nombre de archivo de estilo europeo.
u euroFilename = beforePart + dayPart + '-' + monthPart + '-' + yearPart +
afterPart
# Obtenga las rutas de archivos completas y absolutas.
absWorkingDir = os.path.abspath ('.')
amerFilename = os.path.join (absWorkingDir, amerFilename)
euroFilename = os.path.join (absWorkingDir, euroFilename)
# Cambiar el nombre de los archivos.
v print ('Renombrando "% s" a "% s" ...'% (amerFilename, euroFilename))
w # shutil.move (amerFilename, euroFilename) # descomenta después de la prueba
Almacene la cadena concatenada en una variable llamada euroFilename u. Luego,
pase el nombre del archivo original en amerFilename y la nueva variable euroFilename
a la función shutil.move () para cambiar el nombre del archivo w.
Este programa tiene la llamada shutil.move () comentada y en su lugar
imprime los nombres de archivo que se renombrarán v. Ejecutar el programa como este
primero puede permitirle verificar que los archivos se renombren correctamente. Luego
puede descomentar la llamada shutil.move () y ejecutar el programa nuevamente para
cambiar el nombre de los archivos.
Ideas para programas similares
Hay muchas otras razones por las que es posible que desee cambiar el nombre de una gran cantidad
de archivos.
• Para agregar un prefijo al inicio del nombre de archivo, como agregar spam_ a
cambie el nombre de eggs.txt a spam_eggs.txt
• Para cambiar los nombres de archivo con fechas de estilo europeo a fechas de estilo
americano • Para eliminar los ceros de archivos como spam0042.txt

Proyecto: Copia de seguridad de una carpeta en un archivo ziP


Supongamos que está trabajando en un proyecto cuyos archivos guarda en una carpeta llamada
C: \ AlsPythonBook . Le preocupa perder su trabajo, por lo que le gustaría
crear "instantáneas" de archivos ZIP de toda la carpeta. Le gustaría conservar
diferentes versiones, por lo que desea que el nombre de archivo del archivo ZIP se incremente cada
vez que se crea; por ejemplo, AlsPythonBook_1.zip , AlsPythonBook_2.zip ,
210 Capítulo 9
AlsPythonBook_3.zip , y así sucesivamente. Podrías hacer esto a mano, pero es bastante
molesto y accidentalmente puedes numerar accidentalmente los nombres de los archivos ZIP. Que
sería mucho más fácil de ejecutar un programa que hace esta tarea aburrida para usted.
Para este proyecto, abra una nueva ventana del editor de archivos y
guárdela como backupToZip.py .
Paso 1: Calcule el nombre del archivo ZIP
El código de este programa se colocará en una función llamada backupToZip ().
Esto facilitará copiar y pegar la función en otros programas de Python
que necesiten esta funcionalidad. Al final del programa, se llamará a la función
para realizar la copia de seguridad. Haga que su programa se vea así:
#! python3
# backupToZip.py: copia una carpeta completa y su contenido en
# un archivo ZIP cuyo nombre de archivo se incrementa.
importas zipfile, os
def backupToZip (carpeta):
# Copia de seguridad de todo el contenido de "carpeta" en un archivo ZIP.
folder = os.path.abspath (carpeta) # asegúrese de que la carpeta sea absoluta
# Calcule el nombre de archivo que este código debe usar en función de
# qué archivos ya existen.
v número = 1
w mientras verdadero:
zipFilename = os.path.basename (carpeta) + '_' + str (número) + '.zip'
si no es os.path.exists (zipFilename): número de
ruptura
= número + 1
x # TODO: crea el archivo ZIP.
# TODO: recorra todo el árbol de carpetas y comprima los archivos en cada carpeta.
print ('Hecho')
backupToZip ('C: \\ delicious')
Primero haga lo básico: agregue la línea shebang (#!), Describa lo que hace el programa
e importe los archivos zip y os u.
Defina una función backupToZip () que tome solo un parámetro, carpeta.
Este parámetro es una ruta de cadena a la carpeta cuyo contenido debe copiarse
. La función determinará qué nombre de archivo usar para el archivo ZIP que
creará; entonces la función creará el archivo, recorrerá la carpeta y agregará
cada una de las subcarpetas y archivos al archivo ZIP. Escriba TODO comentarios para estos
pasos en el código fuente para recordar que debe hacerlos más tarde x.
La primera parte, nombrando el archivo ZIP, usa el nombre base de la
ruta absoluta de la carpeta. Si el ser carpeta de copia de seguridad es C: \ delicioso, del archivo ZIP
nombre debe ser delicious_N.zip, donde N = 1 es la primera vez que ejecute el pro-
gramo, N = 2 es la segunda vez, y así sucesivamente.
Organizar archivos 211
Puede determinar qué N debería ser verificando si delicious_1.zip ya existe, luego verificando
si delicious_2.zip ya existe, y así sucesivamente . Use una variable llamada número para N v, y siga
incrementándola dentro del ciclo que llama a os.path.exists () para verificar si el archivo existe
w. El primer nombre de archivo inexistente encontrado hará que el bucle se rompa, ya que
habrá encontrado el nombre de archivo del nuevo zip.

Paso 2: Crear el nuevo archivo ZIP


A continuación, creemos el archivo ZIP. Haga que su programa tenga el siguiente aspecto:
#! python3
# backupToZip.py: copia una carpeta completa y su contenido en
# un archivo ZIP cuyo nombre de archivo se incrementa.
- snip -
while True:
zipFilename = os.path.basename (carpeta) + '_' + str (número) + '.zip'
si no es os.path.exists (zipFilename): número de
ruptura
= número + 1
# Crear el archivo ZIP.
print ('Creando% s ...'% (zipFilename))
u backupZip = zipfile.ZipFile (zipFilename, 'w')
# TODO: recorra todo el árbol de carpetas y comprima los archivos en cada carpeta.
print ('Hecho')
backupToZip ('C: \\ delicious')
Ahora que el nombre del nuevo archivo ZIP está almacenado en la variable zipFilename,
puede llamar a zipfile.ZipFile () para crear realmente el archivo ZIP u. Asegúrese de
pasar 'w' como segundo argumento para que el archivo ZIP se abra en modo de escritura.
Paso 3: recorra el árbol de directorios y agregue al archivo ZIP
Ahora debe usar la función os.walk () para hacer el trabajo de enumerar cada
archivo en la carpeta y sus subcarpetas. Haga que su programa tenga el siguiente aspecto
:
#! python3
# backupToZip.py: copia una carpeta completa y su contenido en
# un archivo ZIP cuyo nombre de archivo se incrementa.
- cortar -
# Recorre todo el árbol de carpetas y comprime los archivos en cada carpeta.
u para nombre de carpeta, subcarpetas, nombres de archivo en os.walk (carpeta):
print ('Agregando archivos en% s ...'% (nombre de carpeta ))
# Agrega la carpeta actual al archivo ZIP.
v backupZip.write (nombre de carpeta)
212 Capítulo 9
# Agregue todos los archivos de esta carpeta al archivo ZIP.
w para nombre de archivo en nombres de archivo:
newBase / os.path.basename (carpeta) + '_'
si filename.startswith (newBase) y filename.endswith ('. zip')
continúan # no
respalden los archivos ZIP de respaldo backupZip.write (os.path.join (nombre de
carpeta , nombre de archivo)) backupZip.close ()
print ('Listo')
backupToZip ('C: \\ delicious')
Puede usar os.walk () en un bucle for u, y en cada iteración
devolverá el nombre de carpeta actual de la iteración, las subcarpetas en esa carpeta
y los nombres de archivo en esa carpeta.
En el bucle for, la carpeta se agrega al archivo ZIP v. El
bucle for anidado puede pasar por cada nombre de archivo en la lista de nombres de archivo
w. Cada uno de estos se
agrega al archivo ZIP, a excepción de los ZIP de respaldo previamente realizados.
Cuando ejecute este programa, producirá una salida que se verá más o menos
así:
Creando delicious_1.zip ...
Agregando archivos en C: \ delicious ...
Agregando archivos en C: \ delicious \ cats ...
Agregando archivos en C: \ delicious \ waffles ...
Agregando archivos en C: \ delicious \ walnut ...
Agregando archivos en C: \ delicious \ walnut \ waffles ...
Hecho.
La segunda vez que lo ejecute, colocará todos los archivos en C: \ delicious en un
archivo ZIP llamado delicious_2.zip, y así sucesivamente.
Ideas para programas similares
Puede recorrer un árbol de directorios y agregar archivos a archivos ZIP comprimidos en
varios otros programas. Por ejemplo, puede escribir programas que hagan lo
siguiente:
• Recorrer un árbol de directorios y archivar solo archivos con ciertas extensiones, como .txt o .py ,
y nada más
• Recorrer un árbol de directorios y archivar todos los archivos excepto los archivos .txt y
.py • Buscar la carpeta en un árbol de directorios que tenga la mayor cantidad de archivos

o la carpeta que usa más espacio en disco


Resumen
Incluso si es un usuario experimentado de la computadora, probablemente maneje los archivos
manualmente con el mouse y el teclado. Los exploradores de archivos modernos facilitan el
trabajo con algunos archivos. Pero a veces necesitará realizar una tarea que
tomaría horas usando el explorador de archivos de su computadora.
Organizar archivos 213
Los módulos os y shutil ofrecen funciones para copiar, mover,
renombrar y eliminar archivos. Al eliminar archivos, es posible que desee utilizar
el módulo send2trash para mover archivos a la papelera de reciclaje o la papelera en lugar de
eliminarlos permanentemente. Y al escribir programas que manejan archivos,
es una buena idea comentar el código que hace la copia / mover /
renombrar / eliminar y agregar una llamada print () para que pueda ejecutar el programa
y verificar exactamente lo que hará.
A menudo, necesitará realizar estas operaciones no solo en los archivos de
una carpeta, sino también en cada carpeta de esa carpeta, en cada carpeta de esas carpetas
, etc. La función os.walk () maneja este recorrido a través de las carpetas
por usted para que pueda concentrarse en lo que su programa necesita hacer con
los archivos en ellas.
El módulo zipfile le brinda una forma de comprimir y extraer archivos
en archivos .zip a través de Python. Combinado con las funciones
de manejo de archivos de os y shutil, zipfile hace que sea fácil empaquetar varios archivos desde
cualquier
lugar en su disco duro. Estos archivos .zip son mucho más fáciles de cargar en sitios web
o enviar como archivos adjuntos de correo electrónico que muchos archivos separados.
Los capítulos anteriores de este libro le han proporcionado el código fuente para que copie.
Pero cuando escribe sus propios programas, probablemente no salgan
perfectamente la primera vez. El siguiente capítulo se centra en algunos módulos de Python que
lo ayudarán a analizar y depurar sus programas para que pueda hacer que funcionen correctamente
de manera rápida
.
Preguntas de práctica
1. ¿Cuál es la diferencia entre shutil.copy () y shutil.copytree ()?
2. ¿Qué función se usa para cambiar el nombre de los archivos?
3. ¿Cuál es la diferencia entre las funciones de eliminación en send2trash?
y módulos shutil?
4. Los objetos ZipFile tienen un método close () al igual que close () de los objetos File
método. ¿Qué método ZipFile es equivalente al método open () de los objetos File
?
Proyectos de
práctica Para practicar, escriba programas para realizar las siguientes tareas.
Copia selectiva
Escriba un programa que recorra un árbol de carpetas y busque archivos con
una determinada extensión de archivo (como .pdf o .jpg). Copie estos archivos desde cualquier
ubicación en la que se encuentren en una nueva carpeta.
Eliminación de archivos innecesarios
No es infrecuente que algunos archivos o carpetas que no sean necesarios, pero a gigantescos
ocupan la mayor parte del espacio en el disco duro. Si intentas liberarte
214 Capítulo 9
espacio en su computadora, obtendrá el máximo rendimiento de su dinero al eliminar
el más masivo de los archivos no deseados. Pero primero tienes que encontrarlos.
Escriba un programa que recorra un árbol de carpetas y busque
archivos o carpetas excepcionalmente grandes, por ejemplo, los que tienen un tamaño de archivo de
más de
100 MB. (Recuerde, para obtener el tamaño de un archivo, puede usar os.path.getsize () desde
el módulo os). Imprima estos archivos con su ruta absoluta a la pantalla.
Cómo llenar los
espacios en
blanco Escriba un programa que encuentre todos los archivos con un prefijo dado, como
spam001.txt, spam002.txt , etc., en una sola carpeta y localice los espacios en
blanco en la numeración (como si hubiera un spam001.txt y spam003.txt pero no spam002.txt ).
Haga que el programa cambie el nombre de todos los archivos posteriores para cerrar esta brecha.
Como desafío adicional, escriba otro programa que pueda insertar huecos
en archivos numerados para que se pueda agregar un nuevo archivo.
10
D e B ugging
Ahora que sabe lo suficiente como para escribir programas más
complicados, puede comenzar a encontrar
ing bugs no tan simples en ellos. Este capítulo
cubre algunas herramientas y técnicas para encontrar
La causa raíz de los errores en su programa para ayudarlo a
corregirlos más rápido y con menos esfuerzo.
Parafraseando un viejo chiste entre programadores, “Escribir código
representa el 90 por ciento de la programación. El código de depuración representa
el otro 90 por ciento ".
Su computadora solo hará lo que usted le indique; no leerá tu
mente ni hará lo que pretendías que hiciera. Incluso los programadores profesionales
crean errores todo el tiempo, así que no se desanime si su programa tiene un
problema.
Afortunadamente, hay algunas herramientas y técnicas para identificar qué
está haciendo exactamente su código y dónde va mal. Primero, verá el registro
y las aserciones, dos características que pueden ayudarlo a detectar errores temprano. En general,
cuanto
antes detecte errores, más fácil será corregirlos.
216 Capítulo 10
En segundo lugar, verá cómo usar el depurador. El depurador es una
característica de IDLE que ejecuta un programa una instrucción a la vez, brindándole la
oportunidad de inspeccionar los valores en las variables mientras se ejecuta su código y realizar un
seguimiento de cómo cambian los valores en el transcurso de su programa. Esto es mucho
más lento que ejecutar el programa a toda velocidad, pero es útil ver los
valores reales en un programa mientras se ejecuta, en lugar de deducir cuáles podrían ser los
valores del código fuente.
aumento de excepciones
Python genera una excepción cada vez que intenta ejecutar código no válido. En el
Capítulo 3, leyó acerca de cómo manejar las excepciones de Python con
sentencias try y except para que su programa pueda recuperarse de las excepciones que
anticipó. Pero también puede plantear sus propias excepciones en su código.
Plantear una excepción es una forma de decir: "Deje de ejecutar el código en esta función
y mueva la ejecución del programa a la instrucción except".
Las excepciones se plantean con una declaración de aumento. En el código, una declaración de
aumento
consta de lo siguiente:

• La palabra clave raise • Una llamada a la función Exception () • Una cadena con un mensaje de
error útil pasado a la función Exception ()

Por ejemplo, ingrese lo siguiente en el shell interactivo:


>>> raise Exception ('Este es el mensaje de error.')
Traceback (última llamada más reciente):
Archivo "<pyshell # 191>", línea 1, en <module>
raise Exception ('Este es el mensaje de error.' )
Excepción: este es el mensaje de error.
Si no hay declaraciones try y except que cubran la declaración raise
que provocó la excepción, el programa simplemente se bloquea y muestra el mensaje de error de la
excepción.
A menudo es el código que llama a la función, no la función en sí misma, lo que
sabe cómo manejar una expección. Por lo tanto, comúnmente verá una declaración de aumento
dentro de una función y las declaraciones try y except en el código que llama a
la función. Por ejemplo, abra una nueva ventana del editor de archivos, ingrese el siguiente
código y guarde el programa como boxPrint.py :
def boxPrint (símbolo, ancho, alto):
if len (símbolo)! = 1:
u elevar Excepción ('El símbolo debe ser una cadena de un solo carácter')
si ancho <= 2:
v elevar Excepción ('El ancho debe ser mayor que 2.')
si la altura <= 2:
w aumento Excepción ('La altura debe ser mayor que 2.')
Depuración 217
print (símbolo * ancho)
para i en rango (alto - 2):
print (símbolo + ('' * (ancho - 2)) + símbolo)
print (símbolo * ancho)
para sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)):
intente :
boxPrint (sym, w, h)
x excepto Exception as err:
y print ('Ha ocurrido una excepción:' + str (err))
Aquí hemos definido una función boxPrint () que toma un carácter, un ancho
y un alto, y usa el carácter para hacer una pequeña imagen de un cuadro con
ese ancho y alto. Esta forma de caja se imprime en la pantalla.
Digamos que queremos que el carácter sea un solo carácter, y que el ancho y la
altura sean mayores que 2. Agregamos declaraciones if para generar excepciones si
no se cumplen estos requisitos. Más tarde, cuando llamamos a boxPrint () con
varios argumentos, nuestro try / except manejará argumentos no válidos.
Este programa utiliza la excepción except como forma err de la declaración except
x. Si se devuelve un objeto Exception de boxPrint () uvw, esta
declaración excepto lo almacenará en una variable llamada err. El objeto Exception
se puede convertir en una cadena pasándolo a str () para generar un
mensaje de error fácil de usar y. Cuando ejecute este boxPrint.py , el resultado se
verá así:
****
**
**
****
OOOOOOOOOOOOOOOOOOOO
OO
OO
OO
OOOOOOOOOOOOOOOOOOOO
Se produjo una excepción: el ancho debe ser mayor que 2.
Se produjo una excepción: el símbolo debe ser una cadena de un solo carácter.
Usando las declaraciones try y except, puede manejar los errores con más gracia en
lugar de dejar que todo el programa se bloquee.
Obtener el rastreo como una cadena
Cuando Python encuentra un error, produce un tesoro de
información de error llamado rastreo . El rastreo incluye el mensaje de error,
el número de línea de la línea que causó el error y la secuencia de las
llamadas de función que condujeron al error. Esta secuencia de llamadas se llama la pila de
llamadas .
Abra una nueva ventana del editor de archivos en IDLE, ingrese el siguiente programa
y guárdelo como errorExample.py :
def spam ():
tocino ()
218 Capítulo 10
def bacon ():
raise Exception ('Este es el mensaje de error')
correo no deseado()
Cuando ejecuta errorExample.py , la salida se verá así:
Rastreo (última llamada más reciente):
archivo "errorExample.py", línea 7, en <module>
spam ()
Archivo "errorExample.py", línea 2, en
tocino de spam ()
Archivo "errorExample.py", línea 5, in tocino
raise Exception ('Este es el mensaje de error')
Excepción: Este es el mensaje de error.
Desde el rastreo, puede ver que el error ocurrió en la línea 5, en
la función bacon (). Esta llamada particular a tocino () procedía de la línea 2, en la
función de correo no deseado (), que a su vez fue llamado en la línea 7. En los programas donde
funcio-
nes se pueden llamar desde múltiples lugares, la pila de llamadas que puede ayudar a deter-
mina de qué llamada condujo al error.
Python muestra el rastreo cuando una excepción planteada
no se controla. Pero también puede obtenerlo como una cadena llamando a
traceback.format_exc (). Esta función es útil si desea la información
del rastreo de una excepción, pero también desea que una instrucción except
maneje correctamente la excepción. Deberá importar el módulo de rastreo de Python
antes de llamar a esta función.
Por ejemplo, en lugar de bloquear su programa justo cuando
ocurre una excepción , puede escribir la información de rastreo en un archivo de registro y
mantener
su programa en funcionamiento. Puede mirar el archivo de registro más tarde, cuando esté listo
para depurar su programa. Ingrese lo siguiente en el shell interactivo:
>>> import traceback
>>> try:
raise Exception ('Este es el mensaje de error')
excepto:
errorFile = open ('errorInfo.txt', 'w')
errorFile.write (traceback.format_exc ())
errorFile. close ()
print ('La información de rastreo se escribió en errorInfo.txt.')
116
La información de rastreo se escribió en errorInfo.txt.
El 116 es el valor de retorno del método write (), ya que se escribieron 116 caracteres
en el archivo. El texto de rastreo se escribió en errorInfo.txt.
Traceback (última llamada más reciente):
Archivo "<pyshell # 28>", línea 2, en <module>
Excepción: este es el mensaje de error.
Depuración 219
Afirmaciones
Una afirmación es un control de cordura para asegurarse de que su código no está haciendo algo
obviamente malo. Estas verificaciones de cordura se realizan mediante declaraciones de
afirmación. Si
la comprobación de cordura falla, se genera una excepción AssertionError. En el código, una
declaración de aserción consiste en lo siguiente:

• La palabra clave de aserción • Una condición (es decir, una expresión que se evalúa como
Verdadero o Falso) • Una coma • Una cadena para mostrar cuando la condición es Falsa

Por ejemplo, ingrese lo siguiente en el shell interactivo:


>>> podBayDoorStatus = 'open'
>>> afirmar podBayDoorStatus == 'open', 'Las puertas de la bahía de pod deben estar
"abiertas".
>>> podBayDoorStatus = 'Lo siento, Dave. Me temo que no puedo hacer eso. ''
>>> afirmar podBayDoorStatus == 'abrir', 'Las puertas de la bahía de la vaina deben estar
"abiertas".
Rastreo (la última llamada más reciente):
Archivo "<pyshell # 10>", línea 1, en <module>
afirmar podBayDoorStatus == 'abierto', 'Las puertas del compartimento del módulo deben estar
"abiertas".
AssertionError: las puertas del compartimento del módulo deben estar "abiertas".
Aquí hemos configurado podBayDoorStatus para 'abrir', por lo que a partir de ahora,
esperamos que el valor de esta variable sea 'abierto'. En un programa que usa esta
variable, podríamos haber escrito mucho código bajo el supuesto de que
el valor es "abierto", código que depende de que esté "abierto" para funcionar
como esperamos. Por lo tanto, agregamos una afirmación para asegurarnos de que tenemos razón al
asumir que
podBayDoorStatus está 'abierto'. Aquí, incluimos el mensaje 'Las puertas de la bahía de la vaina
deben estar "abiertas". así que será fácil ver qué pasa si la afirmación falla.
Más tarde, digamos que cometemos el error obvio de asignar a podBayDoorStatus
otro valor, pero no lo notamos entre muchas líneas de código. La afirmación
capta este error y nos dice claramente qué está mal.
En inglés simple, una declaración de afirmación dice: "Afirmo que esta condición
es verdadera, y si no, hay un error en alguna parte del programa". A diferencia de las
excepciones, su código no debe manejar las declaraciones de afirmación con try y
except; Si una afirmación falla, su programa debería bloquearse. Al fallar tan rápido como esto,
acorta el tiempo entre la causa original del error y la
primera vez que nota el error. Esto reducirá la cantidad de código que tendrá que
verificar antes de encontrar el código que está causando el error.
Las afirmaciones son para errores del programador, no para errores del usuario. Para los errores
que
se pueden recuperar (como un archivo que no se encuentra o el usuario que ingresa
datos no válidos), active una excepción en lugar de detectarlo con una
declaración de afirmación.
Uso de una aserción en una simulación de semáforo
Digamos que está creando un programa de simulación de semáforo. La estructura de datos que
representa los semáforos en una intersección es un diccionario con
220 Capítulo 10
teclas 'ns' y 'ew', para los semáforos con orientación norte-sur y este-oeste,
respectivamente. Los valores en estas teclas serán una de las cadenas 'verde',
'amarillo' o 'rojo'. El código se vería así:
market_2nd = {'ns': 'green', 'ew': 'red'}
mission_16th = {'ns': 'red', 'ew': 'green'}
Estas dos variables serán para las intersecciones de Market Street y
2nd Street, y Mission Street y 16th Street. Para comenzar el proyecto,
desea escribir una función switchLights (), que tomará un diccionario de intersección
como argumento y cambiará las luces.
Al principio, podría pensar que switchLights () simplemente debería cambiar cada
luz al siguiente color en la secuencia: cualquier valor 'verde' debería cambiar a
'amarillo', los valores 'amarillo' deberían cambiar a 'rojo' y 'rojo' los valores deberían
cambiar a 'verde'. El código para implementar esta idea podría verse así:
def switchLights (semáforo):
para la clave en stoplight.keys ():
if stoplight [key] == 'green':
stoplight [key] = 'yellow'
elif stoplight [key] == 'yellow':
stoplight [key] =
semáforo elif 'rojo' [clave] == 'rojo':
semáforo [clave] = 'verde'
switchLights (market_2nd)
Es posible que ya vea el problema con este código, pero supongamos que
escribió el resto del código de simulación, de miles de líneas de largo, sin
darse cuenta. Cuando finalmente ejecuta la simulación, el programa no
falla, ¡pero sus autos virtuales sí lo hacen!
Como ya ha escrito el resto del programa, no tiene idea de
dónde podría estar el error. Tal vez esté en el código que simula los autos o en
el código que simula los conductores virtuales. Podría llevar horas rastrear el
error hasta la función switchLights ().
Pero si mientras escribía switchLights () había agregado una afirmación para verificar
que al menos una de las luces siempre es roja , podría haber incluido lo siguiente
en la parte inferior de la función:
afirme 'rojo' en el semáforo. valores (), '¡Ninguna de las luces es roja! '+ str (semáforo)
Con esta afirmación en su lugar, su programa se bloqueará con este mensaje de error
:
Rastreo (última llamada más reciente):
archivo "carSim.py", línea 14, en <module>
switchLights (market_2nd)
Archivo "carSim.py", línea 13, en switchLights
afirma 'rojo' en semáforo. Valores (), ' ¡Ni la luz es roja! '+ str (semáforo)
u AssertionError: ¡Ninguna luz es roja! {'ns': 'amarillo', 'ew': 'verde'}
Depuración 221
La línea importante aquí es el AssertionError u. Si bien el
bloqueo de su programa no es ideal, inmediatamente señala que falló un control de cordura:
ninguna dirección del tráfico tiene una luz roja, lo que significa que el tráfico podría
ir en ambos sentidos. Al fallar rápidamente al principio de la ejecución del programa, puede
ahorrarse mucho esfuerzo de depuración en el futuro.
Deshabilitación de aserciones Las
aserciones se pueden deshabilitar pasando la opción -O al ejecutar Python.
Esto es bueno para cuando haya terminado de escribir y probar su programa
y no desee que se ralentice realizando comprobaciones de sanidad (aunque la
mayoría de las veces las declaraciones de afirmación no causan una diferencia de velocidad notable
). Las afirmaciones son para el desarrollo, no para el producto final. Cuando
entregue su programa a otra persona para que lo ejecute, debe estar libre de errores
y no requerir controles de cordura. Consulte el Apéndice B para obtener detalles sobre cómo
iniciar sus programas probablemente no locos con la opción -O.
registro
Si alguna vez ha puesto una declaración print () en su código para generar el
valor de alguna variable mientras su programa se está ejecutando, ha utilizado una forma
de registro para depurar
su código. El registro es una excelente manera de comprender lo que sucede en su
programa y en qué orden está sucediendo. El módulo de registro de Python
facilita la creación de un registro de mensajes personalizados que usted escribe. Estos
mensajes de registro describirán cuándo la ejecución del programa ha alcanzado la
llamada a la función de registro y enumerarán las variables que haya especificado en ese momento.
Por otro lado, un mensaje de registro que falta indica que una parte del código se
omitió y nunca se ejecutó.
Uso del módulo de registro
Para permitir que el módulo de registro muestre mensajes de registro en su pantalla mientras se
ejecuta su programa, copie lo siguiente en la parte superior de su programa (pero debajo de
la línea #! Python shebang):
registro de importación
logging.basicConfig (nivel = logging.DEBUG, format = '% (asctime) s -% (levelname) s
-% (message) s')
No necesita preocuparse demasiado sobre cómo funciona esto, pero básicamente,
cuando Python registra un evento, crea un objeto LogRecord que contiene información
sobre ese evento. La función basicConfig () del módulo de registro le permite
especificar qué detalles sobre el objeto LogRecord desea ver y cómo
desea que se muestren esos detalles.
Digamos que escribiste una función para calcular el factorial de un número. En
matemáticas, el factorial 4 es 1 × 2 × 3 × 4, o 24. El factorial 7 es 1 × 2 × 3 × 4 × 5 × 6 × 7,
o 5.040. Abra una nueva ventana del editor de archivos e ingrese el siguiente código. Tiene
un error, pero también ingresará varios mensajes de registro para ayudarse a sí mismo a
descubrir qué está sucediendo. Guarde el programa como factorialLog.py .
222 Capítulo 10
registro de importación
logging.basicConfig (nivel = logging.DEBUG, format = '% (asctime) s -% (levelname) s
-% (message) s')
logging.debug ('Inicio del programa')
def factorial (n):
logging.debug ('Inicio del factorial (% s %%)'% (n))
total = 1
para i en el rango (n + 1):
total * = i
logging.debug ('i is '+ str (i) +', el total es '+ str (total))
logging.debug (' Fin del factorial (% s %%) '% (n))
retorno total
print (factorial (5))
logging.debug ('Fin del programa')
Aquí, utilizamos la función logging.debug () cuando queremos imprimir
información de registro . Esta función debug () llamará a basicConfig () y
se imprimirá una línea de información . Esta información estará en el formato que especificamos
en basicConfig () e incluirá los mensajes que pasamos a debug (). La
llamada print (factorial (5)) es parte del programa original, por lo que el resultado se muestra
incluso si los mensajes de registro están deshabilitados.
El resultado de este programa se ve así:
2015-05-23 16: 20: 12,664 - DEBUG - Inicio del programa
2015-05-23 16: 20: 12,664 - DEBUG - Inicio del factorial (5)
2015-05-23 16: 20: 12,665 - DEBUG - i is 0, total es 0
2015-05-23 16: 20: 12,668 - DEBUG - i es 1, total es 0
2015-05-23 16: 20: 12,670 - DEBUG - i es 2, total es 0
2015-05-23 16: 20: 12,673 - DEPURACIÓN - i es 3, total es 0
2015-05-23 16: 20: 12,675 - DEPURACIÓN - i es 4, total es 0
2015-05-23 16: 20: 12,678 - DEPURACIÓN - i es 5, el total es 0
2015-05-23 16: 20: 12,680 - DEPURACIÓN - Fin del factorial (5)
0
2015-05-23 16: 20: 12,684 - DEPURACIÓN - Fin del programa
La función factorial () devuelve 0 como factorial de 5, lo cual no es
correcto. El bucle for debe multiplicar el valor en total por los números
del 1 al 5. Pero los mensajes de registro que se muestran mediante logging.debug () muestran que
la
variable i comienza en 0 en lugar de 1. Dado que cero por cualquier cosa es cero, el
El resto de las iteraciones también tienen un valor incorrecto para el total. Los mensajes de registro
proporcionan un rastro de migas de pan que pueden ayudarlo a descubrir cuándo las cosas
comenzaron a salir mal.
Cambie la línea for i in range (n + 1): for i in range ( 1, n + 1) :, y
vuelva a ejecutar el programa. La salida se verá así:
2015-05-23 17: 13: 40,650 - DEBUG - Inicio del programa
2015-05-23 17: 13: 40,651 - DEBUG - Inicio del factorial (5)
2015-05-23 17: 13: 40,651 - DEBUG - i is 1, el total es 1
2015-05-23 17: 13: 40,654 - DEPURACIÓN - i es 2, el total es 2
2015-05-23 17: 13: 40,656 - DEPURACIÓN - i es 3, el total es 6
Depuración 223
2015-05-23 17: 13: 40,659 - DEPURACIÓN - i es 4, total es 24
2015-05-23 17: 13: 40,661 - DEPURACIÓN - i es 5, total es 120
2015-05-23 17: 13: 40,661 - DEPURACIÓN - Fin del factorial (5)
120
2015-05-23 17: 13: 40,666 - DEPURACIÓN - Fin del programa
La llamada factorial (5) devuelve correctamente 120. Los mensajes de registro mostraron
lo que estaba sucediendo dentro del bucle, lo que condujo directamente al error.
Puede ver que las llamadas logging.debug () imprimen no solo las cadenas
que se les han pasado, sino también una marca de tiempo y la palabra DEPURAR .
No depure con print ()
Escribir import log y logging.basicConfig (level = logging.DEBUG, format =
'% (asctime) s -% (levelname) s -% (message) s') es algo difícil de manejar. Es posible que
desee utilizar llamadas print () en su lugar, ¡pero no ceda ante esta tentación! Una vez
que haya terminado de depurar, terminará pasando mucho tiempo eliminando
las llamadas print () de su código para cada mensaje de registro. Incluso podría
eliminar accidentalmente algunas llamadas print () que se estaban utilizando para mensajes que no
son de registro.
Lo bueno de los mensajes de registro es que puede llenar su programa
con la cantidad que desee, y siempre puede deshabilitarlos más tarde agregando
una sola llamada logging.disable (logging.CRITICAL). A diferencia de print (), el módulo
de registro
facilita el cambio entre mostrar y ocultar mensajes de registro.
Los mensajes de registro están destinados al programador, no al usuario. Al usuario
no le importará el contenido de algún valor de diccionario que necesite ver para
ayudar con la depuración; use un mensaje de registro para algo así. Para los
mensajes que el usuario querrá ver, como Archivo no encontrado o Entrada no válida,
ingrese un número , debe usar una llamada print (). No desea privar al
usuario de información útil después de deshabilitar los mensajes de registro.
Niveles de
registro Los niveles de registro proporcionan una manera de clasificar los mensajes de registro por
importancia.
Hay cinco niveles de registro, descritos en la Tabla 10-1, de menor a mayor
importancia. Los mensajes se pueden registrar en cada nivel utilizando una función de registro
diferente
.
tabla 10-1: Niveles de registro en el
nivel de Python Registro Descripción de la función
DEBUG logging.debug () El nivel más bajo. Utilizado para pequeños detalles.
Por lo general, solo le importan estos mensajes
cuando diagnostica problemas.
INFO logging.info () Se utiliza para registrar información sobre
eventos generales en su programa o confirmar que las
cosas están funcionando en su punto en el
programa.
ADVERTENCIA logging.warning () Se usa para indicar un problema potencial que
no impide que el programa funcione
pero que podría hacerlo en el futuro.
( continuación )
224 Capítulo 10
tabla 10-1 ( continuación )
Nivel Registro Función Descripción
ERROR logging.error () Se utiliza para registrar un error que causó
programa para no hacer algo.
CRÍTICA logging.critical () El nivel más alto. Se usa para indicar un fatal
error que ha causado o está a punto de hacer que
el programa deje de ejecutarse por completo.
Su mensaje de registro se pasa como una cadena a estas funciones. Los
niveles de registro son sugerencias. En última instancia, depende de usted decidir a qué categoría
pertenece su mensaje de registro. Ingrese lo siguiente en el shell interactivo:
>>> registro de importación
>>> logging.basicConfig (level = logging.DEBUG, format = '% (asctime) s -
% (levelname) s -% (message) s')
>>> logging.debug ('Some debugging detalles. ')
2015-05-18 19: 04: 26,901 - DEPURACIÓN - Algunos detalles de depuración.
>>> logging.info ('El módulo de registro está funcionando')
2015-05-18 19: 04: 35,569 - INFO - El módulo de registro está funcionando.
>>> logging.warning ('Se está por registrar un mensaje de error')
2015-05-18 19: 04: 56,843 - ADVERTENCIA - Se está por registrar un mensaje de error.
>>> logging.error ('Ha ocurrido un error.')
2015-05-18 19: 05: 07,737 - ERROR - Ha ocurrido un error.
>>> logging.critical ('¡El programa no puede recuperarse!')
2015-05-18 19: 05: 45,794 - CRÍTICO - ¡El programa no puede recuperarse!
El beneficio de los niveles de registro es que puede cambiar la prioridad del
mensaje de registro que desea ver. Pasar logging.DEBUG al
argumento de palabra clave de nivel de la función basicConfig () mostrará mensajes de todos los
niveles de registro (DEBUG es el nivel más bajo). Pero después de desarrollar un
poco más su programa , es posible que solo le interesen los errores. En ese caso, puede establecer el
argumento de nivel de basicConfig () en logging.ERROR. Esto mostrará solo
mensajes ERROR y CRÍTICOS y omitirá los mensajes DEBUG, INFO y WARNING
.
Deshabilitar el registro
Después de haber depurado tu programa, probablemente no quieras que todos estos
mensajes de registro llenen la pantalla. La función logging.disable () los desactiva
para que no tenga que ingresar a su programa y eliminar
manualmente todas las llamadas de registro. Simplemente pasa logging.disable () un nivel de
registro, y
suprimirá todos los mensajes de registro en ese nivel o menos. Entonces, si desea deshabilitar el
registro por completo, simplemente agregue logging.disable (logging.CRITICAL) a su programa.
Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> registro de importación
>>> logging.basicConfig (level = logging.INFO, format = '% (asctime) s -
% (levelname) s -% (message) s')
Depuración 225
>>> logging.critical ('¡Error crítico! ¡Error crítico!')
22/05/2015 11: 10: 48,054 - CRÍTICO - ¡Error crítico! ¡Error crítico!
>>> logging.disable (logging.CRITICAL)
>>> logging.critical ('¡Error crítico! ¡Error crítico!')
>>> logging.error ('¡Error! ¡Error!')
Dado que logging.disable () deshabilitará todos los mensajes después de él, probablemente
desee agregarlo cerca de la línea de código de registro de importación en su programa. De esta
manera, puede encontrarlo fácilmente para comentar o descomentar esa llamada para habilitar
o deshabilitar los mensajes de registro según sea necesario.
Iniciar sesión en un archivo
En lugar de mostrar los mensajes de registro en la pantalla, puede escribirlos en
un archivo de texto. La función logging.basicConfig () toma un argumento de palabra clave de
nombre de archivo
, así:
registro de importación
logging.basicConfig ( filename = 'myProgramLog.txt' , level = logging.DEBUG, format = '
% (asctime) s -% (levelname) s -% (message) s')
Los mensajes de registro se guardarán en myProgramLog.txt . Si bien los
mensajes de registro son útiles, pueden saturar su pantalla y dificultar la lectura de
la salida del programa. Escribir los mensajes de registro en un archivo mantendrá su
pantalla limpia y almacenará los mensajes para que pueda leerlos después de ejecutar el
programa. Puede abrir este archivo de texto en cualquier editor de texto, como el Bloc de notas o
TextEdit.
depurador de inactividad
El depurador es una característica de IDLE que le permite ejecutar su programa
una línea a la vez. El depurador ejecutará una sola línea de código y luego esperará
a que le diga que continúe. Al ejecutar su programa "bajo el depurador
" de esta manera, puede tomar todo el tiempo que desee para examinar los valores
en las variables en cualquier punto dado durante la vida útil del programa. Esta es una
herramienta valiosa para localizar errores.
Para habilitar el depurador de IDLE, haga clic en Debug 4 Debugger en la
ventana del shell interactivo . Esto abrirá la ventana de Control de depuración, que se parece
a la Figura 10-1.
Cuando aparezca la ventana de Control de depuración, seleccione las cuatro casillas de
verificación Pila ,
Locales , Fuente y Globales para que la ventana muestre el
conjunto completo de información de depuración. Mientras se muestra la ventana Control de
depuración,
cada vez que ejecuta un programa desde el editor de archivos, el depurador hará una pausa en la
ejecución antes de la primera instrucción y mostrará lo siguiente:

• La línea de código que está por ejecutarse • Una lista de todas las variables locales y sus
valores • Una lista de todas las variables globales y sus valores
226 Capítulo 10
Figura 10-1: La ventana de Control de depuración
Notarás que en la lista de variables globales hay varias variables
que no has definido, como __builtins__, __doc__, __file__, y así sucesivamente.
Estas son variables que Python establece automáticamente cada vez que ejecuta un programa
. El significado de estas variables está más allá del alcance de este libro,
y puede ignorarlas cómodamente.
El programa permanecerá en pausa hasta que presione uno de los cinco botones en
la ventana de Control de depuración: Ir, Paso, Sobre, Salir o Salir.
Ir
Al hacer clic en el botón Ir, el programa se ejecutará normalmente hasta que
finalice o llegue a un punto de interrupción . (Los puntos de interrupción se describen más adelante
en este
capítulo). Si ha terminado de depurar y desea que el programa continúe
normalmente, haga clic en el botón Ir .
Paso
Al hacer clic en el botón Paso, el depurador ejecutará la siguiente línea
de código y luego se detendrá nuevamente. La lista de la ventana de Control de depuración de
variables globales y locales se actualizará si sus valores cambian. Si la siguiente línea de
código es una llamada de función, el depurador "entrará" en esa función y saltará
a la primera línea de código de esa función.
Over
Al hacer clic en el botón Over se ejecutará la siguiente línea de código, similar al
botón Step. Sin embargo, si la siguiente línea de código es una llamada de función, el
botón Over "pasará" por encima del código en la función. El código de la función se
ejecutará a toda velocidad y el depurador hará una pausa tan pronto como vuelva la llamada a la
función
. Por ejemplo, si la siguiente línea de código es una llamada print (), no
Depuración 227
realmente me importa el código dentro de la función incorporada print (); solo quieres que la
cadena que pasas se imprima en la pantalla. Por esta razón, usar el botón Over
es más común que el botón Step.
Salir
Al hacer clic en el botón Salir, el depurador ejecutará líneas de código
a toda velocidad hasta que regrese de la función actual. Si ha ingresado
a una llamada de función con el botón Paso y ahora simplemente desea seguir
ejecutando instrucciones hasta que salga, haga clic en el botón Salir para “salir”
de la llamada de función actual.
Salir
Si desea detener la depuración por completo y no molestarse en continuar ejecutando
el resto del programa, haga clic en el botón Salir . El botón Salir
terminará inmediatamente el programa. Si desea volver a ejecutar su programa normalmente
, seleccione Debug 4 Debugger nuevamente para deshabilitar el depurador.
Depuración de un programa para agregar números
Abra una nueva ventana del editor de archivos e ingrese el siguiente código:
print ('Ingrese el primer número para agregar:')
first = input ()
print ('Ingrese el segundo número para agregar:')
second = input ()
print ('Ingrese el tercer número para agregar:')
third = input ( )
print ('La suma es' + primero + segundo + tercero)
Guárdelo como buggyAddingProgram.py y ejecútelo primero sin el depurador
habilitado. El programa generará algo como esto:
Ingrese el primer número para agregar:
5
Ingrese el segundo número para agregar:
3
Ingrese el tercer número para agregar:
42
La suma es 5342
El programa no se ha bloqueado, pero la suma es obviamente incorrecta. Vamos a
permitir la ventana Control de depurar y ejecutar de nuevo, esta vez bajo el
depurador.
Cuando presiona F5 o selecciona Ejecutar 4 Ejecutar módulo (con Debug 4 Debugger habilitado
y las cuatro casillas de verificación en la ventana Control de depuración marcadas), el programa
comienza en estado de pausa en la línea 1. El depurador siempre se detendrá en la línea de código.
está a punto de ejecutarse. La ventana de Control de depuración se verá como en la Figura 10-2.

228 Capítulo 10
Figura 10-2: La ventana Control de depuración cuando el programa se
inicia por primera vez bajo el depurador
Haga clic en el botón Over una vez para ejecutar la primera llamada print (). Debe
usar Over en lugar de Step aquí, ya que no desea ingresar al código para
la función print (). La ventana Control de depuración se actualizará a la línea 2, y la
línea 2 en la ventana del editor de archivos se resaltará, como se muestra en la Figura 10-3.
Esto le muestra dónde está actualmente la ejecución del programa.
Figura 10-3: La ventana Control de depuración después de hacer clic en
Depuración 229
Haga clic en Más de nuevo para ejecutar la llamada de función de entrada (), y los botones
en la ventana de eliminar errores de control desactivará a sí mismos mientras espera inactivo por
usted para escribir algo para la llamada de entrada () en la
ventana . Ingrese 5 y presione Retorno. Los botones de la ventana de Control de depuración se
volverán
a habilitar.
Siga haciendo clic en Over , ingresando 3 y 42 como los siguientes dos números, hasta que
el depurador esté en la línea 7, la última llamada print () en el programa. La
ventana de Control de depuración debería verse como la Figura 10-4. Puede ver en la
sección Globals que las variables primera, segunda y tercera se establecen en los valores de cadena
'5',
'3' y '42' en lugar de los valores enteros 5, 3 y 42. Cuando se
ejecuta la última línea , estas cadenas se concatenan en lugar de agregarse juntas, causando
el error.
Figura 10-4: La ventana Control de depuración en la última línea.
Las variables se establecen en cadenas, lo que causa el error.
Pasar por el programa con el depurador es útil, pero también puede
ser lento. A menudo querrá que el programa se ejecute normalmente hasta que alcance una
cierta línea de código. Puede configurar el depurador para hacer esto con puntos de interrupción.
Puntos de
interrupción Un punto de interrupción se puede establecer en una línea de código específica y
obliga al depurador a
pausar cada vez que la ejecución del programa llega a esa línea. Abra una nueva
ventana del editor de archivos e ingrese el siguiente programa, que simula lanzar una
moneda 1,000 veces. Guárdelo como coinFlip.py .
230 Capítulo 10
importar
cabezas aleatorias = 0
para i en el rango (1, 1001):
u si random.randint (0, 1) == 1:
heads = heads + 1
si i == 500:
v print ('¡A mitad de camino!')
print ('Heads came up' + str (heads) + 'times.')
La llamada random.randint (0, 1) u devolverá 0 la mitad del tiempo y 1 la
otra mitad del tiempo. Esto se puede utilizar para simular un lanzamiento de moneda 50/50
donde 1 representa caras. Cuando ejecuta este programa sin el depurador
, rápidamente genera algo como lo siguiente:
¡A medio camino!
Las cabezas aparecieron 490 veces.
Si ejecutó este programa bajo el depurador, tendría que hacer clic en
el botón Over miles de veces antes de que el programa terminara. Si
estaba interesado en el valor de las cabezas en el punto medio de la
ejecución del programa , cuando se han completado 500 de 1000 lanzamientos de monedas, en su
lugar, simplemente podría establecer un punto de interrupción en la impresión de línea ('¡Medio
terminado!') V. un
punto de interrupción, haga clic con el botón derecho en la línea en el editor de archivos y
seleccione Establecer punto de interrupción,
como se muestra en la Figura 10-5.
Figura 10-5: Establecer un punto de interrupción
No desea establecer un punto de interrupción en la línea de la instrucción if, ya que la
instrucción if se ejecuta en cada iteración a través del bucle. Al establecer
el punto de interrupción en el código en la instrucción if, el depurador se rompe solo
cuando la ejecución ingresa la cláusula if.
La línea con el punto de interrupción se resaltará en amarillo en el
editor de archivos . Cuando ejecuta el programa bajo el depurador, se iniciará en un
estado de pausa en la primera línea, como de costumbre. Pero si hace clic en Ir, el programa se
ejecutará a toda velocidad hasta que llegue a la línea con el punto de interrupción
establecido. Usted
puede entonces hacer clic en Ir, encima, el paso o salida para continuar como normal.
Depuración 231
Si desea eliminar un punto de interrupción, haga clic con el botón derecho en la línea en el editor de
archivos
y seleccione Borrar punto de interrupción en el menú. El resaltado amarillo
desaparecerá y el depurador no se romperá en esa línea en el futuro.

Las afirmaciones resumidas , las excepciones, el registro y el depurador son herramientas valiosas
para
encontrar y prevenir errores en su programa. Las afirmaciones con la
declaración de afirmación de Python son una buena manera de implementar "comprobaciones de
cordura" que le dan una
advertencia temprana cuando una condición necesaria no es cierta. Las afirmaciones son
solo para errores de los que el programa no debería intentar recuperarse y deberían
fallar rápidamente. De lo contrario, debe plantear una excepción.
El intento puede detectar y manejar una excepción, excepto las declaraciones
. El módulo de registro es una buena forma de ver su código mientras se está
ejecutando y es mucho más conveniente de usar que la función print ()
debido a sus diferentes niveles de registro y la capacidad de iniciar sesión en un archivo de texto.
El depurador le permite recorrer su programa línea por línea.
Alternativamente, puede ejecutar su programa a velocidad normal y hacer que el
depurador pause la ejecución cada vez que llegue a una línea con un punto de interrupción
establecido.
Usando el depurador, puede ver el estado del valor de cualquier variable en cualquier
momento durante la vida útil del programa.
Estas herramientas y técnicas de depuración lo ayudarán a escribir programas
que funcionen. La introducción accidental de errores en su código es una realidad, no
importa cuántos años de experiencia en codificación tenga.
Preguntas de práctica
1. Escriba una declaración de aserción que desencadene un AssertionError si la variable
spam es un número entero menor que 10.
2. Escriba una declaración de aserción que active un AssertionError si las variables
los huevos y el tocino contienen cadenas que son iguales entre sí, incluso si
sus casos son diferentes (es decir, 'hola' y 'hola' se consideran
iguales, y 'adiós' y 'GOODbye' también se consideran iguales).
3. Escriba una declaración de aserción que siempre desencadene un AssertionError.
4. ¿Cuáles son las dos líneas que debe tener su programa para poder
llamar a logging.debug ()?
5. ¿Cuáles son las dos líneas que debe tener su programa para tener
logging.debug () envía un mensaje de registro a un archivo llamado programLog.txt?
6. ¿Cuáles son los cinco niveles de registro?
7. ¿Qué línea de código puede agregar para deshabilitar todos los mensajes de registro en su
¿programa?
8. ¿Por qué es mejor usar mensajes de registro que usar print () para mostrar
mismo mensaje?
9. ¿Cuáles son las diferencias entre los botones Step, Over y Out en
la ventana de control de depuración?
232 Capítulo 10
10. Después de hacer clic en Ir en la ventana Control de depuración, ¿cuándo se detendrá el
depurador
?
11. ¿Qué es un punto de interrupción?
12. ¿Cómo establece un punto de interrupción en una línea de código en IDLE?
Proyecto de
práctica Para practicar, escriba un programa que haga lo siguiente.
Depuración del lanzamiento de monedas
El siguiente programa está destinado a ser un simple juego de adivinanzas. El
jugador tiene dos conjeturas (es un juego fácil). Sin embargo, el programa tiene
varios errores. Ejecute el programa varias veces para encontrar los errores que impiden que
el programa funcione correctamente.
import random
guess = ''
while guess no in ('heads', 'tails'):
print ('¡Adivina el lanzamiento de la moneda! Ingresa cara o cruz:')
guess = input ()
toss = random.randint (0, 1) # 0 es colas, 1 es cara
si arroja == adivinar:
imprimir ('¡Lo tienes!') Más
:
imprimir ('¡No! ¡Adivina otra vez!')
Guessss = input ()
si arrojar == adivinar:
imprimir ('Tú entendido ')
else:
print (' No, eres realmente malo en este juego ')
11
w e BSC r AP ing
En esos raros y terroríficos momentos en que
no tengo Wi-Fi, me doy cuenta de cuánto
de lo que hago en la computadora es realmente lo que
hago en Internet. Por pura costumbre, encontraré
yo mismo tratando de revisar el correo electrónico, leer las noticias de Twitter de
mis amigos o responder la pregunta: "¿Tuvo Kurtwood Smith
algún papel importante antes de estar en el Robo op original de
1987 ?" 1
Dado que tanto trabajo en una computadora implica
conectarse a Internet, sería genial si sus programas pudieran conectarse. Web scraping es el término
para usar un programa para descargar y procesar contenido de la Web. Por
ejemplo, Google ejecuta muchos programas de raspado web para indexar páginas web para
su motor de búsqueda. En este capítulo, aprenderá sobre varios módulos que
facilitan el raspado de páginas web en Python.
1. La respuesta es no.
234 Capítulo 11
webbrowser Viene con Python y abre un navegador a una página específica.
Solicita descargas de archivos y páginas web de Internet.
Beautiful Soup Parses HTML, el formato en el que se escriben las páginas web.
Selenium Inicia y controla un navegador web. Selenium puede
completar formularios y simular clics del mouse en este navegador.
Proyecto: mapit.py con el módulo webbrowser
La función open () del módulo webbrowser puede iniciar un nuevo navegador en una
URL especificada. Ingrese lo siguiente en el shell interactivo:
>>> importar webbrowser
>>> webbrowser.open ('http://inventwithpython.com/')
Se abrirá una pestaña del navegador web en la URL http://inventwithpython.com/ .
Esto es lo único que puede hacer el módulo webbrowser. Aun así, la función
open () hace posibles algunas cosas interesantes. Por ejemplo,
es tedioso copiar una dirección en el portapapeles y mostrar un mapa
en Google Maps. Podrías dar unos pasos fuera de esta tarea escribiendo un
script simple para iniciar automáticamente el mapa en tu navegador usando el
contenido de tu portapapeles. De esta manera, solo tiene que copiar la dirección en un
portapapeles y ejecutar el script, y el mapa se cargará por usted.
Esto es lo que hace su programa:
• Obtiene una dirección de la calle desde los argumentos de la línea de comandos o el
portapapeles. • Abre el navegador web en la página de Google Maps para la dirección.

Esto significa que su código deberá hacer lo siguiente:

• Lea los argumentos de la línea de comandos de sys.argv. • Leer el contenido del


portapapeles. • Llame a la función webbrowser.open () para abrir el navegador web.

Abra una nueva ventana del editor de archivos y guárdela como mapIt.py.
Paso 1: Calcule la URL
Según las instrucciones del Apéndice B, configure mapIt.py para que cuando lo
ejecute desde la línea de comandos, así. . .
C: \> mapit 870 Valencia St, San Francisco, CA 94110
. . . el script usará los argumentos de la línea de comando en lugar del portapapeles
. Si no hay argumentos de línea de comando, entonces el programa
sabrá usar el contenido del portapapeles.
Web Scraping 235
Primero debe averiguar qué URL usar para una dirección de calle determinada.
Cuando carga http://maps.google.com/ en el navegador y busca una
dirección, la URL en la barra de direcciones se ve así: https: //
www.google.com/maps/place/870+Valencia + St / @ 37.7590311, -122.4215096,17z /
data =! 3m1! 4b1! 4m2! 3m1! 1s0x808f7e3dadc07a37: 0xc86b0b2bb93b73d8 .
La dirección está en la URL, pero también hay mucho texto adicional allí
. Los sitios web a menudo agregan datos adicionales a las URL para ayudar a rastrear visitantes o
personalizar
sitios. Pero si intenta ir a https://www.google.com/maps/place/870+
Valencia + St + San + Francisco + CA /, verá que todavía aparece la
página correcta. Por lo tanto, su programa se puede configurar para abrir un navegador web en
'https: //
www.google.com/maps/place/ your_address_string ' (donde your_address_string es
la dirección que desea asignar).
Paso 2: Maneje los argumentos de la línea de comando
Haga que su código se vea así:
#! python3
# mapIt.py: inicia un mapa en el navegador utilizando una dirección de la
# línea de comando o portapapeles.
import webbrowser, sys
if len (sys.argv)> 1:
# Obtenga la dirección desde la línea de comandos.
address = '' .join (sys.argv [1:])
# TODO: Obtenga la dirección del portapapeles.
Después del # del programa! shebang line, debe importar el
módulo webbrowser para iniciar el navegador e importar el módulo sys para leer los
posibles argumentos de la línea de comandos. La variable sys.argv almacena una lista del
nombre de archivo del programa y los argumentos de la línea de comando. Si esta lista tiene más
que
solo el nombre del archivo, len (sys.argv) se evalúa como un número entero mayor que
1, lo que significa que los argumentos de la línea de comandos se han proporcionado.
Los argumentos de la línea de comando generalmente están separados por espacios, pero en
este caso, desea interpretar todos los argumentos como una sola cadena. Como
sys.argv es una lista de cadenas, puede pasarla al método join (), que devuelve
un solo valor de cadena. No desea el nombre del programa en esta cadena, por lo que en
lugar de sys.argv, debe pasar sys.argv [1:] para cortar el primer elemento
de la matriz. La cadena final a la que se evalúa esta expresión se almacena en
la variable de dirección.
Si ejecuta el programa ingresando esto en la línea de comando. . .
mapit 870 Valencia St, San Francisco, CA 94110
. . . la variable sys.argv contendrá este valor de lista:
['mapIt.py', '870', 'Valencia', 'St', 'San', 'Francisco', 'CA', '94110']
La variable de dirección contendrá la cadena '870 Valencia St, San
Francisco, CA 94110'.
236 Capítulo 11
Paso 3: Maneje el contenido del portapapeles e inicie el navegador
Haga que su código tenga el siguiente aspecto:
#! python3
# mapIt.py: inicia un mapa en el navegador utilizando una dirección de la
# línea de comando o portapapeles.
import webbrowser, sys , pyperclip
if len (sys.argv)> 1:
# Obtenga la dirección desde la línea de comandos.
address = '' .join (sys.argv [1:])
else:
# Obtener dirección del portapapeles.
address = pyperclip.paste ()
webbrowser.open ('https://www.google.com/maps/place/' + dirección)
Si no hay argumentos de línea de comando, el programa asumirá que la
dirección está almacenada en el portapapeles. Puede obtener el contenido del portapapeles con
pyperclip.paste () y almacenarlo en una variable denominada dirección. Finalmente, para iniciar
un navegador web con la URL de Google Maps, llame a webbrowser.open ().
Si bien algunos de los programas que escribe realizarán tareas enormes que le ahorrarán
horas, puede ser igual de satisfactorio utilizar un programa que le
ahorre convenientemente unos segundos cada vez que realice una tarea común, como obtener
un mapa de un habla a. La Tabla 11-1 compara los pasos necesarios para mostrar un
mapa con y sin mapIt.py .
tabla 11-1: Obtener un mapa con y sin mapIt.py
obtener manualmente un mapa con mapIt.py
Resalte la dirección.
Copia la dirección.
Abre el navegador web.
Vaya a http://maps.google.com/.
Haz clic en el campo de texto de la dirección.
Pega la dirección.
Presione enter.
Resalta la dirección.
Copia la dirección.
Ejecute mapIt.py.
¿ Ves cómo mapIt.py hace esta tarea menos tediosa?
Ideas para programas similares
Siempre que tenga una URL, el módulo
de navegador web permite a los usuarios cortar el paso de abrir el navegador y dirigirse a un sitio
web. Otros programas
podrían usar esta funcionalidad para hacer lo siguiente:

• Abra todos los enlaces en una página en pestañas separadas del navegador. • Abra el navegador en
la URL de su clima local. • Abra varios sitios de redes sociales que revisa regularmente.

Web Scraping 237


Descarga de archivos de la Web con el módulo de solicitudes
El módulo de solicitudes le permite descargar fácilmente archivos de la Web sin
tener que preocuparse por problemas complicados como errores de red,
problemas de conexión y compresión de datos. El módulo de solicitudes no viene
con Python, por lo que primero deberá instalarlo. Desde la línea de comandos, ejecute
las solicitudes de instalación de pip . (El Apéndice A tiene detalles adicionales sobre cómo
instalar
módulos de terceros).
El módulo de solicitudes se escribió porque el módulo urllib2 de Python es
demasiado complicado de usar. De hecho, tome un marcador permanente y oscurezca todo este
párrafo. Olvida que alguna vez mencioné urllib2. Si necesita descargar
cosas de la Web, simplemente use el módulo de solicitudes.
A continuación, realice una prueba simple para asegurarse de que el módulo de solicitudes se haya
instalado
correctamente. Ingrese lo siguiente en el shell interactivo:
>>> solicitudes de importación
Si no se muestran mensajes de error, el módulo de solicitudes se ha
instalado correctamente.
Descargar una página web con la función request.get ()
La función request.get () toma una cadena de URL para descargar. Al llamar a
type () en el valor de retorno de request.get (), puede ver que devuelve un
objeto Response , que contiene la respuesta que el servidor web le dio a su solicitud.
Explicaré el objeto Respuesta con más detalle más adelante, pero por ahora, ingrese lo
siguiente en el shell interactivo mientras su computadora está conectada a
Internet:
>>> solicitudes de importación
u >>> res = request.get ('https://automatetheboringstuff.com/files/rj.txt')
>>> tipo (res)
<clase 'request.models.Response'>
v >>> res.status_code == request.codes.ok
Verdadero
>>> len (res.text)
178981
>>> print (res.text [: 250])
El Proyecto Gutenberg EBook de Romeo y Julieta, por William Shakespeare
Este eBook es para el uso de cualquier persona en cualquier lugar sin costo y
casi sin restricciones de ningún tipo. Puede copiarlo, regalarlo o
reutilizarlo según los términos del Proyecto
La URL va a una página web de texto para toda la obra de Romeo y Julieta ,
proporcionada en el sitio u de este libro. Puede decir que la solicitud de esta página web se realizó
correctamente al verificar el atributo status_code del objeto Response.
238 Capítulo 11
Si es igual al valor de request.codes.ok, entonces todo salió bien v.
(Por cierto, el código de estado para "OK" en el protocolo HTTP es 200. Es
posible que ya esté familiarizado con el código de estado 404 para "No Encontró.")
Si la solicitud se realizó correctamente, la página web descargada se almacena como una cadena
en la variable de texto del objeto Respuesta. Esta variable contiene una gran cadena de
toda la obra; la llamada a len (res.text) le muestra que tiene más de
178,000 caracteres de longitud. Finalmente, llamar a print (res.text [: 250]) muestra solo
los primeros 250 caracteres.
Comprobación de errores
Como ha visto, el objeto Response tiene un atributo status_code que puede
verificarse con request.codes.ok para ver si la descarga se realizó correctamente. Una
forma más simple de verificar el éxito es llamar al método raise_for_status () en
el objeto Response. Esto generará una excepción si hubo un error al descargar
el archivo y no hará nada si la descarga se realizó correctamente. Ingrese lo
siguiente en el shell interactivo:
>>> res = request.get ('http://inventwithpython.com/page_that_does_not_exist')
>>> res.raise_for_status ()
Traceback (última llamada reciente):
Archivo "<pyshell # 138>", línea 1, en <module>
res.raise_for_status ()
Archivo "C: \ Python34 \ lib \ site-packages \ request \ models.py", línea 773, en raise_for_status
raise HTTPError (http_error_msg, response = self) request.exceptions.HTTPError
: 404 Client Error no encontrado
El método raise_for_status () es una buena manera de garantizar que un programa se
detenga si se produce una descarga incorrecta. Esto es algo bueno: desea que su programa se
detenga tan pronto como ocurra un error inesperado. Si una descarga fallida no es un factor decisivo
para su programa, puede ajustar la línea raise_for_status () con las declaraciones try y except para
manejar este caso de error sin fallar.
importar solicitudes
res = request.get ('http://inventwithpython.com/page_that_does_not_exist')
intente:
res.raise_for_status ()
excepto Excepción como exc:
print ('Hubo un problema:% s'% (exc))
Esta llamada al método raise_for_status () hace que el programa muestre lo
siguiente:
Hubo un problema: Error de cliente 404: no encontrado
Siempre llame a raise_for_status () después de llamar a request.get (). Desea
asegurarse de que la descarga haya funcionado antes de que su programa continúe.
Web Scraping 239
Guardar archivos descargados en el disco duro
Desde aquí, puede guardar la página web en un archivo en su disco duro con la función
estándar open () y el método write (). Sin
embargo, hay algunas pequeñas diferencias . Primero, debe abrir el archivo en modo binario de
escritura pasando
la cadena 'wb' como segundo argumento para abrir (). Incluso si la página está en sin formato
de texto (como el Romeo y Julieta de texto que ha descargado anteriormente), es necesario
escribir datos binarios en lugar de datos de texto con el fin de mantener el Unicode codifi-
ing del texto.
Para escribir la página web en un archivo, puede usar un bucle for con el método iter_content () del
objeto Response
.
>>> solicitudes de importación
>>> res = request.get ( 'https://automatetheboringstuff.com/files/rj.txt')
>>> res.raise_for_status ()
>>> playFile = open ('RomeoAndJuliet.txt' , 'wb')
>>> para el fragmento en res.iter_content (100000):
playFile.write (fragmento)
100000
78981
>>> playFile.close ()
El método iter_content () devuelve "fragmentos" del contenido en cada
iteración a través del bucle. Cada fragmento es del tipo de datos de bytes y puede
especificar cuántos bytes contendrá cada fragmento. Cien
mil bytes son generalmente de buen tamaño, por lo tanto, pase 100000 como argumento a
iter_content ().
El archivo RomeoAndJuliet.txt ahora existirá en el directorio de trabajo actual
. Tenga en cuenta que si bien el nombre de archivo en el sitio web era rj.txt, el archivo en su
disco duro tiene un nombre de archivo diferente. El módulo de solicitudes simplemente se encarga
de
descargar los contenidos de las páginas web. Una vez que se descarga la página,
son simplemente datos en su programa. Incluso si perdiera su
conexión a Internet después de descargar la página web, todos los datos de la página seguirían en
su computadora.
Codificaciones
Unicode Las codificaciones Unicode están más allá del alcance de este libro, pero puede obtener
más información
sobre ellas en estas páginas web:
• Joel on Software: el mínimo absoluto para cada desarrollador de software
Absolutamente, debe saber positivamente sobre los conjuntos de caracteres y Unicode
(¡sin excusas!): Http://www.joelonsoftware.com/articles/Unicode.html

• Unicode pragmático: http://nedbatchelder.com/text/unipain.html


240 Capítulo 11
El método write () devuelve el número de bytes escritos en el archivo. En
el ejemplo anterior, había 100.000 bytes en el primer fragmento, y la
parte restante del archivo solo necesitaba 78.981 bytes.
Para revisar, aquí está el proceso completo para descargar y guardar un archivo:
1. Llame a request.get () para descargar el archivo.
2. Llame a open () con 'wb' para crear un nuevo archivo en modo binario de escritura.
3. Repita el método iter_content () del objeto Response.
4. Llame a write () en cada iteración para escribir el contenido en el archivo.
5. Llame a close () para cerrar el archivo.
¡Eso es todo lo que hay para el módulo de solicitudes! El material for loop e iter_content ()
puede parecer complicado en comparación con el
flujo de trabajo open () / write () / close () que ha estado utilizando para escribir archivos de texto,
pero es para asegurarse de que el
módulo de solicitudes no se coma Demasiada memoria, incluso si descarga
archivos masivos . Puede obtener más información sobre las otras funciones del módulo de
solicitudes en http: //
request.readthedocs.org/ .
html
Antes de separar las páginas web, aprenderá algunos conceptos básicos de HTML. También
verá cómo acceder a las potentes herramientas de desarrollo de su navegador web, lo que
facilitará mucho más el raspado de información de la Web.
Recursos para el aprendizaje del
lenguaje de marcado de hipertexto HTML (HTML) es el formato en el que se escriben las páginas
web
. En este capítulo se supone que tiene una experiencia básica con HTML, pero
si necesita un tutorial para principiantes, le sugiero uno de los siguientes sitios:

• http://htmldog.com/guides/html/beginner/ • http://www.codecademy.com/tracks/web/ • https://dev


eloper.mozilla.org/en-US/learn/html/

Una actualización rápida


En caso de que haya pasado un tiempo desde que ha mirado cualquier HTML, aquí hay una
descripción rápida de los conceptos básicos. Un archivo HTML es un archivo de texto sin formato
con la
extensión de archivo .html . El texto en estos archivos está rodeado de etiquetas, que son palabras
encerradas entre corchetes angulares. Las etiquetas le dicen al navegador cómo formatear la
página web . Una etiqueta de inicio y una etiqueta de cierre pueden incluir texto para formar
un elemento .
El texto (o HTML interno ) es el contenido entre las
etiquetas de inicio y cierre . Por ejemplo, el siguiente HTML mostrará Hello world! en el
navegador, con Hola en negrita:
<strong> ¡Hola </strong> mundo!
Web Scraping 241
Este HTML se verá como la Figura 11-1 en un navegador.
Figura 11-1: ¡Hola mundo! prestado en
el navegador
La etiqueta <strong> de apertura dice que el texto adjunto aparecerá en negrita.
Las etiquetas de cierre </strong> le indican al navegador dónde está el final del texto en negrita.
Hay muchas etiquetas diferentes en HTML. Algunas de estas etiquetas tienen
propiedades adicionales en forma de atributos dentro de los corchetes angulares. Por ejemplo,
la etiqueta <a> encierra el texto que debería ser un enlace. La URL a la que se vincula el texto
está determinada por el atributo href. Aquí hay un ejemplo:
<a href="http://inventwithpython.com"> libros de Python </a> gratuitos de Al.
Este HTML se verá como la Figura 11-2 en un navegador.
Figura 11-2: El enlace representado en el navegador
Algunos elementos tienen un atributo de identificación que se utiliza para identificar de forma
exclusiva
el elemento en la página. A menudo le indicará a sus programas que busquen un
elemento por su atributo de identificación, por lo que averiguar el atributo de identificación de un
elemento utilizando las
herramientas de desarrollo del navegador es una tarea común al escribir programas de raspado web.
Visualización del código fuente HTML de una página web
Deberá consultar el código fuente HTML de las páginas web con las que
trabajarán sus programas . Para hacer esto, haga clic con el botón derecho (o presione Ctrl y haga
clic en OS X) en cualquier
página web de su navegador web y seleccione Ver código fuente o Ver código fuente de
página para ver el texto HTML de la página (consulte la Figura 11-3). Este es el texto que
su navegador realmente recibe. El navegador sabe cómo mostrar o representar la página web desde
este HTML.

242 Capítulo 11

Figura 11-3: Ver el origen de una página web


Recomiendo ver el código fuente HTML de algunos de sus
sitios favoritos. Está bien si no comprende completamente lo que está viendo cuando
mira la fuente. No necesitará dominio de HTML para escribir programas simples de
raspado web ; después de todo, no escribirá sus propios sitios web. Usted
sólo tiene suficiente conocimiento para seleccionar datos de un sitio existente.
Apertura de las herramientas de desarrollo de su navegador
Además de ver la fuente de una página web, puede consultar el
HTML de una página utilizando las herramientas de desarrollo de su navegador. En Chrome e
Internet
Explorer para Windows, las herramientas para desarrolladores ya están instaladas y
puede presionar F12 para que aparezcan (consulte la Figura 11-4). Al presionar F12 nuevamente
, las herramientas de desarrollador desaparecerán. En Chrome, también puede abrir
las herramientas de desarrollador seleccionando View4Developer4Developer Tools.
En OS X, presionar z-option-I abrirá las Herramientas para desarrolladores de Chrome.
Web Scraping 243
Figura 11-4: La ventana Herramientas para desarrolladores en el navegador Chrome
En Firefox, puede abrir el Inspector de herramientas de desarrollador web
presionando ctrl-ShiFt-c en Windows y Linux o presionando z-option-c
en OS X. El diseño es casi idéntico a las herramientas de desarrollador de Chrome.
En Safari, abra la ventana de Preferencias, y en el panel Avanzado
marque la opción Mostrar menú de Desarrollo en la barra de menú . Después de que se haya
habilitado, puede abrir las herramientas de desarrollador presionando z-option-i.
Después de habilitar o instalar las herramientas de desarrollador en su navegador, puede
hacer clic con el botón derecho en cualquier parte de la página web y seleccionar Inspeccionar
elemento en el
menú contextual para que aparezca el HTML responsable de esa parte de la página.
Esto será útil cuando comience a analizar HTML para sus programas de raspado web
.
No use r egul A rex Pr e SSionS to PA rSe ht ml
Localizar una pieza específica de HTML en una cadena parece un caso perfecto para
expresiones regulares. Sin embargo, te aconsejo que no lo hagas. Hay muchas
maneras diferentes en que HTML puede formatearse y aún considerarse HTML válido, pero
tratar de capturar todas estas posibles variaciones en una expresión regular puede ser
tedioso y propenso a errores. Es menos probable que un módulo desarrollado específicamente para
analizar HTML,
como Beautiful Soup, genere errores.
Puede encontrar un argumento extendido de por qué no debe analizar HTML
con expresiones regulares en http://stackoverflow.com/a/1732454/1893164/.
244 Capítulo 11
Uso de las herramientas de desarrollador para encontrar elementos HTML
Una vez que su programa haya descargado una página web utilizando el módulo de solicitudes,
tendrá el contenido HTML de la página como un valor de cadena único. Ahora
debe averiguar qué parte del HTML corresponde a la información
de la página web que le interesa.
Aquí es donde pueden ayudar las herramientas de desarrollo del navegador. Digamos que desea
escribir un programa para obtener datos de pronóstico del tiempo de http://weather.gov/ .
Antes de escribir cualquier código, investigue un poco. Si visita el sitio y busca
el código postal 94105, el sitio lo llevará a una página que muestra el pronóstico
para esa área.
¿Qué sucede si está interesado en raspar la información de temperatura para
ese código postal? Haga clic derecho donde está en la página (o presione la tecla control y haga clic
en OS X)
y seleccione Inspeccionar elemento en el menú contextual que aparece. Aparecerá
la ventana Herramientas para desarrolladores, que le muestra el HTML que
produce esta parte particular de la página web. La Figura 11-5 muestra las herramientas
de desarrollador
abiertas al HTML de la temperatura.
Figura 11-5: Inspeccionar el elemento que contiene el texto de temperatura con las herramientas
de desarrollo
Desde las herramientas del desarrollador, puede ver que el HTML responsable
de la parte de temperatura de la página web es <p class = "myforecast-current
-lrg"> 59 ° F </p>. ¡Esto es exactamente lo que estabas buscando! Parece que
la información de temperatura está contenida dentro de un elemento <p> con la
clase myforecast-current-lrg. Ahora que sabe lo que está buscando, el
módulo BeautifulSoup lo ayudará a encontrarlo en la cadena.
Web Scraping 245
Analizando html con el módulo
BeautifulSoup Beautiful Soup es un módulo para extraer información de una
página HTML (y es mucho mejor para este propósito que las expresiones regulares). El
nombre del módulo BeautifulSoup es bs4 (para Beautiful Soup, versión 4). Para instalarlo
, deberá ejecutar pip install beautifulsoup4 desde la línea de comandos.
(Consulte el Apéndice A para obtener instrucciones sobre cómo instalar módulos de terceros).
Si bien beautifulsoup4 es el nombre utilizado para la instalación, para importar Beautiful
Soup ejecuta import bs4.
Para este capítulo, los ejemplos de Beautiful Soup analizarán (es decir, analizarán
e identificarán las partes de) un archivo HTML en el disco duro. Abra una nueva
ventana del editor de archivos en IDLE, ingrese lo siguiente y guárdelo como example.html.
Alternativamente, descárguelo de http://nostarch.com/automatestuff/ .
<! - Este es el archivo de ejemplo example.html. ->
<html><head> <title> El título del sitio web </title> </head>
<body>
<p> Descargar mi libro <strong> Python </strong> de <a href = "http: //
inventwithpython.com "> mi sitio web </a>. </p>
<p class =" slogan "> ¡Aprenda Python de la manera fácil! </p>
<p> Por <span id =" author "> Al Sweigart </span> < / p>
</body> </html>
Como puede ver, incluso un archivo HTML simple involucra muchas etiquetas
y atributos diferentes , y las cosas se confunden rápidamente con sitios web complejos.
Afortunadamente, Beautiful Soup hace que trabajar con HTML sea mucho más fácil.
Creación de un objeto BeautifulSoup a partir de HTML
La función bs4.BeautifulSoup () debe llamarse con una cadena que contenga
el HTML que analizará. La función bs4.BeautifulSoup () devuelve es un
objeto BeautifulSoup. Ingrese lo siguiente en el shell interactivo mientras
su computadora está conectada a Internet:
>>> solicitudes de importación, bs4
>>> res = request.get ('http://nostarch.com')
>>> res.raise_for_status ()
>>> noStarchSoup = bs4.BeautifulSoup (res.text)
>>> type (noStarchSoup)
<clase 'bs4.BeautifulSoup'>
Este código usa request.get () para descargar la página principal del
sitio web No Starch Press y luego pasa el atributo de texto de la respuesta
a bs4.BeautifulSoup (). El objeto BeautifulSoup que devuelve se almacena en una
variable llamada noStarchSoup.
246 Capítulo 11
También puede cargar un archivo HTML desde su disco duro pasando un
objeto File a bs4.BeautifulSoup (). Ingrese lo siguiente en el shell interactivo
(asegúrese de que el archivo example.html esté en el directorio de trabajo):
>>> exampleFile = open ('example.html')
>>> exampleSoup = bs4.BeautifulSoup (exampleFile)
>>> type (exampleSoup)
<clase 'bs4.BeautifulSoup'>
Una vez que tenga un objeto BeautifulSoup, puede usar sus métodos para localizar
partes específicas de un documento HTML.
Encontrar un elemento con el método select ()
Puede recuperar un elemento de página web de un objeto BeautifulSoup llamando
al método select () y pasando una cadena de un selector CSS para el elemento que
está buscando. Los selectores son como expresiones regulares: especifican un patrón
para buscar, en este caso, en páginas HTML en lugar de cadenas de texto generales.
Una discusión completa de la sintaxis del selector CSS está más allá del alcance de este
libro (hay un buen tutorial de selector en los recursos en http://nostarch.com/
automatestuff / ), pero aquí hay una breve introducción a los selectores. La Tabla 11-2 muestra
ejemplos de los patrones de selector CSS más comunes.
tabla 11-2: Ejemplos de selectores CSS El selector que se
pasa al método select () coincidirá. . .
soup.select ('div') Todos los elementos llamados <div>
soup.select ('# author') El elemento con un atributo de identificación de author
soup.select ('. Notice') Todos los elementos que usan un atributo de clase CSS
bute llamado
Notice soup.select ('div span') Todos los elementos llamados <span> que están dentro
un elemento llamado <div>
soup.select ('div> span') Todos los elementos llamados <span> que son
directamente dentro de un elemento llamado <div>,
sin otro elemento intermedio
soup.select ('input [name]') Todos los elementos llamados <input> que tienen un
atributo de nombre con cualquier valor
soup.select ('input [type = "button"]') Todos los elementos llamados <input> que tienen un
atributo llamado type con el botón value
Los diversos patrones de selector se pueden combinar para hacer combinaciones sofisticadas
. Por ejemplo, soup.select ('p #author') coincidirá con cualquier elemento que
tenga un atributo id de autor, siempre que también esté dentro de un elemento <p>.
El método select () devolverá una lista de objetos Tag, que es cómo
Beautiful Soup representa un elemento HTML. La lista contendrá un
objeto Tag para cada coincidencia en el HTML del objeto BeautifulSoup. Los valores de etiqueta
se pueden pasar a la función str () para mostrar las etiquetas HTML que representan.
Web Scraping 247
Los valores de etiqueta también tienen un atributo attrs que muestra todos los atributos HTML
de la etiqueta como un diccionario. Usando el archivo example.html de antes, ingrese lo
siguiente en el shell interactivo:
>>> import bs4
>>> exampleFile = open ('example.html')
>>> exampleSoup = bs4.BeautifulSoup (exampleFile.read ())
>>> elems = exampleSoup.select ('# author')
>>> type (elems)
<class 'list'>
>>> len (elems)
1
>>> type (elems [0])
<class 'bs4.element.Tag'>
>>> elems [0] .getText ()
' Al Sweigart '
>>> str (elems [0])
' <span id = "author"> Al Sweigart </span> '
>>> elems [0] .attrs
{' id ':' author '}
Este código extraerá el elemento con id = "author" de nuestro
HTML de ejemplo . Usamos select ('# author') para devolver una lista de todos los elementos con
id = "author". Almacenamos esta lista de objetos Tag en la variable elems, y
len (elems) nos dice que hay un objeto Tag en la lista; Hubo un partido.
Llamar a getText () en el elemento devuelve el texto del elemento, o
HTML interno . El texto de un elemento es el contenido entre las etiquetas de apertura y
cierre: en este caso, 'Al Sweigart'.
Pasar el elemento a str () devuelve una cadena con las
etiquetas de inicio y cierre y el texto del elemento. Finalmente, attrs nos da un diccionario con el
atributo del elemento, 'id', y el valor del atributo id, 'author'.
También puede extraer todos los elementos <p> del objeto BeautifulSoup.
Ingrese esto en el shell interactivo:
>>> pElems = exampleSoup.select ('p')
>>> str (pElems [0])
'<p> Descargar mi libro <strong> Python </strong> de <a href = "http: //
inventwithpython. com "> mi sitio web </a>. </p> '
>>> pElems [0] .getText ()
' Descargar mi libro de Python desde mi sitio web '.
>>> str (pElems [1])
'<p class = "slogan"> ¡Aprenda Python de la manera fácil! </p>'
>>> pElems [1] .getText ()
'¡Aprenda Python de la manera fácil!'
>>> str (pElems [2])
'<p> Por <span id = "author"> Al Sweigart </span> </p>'
>>> pElems [2] .getText ()
'Por Al Sweigart'
Esta vez, select () nos da una lista de tres coincidencias, que almacenamos en
pElems. El uso de str () en pElems [0], pElems [1] y pElems [2] muestra cada elemento
como una cadena, y el uso de getText () en cada elemento le muestra su texto.
248 Capítulo 11
Obtención de datos de los atributos de un elemento
El método get () para los objetos Tag facilita el acceso a los valores de los atributos
desde un elemento. Al método se le pasa una cadena de un nombre de atributo y
devuelve el valor de ese atributo. Usando example.html , ingrese lo siguiente en
el shell interactivo:
>>> import bs4
>>> soup = bs4.BeautifulSoup (open ('example.html'))
>>> spanElem = soup.select ('span') [0]
>>> str (spanElem)
'<span id = "author"> Al Sweigart </span> '
>>> spanElem.get (' id ')
' author '
>>> spanElem.get (' some_nonexistent_addr ') == Ninguno
True
>>> spanElem.attrs
{' id ':' autor '}
Aquí usamos select () para encontrar cualquier elemento <span> y luego almacenamos el
primer elemento coincidente en spanElem. Al pasar el nombre de atributo 'id' para obtener (), se
devuelve el valor del atributo, 'author'.
Proyecto: "Me siento afortunado" Búsqueda de Google
Cada vez que busco un tema en Google, no miro solo un resultado de búsqueda
a la vez. Al hacer clic con el botón central en el enlace de un resultado de búsqueda (o al hacer clic
mientras se mantiene presionada la tecla
Ctrl), abro los primeros enlaces en un montón de pestañas nuevas para leer más tarde.
Busco en Google con la frecuencia suficiente para que este flujo de trabajo (abrir mi navegador,
buscar un tema y hacer clic en varios enlaces uno por uno) sea
tedioso. Sería bueno si pudiera simplemente escribir un término de búsqueda en la
línea de comando y hacer que mi computadora abra automáticamente un navegador con todos
los resultados de búsqueda principales en nuevas pestañas. Escribamos un guión para hacer esto.
Esto es lo que hace su programa:

• Obtiene palabras clave de búsqueda de los argumentos de la línea de comandos. • Recupera la


página de resultados de búsqueda. • Abre una pestaña del navegador para cada resultado.

Esto significa que su código deberá hacer lo siguiente:

• Lea los argumentos de la línea de comandos de sys.argv. • Obtenga la página de resultados de


búsqueda con el módulo de solicitudes. • Encuentra los enlaces a cada resultado de
búsqueda. • Llame a la función webbrowser.open () para abrir el navegador web.

Abra una nueva ventana del editor de archivos y guárdela como lucky.py.
Web Scraping 249
Paso 1: Obtenga los argumentos de la línea de comandos y solicite la página de búsqueda
Antes de codificar cualquier cosa, primero debe conocer la URL de la
página de resultados de búsqueda . Al mirar la barra de direcciones del navegador después de hacer
una búsqueda en Google,
puede ver que la página de resultados tiene una URL como https://www.google.com/
search? Q = SEARCH_TERM_HERE . El módulo de solicitudes puede descargar esta
página y luego puede usar Beautiful Soup para encontrar los enlaces de resultados de búsqueda en
el HTML. Finalmente, usará el módulo de navegador web para abrir esos enlaces en
las pestañas del navegador.
Haga que su código tenga el siguiente aspecto:
#! python3
# lucky.py: abre varios resultados de búsqueda de Google.
solicitudes de importación, sys, navegador web, bs4
print ('Google ...') # muestra el texto al descargar la página de Google
res = request.get ('http://google.com/search?q=' + '' .join (sys.argv [1:] ))
res.raise_for_status ()
# TODO: recupera los principales enlaces de resultados de búsqueda.
# TODO: abra una pestaña del navegador para cada resultado.
El usuario especificará los términos de búsqueda utilizando argumentos de línea de comandos
cuando inicie el programa. Estos argumentos se almacenarán como cadenas en
una lista en sys.argv.
Paso 2: Encuentre todos los resultados
Ahora necesita usar Beautiful Soup para extraer los enlaces de resultados de búsqueda principales
de su HTML descargado. Pero, ¿cómo se determina el selector adecuado
para el trabajo? Por ejemplo, no puede buscar todas las etiquetas <a>, porque
hay muchos enlaces que no le interesan en el HTML. En su lugar, debe
inspeccionar la página de resultados de búsqueda con las herramientas de desarrollo del navegador
para tratar de
encontrar un selector que seleccione solo los enlaces que desee.
Después de hacer una búsqueda en Google de Beautiful Soup , puede abrir las
herramientas de desarrollo del navegador e inspeccionar algunos de los elementos de enlace en la
página. Se ven increíblemente complicados, algo como esto: <a href = "/ url? Sa
= t & amp; rct = j & amp; q = & amp; esrc = s & amp; source = web & amp; cd = 1 & amp; cad =
rja & amp; uact = 8 & amp
; ved = 0CCgQFjAA & amp; url = http% 3A% 2F% 2Fwww.crummy.com% 2Fsoftware%
2FBeautifulSoup
% 2F & amp; ei = LHBVU_XDD9KVyAShmYDwCw & amp; USG =
AFQjCNHAxwplurFOBqg5cehWQEVKi-TuLQ & amp
; SIG2 = sdZu6WVlBlVSDrwhtworMA "onMouseDown =" rwt de retorno (esto, '', '' , '', '1', 'AFQ
jCNHAxwplurFOBqg5cehWQEVKi-TuLQ', 'sdZu6WVlBlVSDrwhtworMA', '0CCgQFjAA', '', '',
ev
ent) "data-href =" http://www.crummy.com/software/ BeautifulSoup / "> <em> Beautiful
Soup </em>: Lo llamamos Tortoise porque nos enseñó. </a>.
No importa que el elemento se vea increíblemente complicado. Solo
necesita encontrar el patrón que tienen todos los enlaces de resultados de búsqueda. Pero este
elemento <a>
no tiene nada que lo distinga fácilmente de los elementos <a> de resultados que no son de
búsqueda
en la página.
250 Capítulo 11
Haga que su código tenga el siguiente aspecto:
#! python3
# lucky.py: abre varios resultados de búsqueda de Google.
solicitudes de importación, sys, navegador web, bs4
- cortar -
# Recuperar enlaces de resultados de búsqueda principales.
sopa = bs4.BeautifulSoup (res.text)
# Abra una pestaña del navegador para cada resultado.
linkElems = soup.select ('. r a')
Sin embargo, si busca un poco desde el elemento <a>, hay un elemento
como este: <h3 class = "r">. Mirando a través del resto de la fuente HTML,
parece que la clase r se usa solo para enlaces de resultados de búsqueda. No tiene
que saber qué es la clase r de CSS o qué hace. Simplemente lo usará
como marcador para el elemento <a> que está buscando. Puede crear un
objeto BeautifulSoup a partir del texto HTML de la página descargada y luego usar
el selector '.ra' para encontrar todos los elementos <a> que están dentro de un elemento que
tiene la clase r CSS.
Paso 3: Abra los navegadores web para cada resultado
Finalmente, le diremos al programa que abra las pestañas del navegador web para obtener nuestros
resultados. Agregue
lo siguiente al final de su programa:
#! python3
# lucky.py: abre varios resultados de búsqueda de Google.
solicitudes de importación, sys, navegador web, bs4
- cortar -
# Abra una pestaña del navegador para cada resultado.
linkElems = soup.select ('. r a')
numOpen = min (5, len (linkElems))
para i in range (numOpen):
webbrowser.open ('http://google.com' + linkElems [i]. get ('href'))
De manera predeterminada, abre los primeros cinco resultados de búsqueda en nuevas pestañas con
el
módulo de navegador web. Sin embargo, el usuario puede haber buscado algo que
arrojó menos de cinco resultados. La llamada soup.select () devuelve una lista de todos
los elementos que coinciden con su selector '.ra', por lo que el número de pestañas que
desea abrir es 5 o la longitud de esta lista (lo que sea menor).
La función de Python incorporada min () devuelve el más pequeño de los argumentos enteros
o flotantes que se pasa. (También hay una función incorporada max () que
Web Scraping 251
devuelve el argumento más grande que se pasa.) Puede usar min () para averiguar
si hay menos de cinco enlaces en la lista y almacenar el número de
enlaces para abrir en una variable llamada numOpen. Luego puede ejecutar un bucle for
llamando a range (numOpen).
En cada iteración del bucle, usa webbrowser.open () para abrir una nueva
pestaña en el navegador web. Tenga en cuenta que el valor del atributo href en los
elementos <a> devueltos no tiene la parte inicial http://google.com, por lo que debe
concatenarlo con el valor de cadena del atributo href.
¡Ahora puede abrir instantáneamente los primeros cinco resultados de Google para, digamos,
tutoriales de programación de Python ejecutando tutoriales de programación
de Python afortunados en la
línea de comandos! (Consulte el Apéndice B para saber cómo ejecutar fácilmente programas en su
sistema operativo).
Ideas para programas similares
El beneficio de la navegación con pestañas es que puede abrir fácilmente enlaces en pestañas
nuevas
para leerlas más tarde. Un programa que abre automáticamente varios enlaces a la vez
puede ser un buen acceso directo para hacer lo siguiente:
• Abra todas las páginas de productos después de buscar un sitio de compras
como Amazon

• Abra todos los enlaces a reseñas de un solo producto • Abra los enlaces de resultados a fotos
después de realizar una búsqueda en una foto

sitio como Flickr o Imgur


Proyecto: descargar todos los cómics de xkcd Los
blogs y otros sitios web que se actualizan regularmente suelen tener una página principal con
la publicación más reciente, así como un botón Anterior en la página que lo lleva
a la publicación anterior. Luego, esa publicación también tendrá un botón Anterior, y así
sucesivamente
, creando un rastro desde la página más reciente hasta la primera publicación en el sitio.
Si desea leer una copia del contenido del sitio cuando no está en línea,
puede navegar manualmente por cada página y guardar cada una. Pero este es
un trabajo bastante aburrido, así que escribamos un programa para hacerlo.
XKCD es un popular webcomic geek con un sitio web que se ajusta a esta estructura
(ver Figura 11-6). La página principal en http://xkcd.com/ tiene un botón Anterior que
guía al usuario a través de cómics anteriores. Descargar cada cómic a
mano llevaría una eternidad, pero puedes escribir un guión para hacerlo en un par de
minutos.
Esto es lo que hace su programa:
• Carga la página de inicio de XKCD. • Guarda la imagen cómica en esa página. • Sigue el enlace
de cómic anterior. • Se repite hasta que alcanza el primer cómic.

252 Capítulo 11
Figura 11-6: XKCD, "un cómic web de romance, sarcasmo, matemáticas y lenguaje"
Esto significa que su código deberá hacer lo siguiente:

• Descargar páginas con el módulo de solicitudes. • Encuentre la URL de la imagen cómica de una
página con Beautiful Soup. • Descargue y guarde la imagen cómica en el disco duro con
iter_content (). • Busque la URL del enlace Comic anterior y repita.

Abra una nueva ventana del editor de archivos y guárdela como downloadXkcd.py.
Paso 1: Diseñe el programa
Si abre las herramientas de desarrollo del navegador e inspecciona los elementos en la
página, encontrará lo siguiente:
• La URL del archivo de imagen del cómic viene dada por el atributo href de un elemento
<img>.

• El elemento <img> está dentro de un elemento <div id = "comic">. • El botón Anterior tiene un
atributo rel HTML con el valor anterior. • El botón Prev del primer cómic enlaza con la
http://xkcd.com/# URL, que indica

ing que no hay más páginas anteriores.


Haga que su código tenga el siguiente aspecto:
#! python3
# downloadXkcd.py - Descarga todos los cómics de XKCD.
solicitudes de importación, os, bs4
url = 'http://xkcd.com' # url de inicio
os.makedirs ('xkcd', exist_ok = True) # almacena comics en ./xkcd
Web Scraping 253
mientras que no es url.endswith ('#'):
# TODO: descargue la página.
# TODO: Encuentra la URL de la imagen cómica.
# TODO: Descargue la imagen.
# TODO: guarde la imagen en ./xkcd.
# TODO: Obtenga la URL del botón Prev.
print ('Hecho')
Tendrá una variable de URL que comienza con el valor 'http://xkcd.com'
y la actualiza repetidamente (en un ciclo for) con la URL del
enlace Prev de la página actual . En cada paso del bucle, descargará el cómic en la URL. Sabrás
finalizar el ciclo cuando la url termine con '#'.
Descargará los archivos de imagen a una carpeta en el
directorio de trabajo actual llamado xkcd . La llamada os.makedirs () asegura que esta carpeta
exista,
y el argumento de palabra clave exist_ok = True evita que la función arroje
una excepción si esta carpeta ya existe. El resto del código son solo
comentarios que describen el resto de su programa.
Paso 2: descargue la página web
Implementemos el código para descargar la página. Haga que su código tenga el siguiente aspecto
:
#! python3
# downloadXkcd.py - Descarga todos los cómics de XKCD.
solicitudes de importación, os, bs4
url = 'http://xkcd.com' # url de inicio
os.makedirs ('xkcd', exist_ok = True) # almacena historietas en ./xkcd
mientras que no es url.endswith ('#'):
# Descarga la página.
print ('Descargando la página% s ...'% url)
res = request.get ( url)
res.raise_for_status ()
sopa = bs4.BeautifulSoup (res.text)
# TODO: Encuentra la URL de la imagen cómica.
# TODO: Descargue la imagen.
# TODO: guarde la imagen en ./xkcd.
# TODO: Obtenga la URL del botón Prev.
print ('Hecho')
254 Capítulo 11
Primero, imprima la URL para que el usuario sepa qué URL está a punto de
descargar el programa; luego use la función request.get () del módulo de solicitudes para
descargarlo
. Como siempre, inmediatamente llama al
método raise_for_ status () del objeto Response para lanzar una excepción y finalizar el programa si
algo salió
mal con la descarga. De lo contrario, crea un objeto BeautifulSoup a partir
del texto de la página descargada.
Paso 3: busque y descargue la imagen cómica
Haga que su código tenga el siguiente aspecto:
#! python3
# downloadXkcd.py - Descarga todos los cómics de XKCD.
solicitudes de importación, os, bs4
- cortar -
# Encuentra la URL de la imagen cómica.
comicElem = soup.select ('# comic img')
if comicElem == []:
print ('No se pudo encontrar la imagen del comic.')
sino:
comicUrl = 'http:' + comicElem [0] .get ('src')
# Descargar la imagen.
print ('Descargando imagen% s ...'% (comicUrl))
res = request.get (comicUrl)
res.raise_for_status ()
# TODO: guarde la imagen en ./xkcd.
# TODO: Obtenga la URL del botón Prev.
print ('Hecho')
Al inspeccionar la página de inicio de XKCD con sus herramientas de desarrollador,
sabe que el elemento <img> para la imagen cómica está dentro de un elemento <div>
con el atributo id establecido en comic, por lo que el selector '#comic img' le dará el
elemento <img> correcto del objeto BeautifulSoup.
Algunas páginas XKCD tienen contenido especial que no es un simple archivo de imagen.
Esta bien; solo te saltearás esos. Si su selector no encuentra ningún elemento,
soup.select ('# comic img') devolverá una lista en blanco. Cuando eso sucede,
el programa puede simplemente imprimir un mensaje de error y continuar sin descargar
la imagen.
De lo contrario, el selector devolverá una lista que contiene un elemento <img>. Puede
obtener el atributo src de este elemento <img> y pasarlo a request.get ()
para descargar el archivo de imagen del cómic.
Web Scraping 255
Paso 4: guarda la imagen y encuentra el cómic anterior
Haz que tu código se vea así:
#! python3
# downloadXkcd.py - Descarga todos los cómics de XKCD.
solicitudes de importación, os, bs4
- cortar -
# Guarde la imagen en ./xkcd.
imageFile = open (os.path.join ('xkcd', os.path.basename (comicUrl)), 'wb')
para el fragmento en res.iter_content (100000):
imageFile.write (fragmento)
imageFile.close ()
# Obtenga la URL del botón Prev.
prevLink = soup.select ('a [rel = "prev"]') [0]
url = 'http://xkcd.com' + prevLink.get ('href')
print ('Hecho')
En este punto, el archivo de imagen del cómic se almacena en la variable res.
Necesita escribir estos datos de imagen en un archivo en el disco duro.
Necesitará un nombre de archivo para que el archivo de imagen local pase a open ().
El comicUrl tendrá un valor como 'http://imgs.xkcd.com/comics/heartbleed
_explanation.png', que quizás haya notado que se parece mucho a una ruta de archivo.
Y, de hecho, puede llamar a os.path.basename () con comicUrl, y devolverá
solo la última parte de la URL, 'heartbleed_explanation.png'. Puede usar esto
como nombre de archivo al guardar la imagen en su disco duro. Une este
nombre con el nombre de su carpeta xkcd usando os.path.join () para que su
programa use barras invertidas (\) en Windows y barras diagonales (/) en OS X
y Linux. Ahora que finalmente tiene el nombre de archivo, puede llamar a open () para
abrir un nuevo archivo en modo 'wb' “write binary”.
Recuerde que al principio de este capítulo, para guardar los archivos que ha descargado
usando Solicitudes, debe recorrer el valor de retorno del
método iter_content () . El código en el bucle for escribe fragmentos de los datos de la imagen
(como
máximo 100,000 bytes cada uno) en el archivo y luego cierra el archivo. La imagen
ahora se guarda en su disco duro.
Luego, el selector 'a [rel = "prev"]' identifica el elemento <a> con
el atributo rel establecido en prev, y puede usar el atributo href de este elemento <a>
para obtener la URL del cómic anterior, que se almacena en url. Luego, el
ciclo while comienza todo el proceso de descarga nuevamente para este cómic.
El resultado de este programa se verá así:
Descargando la página http: //xkcd.com ...
Descargando la imagen http: //imgs.xkcd.com/comics/phone_alarm.png ...
Descargando la página http: //xkcd.com/1358 / ...
256 Capítulo 11
Descargando la imagen http: //imgs.xkcd.com/comics/nro.png ...
Descargando la página http: //xkcd.com/1357 / ...
Descargando la imagen http://imgs.xkcd.com/comics/free_speech .png ...
Página de descarga http: //xkcd.com/1356 / ...
Descargando imagen http: //imgs.xkcd.com/comics/orbital_mechanics.png ...
Página de descarga http://xkcd.com/ 1355 / ...
Descargando la imagen http: //imgs.xkcd.com/comics/airplane_message.png ...
Descargando la página http: //xkcd.com/1354 / ...
Descargando la imagen http: //imgs.xkcd. com / comics / heartbleed_explanation.png ...
- recorte -
Este proyecto es un buen ejemplo de un programa que puede
seguir automáticamente los enlaces para extraer grandes cantidades de datos de la Web. Puede
obtener información sobre otras características de Beautiful Soup en su documentación
en http://www.crummy.com/software/BeautifulSoup/bs4/doc/.
Ideas para programas similares La
descarga de páginas y los siguientes enlaces son la base de muchos programas de rastreo web
. Programas similares también podrían hacer lo siguiente:

• Haga una copia de seguridad de un sitio completo siguiendo todos sus enlaces. • Copie todos los
mensajes de un foro web. • Duplicar el catálogo de artículos a la venta en una tienda en
línea.

Las solicitudes y los módulos de BeautifulSoup son geniales siempre que pueda
averiguar la URL que necesita pasar a request.get (). Sin embargo, a veces
esto no es tan fácil de encontrar. O tal vez el sitio web que desea que
navegue su programa requiere que inicie sesión primero. El módulo de selenio le dará a sus
programas
el poder de realizar tareas tan sofisticadas.
control del navegador con el módulo de selenio
El módulo de selenio le permite a Python controlar directamente el navegador
haciendo clic programáticamente en los enlaces y completando la información de inicio de sesión,
casi como si
hubiera un usuario humano interactuando con la página. Selenium le permite
interactuar con páginas web de una manera mucho más avanzada que Requests y
Beautiful Soup; pero debido a que lanza un navegador web, es un poco más lento y
difícil de ejecutar en segundo plano si, por ejemplo, solo necesita descargar algunos archivos
de la Web.
El Apéndice A tiene pasos más detallados sobre la instalación de módulos de terceros.
Inicio de un navegador controlado por Selenium
Para estos ejemplos, necesitará el navegador web Firefox. Este será el
navegador que controlas. Si aún no tiene Firefox, puede descargarlo
gratuitamente desde http://getfirefox.com/.
Web Scraping 257
Importar los módulos para Selenium es un poco complicado. En lugar de importar
selenio, debe ejecutar desde el controlador web de importación de selenio. (La razón exacta por la
cual el módulo de selenio está configurado de esta manera está más allá del alcance de este libro).
Después de eso, puede iniciar el navegador Firefox con Selenium. Ingrese lo
siguiente en el shell interactivo:
>>> desde selenium import webdriver
>>> browser = webdriver.Firefox ()
>>> type (browser)
<class 'selenium.webdriver.firefox.webdriver.WebDriver'>
>>> browser.get ('http: // inventwithpython.com ')
Notarás que cuando se llama a webdriver.Firefox (), se
inicia el navegador web Firefox . Al llamar a type () en el valor webdriver, Firefox () revela que es
del
tipo de datos WebDriver. Y llamando a browser.get ('http://inventwithpython.com')
dirige el navegador a http://inventwithpython.com/ . Su navegador debería parecerse
a la Figura 11-7.
Figura 11-7: Después de llamar a webdriver.Firefox () y get () en IDLE, aparece el navegador
Firefox.
Búsqueda de elementos en la página Los
objetos WebDriver tienen bastantes métodos para buscar elementos en una
página. Se dividen en los métodos find_element_ * y find_elements_ *.
Los métodos find_element_ * devuelven un único objeto WebElement, que representa
el primer elemento en la página que coincide con su consulta. Los
métodos find_elements_ * devuelven una lista de objetos WebElement_ * para cada elemento
coincidente en
la página.
La Tabla 11-3 muestra varios ejemplos de métodos find_element_ * y find_elements_ * que se
invocan
en un objeto WebDriver que se almacena en el navegador de variables
.
258 Capítulo 11
tabla 11-3: Métodos WebDriver de Selenium para encontrar elementos
nombre del método Elemento / lista WebElement devuelto
browser.find_element_by_class_name ( nombre )
browser.find_elements_by_class_name ( nombre )
Elementos que usan el nombre de la clase CSS
browser.find_element_by_css_selector ( selector )
browser.find_elements_by_css_selector ( selector )
Elementos que coinciden con el selector CSS
browser.find_element_by_id ( id )
browser.find_elements_by_id ( id )
Elementos con un valor de atributo de ID coincidente
browser.find_element_by_link_text ( texto )
browser.find_elements_by_link_text ( texto )
<a> elementos que
coinciden completamente con el texto proporcionado
browser.find_element_by_partial_link_text ( texto )
browser.find_elements_by_partial_link_text ( texto )

<a> elementos que contienen el texto proporcionado


browser.find_element_by_name ( nombre )
browser.find_elements_by_name ( nombre )

Elementos con un valor de atributo de nombre coincidente


browser.find_element_by_tag_name ( nombre )
browser.find_elements_by_tag_name ( nombre )
Elementos con un nombre de etiqueta coincidente (no distingue entre mayúsculas y minúsculas; un
elemento <a> coincide con 'a' y 'A')
Excepto por los métodos * _by_tag_name (), los argumentos de todos los
métodos distinguen entre mayúsculas y minúsculas. Si no existen elementos en la página que
coincidan con
lo que está buscando el método, el módulo de selenio genera una
excepción NoSuchElement . Si no desea que esta excepción bloquee su programa,
agregue sentencias try
y except a su código.
Una vez que tenga el objeto WebElement, puede obtener más información al
leer los atributos o llamar a los métodos en la Tabla 11-4.
tabla 11-4: Atributos y métodos de WebElement Atributo
o método Descripción
tag_name El nombre de la etiqueta, como 'a' para un elemento <a>
get_attribute ( nombre ) El valor para el
texto del atributo de nombre del elemento El texto dentro del elemento, como ' hola 'en <span> hola
</span>
clear () Para los elementos de campo de texto o área de texto, borra el texto escrito en él
is_displayed () Devuelve True si el elemento es visible; de lo contrario, devuelve False
is_enabled () Para los elementos de entrada, devuelve True si el elemento está habilitado; otro-
wise devuelve False
is_selected () Para los elementos de casilla de verificación o botón de opción, devuelve True si el
elemento
se selecciona ment; de lo contrario, devuelve False
location Un diccionario con las teclas 'x' e 'y' para la posición de la ele-
ment en la página
Por ejemplo, abra un nuevo editor de archivos e ingrese el siguiente programa:
desde selenium import webdriver
browser = webdriver.Firefox ()
browser.get ('http://inventwithpython.com')
Web Scraping 259
intente:
elem = browser.find_element_by_class_name ('bookcover')
print ('Elemento encontrado'% s> con ese nombre de clase! '% (elem.tag_name))
excepto:
print (' No se pudo encontrar un elemento con ese nombre. ')
Aquí abrimos Firefox y lo dirigimos a una URL. En esta página, tratamos de encontrar
elementos con el nombre de clase 'bookcover', y si se encuentra dicho elemento,
imprimimos su nombre de etiqueta usando el atributo tag_name. Si no se encuentra dicho elemento
, imprimimos un mensaje diferente.
Este programa generará lo siguiente:
¡Se encontró el elemento <img> con ese nombre de clase!
Encontramos un elemento con el nombre de clase 'bookcover' y el nombre de etiqueta
'img'.
Al hacer clic en los
objetos Page WebElement devueltos por los métodos find_element_ * y find_elements_ *
tienen un método click () que simula un clic del mouse sobre ese elemento
. Este método se puede usar para seguir un enlace, hacer una selección en un
botón de radio , hacer clic en el botón Enviar o activar cualquier otra cosa que pueda ocurrir
cuando
el mouse hace clic en el elemento. Por ejemplo, ingrese lo siguiente en el
shell interactivo:
>>> desde selenium import webdriver
>>> browser = webdriver.Firefox ()
>>> browser.get ('http://inventwithpython.com')
>>> linkElem = browser.find_element_by_link_text ('Read It Online')
> >> type (linkElem)
<class 'selenium.webdriver.remote.webelement.WebElement'>
>>> linkElem.click () # sigue el enlace "Read It Online"
Esto abre Firefox a http://inventwithpython.com/ , obtiene el
objeto WebElement para el elemento <a> con el texto Read It Online y luego simula
hacer clic en ese elemento <a>. Es como si hicieras clic en el enlace tú mismo; el
navegador luego sigue ese enlace.
Completar y enviar formularios
Enviar teclas a campos de texto en una página web es cuestión de encontrar el elemento <input>
o <textarea> para ese campo de texto y luego llamar al método send_keys ()
. Por ejemplo, ingrese lo siguiente en el shell interactivo:
>>> desde selenium import webdriver
>>> browser = webdriver.Firefox ()
>>> browser.get ('https://mail.yahoo.com')
>>> emailElem = browser.find_element_by_id ('login-username' )
>>> emailElem.send_keys ('not_my_real_email')
>>> passwordElem = browser.find_element_by_id ('login-passwd')
260 Capítulo 11
>>> contraseñaElem.send_keys ('12345')
>>> contraseñaElem.submit ()
Mientras Gmail no haya cambiado la identificación de los
campos de texto Nombre de usuario y Contraseña desde que se publicó este libro, el código anterior
completará
esos campos de texto con el texto proporcionado. (Siempre puede usar el
inspector del navegador para verificar la identificación). Llamar al método submit () en cualquier
elemento
tendrá el mismo resultado que hacer clic en el botón Enviar para el formulario en el que
se encuentra ese elemento. (Podría haber llamado fácilmente emailElem .submit (), y
el código habría hecho lo mismo.)
Envío de teclas especiales
Selenium tiene un módulo para teclas de teclado que son imposibles de escribir en un
valor de cadena, que funcionan de manera muy similar a los caracteres de escape. Estos valores se
almacenan en atributos en el módulo selenium.webdriver.common.keys. Como ese
es un nombre de módulo tan largo, es mucho más fácil ejecutarlo desde selenium.webdriver
.common.keys import Keys en la parte superior de su programa; si lo hace,
simplemente puede escribir Keys en cualquier lugar donde normalmente tendría que escribir
selenium.webdriver
.common.keys. La Tabla 11-5 enumera las variables de Keys comúnmente utilizadas.
tabla 11-5: Variables de uso común en el módulo selenium.webdriver.common.keys
Atributos significados
Keys.DOWN, Keys.UP, Keys.LEFT,
Keys.RIGHT
Las teclas de flecha del teclado
Keys.ENTER, Keys.RETURN Las teclas enter y return
Keys.HOME, Keys.END, Keys.PAGE_DOWN,
Keys.PAGE_UP
Las teclas de inicio, fin, pagedown y pageup
Keys.ESCAPE, Keys.BACK_SPACE,
Keys.DELETE
Las teclas esc, retroceso y eliminar
Keys.F1, Keys.F2,. . . , Keys.F12 Las teclas F1 a F12 en la parte superior del teclado
Keys.TAB La tecla Tab
Por ejemplo, si el cursor no está actualmente en un campo de texto, al presionar las teclas de
inicio y fin, el navegador se desplazará hacia la parte superior e inferior de la página,
respectivamente. Ingrese lo siguiente en el shell interactivo y observe cómo
las llamadas a send_keys () desplazan la página:
>>> desde selenium import webdriver
>>> desde selenium.webdriver.common.keys import Keys
>>> browser = webdriver.Firefox ()
>>> browser.get ('http://nostarch.com')
>>> htmlElem = browser.find_element_by_tag_name ( 'html')
>>> htmlElem.send_keys (Keys.END) # volutas a abajo
>>> htmlElem.send_keys (Keys.HOME) # desplaza a la parte superior
Web Scraping 261
La etiqueta <html> es la etiqueta base en los archivos HTML: el contenido completo del
archivo HTML se encuentra dentro de las etiquetas <html> y </html>. Llamar al navegador
.find_element_by_tag_name ('html') es un buen lugar para enviar claves a la
página web general . Esto sería útil si, por ejemplo, se carga contenido nuevo una vez
que se ha desplazado al final de la página.
Al hacer clic en los botones del navegador
Selenium puede simular clics en varios botones del navegador a través de
los siguientes métodos:
browser.back () Hace clic en el botón Atrás.
browser.forward () Hace clic en el botón Adelante.
browser.refresh () Hace clic en el botón Actualizar / Recargar.
browser.quit () Hace clic en el botón Cerrar ventana.
Más información sobre selenio El
selenio puede hacer mucho más que las funciones descritas aquí. Puede
modificar las cookies de su navegador, tomar capturas de pantalla de páginas web y ejecutar
JavaScript personalizado. Para obtener más información sobre estas características, puede visitar la
documentación de Selenium en http://selenium-python.readthedocs.org/ .
Resumen
La mayoría de las tareas aburridas no se limitan a los archivos en su computadora. Ser capaz
de descargar páginas web mediante programación extenderá sus programas a
Internet. El módulo de solicitudes facilita la descarga y,
con algunos conocimientos básicos de conceptos y selectores de HTML, puede utilizar
el módulo BeautifulSoup para analizar las páginas que descarga.
Pero para automatizar completamente cualquier tarea basada en la web, necesita el control directo
de
su navegador web a través del módulo de selenio. El módulo de selenio le
permitirá iniciar sesión en sitios web y completar formularios automáticamente. Dado que un
navegador web es la forma más común de enviar y recibir información a través de
Internet, esta es una gran capacidad para tener en su kit de herramientas de programador.
Preguntas de práctica
1. Describa brevemente las diferencias entre el navegador web, las solicitudes,
BeautifulSoup, y los módulos de selenio.
2. ¿Qué tipo de objeto es devuelto por request.get ()? ¿Cómo puedes acceder?
el contenido descargado como un valor de cadena?
3. ¿Qué método de Solicitudes verifica que la descarga funcionó?
4. ¿Cómo puede obtener el código de estado HTTP de una respuesta a Solicitudes?
5. ¿Cómo guarda una respuesta de Solicitud en un archivo?
262 Capítulo 11
6. ¿Cuál es el atajo de teclado para abrir las herramientas de desarrollador de un navegador?
7. ¿Cómo puede ver (en las herramientas de desarrollador) el HTML de un elemento específico?
ment en una página web?
8. ¿Cuál es la cadena de selector CSS que encontraría el elemento con una identificación?
atributo de main?
9. ¿Cuál es la cadena de selector CSS que encontraría los elementos con un CSS?
clase de destaque?
10. ¿Cuál es la cadena de selector CSS que encontraría todos los elementos <div>
dentro de otro elemento <div>?
11. ¿Cuál es la cadena de selector CSS que encontraría el elemento <button>
con un atributo de valor establecido en favorito?
12. Digamos que tiene un objeto Beautiful Soup Tag almacenado en la variable spam para
el elemento <div> ¡Hola mundo! </div>. ¿Cómo puedes obtener una cadena 'Hola
mundo!' del objeto Tag?
13. ¿Cómo almacenaría todos los atributos de un objeto Beautiful Soup Tag en
una variable llamada linkElem?
14. Ejecutar import selenium no funciona. ¿Cómo se importa correctamente el
módulo de selenio?
15. ¿Cuál es la diferencia entre los métodos find_element_ * y find_elements_ *
?
16. ¿Qué métodos tienen los objetos WebElement de Selenium para simular
los clics del mouse y las teclas del teclado?
17. Puede llamar a send_keys (Keys.ENTER) en el objeto WebElement del botón Enviar
, pero ¿cuál es una forma más fácil de enviar un formulario con Selenium?
18. ¿Cómo puede simular hacer clic en los botones Adelante, Atrás y Actualizar de un navegador
con Selenium?
Proyectos de
práctica Para practicar, escriba programas para realizar las siguientes tareas.
Emailer de línea de comando
Escriba un programa que tome una dirección de correo electrónico y una cadena de texto en la
línea de comando y luego, usando Selenium, inicie sesión en su cuenta de correo electrónico y
envíe un correo electrónico de la cadena a la dirección proporcionada. (Es posible que desee
configurar
una cuenta de correo electrónico separada para este programa).
Esta sería una buena manera de agregar una función de notificación a sus programas.
También puede escribir un programa similar para enviar mensajes desde una cuenta de Facebook
o Twitter.
Web Scraping 263
Image Site Downloader
Escriba un programa que vaya a un sitio para compartir fotos como Flickr o Imgur,
busque una categoría de fotos y luego descargue todas las
imágenes resultantes . Puede escribir un programa que funcione con cualquier sitio de fotos que
tenga
una función de búsqueda.
2048
2048 es un juego simple donde combinas fichas deslizándolas hacia arriba, abajo,
izquierda o derecha con las teclas de flecha. En realidad, puede obtener una puntuación bastante
alta
deslizándose repetidamente en un patrón hacia arriba, hacia la derecha, hacia abajo y hacia la
izquierda una y otra
vez. Escriba un programa que abrirá el juego en https: // gabrielecirulli
.github.io / 2048 / y siga enviando pulsaciones de teclas hacia arriba, hacia la derecha, hacia abajo y
hacia la izquierda para
jugar automáticamente el juego.
Verificación de enlaces
Escriba un programa que, dada la URL de una página web, intentará descargar
cada página vinculada en la página. El programa debe marcar las páginas
que tengan un código de estado 404 "No encontrado" e imprimirlas como enlaces rotos.
12
trabajando conhex C el
Hojas de cálculo
Excel es una aplicación de hoja de cálculo popular y potente
para Windows. El openpyxl
El módulo permite que sus programas Python
lean y modifiquen archivos de hojas de cálculo de Excel. por
Por ejemplo, podría tener la aburrida tarea de copiar
ciertos datos de una hoja de cálculo y pegarlos en
otra. O puede que tenga que pasar por miles de filas y elegir
solo un puñado de ellas para realizar pequeñas ediciones basadas en algunos criterios. O
puede que tenga que mirar a través de cientos de hojas de cálculo de
presupuestos de departamento , buscando cualquiera que esté en rojo. Estos son exactamente el tipo
de
tareas aburridas y sin sentido que Python puede hacer por usted.
Aunque Excel es un software propietario de Microsoft, existen
alternativas gratuitas que se ejecutan en Windows, OS X y Linux. Tanto LibreOffice Calc
como OpenOffice Calc funcionan con el formato de archivo .xlsx de Excel para hojas de cálculo, lo
que significa que el módulo openpyxl también puede funcionar en hojas de cálculo desde estas
aplicaciones
. Puede descargar el software desde https: // www. libreoffice
.org / y http://www.openoffice.org/, respectivamente. Incluso si ya tienes
266 Capítulo 12
Excel instalado en su computadora, puede encontrar estos programas más fáciles de
usar. Sin embargo, las capturas de pantalla de este capítulo son todas de Excel 2010 en
Windows 7.
documentos de Excel
Primero, repasemos algunas definiciones básicas: un documento de hoja de cálculo de Excel
se llama libro de trabajo. Un solo libro de trabajo se guarda en un archivo con la extensión .xlsx
. Cada libro puede contener varias hojas (también llamadas hojas de trabajo ). La
hoja que el usuario está viendo actualmente (o la última vez que se vio antes de cerrar Excel) se
llama hoja activa .
Cada hoja tiene columnas (tratadas con letras que comienzan en A ) y filas (tratadas con números
que comienzan en 1). Un cuadro en una columna y fila en particular se llama celda . Cada celda
puede contener un número o valor de texto. La cuadrícula de celdas con datos forma una hoja.

instalar el módulo openpyxl


Python no viene con OpenPyXL, por lo que tendrá que instalarlo. Siga
las instrucciones para instalar módulos de terceros en el Apéndice A; El nombre
del módulo es openpyxl. Para probar si está instalado correctamente, ingrese lo
siguiente en el shell interactivo:
>>> importar openpyxl
Si el módulo se instaló correctamente, esto no debería generar
mensajes de error . Recuerde importar el módulo openpyxl antes de ejecutar los
ejemplos de shell interactivos en este capítulo, o obtendrá un NameError: el nombre 'openpyxl'
no es un error definido.
Este libro cubre la versión 2.1.4 de OpenPyXL, pero
el equipo de OpenPyXL lanza regularmente nuevas versiones . Sin embargo, no se preocupe: las
nuevas versiones
deberían ser compatibles con las instrucciones de este libro durante bastante
tiempo. Si tiene una versión más nueva y desea ver qué características adicionales
pueden estar disponibles para usted, puede consultar la documentación completa de
OpenPyXL en http://openpyxl.readthedocs.org/ .
lectura de documentos de Excel
Los ejemplos en este capítulo utilizarán una hoja de cálculo llamada example.xlsx almacenada en la
carpeta raíz. Puede crear la hoja de cálculo usted mismo o descargarla
desde http://nostarch.com/automatestuff/ . La Figura 12-1 muestra las pestañas de las tres hojas
predeterminadas denominadas Hoja1 , Hoja2 y Hoja3 que Excel proporciona automáticamente para
los libros nuevos. (El número de hojas predeterminadas creadas puede variar entre los sistemas
operativos y los programas de hojas de cálculo).

Trabajar con hojas de cálculo de Excel 267


Figura 12-1: Las pestañas para las hojas de un libro de trabajo están en
la esquina inferior izquierda de Excel.
La Hoja 1 en el archivo de ejemplo debería verse como la Tabla 12-1. (Si no
descargó example.xlsx del sitio web, debe ingresar estos datos en la
hoja usted mismo).
tabla 12-1: El ejemplo.xlsx Hoja de cálculo
AB c
1 4/5/2015 1:34:02 PM Manzanas 73
2 4/5/2015 3:41:23 AM Cerezas 85
3 4/6/2015 12:46:51 PM Peras 14
4 8/8/2015 8: 59:43 AM Naranjas 52
5 10/04/2015 2:07:00 AM Manzanas 152
6 10/04/2015 6:10:37 PM Plátanos 23
7 10/04/2015 2:40:46 Fresas 98
Ahora que tenemos nuestra hoja de cálculo de ejemplo, veamos cómo podemos
manipularla con el módulo openpyxl.
Abrir documentos de Excel con OpenPyXL
Una vez que haya importado el módulo openpyxl, podrá usar la función openpyxl
.load_workbook (). Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('ejemplo.xlsx')
>>> tipo (wb)
<clase 'openpyxl.workbook.workbook.Workbook'>
La función openpyxl.load_workbook () toma el nombre del archivo y devuelve
un valor del tipo de datos del libro. Este objeto de libro de trabajo representa el archivo de Excel
, un poco como un objeto de archivo representa un archivo de texto abierto.
Recuerde que example.xlsx debe estar en el directorio de trabajo actual
para que pueda trabajar con él. Puede averiguar cuál es el
directorio de trabajo actual importando os y usando os.getcwd (), y puede
cambiar el directorio de trabajo actual usando os.chdir ().
268 Capítulo 12
Obtención de hojas del
libro de trabajo Puede obtener una lista de todos los nombres de las hojas del libro de trabajo
llamando al
método get_sheet_names (). Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('ejemplo.xlsx')
>>> wb.get_sheet_names ()
['Hoja1', 'Hoja2', 'Hoja3']
>>> hoja = wb.get_sheet_by_name ( 'Sheet3')
>>> sheet
<Worksheet "Sheet3">
>>> type (sheet)
<class 'openpyxl.worksheet.worksheet.Worksheet'>
>>> sheet.title
'Sheet3'
>>> anotherSheet = wb.get_active_sheet ()
>>> anotherSheet
<Hoja de cálculo "Sheet1">
Cada hoja está representada por un objeto Hoja de trabajo, que puede obtener
pasando la cadena del nombre de la hoja al método de libro get_sheet_by_name ().
Finalmente, puede llamar al método get_active_sheet () de un objeto Workbook para
obtener la hoja activa del libro. La hoja activa es la hoja que está en la parte superior
cuando se abre el libro en Excel. Una vez que tenga el objeto Hoja de trabajo,
puede obtener su nombre del atributo de título.
Obtención de celdas de las hojas
Una vez que tenga un objeto de hoja de trabajo, puede acceder a un objeto de celda por su nombre.
Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('example.xlsx')
>>> sheet = wb.get_sheet_by_name ('Sheet1')
>>> sheet ['A1']
<Cell Sheet1.A1>
>> > hoja ['A1']. valor
datetime.datetime (2015, 4, 5, 13, 34, 2)
>>> c = hoja ['B1']
>>> c.valor
'Manzanas'
>>> 'Fila '+ str (c.row) +', Columna '+ c.columna +' es '+ c.valor
' Fila 1, Columna B es Manzanas '
>>> ' Celda '+ c.coordinado +' es '+ c .value
'Cell B1 is Apples'
>>> sheet ['C1']. value
73
El objeto Cell tiene un atributo de valor que contiene, como era de esperar, el
valor almacenado en esa celda. Los objetos de celda también tienen atributos de fila, columna y
coordenadas
que proporcionan información de ubicación para la celda.
Trabajar con hojas de cálculo de Excel 269
Aquí, acceder al atributo de valor de nuestro objeto Cell para la celda B1
nos da la cadena 'Manzanas'. El atributo de fila nos da el número entero 1, el atributo de columna
nos da 'B' y el atributo de coordenadas nos da 'B1'.
OpenPyXL interpretará automáticamente las fechas en la columna A y las
devolverá como valores de fecha y hora en lugar de cadenas. El tipo de datos de fecha y hora
se explica más detalladamente en el Capítulo 16.
Especificar una columna por letra puede ser difícil de programar, especialmente
porque después de la columna Z, las columnas comienzan usando dos letras: AA, AB,
AC, etc. Como alternativa, también puede obtener una celda usando el
método cell () de la hoja y pasando enteros para sus argumentos de palabras clave de fila y
columna
. El primer entero de fila o columna es 1, no 0. Continúe con el ejemplo de shell interactivo
ingresando lo siguiente:
>>> sheet.cell (row = 1, column = 2)
<Cell Sheet1.B1>
>>> sheet.cell (row = 1, column = 2) .value
'Apples'
>>> para i en el rango (1 , 8, 2):
print (i, sheet.cell (row = i, column = 2) .value)
1 manzanas
3 peras
5 manzanas
7 fresas
Como puede ver, al usar el método cell () de la hoja y pasarlo fila = 1
y columna = 2 se obtiene un objeto Cell para la celda B1, al igual que se hizo al especificar la hoja
['B1']
. Luego, utilizando el método cell () y sus argumentos de palabras clave, puede
escribir un bucle for para imprimir los valores de una serie de celdas.
Supongamos que desea bajar la columna B e imprimir el valor en cada celda
con un número de fila impar. Al pasar 2 para el
parámetro "paso" de la función range () , puede obtener celdas de cada segunda fila (en este caso,
todas las
filas impares). La variable i del bucle for se pasa por el
argumento de palabra clave de fila al método cell (), mientras que 2 siempre se pasa por
el argumento de palabra clave de columna
. Tenga en cuenta que se pasa el entero 2, no la cadena 'B'.
Puede determinar el tamaño de la hoja con los
métodos get_highest_row () y get_highest_column () del objeto Hoja de trabajo . Ingrese lo
siguiente
en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('example.xlsx')
>>> sheet = wb.get_sheet_by_name ('Sheet1')
>>> sheet.get_highest_row ()
7
>>> sheet.get_highest_column ()
3
Tenga en cuenta que el método get_highest_column () devuelve un número entero en lugar
de la letra que aparece en Excel.
270 Capítulo 12
Conversión entre letras y números de columna
Para convertir de letras a números, llame a la función openpyxl.cell.column_index_from
_string (). Para convertir de números a letras, llame a la función openpyxl.cell
.get_column_letter (). Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> desde openpyxl.cell import get_column_letter, column_index_from_string
>>> get_column_letter (1)
'A'
>>> get_column_letter (2 )
'B'
>>> get_column_letter (27)
'AA'
>>> get_column_letter (900)
'AHP'
>>> wb = openpyxl.load_workbook ('example.xlsx')
>>> sheet = wb.get_sheet_by_name ('Sheet1')
>>> get_column_letter (sheet.get_highest_column ())
'C'
>> > column_index_from_string ('A')
1
>>> column_index_from_string ('AA')
27
Después de importar estas dos funciones desde el módulo openpyxl.cell,
puede llamar a get_column_letter () y pasarle un número entero como 27 para averiguar cuál es
el nombre de la letra de la columna 27. La función column_index_string ()
hace lo contrario: le pasa el nombre de la letra de una columna y le dice
qué número es esa columna. No necesita tener un libro de trabajo cargado para
usar estas funciones. Si lo desea, puede cargar un libro de trabajo, obtener un
objeto de hoja de trabajo y llamar a un método de objeto de hoja de trabajo como
get_highest_column () para obtener un
número entero. Luego, puede pasar ese número entero a get_column_letter ().
Obtención de filas y columnas de las hojas
Puede cortar objetos
de la hoja de trabajo para obtener todos los objetos de celda en una fila, columna o área rectangular
de la hoja de cálculo. Luego puede recorrer todas las celdas
en el segmento. Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('example.xlsx')
>>> sheet = wb.get_sheet_by_name ('Sheet1')
>>> tuple (sheet ['A1': 'C3'])
( (<Cell Sheet1.A1>, <Cell Sheet1.B1>, <Cell Sheet1.C1>), (<Cell Sheet1.A2>,
<Cell Sheet1.B2>, <Cell Sheet1.C2>), (<Cell Sheet1 .A3>, <Cell Sheet1.B3>,
<Cell Sheet1.C3>))
u >>> para rowOfCellObjects en la hoja ['A1': 'C3']:
v para cellObj en rowOfCellObjects:
print (cellObj.coordinate, cellObj.value)
print ('--- FIN DE LA FILA ---')
Trabajar con hojas de cálculo de Excel 271
A1 2015-04-05 13:34:02
B1 Manzanas
C1 73
--- FIN DE LA FILA ---
A2 2015-04-05 03:41:23
B2 Cerezas
C2 85
--- FIN DE LA FILA ---
A3 2015 -04-06 12:46:51
B3 Peras
C3 14
--- FIN DE LA FILA ---
Aquí, especificamos que queremos los objetos Cell en el área rectangular
de A1 a C3, y obtenemos un objeto Generator que contiene los objetos Cell en
esa área. Para ayudarnos a visualizar este objeto Generador, podemos usar tuple () en él
para mostrar sus objetos Cell en una tupla.
Esta tupla contiene tres tuplas: una para cada fila, desde la parte superior del
área deseada hasta la parte inferior. Cada una de estas tres tuplas internas contiene los
objetos Cell en una fila de nuestra área deseada, desde la celda más a la izquierda a la derecha.
Entonces, en general, nuestro segmento de la hoja contiene todos los objetos de Celda en el área
desde A1 a C3, comenzando desde la celda superior izquierda y terminando con la celda inferior
derecha.
Para imprimir los valores de cada celda en el área, usamos dos para bucles. El
bucle for externo va sobre cada fila en el segmento u. Luego, para cada fila, el
bucle anidado pasa por cada celda en esa fila v.
Para acceder a los valores de las celdas en una fila o columna en particular, también puede
usar el atributo de filas y columnas de un objeto Hoja de trabajo. Ingrese lo siguiente en
el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('example.xlsx')
>>> sheet = wb.get_active_sheet ()
>>> sheet.columns [1]
(<Cell Sheet1.B1>, <Cell Sheet1 .B2>, <Cell Sheet1.B3>, <Cell Sheet1.B4>,
<Cell Sheet1.B5>, <Cell Sheet1.B6>, <Cell Sheet1.B7>)
>>> para cellObj en sheet.columns [1 ]:
print (cellObj.value)
Manzanas
Cerezas
Peras
Naranjas
Manzanas
Plátanos
Fresas
El uso del atributo de filas en un objeto de hoja de trabajo le dará una tupla de
tuplas. Cada una de estas tuplas internas representa una fila y contiene los
objetos Cell en esa fila. El atributo de columnas también le da una tupla de tuplas,
con cada una de las tuplas internas que contienen los objetos Cell en un determinado
272 Capítulo 12
columna. Por ejemplo , xlsx , dado que hay 7 filas y 3 columnas, las filas
nos dan una tupla de 7 tuplas (cada una con 3 objetos de Celda), y las columnas nos dan una
tupla de 3 tuplas (cada una con 7 objetos de Celda).
Para acceder a una tupla en particular, puede referirse a ella por su índice en la
tupla más grande. Por ejemplo, para obtener la tupla que representa la columna B, utilice
sheet.columns [1]. Para obtener la tupla que contiene los objetos Cell en la columna A,
usaría sheet.columns [0]. Una vez que tenga una tupla que represente una fila o
columna, puede recorrer sus objetos Cell e imprimir sus valores.
Libros de trabajo, hojas, celdas
Como una revisión rápida, aquí hay un resumen de todas las funciones, métodos y tipos de datos
involucrados en la lectura de una celda de un archivo de hoja de cálculo:
1. Importe el módulo openpyxl.
2. Llame a la función openpyxl.load_workbook ().
3. Obtenga un objeto Libro de trabajo.
4. Llame al método de libro get_active_sheet () o get_sheet_by_name ().
5. Obtenga un objeto de hoja de trabajo.
6. Utilice la indexación o el método de hoja cell () con palabra clave de fila y columna
argumentos
7. Obtenga un objeto Cell.
8. Lea el atributo de valor del objeto Cell.
Proyecto: lectura de datos de una hoja de cálculo
Supongamos que tiene una hoja de cálculo de datos del Censo de los EE. UU. 2010 y que
tiene la aburrida tarea de recorrer sus miles de filas para contar
la población total y el número de secciones del censo para cada condado. (Un
tramo censal es simplemente un área geográfica definida para los fines del
censo). Cada fila representa un tramo censal único. Llamaremos a la spread-
censuspopdata.xlsx archivo de hoja, y se puede descargar desde http: // nostarch
.com / automatestuff / . Su contenido se parece a la Figura 12-2.
Figura 12-2: La hoja de cálculo del censopopdata .xlsx
Trabajar con hojas de cálculo de Excel 273
Aunque Excel puede calcular la suma de varias celdas seleccionadas,
aún tendría que seleccionar las celdas para cada uno de los más de 3.000 condados. Incluso
si toma solo unos segundos calcular la población de un condado a mano,
esto tomaría horas para toda la hoja de cálculo.
En este proyecto, escribirá un guión que puede leer el archivo de la hoja de cálculo del censo
y calcular las estadísticas de cada condado en cuestión de segundos.
Esto es lo que hace su programa:

• Lee los datos de la hoja de cálculo de Excel. • Cuenta el número de secciones censales en cada
condado. • Cuenta la población total de cada condado. • Imprime los resultados.

Esto significa que su código deberá hacer lo siguiente:

• Abra y lea las celdas de un documento de Excel con el módulo openpyxl. • Calcule todos los datos
de la zona y la población y almacénelos en una estructura de datos. • Escriba la estructura de datos
en un archivo de texto con la extensión .py usando el
Módulo pprint.
Paso 1: Lea los datos de la hoja de cálculo
Solo hay una hoja en la hoja de cálculo censuspopdata.xlsx , denominada
'Población por tramo censal', y cada fila contiene los datos de un solo centro
. Las columnas son el número del tracto (A), la abreviatura del estado (B),
el nombre del condado (C) y la población del tracto (D).
Abra una nueva ventana del editor de archivos e ingrese el siguiente código. Guarde el
archivo como readCensusExcel.py.
#! python3
# readCensusExcel.py - Tabula la población y el número de secciones censales para
# cada condado.
u importar openpyxl, pprint
print ('Abrir libro de trabajo ...')
v wb = openpyxl.load_workbook ('censuspopdata.xlsx')
w sheet = wb.get_sheet_by_name ('Población por sector censal')
countyData = {}
# TODO: Complete los datos del condado con la población y las zonas de cada condado.
print ('Leyendo filas ...')
x para la fila en el rango (2, sheet.get_highest_row () + 1):
# Cada fila en la hoja de cálculo tiene datos para una sección censal.
estado = hoja ['B' + str (fila)]. valor
condado = hoja ['C' + str (fila)]. valor
pop = hoja ['D' + str (fila)]. valor
# TODO: abra un nuevo archivo de texto y escriba el contenido de countyData.
274 Capítulo 12
Este código importa el módulo openpyxl, así como el módulo pprint que
usará para imprimir los datos finales del condado u. Luego abre el
archivo censuspopdata .xlsx v, obtiene la hoja con los datos del censo w y comienza a iterar sobre
sus filas x.
Tenga en cuenta que también ha creado una variable llamada countyData, que
contendrá las poblaciones y el número de tratados que calcula para cada condado.
Sin embargo, antes de poder almacenar algo en él, debe determinar exactamente
cómo estructurará los datos que contiene.
Paso 2: llenar la estructura de
datos La estructura de datos almacenada en countyData será un diccionario con abreviaturas de
estado
como claves. Cada abreviatura estatal se asignará a otro diccionario,
cuyas claves son cadenas de los nombres de condado en ese estado. El nombre de cada condado
a su vez se asignará a un diccionario con solo dos claves, 'tratados' y 'pop'. Estas
claves corresponden al número de distritos censales y la población del condado. Por
ejemplo, el diccionario se verá similar a esto:
{'AK': {'Aleutians East': {'pop': 3141, 'tracts': 1},
'Aleutians West': {'pop': 5561, 'tracts': 2},
'Anchorage': {' pop ': 291826,' tracts ': 55},
' Bethel ': {' pop ': 17013,' tracts ': 3},
' Bristol Bay ': {' pop ': 997,' tracts ': 1},
- - cortar -
Si el diccionario anterior se almacenara en countyData, las siguientes
expresiones se evaluarían así:
>>> countyData ['AK'] ['Anchorage'] ['pop']
291826
>>> countyData ['AK'] ['Anchorage'] ['tratados']
55
En términos más generales, las claves del diccionario countyData se verán así:
countyData [ estado abreviado ] [ condado ] ['tratados']
countyData [ estado abreviado ] [ condado ] ['pop']
Ahora que sabe cómo se estructurará countyData, puede escribir el
código que lo completará con los datos del condado. Agregue el siguiente código a la parte
inferior de su programa:
#! python 3
# readCensusExcel.py - Tabula la población y el número de secciones censales para
# cada condado.
- cortar -
Trabajar con hojas de cálculo de Excel 275
para fila en rango (2, sheet.get_highest_row () + 1):
# Cada fila en la hoja de cálculo tiene datos para un tramo censal.
estado = hoja ['B' + str (fila)]. valor
condado = hoja ['C' + str (fila)]. valor
pop = hoja ['D' + str (fila)]. valor
# Asegúrese de que exista la clave para este estado.
u countyData.setdefault (estado, {})
# Asegúrese de que exista la clave para este condado en este estado.
v countyData [estado] .setdefault (condado, {'tratados': 0, 'pop': 0})
# Cada fila representa una sección censal, por lo tanto, incremente en una.
w countyData [estado] [condado] ['tratados'] + = 1
# Aumentar el pop del condado por el pop en esta sección del censo.
x countyData [estado] [condado] ['pop'] + = int (pop)
# TODO: abra un nuevo archivo de texto y escriba el contenido de countyData.
Las últimas dos líneas de código realizan el trabajo de cálculo real, incrementando
el valor de los tractos w y aumentando el valor de pop x para el
condado actual en cada iteración del ciclo for.
El otro código está allí porque no puede agregar un diccionario del condado como
valor para una clave de abreviatura estatal hasta que la clave en sí misma exista en countyData.
(Es decir, countyData ['AK'] ['Anchorage'] ['tracts'] + = 1 causará un error si
la clave 'AK' aún no existe). Para asegurarse de que la clave de abreviatura de estado existe
en su estructura de datos, debe llamar al método setdefault () para establecer un
valor si aún no existe uno para el estado u.
Así como el diccionario countyData necesita un diccionario como valor para cada
clave de abreviatura estatal, cada uno de esos diccionarios necesitará su propio diccionario
como valor para cada clave de condado v. Y cada uno de esos diccionarios a su vez
necesitará claves 'tratados' y ' pop 'que comienza con el valor entero 0. (Si
alguna vez pierde la noción de la estructura del diccionario, consulte el diccionario de ejemplo
al comienzo de esta sección).
Dado que setdefault () no hará nada si la clave ya existe, puede llamarla
en cada iteración del bucle for sin ningún problema.
Paso 3: Escriba los resultados en un archivo
Una vez que el ciclo for haya finalizado, el diccionario countyData contendrá toda
la información de población y tracto con clave por condado y estado. En este
punto, podría programar más código para escribir esto en un archivo de texto u otra
hoja de cálculo de Excel. Por ahora, usemos la función pprint.pformat () para
escribir el valor del diccionario countyData como una cadena masiva en un archivo llamado
census2010.py . Agregue el siguiente código al final de su programa
(asegurándose de mantenerlo sin sangría para que se mantenga fuera del ciclo for):
#! python 3
# readCensusExcel.py - Tabula la población y el número de secciones censales para
# cada condado.
276 Capítulo 12
- cortar -
para fila en rango (2, sheet.get_highest_row () + 1):
- snip -
# Abra un nuevo archivo de texto y escriba el contenido de countyData.
print ('Escribiendo resultados ...')
resultFile = open ('census2010.py', 'w')
resultFile.write ('allData =' + pprint.pformat (countyData))
resultFile.close ()
print ('Hecho. ')
La función pprint.pformat () produce una cadena que está formateada
como código Python válido. Al enviarlo a un archivo de texto llamado census2010.py,
¡ha generado un programa Python a partir de su programa Python! Esto puede
parecer complicado, pero la ventaja es que ahora puede importar census2010.py como cualquier
otro módulo de Python. En el shell interactivo, cambie el directorio de trabajo actual a la carpeta
con su archivo census2010.py recién creado (en mi computadora portátil, esto es C: \ Python34 ), y
luego impórtelo:

>>> import os
>>> os.chdir ('C: \\ Python34')
>>> import census2010
>>> census2010.allData ['AK'] ['Anchorage']
{'pop': 291826, 'tratados ': 55}
>>> anchoragePop = census2010.allData [' AK '] [' Anchorage '] [' pop ']
>>> print (' La población 2010 de Anchorage era '+ str (anchoragePop))
La población 2010 de Anchorage fue 291826
El programa readCensusExcel.py fue un código desechable: una vez que haya
guardado sus resultados en census2010.py , no necesitará ejecutar el programa nuevamente.
Siempre que necesite los datos del condado, puede ejecutar el censo de importación 2010.
Calcular estos datos a mano habría llevado horas; Este programa lo
hizo en unos segundos. Con OpenPyXL, no tendrá problemas para extraer
información guardada en una hoja de cálculo de Excel y realizar cálculos
en ella. Puede descargar el programa completo desde http: // nostarch
.com / automatestuff / .
Ideas para programas similares
Muchas empresas y oficinas usan Excel para almacenar varios tipos de datos, y
no es raro que las hojas de cálculo se vuelvan grandes y difíciles de manejar. Cualquier
programa que analice una hoja de cálculo de Excel tiene una estructura similar: carga
el archivo de hoja de cálculo, prepara algunas variables o estructuras de datos y luego recorre
cada una de las filas de la hoja de cálculo. Tal programa podría hacer lo
siguiente:

• Comparar datos en varias filas en una hoja de cálculo. • Abra varios archivos de Excel y compare
datos entre hojas de cálculo.

Trabajar con hojas de cálculo de Excel 277


• Compruebe si una hoja de cálculo tiene filas en blanco o datos no válidos en alguna celda y alerta
al usuario si es así.
• Lea los datos de una hoja de cálculo y utilícelos como entrada para sus programas
de Python .
escribir documentos de Excel
OpenPyXL también proporciona formas de escribir datos, lo que significa que sus programas
pueden crear y editar archivos de hojas de cálculo. Con Python, es simple crear
hojas de cálculo con miles de filas de datos.
Crear y guardar documentos de Excel
Llame a la función openpyxl.Workbook () para crear un nuevo objeto de libro en blanco.
Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.Workbook ()
>>> wb.get_sheet_names ()
['Hoja']
>>> sheet = wb.get_active_sheet ()
>>> sheet.title
'Hoja'
>>> sheet.title = 'Hoja de huevos de tocino con spam'
>>> wb.get_sheet_names ()
['Hoja de huevos de tocino con spam']
El libro comenzará con una sola hoja llamada Hoja . Puede
cambiar el nombre de la hoja almacenando una nueva cadena en su atributo de título.
Cada vez que modifique el objeto Libro de trabajo o sus hojas y celdas, el
archivo de hoja de cálculo no se guardará hasta que llame al método de libro guardar ().
Ingrese lo siguiente en el shell interactivo (con example.xlsx en el
directorio de trabajo actual):
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('example.xlsx')
>>> sheet = wb.get_active_sheet ()
>>> sheet.title = 'Spam Spam Spam'
>>> wb.save (' example_copy.xlsx ')
Aquí, cambiamos el nombre de nuestra hoja. Para guardar nuestros cambios, pasamos un
nombre de archivo como una cadena al método save (). Pasar un nombre de archivo diferente
al original, como 'example_copy.xlsx', guarda los cambios en una copia de la hoja de
cálculo.
Siempre que edite una hoja de cálculo que haya cargado desde un archivo,
siempre debe guardar la nueva hoja de cálculo editada en un nombre de archivo diferente al
original. De esa manera, todavía tendrá el archivo de hoja de cálculo original para trabajar
en caso de que un error en su código haga que el archivo nuevo guardado tenga datos incorrectos o
corruptos.
278 Capítulo 12
Creación y eliminación de hojas Las
hojas se pueden agregar y quitar de un libro de trabajo con los métodos create_sheet ()
y remove_sheet (). Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.Workbook ()
>>> wb.get_sheet_names ()
['Hoja']
>>> wb.create_sheet ()
<Hoja de trabajo "Hoja1">
>>> wb.get_sheet_names ()
['Hoja', 'Hoja1']
>>> wb.create_sheet (index = 0, title = 'Primera hoja')
<Hoja de trabajo "Primera hoja">
>>> wb.get_sheet_names ()
['Primera hoja', 'Hoja ',' Sheet1 ']
>>> wb.create_sheet (index = 2, title =' Middle Sheet ')
<Worksheet "Middle Sheet">
>>> wb.get_sheet_names ()
[' First Sheet ',' Sheet ',' Middle Sheet ',' Sheet1 ']
El método create_sheet () devuelve un nuevo objeto de hoja de trabajo llamado Hoja X ,
que por defecto está configurado para ser la última hoja del libro. Opcionalmente, el
índice y el nombre de la nueva hoja se pueden especificar con los argumentos de índice y título de
palabras clave.
Continúe con el ejemplo anterior ingresando lo siguiente:
>>> wb.get_sheet_names ()
['Primera hoja', 'Hoja', 'Hoja central', 'Hoja1']
>>> wb.remove_sheet (wb.get_sheet_by_name ('Hoja central'))
>>> wb.remove_sheet (wb.get_sheet_by_name ('Sheet1'))
>>> wb.get_sheet_names ()
['Primera hoja', 'Hoja']
El método remove_sheet () toma un objeto de
hoja de trabajo, no una cadena del nombre de la hoja, como argumento. Si solo conoce el nombre de
una hoja que desea
eliminar, llame a get_sheet_by_name () y pase su valor de retorno a remove_sheet ().
Recuerde llamar al método save () para guardar los cambios después de agregar
o quitar hojas del libro.
Escribir valores en celdas
Escribir valores en celdas es muy parecido a escribir valores en claves en un diccionario.
Ingrese esto en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.Workbook ()
>>> sheet = wb.get_sheet_by_name ('Sheet')
>>> sheet ['A1'] = '¡Hola mundo!'
>>> hoja ['A1']. valor
'¡Hola mundo!'
Trabajar con hojas de cálculo de Excel 279
Si tiene la coordenada de la celda como una cadena, puede usarla como una clave de diccionario
en el objeto Hoja de trabajo para especificar en qué celda escribir.
Proyecto: actualización de una hoja de cálculo
En este proyecto, escribirá un programa para actualizar celdas en una hoja de cálculo de
ventas de productos. Su programa buscará en la hoja de cálculo, encontrará
tipos específicos de productos y actualizará sus precios. Descargue esta hoja
de cálculo de http://nostarch.com/automatestuff/ . La Figura 12-3 muestra cómo se ve la hoja
de cálculo
.
Figura 12-3: una hoja de cálculo de ventas de productos
Cada fila representa una venta individual. Las columnas son el tipo de
producto vendido (A), el costo por libra de ese producto (B), la cantidad de
libras vendidas (C) y los ingresos totales de la venta (D). La
columna TOTAL se establece en la fórmula de Excel = REDONDA (B3 * C3, 2) , que multiplica el
costo por libra por la cantidad de libras vendidas y redondea el resultado al
centavo más cercano. Con esta fórmula, las celdas en la columna TOTAL se
actualizarán automáticamente
si hay un cambio en la columna B o C.
Ahora imagine que los precios del ajo, el apio y los limones se ingresaron
incorrectamente, dejándolo con la aburrida tarea de pasar por miles
de filas en esta hoja de cálculo para actualizar el costo por libra de cualquier
fila de ajo, bodega y limón. No puede hacer una simple búsqueda y reemplazo del precio
porque puede haber otros artículos con el mismo precio que no desea
"corregir" por error. Para miles de filas, esto llevaría horas hacerlo
a mano . Pero puede escribir un programa que pueda lograr esto en segundos.
Su programa hace lo siguiente:

• Recorre todas las filas. • Si la fila es para ajo, apio o limones, cambia el precio.

280 Capítulo 12
Esto significa que su código deberá hacer lo siguiente:

• Abra el archivo de hoja de cálculo. • Para cada fila, verifique si el valor en la columna A es Apio,
Ajo,

o limón.
• Si es así, actualice el precio en la columna B. • Guarde la hoja de cálculo en un nuevo archivo
(para que no pierda la antigua distribución)

hoja, por si acaso).


Paso 1: configure una estructura de datos con la información de actualización
Los precios que necesita actualizar son los siguientes:
Apio 1.19
Ajo 3.07
Limón 1.27
Podrías escribir código como este:
if produceName == 'Celery':
cellObj = 1.19
if produceName == 'Garlic':
cellObj = 3.07
if produceName == 'Lemon':
cellObj = 1.27
Tener el producto y los datos de precios actualizados codificados de esta manera es un
poco poco elegante. Si necesita actualizar la hoja de cálculo nuevamente con diferentes
precios o diferentes productos, tendrá que cambiar mucho el código.
Cada vez que cambia el código, corre el riesgo de introducir errores.
Una solución más flexible es almacenar la información de precios corregida en un
diccionario y escribir su código para usar esta estructura de datos. En una nueva ventana del editor
de archivos
, ingrese el siguiente código:
#! python3
# updateProduce.py: corrige los costos en la hoja de cálculo de ventas de productos.
importar openpyxl
wb = openpyxl.load_workbook ('produceSales.xlsx')
sheet = wb.get_sheet_by_name ('Sheet')
# Los tipos de productos y sus precios actualizados
PRICE_UPDATES = {'Ajo': 3.07,
'Apio': 1.19,
'Limón': 1.27}
# TODO: recorre las filas y actualiza los precios.
Guarde esto como updateProduce.py . Si necesita actualizar la hoja de cálculo nuevamente,
deberá actualizar solo el diccionario PRICE_UPDATES, no cualquier otro código.
Trabajar con hojas de cálculo de Excel 281
Paso 2: Verifique todas las filas y actualice los precios incorrectos
La siguiente parte del programa recorrerá todas las filas de la
hoja de cálculo . Agregue el siguiente código al final de updateProduce.py :
#! python3
# updateProduce.py: corrige los costos en la hoja de cálculo de ventas de productos.
- cortar -
# Recorre las filas y actualiza los precios.
u para rowNum en rango (2, sheet.get_highest_row ()): # omita la primera fila
v produceName = sheet.cell (row = rowNum, column = 1) .value
w si produceName en PRICE_UPDATES:
sheet.cell (row = rowNum, column = 2) .value = PRICE_UPDATES [produceName]
x wb.save ('updatedProduceSales.xlsx')
Recorremos las filas comenzando en la fila 2, ya que la fila 1 es solo el
encabezado u. La celda en la columna 1 (es decir, la columna A) se almacenará en la
variable produceName v. Si produceName existe como una clave en el diccionario
PRICE_UPDATES
w, entonces sabe que esta es una fila que debe tener su precio corregido.
El precio correcto estará en PRICE_UPDATES [produceName].
Observe qué tan limpio usando PRICE_UPDATES hace el código. Solo
se necesita una declaración de estado , en lugar de código como si produceName == 'Ajo':, para
que se actualice cada tipo de producto. Y dado que el código usa el
diccionario PRICE_UPDATES en lugar de codificar los nombres de los productos y los costos
actualizados
en el ciclo for, solo modifica el diccionario PRICE_UPDATES y no el
código si la hoja de cálculo de ventas de productos necesita cambios adicionales.
Después
de revisar toda la hoja de cálculo y realizar cambios, el código guarda el objeto Libro
de trabajo en updatedProduceSales.xlsx x. No sobrescribe
la hoja de cálculo anterior en caso de que haya un error en su programa y la
hoja de cálculo actualizada sea incorrecta. Después de comprobar que la hoja de
cálculo actualizada
se ve bien, puede eliminar la hoja de cálculo anterior.
Puede descargar el código fuente completo de este programa desde
http://nostarch.com/automatestuff/ .
Ideas para programas similares
Dado que muchos empleados de oficina usan hojas de cálculo de Excel todo el tiempo, un
programa
que puede editar y escribir automáticamente archivos de Excel podría ser realmente útil. Tal
programa podría hacer lo siguiente:

• Leer datos de una hoja de cálculo y escribirlos en partes de otras hojas de cálculo.
• Leer datos de sitios web, archivos de texto o el portapapeles y escribirlos en una hoja de
cálculo.
• Automáticamente "limpiar" datos en hojas de cálculo. Por ejemplo, podría usar expresiones
regulares para leer múltiples formatos de números de teléfono y editarlos en un solo formato
estándar.
282 Capítulo 12
Establecer el estilo de fuente de las celdas El
diseño de ciertas celdas, filas o columnas puede ayudarlo a enfatizar
Tant áreas en su hoja de cálculo. En la hoja de cálculo de producción, por ejemplo,
su programa podría aplicar texto en negrita a las filas de papa, ajo y chirivía.
O tal vez quiera poner en cursiva cada fila con un costo por libra mayor
de $ 5. Diseñar partes de una hoja de cálculo grande a mano sería tedioso, pero
sus programas pueden hacerlo al instante.
Para personalizar los estilos de fuente en las celdas, importante, importe las funciones Font () y
Style () desde el módulo openpyxl.styles.
from openpyxl.styles import Font, Style
Esto le permite escribir Font () en lugar de openpyxl.styles.Font (). (Consulte
“Importar módulos” en la página 57 para revisar este estilo de declaración de importación).
Aquí hay un ejemplo que crea un nuevo libro de trabajo y configura la celda A1 para que tenga
una fuente en cursiva de 24 puntos. Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> from openpyxl.styles import Font, Style
>>> wb = openpyxl.Workbook ()
>>> sheet = wb.get_sheet_by_name ('Hoja')
u >>> italic24Font = Fuente (tamaño = 24, cursiva = Verdadero)
v >>> styleObj = Estilo (font = italic24Font)
w >>> hoja ['A1']. style = styleObj
>>> sheet ['A1'] = '¡Hola mundo!'
>>> wb.save ('styled.xlsx')
OpenPyXL representa la colección de configuraciones de estilo para una celda con un
objeto Style, que se almacena en el atributo de estilo del objeto Cell. El estilo de una celda
se puede configurar asignando el objeto Estilo al atributo de estilo.
En este ejemplo, Font (size = 24, italic = True) devuelve un objeto Font, que
se almacena en italic24Font u. Los argumentos de palabras clave para Font (), size y italic,
configuran los atributos de estilo del objeto Font. Este objeto Font se pasa
a la llamada Style (font = italic24Font), que devuelve el valor que almacenó en
styleObj v. Y cuando styleObj se asigna al atributo de estilo de la celda w, toda
esa información de estilo de fuente se aplica a la celda A1.
Objetos de fuente
Los atributos de estilo en los objetos de fuente afectan la forma en que se muestra el texto en las
celdas
. Para establecer atributos de estilo de fuente, pasa argumentos de palabras clave a Font ().
La Tabla 12-2 muestra los posibles argumentos de palabras clave para la función Font ().
Trabajar con hojas de cálculo de Excel 283
tabla 12-2: Argumentos de palabras clave para el estilo de fuente Atributos
argumento de palabra clave Tipo de datos Nombre de la descripción
Cadena El nombre de la fuente, como 'Calibri'
o 'Times New Roman'
Tamaño entero El tamaño en puntos en
negrita Boolean True, para negrita
cursiva Boolean True, para cursiva
Puede llamar a Font () para crear un objeto Font y almacenar ese objeto Font en
una variable. Luego pasa eso a Style (), almacena el objeto Style resultante
en una variable y asigna esa variable al atributo de estilo de un objeto Cell. Por
ejemplo, este código crea varios estilos de fuente:
>>> import openpyxl
>>> from openpyxl.styles import Font, Style
>>> wb = openpyxl.Workbook ()
>>> sheet = wb.get_sheet_by_name ('Hoja')
>>> fontObj1 = Font (name = 'Times New Roman', negrita = True)
>>> styleObj1 = Style (font = fontObj1)
>>> hoja ['A1']. style / styleObj
>>> hoja ['A1 '] =' Negrita Times New Roman '
>>> fontObj2 = Fuente (tamaño = 24, cursiva = Verdadero)
>>> styleObj2 = Estilo (font = fontObj2)
>>> hoja ['B3']. style / styleObj
>>> hoja ['B3'] = ' 24 pt cursiva '
>>> wb.save ('styles.xlsx')
Aquí, almacenamos un objeto Font en fontObj1 y lo usamos para crear un objeto Style,
que almacenamos en styleObj1, y luego establecemos el atributo de estilo del objeto A1 Cell en
styleObj. Repetimos el proceso con otro objeto Font y Style para
establecer el estilo de una segunda celda. Después de ejecutar este código, los estilos de las
celdas A1 y B3 en la hoja de cálculo se establecerán en estilos de fuente personalizados, como se
muestra en la
Figura 12-4.
Figura 12-4: una hoja de cálculo con estilos de fuente personalizados
284 Capítulo 12
Para la celda A1, establecemos el nombre de la fuente en 'Times New Roman' y ponemos negrita en
verdadero,
por lo que nuestro texto aparece en negrita Times New Roman. No especificamos un tamaño, por
lo que se usa el valor predeterminado de openpyxl, 11. En la celda B3, nuestro texto está en cursiva,
con un tamaño de 24;
no especificamos un nombre de fuente, por lo que se usa el valor predeterminado de openpyxl,
Calibri.
fórmulas
Las fórmulas , que comienzan con un signo igual, pueden configurar celdas para contener
valores calculados a partir de otras celdas. En esta sección, usará el
módulo openpyxl para agregar fórmulas mediante programación a las celdas, al igual que cualquier
valor normal.
Por ejemplo:
>>> hoja ['B9'] = '= SUMA (B1: B8)'
Esto almacenará = SUMA (B1: B8) como el valor en la celda B9. Esto establece la celda B9
en una fórmula que calcula la suma de valores en las celdas B1 a B8. Puede ver
esto en acción en la Figura 12-5.
Figura 12-5: la celda B9 contiene la fórmula = SUMA (B1: B8) ,
que agrega las celdas B1 a B8.
Una fórmula se establece como cualquier otro valor de texto en una celda. Ingrese lo siguiente
en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.Workbook ()
>>> sheet = wb.get_active_sheet ()
>>> sheet ['A1'] = 200
>>> sheet ['A2'] = 300
>>> sheet ['A3'] = '= SUMA (A1: A2)'
>>> wb.save ('writeFormula.xlsx')
Trabajar con hojas de cálculo de Excel 285
Las celdas en A1 y A2 se establecen en 200 y 300, respectivamente. El valor
en la celda A3 se establece en una fórmula que suma los valores en A1 y A2. Cuando se abre la
hoja de cálculo en Excel, A3 mostrará su valor como 500.
También puede leer la fórmula en una celda como lo haría con cualquier valor.
Sin embargo, si desea ver el resultado del cálculo de la fórmula en
lugar de la fórmula literal, debe pasar True para el
argumento de palabra clave data_only a load_workbook (). Esto significa que un objeto Workbook
puede mostrar
las fórmulas o el resultado de las fórmulas, pero no ambas. (Pero puede tener
varios objetos del libro de trabajo cargados para el mismo archivo de hoja de cálculo). Ingrese lo
siguiente en el shell interactivo para ver la diferencia entre cargar un
libro de trabajo con y sin el argumento de palabra clave data_only:
>>> import openpyxl
>>> wbFormulas = openpyxl.load_workbook ('writeFormula.xlsx')
>>> sheet = wbFormulas.get_active_sheet ()
>>> hoja ['A3']. value
'= SUMA (A1: A2)'
>>> wbDataOnly = openpyxl.load_workbook ('writeFormula.xlsx', data_only = True)
>>> sheet = wbDataOnly.get_active_sheet ()
>>> hoja ['A3']. valor
500
Aquí, cuando se llama a load_workbook () con data_only = True, la celda A3
muestra 500, el resultado de la fórmula = SUMA (A1: A2) , en lugar del texto de
la fórmula.
Las fórmulas de Excel ofrecen un nivel de programabilidad para hojas de cálculo, pero pueden
volverse rápidamente inmanejables para tareas complicadas. Por ejemplo, incluso si
está profundamente familiarizado con las fórmulas de Excel, es un dolor de cabeza intentar
descifrar
qué = IFERROR (TRIM (IF (LEN (VLOOKUP (F7, Sheet2! $ A $ 1: $ B $ 10000, 2,
FALSE)) > 0, SUBSTITUTE (VLOOKUP (F7, Sheet2! $ A $ 1: $ B $ 10000, 2, FALSE),
"", ""), "")), "") realmente lo hace. El código de Python es mucho más legible.
Ajuste de filas y columnas
En Excel, ajustar el tamaño de las filas y columnas es tan fácil como hacer clic y
arrastrar los bordes de una fila o encabezado de columna. Pero si necesita establecer
el tamaño de una fila o columna en función del contenido de sus celdas o si desea establecer
tamaños en una
gran cantidad de archivos de hoja de cálculo, será mucho más rápido escribir un programa Python
para hacerlo.
Las filas y columnas también se pueden ocultar por completo de la vista. O se pueden
"congelar" en su lugar para que siempre estén visibles en la pantalla y aparezcan
en cada página cuando se imprime la hoja de cálculo (lo cual es útil para los encabezados).
286 Capítulo 12
La configuración de los
objetos de hoja de trabajo de altura de fila y ancho de columna tienen atributos row_dimensions y
column_dimensions que
controlan las alturas de fila y los anchos de columna. Ingrese esto en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.Workbook ()
>>> sheet = wb.get_active_sheet ()
>>> sheet ['A1'] = 'Fila alta'
>>> sheet ['B2'] = ' Columna ancha '
>>> sheet.row_dimensions [1] .height = 70
>>> sheet.column_dimensions [' B ']. Width = 20
>>> wb.save (' dimensions.xlsx ')
Las fila_dimensiones y columna_dimensiones de una hoja son valores tipo diccionario;
row_dimensions contiene objetos RowDimension y column_dimensions contiene
objetos ColumnDimension. En row_dimensions, puede acceder a uno de los objetos
utilizando el número de la fila (en este caso, 1 o 2). En column_dimensions,
puede acceder a uno de los objetos utilizando la letra de la columna (en este caso,
A o B).
La hoja de cálculo Dimensions.xlsx se parece a la Figura 12-6.
Figura 12-6: Fila 1 y columna B configuradas en
alturas y anchos más grandes
Una vez que tenga el objeto RowDimension, puede establecer su altura. Una vez que
tenga el objeto ColumnDimension, puede establecer su ancho. La altura de la fila se puede
establecer en un valor entero o flotante entre 0 y 409. Este valor representa la
altura medida en puntos , donde un punto equivale a 1/72 de pulgada. El
alto de fila predeterminado es 12.75. El ancho de columna se puede establecer en un
valor entero o flotante entre 0 y 255. Este valor representa el número de caracteres
en el tamaño de fuente predeterminado (11 puntos) que se puede mostrar en la celda. El
ancho de columna predeterminado es 8.43 caracteres. Las columnas con anchos de 0 o filas
con alturas de 0 están ocultas para el usuario.
Combinar y separar celdas
Un área rectangular de celdas se puede fusionar en una sola celda con el
método de hoja merge_cells (). Ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.Workbook ()
Trabajar con hojas de cálculo de Excel 287
>>> sheet = wb.get_active_sheet ()
>>> sheet.merge_cells ('A1: D3')
>>> sheet ['A1'] = 'Doce celdas fusionadas'.
>>> sheet.merge_cells ('C5: D5')
>>> sheet ['C5'] = 'Dos celdas combinadas'.
>>> wb.save ('merged.xlsx')
El argumento de merge_cells () es una sola cadena de las
celdas superior izquierda e inferior derecha del área rectangular que se fusionará: 'A1: D3' combina
12 celdas en una sola celda. Para establecer el valor de estas celdas combinadas, simplemente
configure
el valor de la celda superior izquierda del grupo combinado.
Cuando ejecute este código, merged.xlsx se verá como en la Figura 12-7.
Figura 12-7: Celdas combinadas en una hoja de cálculo
Para separar las celdas, llame al método de hoja unmerge_cells (). Ingrese esto en
el shell interactivo.
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('merged.xlsx')
>>> sheet = wb.get_active_sheet ()
>>> sheet.unmerge_cells ('A1: D3')
>>> sheet.unmerge_cells ( 'C5: D5')
>>> wb.save ('merged.xlsx')
Si guarda sus cambios y luego mira la hoja de cálculo,
verá que las celdas combinadas han vuelto a ser celdas individuales.
Congelar paneles
Para que las hojas de cálculo sean demasiado grandes para mostrarse de una vez, es útil "congelar"
algunas de las filas superiores o columnas más a la izquierda en la pantalla. Los
encabezados de columnas o filas congeladas , por ejemplo, siempre son visibles para el usuario
incluso cuando se desplazan
por la hoja de cálculo. Estos se conocen como paneles de congelación . En OpenPyXL,
cada objeto de hoja de trabajo tiene un atributo freeze_panes que se puede establecer en un
objeto Cell o en una cadena de coordenadas de una celda. Tenga en cuenta que todas las filas de
arriba y todas las
columnas a la izquierda de esta celda se congelarán, pero la fila y la columna de la
celda no se congelarán.
Para descongelar todos los paneles, configure freeze_panes en None o 'A1'. La Tabla 12-3
muestra qué filas y columnas se congelarán para algunos ajustes de ejemplo
de freeze_panes.
288 Capítulo 12
tabla 12-3: Ejemplos de
paneles congelados freeze_panes configurando filas y columnas frozen
sheet.freeze_panes = 'A2' Fila 1
sheet.freeze_panes = 'B1' Columna A
sheet.freeze_panes = 'C1' Columnas A y B
sheet.freeze_panes = 'C2' Fila 1 y columnas A y B
sheet.freeze_panes = 'A1' o
sheet.freeze_panes = Ninguno
Sin paneles congelados
Asegúrese de tener la hoja de cálculo de ventas de productos de http: // nostarch
.com / automatestuff / . Luego ingrese lo siguiente en el shell interactivo:
>>> import openpyxl
>>> wb = openpyxl.load_workbook ('produceSales.xlsx')
>>> sheet = wb.get_active_sheet ()
>>> sheet.freeze_panes = 'A2'
>>> wb.save ('freezeExample. xlsx ')
Si establece el atributo freeze_panes en 'A2', la fila 1 siempre será visible
, sin importar dónde se desplace el usuario en la hoja de cálculo. Puede ver esto
en la Figura 12-8.
Figura 12-8: Con freeze_panes establecido en 'A2', la fila 1 siempre es visible incluso cuando el
usuario se
desplaza hacia abajo.
gráficos
OpenPyXL admite la creación de gráficos de barras, líneas, dispersión y gráficos circulares
utilizando los
datos en las celdas de una hoja. Para hacer un gráfico, debe hacer lo siguiente:
1. Cree un objeto de referencia a partir de una selección rectangular de celdas.
2. Cree un objeto Serie pasando el objeto Referencia.
3. Crear un objeto gráfico.
Trabajar con hojas de cálculo de Excel 289
4. Agregue el objeto Serie al objeto Gráfico.
5. Opcionalmente, establezca drawing.top, drawing.left, drawing.width y
drawing.height variables del objeto Chart.
6. Agregue el objeto Gráfico al objeto Hoja de trabajo.
El objeto de referencia requiere alguna explicación. Los objetos de referencia se
crean llamando a la función openpyxl.charts.Reference () y pasando
tres argumentos:
1. El objeto Hoja de trabajo que contiene los datos de su gráfico.
2. Una tupla de dos enteros, que representa la celda superior izquierda del rectángulo
selección de celdas que contienen los datos del gráfico: el primer entero de la
tupla es la fila y el segundo la columna. Tenga en cuenta que 1 es la primera
fila, no 0.
3. Una tupla de dos enteros, que representa la celda inferior derecha de la
selección rectangular de celdas que contienen los datos del gráfico: el primer entero en
la tupla es la fila, y el segundo es la columna.
La figura 12-9 muestra algunos ejemplos de argumentos de coordenadas.
Figura 12-9: de izquierda a derecha: (1, 1), (10, 1); (3, 2), (6, 4); (5, 3), (5, 3)
Ingrese este ejemplo de shell interactivo para crear un gráfico de barras y agréguelo a
la hoja de cálculo:
>>> import openpyxl
>>> wb = openpyxl.Workbook ()
>>> sheet = wb.get_active_sheet ()
>>> para i en el rango (1, 11): # crea algunos datos en la columna A
hoja ['A' + str (i)] = i
>>> refObj = openpyxl.charts.Reference (hoja, (1, 1), (10, 1))
>>> seriesObj = openpyxl.charts.Series (refObj, title = 'Primera serie')
>>> chartObj = openpyxl.charts.BarChart ()
>>> chartObj.append (seriesObj)
290 Capítulo 12
>>> chartObj.drawing.top = 50 # establece la posición
>>> chartObj.drawing.left = 100
>>> chartObj.drawing.width = 300 # establece el tamaño
>>> chartObj.drawing.height = 200
>>> sheet.add_chart (chartObj)
>>> wb.save ('sampleChart.xlsx')
Esto produce una hoja de cálculo que se parece a la Figura 12-10.
50 píxeles
100 píxeles
300 píxeles de ancho
200 píxeles de
alto
Figura 12-10: una hoja de cálculo con un gráfico agregado
Hemos creado un gráfico de barras llamando a openpyxl.charts.BarChart (). También
puede crear gráficos de líneas, gráficos de dispersión y gráficos circulares llamando a openpyxl
.charts.LineChart (), openpyxl.charts.ScatterChart () y openpyxl.charts
.PieChart ().
Desafortunadamente, en la versión actual de OpenPyXL (2.1.4), la función load_
workbook () no carga gráficos en archivos de Excel. Incluso si el archivo de Excel
tiene gráficos, el objeto del libro cargado no los incluirá. Si carga un
objeto de libro de trabajo y lo guarda inmediatamente en el mismo nombre de archivo .xlsx,
eliminará efectivamente los gráficos del mismo.
Resumen
A menudo, la parte difícil del procesamiento de la información no es el procesamiento en sí mismo,
sino
simplemente obtener los datos en el formato correcto para su programa. Pero una vez que
haya cargado su hoja de cálculo en Python, puede extraer y manipular
sus datos mucho más rápido de lo que podría hacerlo a mano.
También puede generar hojas de cálculo como salida de sus programas. Por
lo tanto, si sus colegas necesitan su archivo de texto o PDF de miles de contactos de ventas
transferidos
a un archivo de hoja de cálculo, no tendrá que copiar y pegar tediosamente todo
en Excel.
Equipado con el módulo openpyxl y algunos conocimientos de programación
, encontrará que procesar incluso las hojas de cálculo más grandes es pan comido.
Trabajar con hojas de cálculo de Excel 291
Preguntas de práctica
Para las siguientes preguntas, imagine que tiene un objeto Libro de trabajo en la variable
wb, un objeto Hoja de trabajo en hoja, un objeto Celda en celda, un objeto Comentario en
comunicación y un objeto Imagen en img.
1. ¿Qué devuelve la función openpyxl.load_workbook ()?
2. ¿Qué devuelve el método de libro get_sheet_names ()?
3. ¿Cómo recuperaría el objeto Hoja de trabajo para una hoja llamada 'Hoja1'?
4. ¿Cómo recuperaría el objeto Hoja de trabajo para el libro activo?
¿hoja, lámina?
5. ¿Cómo recuperarías el valor en la celda C5?
6. ¿Cómo establecería el valor en la celda C5 en "Hola"?
7. ¿Cómo recuperarías la fila y la columna de la celda como enteros?
8. ¿Qué hacen los métodos de hoja get_highest_column () y get_highest_row ()
return, y ¿cuál es el tipo de datos de estos valores de retorno?
9. Si necesita obtener el índice entero para la columna 'M', qué función
necesitarías llamar?
10. Si necesita obtener el nombre de cadena para la columna 14, qué función
necesitarías llamar?
11. ¿Cómo puede recuperar una tupla de todos los objetos Cell de A1 a F1?
12. ¿Cómo guardaría el libro en el nombre de archivo example.xlsx?
13. ¿Cómo se configura una fórmula en una celda?
14. Si desea recuperar el resultado de la fórmula de una celda en lugar de la de la celda
fórmula en sí, ¿qué debes hacer primero?
15. ¿Cómo establecería la altura de la fila 5 a 100?
16. ¿Cómo esconderías la columna C?
17. Nombra algunas características que OpenPyXL 2.1.4 no carga desde una extensión
archivo de hoja
18. ¿Qué es un panel de congelación?
19. ¿Qué cinco funciones y métodos tienes que llamar para crear una barra?
¿gráfico?
Proyectos de
práctica Para practicar, escriba programas que realicen las siguientes tareas.
Multiplication Table Maker
Cree un programa multiplicationTable.py que tome un número N de la
línea de comando y cree una tabla de multiplicación N × N en una hoja de cálculo de Excel.
Por ejemplo, cuando el programa se ejecuta así:
py multiplicationTable.py 6
292 Capítulo 12
. . . debería crear una hoja de cálculo similar a la Figura 12-11.
Figura 12-11: una tabla de multiplicación generada en una hoja de cálculo
La fila 1 y la columna A deben usarse para las etiquetas y deben estar en negrita.
Insertador de fila en blanco
Cree un programa blankRowInserter.py que tome dos enteros y una
cadena de nombre de archivo como argumentos de línea de comando. Llamemos al primer entero N
y el sec-
ond número entero M . Comenzando en la fila N , el programa debe insertar M filas en blanco
en la hoja de cálculo. Por ejemplo, cuando el programa se ejecuta así:
python blankRowInserter.py 3 2 myProduce.xlsx
. . . las hojas de cálculo "antes" y "después" deben verse como en la Figura 12-12.
Figura 12-12: Antes (izquierda) y después (derecha) las dos filas en blanco se insertan en la fila 3
Puede escribir este programa leyendo el contenido de la
hoja de cálculo . Luego, cuando escriba la nueva hoja de cálculo, use un bucle for para copiar
las primeras N líneas. Para las líneas restantes, agregue M al número de fila en la
hoja de cálculo de salida.
Inversor de celda de hoja de cálculo
Escriba un programa para invertir la fila y la columna de las celdas en la
hoja de cálculo . Por ejemplo, el valor en la fila 5, columna 3 estará en la fila 3, columna 5
(y viceversa). Esto debe hacerse para todas las celdas en la hoja de cálculo. Por
ejemplo, las hojas de cálculo "antes" y "después" se parecerían a la
Figura 12-13.
Trabajar con hojas de cálculo de Excel 293
Figura 12-13: La hoja de cálculo antes (arriba) y después (abajo) de la inversión
Puede escribir este programa utilizando bucles anidados para leer los
datos de la hoja de cálculo en una lista de estructuras de datos de listas. Esta estructura de datos
podría tener sheetData [x] [y] para la celda en la columna xy la fila y. Luego, al
escribir la nueva hoja de cálculo, use sheetData [y] [x] para la celda en la columna xy la
fila y.
Archivos de texto a hoja de cálculo
Escriba un programa para leer el contenido de varios archivos de texto (puede hacer
los archivos de texto usted mismo) e inserte ese contenido en una hoja de cálculo, con
una línea de texto por fila. Las líneas del primer archivo de texto estarán en las celdas de la
columna A, las líneas del segundo archivo de texto estarán en las celdas de la columna B,
y así sucesivamente.
Utilice el método de objeto de archivo readlines () para devolver una lista de cadenas, una
cadena por línea en el archivo. Para el primer archivo, envíe la primera línea a la columna 1,
fila 1. La segunda línea debe escribirse en la columna 1, fila 2, y así sucesivamente. El
siguiente archivo que se lee con readlines () se escribirá en la columna 2, el siguiente
archivo en la columna 3, y así sucesivamente.
Hoja de cálculo en archivos de texto
Escriba un programa que realice las tareas del programa anterior en
orden inverso : el programa debe abrir una hoja de cálculo y escribir las celdas de la
columna A en un archivo de texto, las celdas de la columna B en otro archivo de texto y
pronto.
13
trabajos con PD f
A n D wor DD o C ument S
Los documentos PDF y Word son archivos binarios, lo
que los hace mucho más complejos
que los archivos de texto sin formato. Además del texto,
almacenan mucha información sobre fuentes, colores y diseños.
ción Si desea que sus programas lean o escriban en
archivos PDF o documentos de Word, deberá hacer más
que simplemente pasar sus nombres de archivo para abrir ().
Afortunadamente, hay módulos de Python que facilitan la
interacción con archivos PDF y documentos de Word. Este capítulo cubrirá dos de estos
módulos: PyPDF2 y Python-Docx.
Documentos
PDF PDF significa Formato de documento portátil y utiliza la extensión de archivo .pdf.
Aunque los archivos PDF admiten muchas funciones, este capítulo se centrará en las dos
cosas que hará con más frecuencia con ellos: leer contenido de texto de
archivos PDF y crear nuevos archivos PDF a partir de documentos existentes.
296 Capítulo 13
El módulo que usará para trabajar con archivos PDF es PyPDF2. Para instalarlo, ejecute
pip install PyPDF2 desde la línea de comandos. El nombre de este módulo es sensible a mayúsculas
y minúsculas
, así que asegúrese de que y esté en minúscula y todo lo demás esté en mayúscula.
(Consulte el Apéndice A para obtener detalles completos sobre la instalación de
módulos de terceros ). Si el módulo se instaló correctamente, la ejecución de import PyPDF2 en el
shell interactivo no debería mostrar ningún error.
Extracción de texto de archivos PDF
PyPDF2 no tiene una forma de extraer imágenes, gráficos u otros medios de los
documentos PDF, pero puede extraer texto y devolverlo como una cadena de Python. Para
comenzar a aprender cómo funciona PyPDF2, lo usaremos en el PDF de ejemplo que se muestra
en la Figura 13-1.
Figura 13-1: La página PDF de la que
extraeremos texto
l Probl em At iC PDf for m At
Si bien los archivos PDF son excelentes para diseñar texto de una manera que sea fácil de
imprimir y leer para la gente , no es sencillo para el software analizarlo en texto sin formato.
Como tal, PyPDF2 puede cometer errores al extraer texto de un PDF e
incluso puede ser incapaz de abrir algunos archivos PDF.
Desafortunadamente, no hay mucho que puedas hacer al respecto. PyPDF2 puede simplemente ser
incapaz de trabajar con algunos de
sus archivos PDF particulares. Dicho esto, hasta ahora no he encontrado ningún archivo PDF que
no se pueda abrir con PyPDF2.
Trabajar con documentos PDF y Word 297
Descargue este PDF de http://nostarch.com/automatestuff/ e ingrese
lo siguiente en el shell interactivo:
>>> importar PyPDF2
>>> pdfFileObj = abierto ('meetingminutes.pdf', 'rb')
>>> pdfReader = PyPDF2.PdfFileReader (pdfFileObj)
u >>> pdfReader.numPages
19
v >>> pageObj = pdfReader.getPage (0)
w >>> pageObj.extractText ()
'REUNIÓN OFICIAL DE BBOOAARRDD MMIINNUUTTEESS del 7 de marzo de 2015
\ n La Junta de Educación Primaria y Secundaria proporcionará liderazgo
y creará políticas para la educación que amplíen las oportunidades para los niños,
empoderen a las familias y las comunidades, y promuevan Louisiana en un mercado global cada vez
más
competitivo. JUNTA DE EDUCACIÓN PRIMARIA Y SECUNDARIA '
Primero, importe el módulo PyPDF2. Luego abra meetingminutes.pdf en
modo binario de lectura y guárdelo en pdfFileObj. Para obtener un objeto PdfFileReader que
represente
este PDF, llame a PyPDF2.PdfFileReader () y páselo pdfFileObj. Almacene este
objeto PdfFileReader en pdfReader.
El número total de páginas en el documento se almacena en el
atributo numPages de un objeto PdfFileReader u. El PDF de ejemplo tiene 19 páginas, pero
extraigamos texto solo de la primera página.
Para extraer texto de una página, necesita obtener un objeto Page, que representa
una sola página de un PDF, de un objeto PdfFileReader. Puede obtener un
objeto Page llamando al método getPage () v en un objeto PdfFileReader y pasándole
el número de página de la página que le interesa, en nuestro caso, 0.
PyPDF2 utiliza un índice de base cero para obtener páginas: la primera página es la página 0,
la segunda es la página 1, y así sucesivamente. Este es siempre el caso, incluso si las páginas están
numeradas de manera diferente dentro del documento. Por ejemplo, supongamos que su PDF es
un extracto de tres páginas de un informe más largo, y sus páginas están numeradas 42,
43 y 44. Para obtener la primera página de este documento, debe llamar a
pdfReader. getPage (0), no getPage (42) o getPage (1).
Una vez que tenga su objeto Page, llame a su método extractText () para devolver una
cadena del texto de la página w. La extracción de texto no es perfecta: el texto Charles E.
"Chas" Roemer, presidente del PDF está ausente de la cadena devuelta por
extractText (), y el espaciado a veces está desactivado. Aún así, esta aproximación del
contenido del texto PDF puede ser lo suficientemente buena para su programa.
Descifrar archivos
PDF Algunos documentos PDF tienen una función de cifrado que evitará que se
lean hasta que quien abra el documento proporcione una contraseña.
Ingrese lo siguiente en el shell interactivo con el PDF que descargó,
que se ha cifrado con la contraseña rosebud :
>>> importar PyPDF2
>>> pdfReader = PyPDF2.PdfFileReader (abierto ('encrypted.pdf', 'rb'))
u >>> pdfReader.isEncrypted
True
298 Capítulo 13
>>> pdfReader.getPage (0)
v Traceback (última llamada más reciente):
Archivo "<pyshell # 173>", línea 1, en <module>
pdfReader.getPage ()
- snip -
Archivo "C: \ Python34 \ lib \ site-packages \ PyPDF2 \ pdf.py", línea 1173, en getObject
raise utils.PdfReadError ("el archivo no ha sido descifrado")
PyPDF2.utils.PdfReadError: el archivo no ha sido descifrado
w >>> pdfReader.decrypt ('rosebud')
1
>>> pageObj = pdfReader.getPage (0)
Todos los objetos PdfFileReader tienen un atributo isEncrypted que es True si el
PDF está encriptado y False si no es u. Cualquier intento de llamar a una función que
lee el archivo antes de que se haya descifrado con la contraseña correcta dará como
resultado un error v.
Para leer un PDF encriptado, llame a la función descifrar () y pase la contraseña
como una cadena w. Después de llamar a descifrar () con la contraseña correcta,
verá que llamar a getPage () ya no causa un error. Si se le da una contraseña incorrecta
, la función descifrar () devolverá 0 y getPage () continuará fallando.
Tenga en cuenta que el método decrypt () descifra solo el objeto PdfFileReader, no
el archivo PDF real. Después de que su programa finaliza, el archivo en su disco
duro permanece encriptado. Su programa tendrá que volver a llamar a descifrar () la
próxima vez que se ejecute.
Creación de archivos PDF
La contraparte de PyPDF2 a los objetos PdfFileReader son los objetos PdfFileWriter, que
pueden crear nuevos archivos PDF. Pero PyPDF2 no puede escribir texto arbitrario en un PDF
como Python puede hacerlo con archivos de texto sin formato. En cambio, las capacidades de
escritura de PDF de PyPDF2
se limitan a copiar páginas de otros PDF, rotar páginas, superponer
páginas y cifrar archivos.
PyPDF2 no le permite editar directamente un PDF. En su lugar, debe
crear un nuevo PDF y luego copiar el contenido de un documento existente.
Los ejemplos en esta sección seguirán este enfoque general:
1. Abra uno o más archivos PDF existentes (los archivos PDF de origen) en objetos PdfFileReader
.
2. Cree un nuevo objeto PdfFileWriter.
3. Copie páginas de los objetos PdfFileReader en el objeto PdfFileWriter.
4. Finalmente, use el objeto PdfFileWriter para escribir el PDF de salida.
Crear un objeto PdfFileWriter crea solo un valor que representa un
documento PDF en Python. No crea el archivo PDF real. Para eso,
debe llamar al método write () de PdfFileWriter.
Trabajar con documentos PDF y Word 299
El método write () toma un objeto File normal que se ha abierto en modo
write-binary . Puede obtener dicho objeto File llamando a la función open () de Python
con dos argumentos: la cadena de lo que desea que sea el nombre del archivo PDF
y 'wb' para indicar que el archivo debe abrirse en modo de escritura binaria.
Si esto suena un poco confuso, no se preocupe, verá cómo funciona
en los siguientes ejemplos de código.
Copiar páginas
Puede usar PyPDF2 para copiar páginas de un documento PDF a otro.
Esto le permite combinar múltiples archivos PDF, cortar páginas no deseadas o
reordenar páginas.
Descargue meetingminutes.pdf y meetingminutes2.pdf desde http: // nostarch
.com / automatestuff / y coloque los archivos PDF en el directorio de trabajo actual.
Ingrese lo siguiente en el shell interactivo:
>>> importar PyPDF2
>>> pdf1File = open ('meetingminutes.pdf', 'rb')
>>> pdf2File = open ('meetingminutes2.pdf', 'rb')
u >>> pdf1Reader = PyPDF2.PdfFileReader (pdf1File)
v >>> pdf2Reader = PyPDF2.PdfFileReader (pdf2File)
w >>> pdfWriter = PyPDF2.PdfFileWriter ()
>>> para pageNum en rango (pdf1Reader.numPages):
x pageObj = pdf1Reader.getPage (pageNum)
y pdfWriter.addPage (pageObj)
>>> para pageNum en rango (pdf2Reader.numPages):
x pageObj = pdf2Reader.getPage (pageNum)
y pdfWriter.addPage (pageObj)
z >>> pdfOutputFile = open ('combineminutes.pdf', 'wb')
>>> pdfWriter.write (pdfOutputFile)
>>> pdfOutputFile.close ()
>>> pdf1File.close ()
>>> pdf2File.close ( )
Abra ambos archivos PDF en modo binario de lectura y almacene los dos
objetos de archivo resultantes en pdf1File y pdf2File. Llame a PyPDF2.PdfFileReader () y páselo
pdf1File para obtener un objeto PdfFileReader para meetingminutes.pdf u. Llámelo nuevamente
y páselo pdf2File para obtener un objeto PdfFileReader para meetingminutes2.pdf v.
Luego cree un nuevo objeto PdfFileWriter, que representa un documento PDF en blanco
w.
A continuación, copie todas las páginas de los dos PDF de origen y agréguelas
al objeto PdfFileWriter. Obtenga el objeto Page llamando a getPage () en un
objeto PdfFileReader x. Luego pase ese objeto de página al método addPage () de su PdfFileWriter
y. Estos pasos se realizan primero para pdf1Reader y luego
300 Capítulo 13
nuevamente para pdf2Reader. Cuando haya terminado de copiar páginas, escribir un nuevo PDF
llamado combinedminutes.pdf pasando un objeto File para PdfFileWriter del
método de escritura z ().
note PyPDF2 no puede insertar páginas en el medio de un objeto
PdfFileWriter; El método addPage ()
solo agregará páginas hasta el final.
Ahora ha creado un nuevo archivo PDF que combina las páginas de
meetingminutes.pdf y meetingminutes2.pdf en un solo documento. Recuerde
que el objeto File pasado a PyPDF2.PdfFileReader () necesita abrirse
en modo de lectura binaria pasando 'rb' como el segundo argumento para abrir (). Del mismo
modo, el objeto File pasado a PyPDF2.PdfFileWriter () necesita abrirse en modo de
escritura binaria con 'wb'.
Rotación de páginas
Las páginas de un PDF también se pueden rotar en incrementos de 90 grados con
los métodos rotateClockwise () y rotateCounterClockwise (). Pase uno de
los enteros 90, 180 o 270 a estos métodos. Ingrese lo siguiente en el
shell interactivo, con el archivo meetingminutes.pdf en el directorio de trabajo actual
:
>>> import PyPDF2
>>> minutesFile = open ('meetingminutes.pdf', 'rb') >>> pdfReader = PyPDF2.PdfFileReader
(minutesFile)
u >>> página = pdfReader.getPage (0)
v >>> página.rotateClockwise (90)
{'/ Contenido': [IndirectObject (961, 0), IndirectObject (962, 0),
- snip -
}
>>> pdfWriter = PyPDF2.PdfFileWriter ()
>>> pdfWriter.addPage (página)
w >>> resultPdfFile = open ('rotatedPage.pdf', 'wb')
>>> pdfWriter.write (resultPdfFile)
>>> resultPdfFile.close ()
>>> minutesFile.close ()
Aquí usamos getPage (0) para seleccionar la primera página del PDF u, y luego
llamamos rotateClockwise (90) en esa página v. Escribimos un nuevo PDF con la
página girada y lo guardamos como rotatedPage.pdf w.
El PDF resultante tendrá una página, girada 90 grados en el sentido de las agujas del reloj
, como en la Figura 13-2. Los valores de retorno de rotateClockwise () y
rotateCounterClockwise () contienen mucha información que puede ignorar.
Trabajar con documentos PDF y Word 301
Figura 13-2: El archivo .pdf rotatedPage con la página
girada 90 grados en sentido horario
Superposición de páginas
PyPDF2 también puede superponer el contenido de una página sobre otra, lo cual es
útil para agregar un logotipo, marca de tiempo o marca de agua a una página. Con Python,
es fácil agregar marcas de agua a múltiples archivos y solo a las páginas que especifique su
programa
.
Descargue watermark.pdf desde http://nostarch.com/automatestuff/ y coloque
el PDF en el directorio de trabajo actual junto con meetingminutes.pdf . Luego
ingrese lo siguiente en el shell interactivo:
>>> import PyPDF2
>>> minutesFile = open ('meetingminutes.pdf', 'rb')
u >>> pdfReader = PyPDF2.PdfFileReader (minutesFile)
v >>> minutesFirstPage = pdfReader.getPage (0)
w >>> pdfWatermarkReader = PyPDF2.PdfFileReader (abierto ('watermark.pdf', 'rb'))
x >> > minutesFirstPage.mergePage (pdfWatermarkReader.getPage (0))
y >>> pdfWriter = PyPDF2.PdfFileWriter ()
z >>> pdfWriter.addPage (minutesFirstPage)
{>>> para pageNum en rango (1, pdfReader.numPages):
pageObj = pdfReader.getPage (pageNum)
pdfWriter.addPage (pageObj)
302 Capítulo 13
>>> resultPdfFile = open ('watermarkedCover.pdf', 'wb')
>>> pdfWriter.write (resultPdfFile)
>>> minutesFile.close ()
>>> resultPdfFile.close ()
Aquí hacemos un objeto PdfFileReader de meetingminutes.pdf u. Llamamos a
getPage (0) para obtener un objeto Page para la primera página y almacenamos este objeto en
minutos. FirstPage v. Luego hacemos un objeto PdfFileReader para la marca de agua
.pdf w y llamamos a mergePage () en minutesFirstPage x. El argumento que pasamos
a mergePage () es un objeto de página para la primera página de watermark.pdf.
Ahora que hemos llamado mergePage () en minutesFirstPage, minutesFirstPage
representa el agua marcada en la primera página. Creamos un objeto PdfFileWriter y
y agregamos la primera página con marca de agua z. Luego recorremos el resto de
las páginas en meetingminutes.pdf y las agregamos al objeto PdfFileWriter {.
Finalmente, abrimos un nuevo PDF llamado watermarkedCover.pdf y escribimos el contenido
del PdfFileWriter en el nuevo PDF.
La figura 13-3 muestra los resultados. Nuestro nuevo PDF, watermarkedCover.pdf , tiene
todos los contenidos de meetingminutes.pdf, y la primera página tiene una marca de agua.
Figura 13-3: PDF original (izquierda), PDF de marca de agua (centro) y PDF combinado
(derecha)
Cifrado de archivos PDF
Un objeto PdfFileWriter también puede agregar cifrado a un documento PDF. Ingrese
lo siguiente en el shell interactivo:
>>> import PyPDF2
>>> pdfFile = open ('meetingminutes.pdf', 'rb')
>>> pdfReader = PyPDF2.PdfFileReader (pdfFile)
>>> pdfWriter = PyPDF2.PdfFileWriter ()
>>> para pageNum en rango (pdfReader.numPages):
pdfWriter.addPage (pdfReader.getPage (pageNum))
u >>> pdfWriter.encrypt ('swordfish')
>>> resultPdf = open ('encryptedminutes.pdf', 'wb')
>>> pdfWriter.write (resultPdf)
>>> resultPdf.close ()
Trabajar con documentos PDF y Word 303
Antes de llamar al método write () para guardar en un archivo, llame al
método encrypt () y pásele una cadena de contraseña u. Los archivos PDF pueden tener
una contraseña de usuario (que le permite ver el PDF) y una contraseña de propietario (que le
permite establecer permisos para imprimir, comentar, extraer texto y otras funciones). La contraseña
del usuario y la contraseña del propietario son el primer y el segundo argumento para cifrar (),
respectivamente. Si solo se pasa un argumento de cadena a encrypt (), se usará para ambas
contraseñas.

En este ejemplo, copiamos las páginas de meetingminutes.pdf a un


objeto PdfFileWriter. Encriptamos el PdfFileWriter con la contraseña
pez espada, abrimos un nuevo PDF llamado encryptedminutes.pdf y escribimos el
contenido del PdfFileWriter en el nuevo PDF. Antes de que alguien pueda ver
encryptedminutes.pdf , deberán ingresar esta contraseña. Es posible que desee
eliminar el archivo original, no encriptado meetingminutes.pdf después de asegurarse de que
su copia esté
encriptada correctamente.
Proyecto: combina páginas seleccionadas de muchos archivos PDF.
Digamos que tiene el aburrido trabajo de combinar varias docenas de documentos PDF en
un solo archivo PDF. Cada uno de ellos tiene una portada como primera página, pero
no desea que la portada se repita en el resultado final. Aunque hay
muchos programas gratuitos para combinar archivos PDF, muchos de ellos simplemente combinan
archivos completos. Escribamos un programa de Python para personalizar las páginas
que desea en el PDF combinado.
A un alto nivel, esto es lo que hará el programa:

• Encuentre todos los archivos PDF en el directorio de trabajo actual. • Ordene los nombres de
archivo para que los PDF se agreguen en orden. • Escriba cada página, excluyendo la primera
página, de cada PDF en el

archivo de salida.
En términos de implementación, su código deberá hacer lo siguiente:
• Llame a os.listdir () para buscar todos los archivos en el directorio de trabajo y eliminar cualquier
archivo que no sea PDF.

• Llame al método de lista sort () de Python para alfabetizar los nombres de los archivos. • Cree un
objeto PdfFileWriter para el PDF de salida. • Pase por cada archivo PDF, creando un objeto
PdfFileReader para él. • Pase cada página (excepto la primera) en cada archivo PDF. • Agregue las
páginas al PDF de salida. • Escriba el PDF de salida en un archivo llamado
allminutes.pdf.

Para este proyecto, abra una nueva ventana del editor de archivos y
guárdela como combinePdfs.py .
304 Capítulo 13
Paso 1: Buscar todos los archivos PDF
Primero, su programa necesita obtener una lista de todos los archivos con la extensión .pdf en
el directorio de trabajo actual y ordenarlos. Haga que su código tenga el siguiente aspecto
:
#! python3
# combinePdfs.py: combina todos los PDF del directorio de trabajo actual en
# en un solo PDF.
u importa PyPDF2, os
# Obtenga todos los nombres de archivos PDF.
pdfFiles = []
para el nombre de archivo en os.listdir ('.'):
if filename.endswith ('. pdf'):
v pdfFiles.append (nombre de archivo)
w pdfFiles.sort (key = str.lower)
x pdfWriter = PyPDF2.PdfFileWriter ()
# TODO: recorre todos los archivos PDF.
# TODO: recorre todas las páginas (excepto la primera) y agrégalas.
# TODO: guarde el PDF resultante en un archivo.
Después de la línea shebang y el comentario descriptivo sobre lo que hace
el programa, este código importa los módulos os y PyPDF2 u. La
llamada os.listdir ('.') Devolverá una lista de cada archivo en el
directorio de trabajo actual . El código recorre esta lista y agrega solo aquellos archivos con
la extensión
.pdf a pdfFiles v. Luego, esta lista se ordena en orden alfabético
con el argumento de palabra clave key = str.lower para ordenar () w.
Se crea un objeto PdfFileWriter para contener las páginas PDF combinadas x.
Finalmente, algunos comentarios resumen el resto del programa.
Paso 2: Abra cada PDF
Ahora el programa debe leer cada archivo PDF en archivos PDF. Agregue lo siguiente a
su programa:
#! python3
# combinePdfs.py: combina todos los archivos PDF del directorio de trabajo actual en
# un solo PDF.
importar PyPDF2, os
# Obtenga todos los nombres de archivos PDF.
pdfFiles = []
- recorte -
Trabajar con documentos PDF y Word 305
# Recorrer todos los archivos PDF.
para el nombre de archivo en pdfFiles:
pdfFileObj = abierto (nombre de archivo, 'rb')
pdfReader = PyPDF2.PdfFileReader (pdfFileObj) # TODO: Pase
por todas las páginas (excepto la primera) y agréguelas.
# TODO: guarde el PDF resultante en un archivo.
Para cada PDF, el bucle abre un nombre de archivo en modo de lectura binaria llamando a
open () con 'rb' como segundo argumento. La llamada open () devuelve un objeto File,
que se pasa a PyPDF2.PdfFileReader () para crear un objeto PdfFileReader
para ese archivo PDF.
Paso 3: Agregue cada página
Para cada PDF, querrá recorrer cada página, excepto la primera. Agregue este
código a su programa:
#! python3
# combinePdfs.py: combina todos los archivos PDF del directorio de trabajo actual en
# un solo PDF.
importar PyPDF2, os
- cortar -
# Recorrer todos los archivos PDF.
para el nombre de archivo en PDFfiles:
- SNIP -
# Bucle a través de todas las páginas (excepto el primero) y añadirlos.
u para pageNum en rango (1, pdfReader.numPages):
pageObj = pdfReader.getPage (pageNum)
pdfWriter.addPage (pageObj)
# TODO: guarde el PDF resultante en un archivo.
El código dentro del bucle for copia cada objeto de página individualmente al
objeto PdfFileWriter. Recuerda, quieres saltarte la primera página. Dado que
PyPDF2 considera que 0 es la primera página, su ciclo debe comenzar en 1 u y
luego subir, pero no incluir, el entero en pdfReader.numPages.
Paso 4: guarde los resultados
Después de que estos bucles anidados se completen, la variable pdfWriter
contendrá un objeto PdfFileWriter con las páginas para todos los PDF combinados. El
último paso es escribir este contenido en un archivo en el disco duro. Agregue este código a
su programa:
#! python3
# combinePdfs.py: combina todos los archivos PDF del directorio de trabajo actual en
# un solo PDF.
306 Capítulo 13
importar PyPDF2, os
- cortar -
# Recorrer todos los archivos PDF.
para el nombre de archivo en PDFfiles:
- SNIP -
# Bucle a través de todas las páginas (excepto el primero) y añadirlos.
para pageNum en rango (1, pdfReader.numPages):
- snip -
# Guarde el PDF resultante en un archivo.
pdfOutput = open ('allminutes.pdf', 'wb')
pdfWriter.write (pdfOutput)
pdfOutput.close ()
Al pasar 'wb' para abrir () se abre el archivo PDF de salida, allminutes.pdf, en
modo de escritura binaria. Luego, pasar el objeto File resultante al método write ()
crea el archivo PDF real. Una llamada al método close () finaliza el programa.
Ideas para programas similares
Ser capaz de crear archivos PDF a partir de las páginas de otros archivos PDF le permitirá crear
programas que pueden hacer lo siguiente:

• Recorte páginas específicas de archivos PDF. • Reordenar páginas en un PDF. • Cree un PDF solo
a partir de aquellas páginas que tienen texto específico, identi

Fied por extractText ().


documentos de Word
Python puede crear y modificar documentos de Word, que tienen la
extensión de archivo .docx , con el módulo python-docx. Puede instalar el módulo ejecutando
pip install python-docx. (El Apéndice A tiene detalles completos sobre la instalación
de módulos de terceros).
note Cuando use pip para instalar Python-Docx por primera vez, asegúrese de instalar python-
docx, no docx.
El nombre de instalación docx es para un módulo diferente que este libro no cubre.
Sin embargo, cuando vaya a importar el módulo python-docx, deberá ejecutar
import docx, no importar python-docx.
Si no tiene Word, LibreOffice Writer y OpenOffice Writer son
aplicaciones alternativas gratuitas para Windows, OS X y Linux que se pueden
usar para abrir archivos .docx. Puede descargarlos de https: //www.libreoffice
.org y http://openoffice.org, respectivamente. La documentación completa de Python-
Docx está disponible en https://python-docx.readthedocs.org/ . Aunque hay una
versión de Word para OS X, este capítulo se centrará en Word para Windows.
Trabajar con documentos PDF y Word 307
En comparación con el texto sin formato, los archivos .docx tienen mucha estructura. Esta
estructura
está representada por tres tipos de datos diferentes en Python-Docx. En el
nivel más alto, un objeto Documento representa todo el documento. El objeto Documento
contiene una lista de objetos Párrafo para los párrafos del documento. (Un
nuevo párrafo comienza cada vez que el usuario presiona enter o return mientras
escribe un documento de Word). Cada uno de estos objetos de párrafo contiene una lista
de uno o más objetos Run. El párrafo de una sola oración en la Figura 13-4
tiene cuatro carreras.
Un párrafo simple con algo de negrita y algo de cursiva
Run Run RunRun
Figura 13-4: Los objetos Ejecutar identificados en un objeto Párrafo
El texto en un documento de Word es más que solo una cadena. Tiene fuente, tamaño,
color y otra información de estilo asociada. Un estilo en Word es una
colección de estos atributos. Un objeto Ejecutar es una ejecución contigua de texto con
el mismo estilo. Se necesita un nuevo objeto Ejecutar siempre que cambie el estilo del texto.
Lectura de documentos de Word
Experimentemos con el módulo python-docx. Descargue demo.docx desde
http://nostarch.com/automatestuff/ y guarde el documento en el directorio de trabajo
. Luego ingrese lo siguiente en el shell interactivo:
>>> import docx
u >>> doc = docx.Document ('demo.docx')
v >>> len (doc.paragraphs)
7
w >>> doc.paragraphs [0] .text
'Título del documento'
x >>> doc.paragraphs [1] .text
'Un párrafo simple con negrita y cursiva'
y >>> len (doc.paragraphs [1] .runs)
4
z >>> doc.paragraphs [1] .runs [0] .text
'Un párrafo simple con algunos'
{>>> doc.paragraphs [1] .runs [1] .text
'negrita'
| >>> doc.paragraphs [1] .runs [2] .text
'y algunos'
} >>> doc.paragraphs [1] .runs [3] .text
'itálico'
En u, abrimos un archivo .docx en Python, llamamos a docx.Document () y pasamos
el nombre de archivo demo.docx. Esto devolverá un objeto Documento, que tiene un
atributo de párrafo que es una lista de objetos Párrafo. Cuando llamamos a len ()
en doc. párrafos, devuelve 7, lo que nos dice que hay siete objetos de párrafo
en este documento v. Cada uno de estos objetos de párrafo tiene un texto
308 Capítulo 13
atributo que contiene una cadena de texto en ese párrafo (sin la
información de estilo). Aquí, el primer atributo de texto contiene 'DocumentTitle' w,
y el segundo contiene 'Un párrafo simple con negrita y cursiva' x.
Cada objeto de párrafo también tiene un atributo de ejecución que es una lista de
objetos de ejecución . Los objetos de ejecución también tienen un atributo de texto, que contiene
solo el texto de
esa ejecución en particular. Veamos los atributos de texto en el segundo
objeto Párrafo , 'Un párrafo simple con algo en negrita y algo en cursiva'. Llamar a len () en
este objeto Párrafo nos dice que hay cuatro objetos Ejecutar y. El primer
objeto de ejecución contiene 'Un párrafo simple con algo' z. Luego, el texto cambia
a un estilo en negrita, por lo que 'negrita' inicia un nuevo objeto Ejecutar {.
Después de eso, el texto vuelve a un estilo sin negrita, que da como resultado un tercer objeto
Ejecutar, 'y algunos' |.
Finalmente, el cuarto y último objeto Run contiene 'cursiva' en un estilo cursiva}.
Con Python-Docx, sus programas de Python ahora podrán leer el
texto de un archivo .docx y usarlo como cualquier otro valor de cadena.
Obtención del texto completo de un archivo .docx
Si solo le importa el texto, no la información de estilo, en el
documento de Word , puede usar la función getText (). Acepta un nombre de archivo de un
archivo .docx y devuelve un solo valor de cadena de su texto. Abra una nueva
ventana del editor de archivos e ingrese el siguiente código, guardándolo como readDocx.py :
#! python3
importar docx
def getText (nombre de archivo):
doc = docx.Document (nombre de archivo)
fullText = []
para para en doc.paragraphs:
fullText.append (para.text)
return '\ n'.join (fullText)
La función getText () abre el documento de Word, recorre todos los
objetos de párrafo en la lista de párrafos y luego agrega su texto a la lista
en texto completo. Después del bucle, las cadenas en texto completo se unen con
caracteres de nueva línea.
El programa readDocx.py se puede importar como cualquier otro módulo.
Ahora, si solo necesita el texto de un documento de Word, puede ingresar lo
siguiente:
>>> import readDocx
>>> print (readDocx.getText ('demo.docx'))
Título del documento
Un párrafo simple con algunos títulos en negrita y cursiva
, nivel 1
Comillas intensas
primer elemento en la lista desordenada
primer elemento en la lista ordenada
Trabajar con documentos PDF y Word 309
También puede ajustar getText () para modificar la cadena antes de devolverla
. Por ejemplo, para sangrar cada párrafo, reemplace la llamada append () en
readDocx.py con esto:
fullText.append ( '' + para.text)
Para agregar un doble espacio entre párrafos, cambie el código de llamada join ()
a esto:
return '\ n \ n ' .join (texto completo)
Como puede ver, solo se necesitan unas pocas líneas de código para escribir funciones que
leerán un archivo .docx y devolverán una cadena de su contenido a su gusto.
Párrafo de estilo y objetos de ejecución
En Word para Windows, puede ver los estilos presionando ctrl-Alt-ShiFt-S para
mostrar el panel Estilos, que se parece a la Figura 13-5. En OS X, puede ver
el panel Estilos haciendo clic en el elemento del menú Ver 4 estilos .
Figura 13-5: muestre el panel Estilos presionando ctrl-alt-shift-S en Windows.
Word y otros procesadores de texto usan estilos para mantener la presentación visual.
ción de tipos similares de texto coherente y fácil de cambiar. Por ejemplo,
quizás desee establecer párrafos del cuerpo en texto de 11 puntos, Times New Roman,
justificado a la izquierda, desigual a la derecha. Puede crear un estilo con esta configuración y
310 Capítulo 13
asignarlo a todos los párrafos del cuerpo. Luego, si luego desea cambiar la
presentación de todos los párrafos del cuerpo del documento, puede cambiar el
estilo y todos esos párrafos se actualizarán automáticamente.
Para los documentos de Word, hay tres tipos de estilos: los estilos de párrafo se
pueden aplicar a los objetos de párrafo, los estilos de caracteres se pueden aplicar a los objetos
Ejecutar
y los estilos vinculados se pueden aplicar a ambos tipos de objetos. Puede
asignar estilos a los objetos Párrafo y Ejecutar configurando su atributo de estilo en una cadena.
Esta cadena debe ser el nombre de un estilo. Si el estilo se establece en Ninguno, no
habrá ningún estilo asociado con el objeto Párrafo o Ejecutar.
Los valores de cadena para los estilos de Word predeterminados son los siguientes:
'Normal'
'BodyText'
'BodyText2'
'BodyText3'
'Caption'
'Heading1'
'Heading2'
'Heading3'
'Heading4'
'Encabezado5'
'Encabezado6'
'Encabezado7'
'Encabezado8'
'Encabezado9'
'Cita intensa'
'Lista'
'Lista2'
'Lista3'
'ListBullet'
'ListBullet2'
'ListBullet3'
'ListContinue'
'ListContinue2'
'ListContinue3'
'ListNumber'
'ListNumber2'
'ListNumber3'
'ListParagraph'
'MacroText'
'NoSpacing'
'Quote'
'Subtitle'
'TOCHeading'
'Title'
Al configurar el atributo de estilo, no use espacios en el nombre del estilo. Por
ejemplo, aunque el nombre del estilo puede ser Énfasis sutil, debe establecer el
atributo de estilo en el valor de cadena 'Énfasis sutil' en lugar de 'Énfasis sutil'.
La inclusión de espacios hará que Word lea mal el nombre del estilo y no lo aplique.
Cuando utilice un estilo vinculado para un objeto Ejecutar, deberá agregar 'Char'
al final de su nombre. Por ejemplo, para establecer el estilo vinculado Cita para un
objeto Párrafo, usará el párrafoObj.style = ' Citar', pero para un objeto Ejecutar
, usaría runObj.style = 'QuoteChar'.
En la versión actual de Python-Docx (0.7.4), los únicos estilos que se
pueden usar son los estilos predeterminados de Word y los estilos en el .docx abierto .
No se pueden crear nuevos estilos, aunque esto puede cambiar en futuras versiones de
Python-Docx.
Creación de documentos de Word con
estilos no predeterminados Si desea crear documentos de Word que usen estilos más allá de los
predeterminados
, deberá abrir Word en un documento de Word en blanco y crear los
estilos usted mismo haciendo clic en el botón Nuevo estilo en la parte inferior del panel Estilos
(La Figura 13-6 muestra esto en Windows).
Esto abrirá el cuadro de diálogo Crear nuevo estilo a partir de formato, donde
puede ingresar el nuevo estilo. Luego, regrese al shell interactivo y abra
este documento de Word en blanco con docx.Document (), utilizándolo como base para su
documento de Word. El nombre que le dio a este estilo ahora estará disponible para usar
con Python-Docx.
Trabajar con documentos PDF y Word 311
Figura 13-6: El botón Nuevo estilo (izquierda) y el cuadro de diálogo Crear nuevo estilo a partir de
formato
(derecha)
Atributos de ejecución Las
ejecuciones se pueden diseñar aún más utilizando atributos de texto. Cada atributo se puede
establecer
en uno de tres valores: Verdadero (el atributo siempre está habilitado, sin importar qué
otros estilos se apliquen a la ejecución), Falso (el atributo siempre está deshabilitado)
o Ninguno (el valor predeterminado es el estilo de la ejecución ajustado a).
La Tabla 13-1 enumera los atributos de texto que se pueden establecer en los objetos Ejecutar.
tabla 13-1: Ejecutar texto del objeto
Atributos Descripción del atributo
negrita El texto aparece en negrita.
cursiva El texto aparece en cursiva.
subrayado El texto está subrayado.
huelga El texto aparece con tachado.
double_strike El texto aparece con doble tachado.
all_caps El texto aparece en mayúsculas.
small_caps El texto aparece en mayúsculas, con
letras minúsculas dos puntos más pequeñas.
sombra El texto aparece con una sombra.
esquema El texto aparece resumido en lugar de sólido.
rtl El texto está escrito de derecha a izquierda.
impresión El texto aparece presionado en la página.
relieve El texto aparece en relieve fuera de la página.
312 Capítulo 13
Por ejemplo, para cambiar los estilos de demo.docx , ingrese lo siguiente en
el shell interactivo:
>>> doc = docx.Document ('demo.docx')
>>> doc.paragraphs [0] .text
'Document Title'
>>> doc.paragraphs [0] .style
'Title'
>>> doc.paragraphs [0] .style = 'Normal'
>>> doc.paragraphs [1] .text
'Un párrafo simple con negrita y cursiva'
>>> (doc.paragraphs [1] .runs [0] .text, doc .paragraphs [1] .runs [1] .text, doc.
párrafos [1] .runs [2] .text, doc.paragraphs [1] .runs [3] .text)
('Un párrafo simple con algunos', 'bold', 'y some', 'italic')
>>> doc.paragraphs [1] .runs [0] .style = 'QuoteChar'
>>> doc.paragraphs [1] .runs [1] .underline = Verdadero
>>> doc.paragraphs [1] .runs [3] .underline = Verdadero
>>> doc.save ('restyled.docx')
Aquí, utilizamos los atributos de texto y estilo para ver fácilmente lo que hay en los
párrafos de nuestro documento. Podemos ver que es simple dividir un párrafo
en corridas y acceder a cada corrida individualmente. Entonces obtenemos la primera,
segunda y cuarta corridas en el segundo párrafo, damos estilo a cada corrida y guardamos
los resultados en un nuevo documento.
Las palabras Título del documento en la parte superior de restyled.docx tendrán el
estilo Normal en lugar del estilo Título, el objeto Ejecutar para el texto Un
párrafo simple con algunas tendrá el estilo QuoteChar y los dos objetos Ejecutar
para las palabras en negrita y cursiva tendrá sus atributos de subrayado establecidos en True.
La Figura 13-7 muestra cómo se ven los estilos de párrafos y ejecuciones en restyled.docx .
Figura 13-7: El archivo .docx rediseñado
Puede encontrar documentación más completa sobre el uso de
estilos de Python-Docx en https://python-docx.readthedocs.org/en/latest/user/styles.html .
Escribir documentos de Word
Ingrese lo siguiente en el shell interactivo:
>>> import docx
>>> doc = docx.Document ()
>>> doc.add_paragraph ('¡Hola mundo!')
<docx.text.Paragraph objeto en 0x0000000003B56F60>
>>> doc.save ('helloworld.docx' )
Trabajar con documentos PDF y Word 313
Para crear su propio archivo .docx, llame a docx.Document () para devolver un nuevo
objeto de documento de Word en blanco . El método de documento add_paragraph () agrega un
nuevo
párrafo de texto al documento y devuelve una referencia al
objeto Paragraph que se agregó. Cuando termine de agregar texto, pase una cadena de nombre de
archivo
al método de documento save () para guardar el objeto Documento en un archivo.
Esto creará un archivo llamado helloworld.docx en el directorio de trabajo actual
que, cuando se abre, se parece a la Figura 13-8.
Figura 13-8: El documento de Word creado usando add_paragraph ('¡Hola, mundo!')
Puede agregar párrafos llamando nuevamente al método add_paragraph ()
con el texto del nuevo párrafo. O para agregar texto al final de un párrafo existente
, puede llamar al método add_run () del párrafo y pasarle una cadena.
Ingrese lo siguiente en el shell interactivo:
>>> import docx
>>> doc = docx.Document ()
>>> doc.add_paragraph ('¡Hola mundo!')
<docx.text.Paragraph objeto en 0x000000000366AD30>
>>> paraObj1 = doc.add_paragraph ('Esto es un segundo párrafo. ')
>>> paraObj2 = doc.add_paragraph (' Este es otro párrafo más. ')
>>> paraObj1.add_run (' Este texto se está agregando al segundo párrafo. ')
<docx.text. Ejecutar objeto en 0x0000000003A2C860>
>>> doc.save ('multipleParagraphs.docx')
El documento resultante se verá como en la Figura 13-9. Tenga en cuenta que el texto Este
texto se agrega al segundo párrafo. se agregó al objeto Párrafo en
paraObj1, que fue el segundo párrafo agregado al documento. Las funciones add_paragraph ()
y add_run () devuelven objetos de párrafo y Ejecutar, respectivamente, para
evitar la molestia de extraerlos como un paso separado.
Tenga en cuenta que a partir de Python-Docx versión 0.5.3, los nuevos objetos de párrafo solo
se pueden agregar al final del documento, y los nuevos objetos de ejecución se pueden
agregar solo al final de un objeto de párrafo.
Se puede volver a llamar al método save () para guardar los cambios adicionales
que haya realizado.
314 Capítulo 13
Figura 13-9: El documento con múltiples objetos Paragraph y Run agregados
Tanto add_paragraph () como add_run () aceptan un segundo argumento opcional
es una cadena del estilo del objeto Párrafo o Ejecutar. Por ejemplo:
>>> doc.add_paragraph ('¡Hola mundo!', 'Título')
Esta línea agrega un párrafo con el texto ¡Hola mundo! en el estilo del título.
Agregar encabezados Al
llamar a add_heading (), se agrega un párrafo con uno de los estilos de encabezado. Ingrese
lo siguiente en el shell interactivo:
>>> doc = docx.Document ()
>>> doc.add_heading ('Encabezado 0', 0)
<docx.text.Paragraph objeto en 0x00000000036CB3C8>
>>> doc.add_heading ('Encabezado 1', 1)
<docx .text.Paragraph object en 0x00000000036CB630>
>>> doc.add_heading ('Header 2', 2)
<docx.text.Paragraph object en 0x00000000036CB828>
>>> doc.add_heading ('Header 3', 3)
<docx.text .Paragraph object en 0x00000000036CB2E8>
>>> doc.add_heading ('Header 4', 4)
<docx.text.Paragraph object en 0x00000000036CB3C8>
>>> doc.save ('headings.docx')
Los argumentos para add_heading () son una cadena del texto del encabezado y
un número entero de 0 a 4. El número entero 0 hace que el título sea el estilo Título,
que se utiliza para la parte superior del documento. Los enteros 1 a 4 son para varios
niveles de encabezado, siendo 1 el encabezado principal y 4 el subtítulo más bajo.
La función add_heading () devuelve un objeto Párrafo para guardar el paso de
extraerlo del objeto Documento como un paso separado.
Trabajar con documentos PDF y Word 315
El archivo resultante headings.docx se verá como en la Figura 13-10.
Figura 13-10: Los encabezados .docx documento con encabezados 0 a 4
Agregar saltos de línea y página
Para agregar un salto de línea (en lugar de comenzar un párrafo completamente nuevo), puede
llamar al método add_break () en el objeto Ejecutar que desea que
aparezca el salto después. Si desea agregar un salto de página, debe pasar el
valor docx.text.WD_BREAK.PAGE como argumento único para add_break (), como se hace en
el medio del siguiente ejemplo:
>>> doc = docx.Document ()
>>> doc.add_paragraph ('¡Esto está en la primera página!')
<docx.text.Paragraph objeto en 0x0000000003785518>
u >>> doc.paragraphs [0] .runs [0] .add_break (docx.text.WD_BREAK.PAGE)
>>> doc.add_paragraph ('¡Esto está en la segunda página!')
<docx.text.Paragraph object en 0x00000000037855F8>
>>> doc.save ('twoPage.docx')
Esto crea un documento de Word de dos páginas con ¡Esto está en la primera página!
en la primera página y ¡Esto está en la segunda página! en el segundo. Aunque
todavía había mucho espacio en la primera página después del texto ¡Esto está en la
primera página !, forzamos el siguiente párrafo a comenzar en una nueva página insertando
un salto de página después de la primera ejecución del primer párrafo u .
Agregar imágenes
Los objetos de documento tienen un método add_picture () que le permitirá agregar una
imagen al final del documento. Supongamos que tiene un archivo zophie.png en el
directorio de trabajo actual. Puede agregar zophie.png al final de su documento
con un ancho de 1 pulgada y una altura de 4 centímetros (Word puede usar
unidades imperiales y métricas) ingresando lo siguiente:
>>> doc.add_picture ('zophie.png', ancho = docx.shared.Inches (1),
height = docx.shared.Cm (4))
<docx.shape.InlineShape objeto en 0x00000000036C7D30>
316 Capítulo 13
El primer argumento es una cadena del nombre de archivo de la imagen. Los
argumentos opcionales de palabras clave de ancho y alto establecerán el ancho y alto de la
imagen en el documento. Si no se incluye, el ancho y la altura tendrán el
tamaño normal de la imagen.
Probablemente prefiera especificar el alto y el ancho de una imagen en
unidades conocidas como pulgadas y centímetros, para que pueda usar las funciones
docx.shared.Inches ()
y docx.shared.Cm () cuando especifique el ancho y argumentos de altura de
palabras clave.

La información de texto de resumen no es solo para archivos de texto sin formato; de hecho, es
muy probable que
maneje documentos PDF y Word con mucha más frecuencia. Puede usar
el módulo PyPDF2 para leer y escribir documentos PDF. Desafortunadamente, leer el
texto de documentos PDF puede no siempre resultar en una traducción perfecta
a una cadena debido al complicado formato de archivo PDF, y algunos PDF
pueden no ser legibles en absoluto. En estos casos, no tiene suerte a menos que las futuras
actualizaciones de PyPDF2 admitan funciones PDF adicionales.
Los documentos de Word son más confiables y puede leerlos con
el módulo python-docx. Puede manipular texto en documentos de Word a través de
objetos de párrafo y ejecución. Estos objetos también pueden recibir estilos, aunque
deben ser del conjunto predeterminado de estilos o estilos que ya están en el documento. Puede
agregar nuevos párrafos, encabezados, saltos e imágenes al documento,
aunque solo hasta el final.
Muchas de las limitaciones que conlleva trabajar con archivos PDF y
documentos de Word se deben a que estos formatos están destinados a ser visualizados de manera
agradable para
los lectores humanos, en lugar de ser fáciles de analizar por software. El siguiente capítulo
analiza otros dos formatos comunes para almacenar información:
archivos JSON y CSV. Estos formatos están diseñados para ser utilizados por computadoras, y
verá que Python puede trabajar con estos formatos mucho más fácilmente.
Preguntas de práctica
1. Un valor de cadena del nombre de archivo PDF no se pasa al PyPDF2
.PdfFileReader () función. ¿Qué pasas a la función en su lugar?
2. ¿Qué modos tienen los objetos File para PdfFileReader () y PdfFileWriter ()
necesita ser abierto?
3. ¿Cómo se adquiere un objeto de página para la página 5 de un objeto PdfFileReader?
4. Qué variable PdfFileReader almacena el número de páginas en el PDF
¿documento?
5. Si el PDF de un objeto PdfFileReader está encriptado con la contraseña de pez espada,
¿Qué debe hacer antes de poder obtener objetos de página?
6. ¿Qué métodos utilizas para rotar una página?
7. ¿Qué método devuelve un objeto Document para un archivo llamado demo.docx?
Trabajar con documentos PDF y Word 317
8. ¿Cuál es la diferencia entre un objeto Párrafo y un objeto Ejecutar?
9. ¿Cómo se obtiene una lista de objetos de párrafo para un objeto de documento que es
almacenado en una variable llamada doc?
10. ¿Qué tipo de objeto tiene las variables negrita, subrayado, cursiva, tachado y de contorno?
11. ¿Cuál es la diferencia entre establecer la variable en negrita en Verdadero, Falso,
o ninguno?
12. ¿Cómo se crea un objeto Documento para un nuevo documento de Word?
13. ¿Cómo se agrega un párrafo con el texto "Hola!" a un documento
objeto almacenado en una variable llamada doc?
14. Qué números enteros representan los niveles de encabezados disponibles en Word
¿documentos?
Proyectos de
práctica Para practicar, escriba programas que hagan lo siguiente.
PDF Paranoia
Usando la función os.walk () del Capítulo 9, escriba un script que recorra
cada PDF en una carpeta (y sus subcarpetas) y encripte los PDF
usando una contraseña provista en la línea de comando. Guarde cada
PDF cifrado con un sufijo _encrypted.pdf agregado al nombre de archivo original. Antes de
eliminar el archivo original, haga que el programa intente leer y descifrar
el archivo para asegurarse de que se haya cifrado correctamente.
Luego, escriba un programa que encuentre todos los PDF cifrados en una carpeta (y sus
subcarpetas) y cree una copia descifrada del PDF utilizando una contraseña provista
. Si la contraseña es incorrecta, el programa debe imprimir un mensaje para
el usuario y continuar con el siguiente PDF.
Invitaciones personalizadas como documentos de Word
Digamos que tiene un archivo de texto de nombres de invitados. Este archivo guest.txt tiene un
nombre por
línea, de la siguiente manera:
Prof. Plum
Miss Scarlet
Col. Mostaza
Al Sweigart
RoboCop
Escriba un programa que genere un documento de Word con invitaciones personalizadas
como la Figura 13-11.
Dado que Python-Docx solo puede usar los estilos que ya existen en el
documento de Word, primero deberá agregar estos estilos a un archivo de Word en blanco
y luego abrir ese archivo con Python-Docx. Debe haber una invitación
por página en el documento de Word resultante, así que llame a add_break () para agregar un
salto de página después del último párrafo de cada invitación. De esta manera, deberá
abrir solo un documento de Word para imprimir todas las invitaciones a la vez.
318 Capítulo 13
Figura 13-11: El documento de Word generado por su script de invitación personalizado
Puede descargar un archivo invitados.txt de muestra de http://nostarch.com/
automatestuff / .
Brute-Force PDF Password Breaker
Digamos que tiene un PDF cifrado en el que ha olvidado la contraseña,
pero recuerda que era una sola palabra en inglés. Intentar adivinar su
contraseña olvidada es una tarea bastante aburrida. En su lugar, puede escribir un programa que
descifre el PDF probando todas las palabras posibles en inglés hasta que encuentre una
que funcione. Esto se llama un ataque de contraseña de fuerza bruta. Descargue el archivo de texto
dictionary.txt de http://nostarch.com/automatestuff/. Este archivo de diccionario contiene
más de 44,000 palabras en inglés con una palabra por línea.
Utilizando las habilidades de lectura de archivos que aprendió en el Capítulo 8, cree una lista de
cadenas de palabras leyendo este archivo. Luego repita cada palabra en esta lista, pasándola
al método descifrar (). Si este método devuelve el entero 0, la contraseña
era incorrecta y su programa debería continuar con la siguiente contraseña.
Si decrypt () devuelve 1, entonces su programa debería salir del ciclo e
imprimir la contraseña pirateada. Debes probar tanto en mayúsculas como en minúsculas para
cada palabra. (En mi computadora portátil, revisar las 88,000
palabras en mayúsculas y minúsculas del archivo del diccionario toma un par de minutos. Es
por eso que no debe usar una palabra simple en inglés para sus contraseñas).
14
trabajos con CS vfile S
A n D j S en DA t A
En el Capítulo 13, aprendió a extraer
texto de documentos PDF y Word. Estas
los archivos estaban en formato binario, lo que requería
módulos especiales de Python para acceder a sus datos.
Los archivos CSV y JSON, por otro lado, son solo
archivos de texto sin formato. Puede verlos en un editor de texto, como
el editor de archivos de IDLE. Pero Python también viene con los
módulos especiales csv y json, cada uno con funciones
para ayudarlo a trabajar con estos formatos de archivo.
CSV significa "valores separados por comas", y los archivos CSV son
hojas de cálculo simplificadas almacenadas como archivos de texto sin formato. El módulo csv de
Python facilita el
análisis de archivos CSV.
JSON (pronunciado "JAY-sawn" o "Jason", no importa cómo,
porque de cualquier manera la gente dirá que lo está pronunciando mal) es un
formato que almacena información como código fuente JavaScript en archivos de texto sin formato.
320 Capítulo 14
(JSON es la abreviatura de JavaScript Object Notation). No necesita conocer el
lenguaje de programación JavaScript para usar archivos JSON, pero el formato JSON
es útil porque se usa en muchas aplicaciones web.
el módulo csv
Cada línea en un archivo CSV representa una fila en la hoja de cálculo, y las comas
separan las celdas en la fila. Por ejemplo, la hoja de cálculo example.xlsx de
http://nostarch.com/automatestuff/ se vería así en un archivo CSV:
4/4/2015 13: 34, Manzanas, 73
5/5/2015 3:41, Cerezas, 85
6/4/2015 12: 46, Peras, 14
8/4/2015 8: 59, Naranjas, 52
4 / 10/2015 2: 07, Manzanas, 152 10/04/2015 18:10
, Plátanos, 23 10/10/2015 2:40
, Fresas, 98
Usaré este archivo para los ejemplos de shell interactivos de este capítulo. Puede
descargar example.csv desde http://nostarch.com/automatestuff/ o ingresar el texto
en un editor de texto y guardarlo como example.csv .
Los archivos CSV son simples y carecen de muchas de las características de una hoja de cálculo de
Excel
. Por ejemplo, archivos CSV

• no tienen tipos por sus valores, todo es una cadena • no tienen valores para el tamaño de fuente o
el color • No tenemos varias hojas de cálculo • No se puede especificar anchuras y alturas de
células • No se puede tener celdas combinadas • Can No tienen imágenes o gráficos incrustados en
ellos
La ventaja de los archivos CSV es la simplicidad. Los archivos CSV son ampliamente compatibles
con muchos tipos de programas, se pueden ver en editores de texto (incluido el
editor de archivos IDLE ) y son una forma sencilla de representar datos de hojas de cálculo.
El formato CSV es exactamente como se anuncia: es solo un archivo de texto de valores separados
por comas
.
Dado que los archivos CSV son solo archivos de texto, es posible que tenga la tentación de leerlos
como una cadena y luego procesar esa cadena usando las técnicas que aprendió
en el Capítulo 8. Por ejemplo, dado que cada celda en un archivo CSV está separada por una
coma, tal vez simplemente puede llamar al método split () en cada línea de texto para
obtener los valores. Pero no todas las comas en un archivo CSV representan el límite
entre dos celdas. Los archivos CSV también tienen su propio conjunto de caracteres de escape para
permitir que se incluyan comas y otros caracteres como parte de los valores . El
método split () no maneja estos caracteres de escape. Debido a estas
posibles dificultades, siempre debe usar el módulo csv para leer y
escribir archivos CSV.
Trabajar con archivos CSV y datos JSON 321
Objetos de lector
Para leer datos de un archivo CSV con el módulo csv, debe crear un
objeto de lector . Un objeto Reader le permite iterar sobre líneas en el archivo CSV. Ingrese lo
siguiente en el shell interactivo, con example.csv en el directorio de trabajo actual
:
u >>> import csv
v >>> exampleFile = open ('example.csv')
w >>> exampleReader = csv.reader (exampleFile)
x >>> exampleData = list (exampleReader)
y >>> exampleData
[['4/5/2015 13:34', 'Manzanas', '73'], ['4/5/2015 3:41', 'Cerezas', '85'],
['4/6/2015 12:46 ',' Peras ',' 14 '], [' 8/4/2015 8:59 ',' Naranjas ',' 52 '],
[' 10/04/2015 2:07 ',' Manzanas ' , '152'], ['10/04/2015 18:10', 'Bananas', '23'],
['10/10/2015 2:40', 'Fresas', '98']]
El módulo csv viene con Python, por lo que podemos importarlo sin tener
que instalarlo primero.
Para leer un archivo CSV con el módulo csv, primero ábralo usando la función open ()
v, como lo haría con cualquier otro archivo de texto. Pero en lugar de llamar al
método read () o readlines () en el objeto File que devuelve open (),
pásalo a la función csv.reader () w. Esto devolverá un objeto Reader para que lo
use. Tenga en cuenta que no pasa una cadena de nombre de archivo directamente a la función
csv.reader ()
.
La forma más directa de acceder a los valores en el objeto Reader es convertirlo
a una lista de Python simple pasándolo a list () x. El uso de list () en este
objeto Reader devuelve una lista de listas, que puede almacenar en una variable como
exampleData. Al ingresar exampleData en el shell, se muestra la lista de listas y.
Ahora que tiene el archivo CSV como una lista de listas, puede acceder al valor
en una fila y columna en particular con la expresión exampleData [row] [col],
donde row es el índice de una de las listas en exampleData, y col es el índice
del elemento que desea de esa lista. Ingrese lo siguiente en el shell interactivo
:
>>> exampleData [0] [0]
'4/5/2015 13:34'
>>> exampleData [0] [1]
'Apples'
>>> exampleData [0] [2]
'73'
>>> exampleData [1] [1]
'Cerezas'
>>> ejemploDatos [6] [1]
'Fresas'
exampleData [0] [0] va a la primera lista y nos da la primera cadena,
exampleData [0] [2] va a la primera lista y nos da la tercera cadena, y
así sucesivamente.
322 Capítulo 14
Lectura de datos de los objetos Reader en un bucle for
Para archivos CSV grandes, querrá usar el objeto Reader en un bucle for. Esto
evita cargar todo el archivo en la memoria a la vez. Por ejemplo, ingrese lo
siguiente en el shell interactivo:
>>> import csv
>>> exampleFile = open ('example.csv')
>>> exampleReader = csv.reader (exampleFile)
>>> para la fila en exampleReader:
print ('Row #' + str (exampleReader.line_num) + '' + str (fila))
Fila # 1 ['4/5/2015 13:34', 'Manzanas', '73']
Fila # 2 ['5/5/2015 3:41', 'Cerezas', '85']
Fila # 3 [ '4/6/2015 12:46', 'Peras', '14']
Fila # 4 ['4/8/2015 8:59', 'Naranjas', '52']
Fila # 5 ['4/10 / 2015 2:07 ',' Manzanas ',' 152 ']
Fila # 6 [' 10/04/2015 18:10 ',' Bananas ',' 23 ']
Fila # 7 [' 10/04/2015 2: 40 ',' Fresas ',' 98 ']
Después de importar el módulo csv y crear un objeto Reader desde el
archivo CSV, puede recorrer las filas en el objeto Reader. Cada fila es
una lista de valores, y cada valor representa una celda.
La llamada a la función print () imprime el número de la fila actual y el
contenido de la fila. Para obtener el número de fila, use la variable line_num del objeto Reader
, que contiene el número de la línea actual.
El objeto Reader solo se puede recorrer una vez. Para volver a leer el archivo CSV,
debe llamar a csv.reader para crear un objeto Reader.
Objetos de escritor
Un objeto de escritor le permite escribir datos en un archivo CSV. Para crear un objeto Writer,
utiliza la función csv.writer (). Ingrese lo siguiente en el shell interactivo:
>>> import csv
u >>> outputFile = open ('output.csv', 'w', newline = '')
v >>> outputWriter = csv.writer (outputFile)
>>> outputWriter.writerow (['' spam ',' eggs ',' bacon ',' ham '])
21
>>> outputWriter.writerow ([' Hello, world! ',' eggs ',' bacon ',' ham '])
32
>>> outputWriter.writerow ([1, 2, 3.141592, 4])
16
>>> outputFile.close ()
Primero, llame a open () y páselo 'w' para abrir un archivo en modo de escritura u. Esto
creará el objeto que luego puede pasar a csv.writer () v para crear un objeto Writer.
En Windows, también deberá pasar una cadena en blanco para el
argumento de palabra clave de nueva línea de la función open () . Por razones técnicas más allá del
alcance
de este libro, si olvida establecer el argumento de nueva línea, las filas en output.csv estarán a doble
espacio, como se muestra en la Figura 14-1.
Trabajar con archivos CSV y datos JSON 323
Figura 14-1: Si olvida el argumento de palabra clave newline = '' en open (), el archivo CSV
tendrá doble espacio.
El método writerow () para objetos Writer toma un argumento de lista.
Cada valor en la lista se coloca en su propia celda en el archivo CSV de salida. El
valor de retorno de writerow () es el número de caracteres escritos en el archivo
para esa fila (incluidos los caracteres de nueva línea).
Este código produce un archivo output.csv que se ve así:
spam, huevos, tocino, jamón
"¡Hola, mundo!", huevos, tocino, jamón
1,2,3.141592,4
Observe cómo el objeto Escritor escapa automáticamente de la coma en el
valor '¡Hola, mundo!' con comillas dobles en el archivo CSV. El módulo csv le
ahorra tener que manejar estos casos especiales usted mismo.
El delimitador y el terminador de línea Argumentos de palabras clave
Supongamos que desea separar las celdas con un carácter de tabulación en lugar de una coma y
desea que las filas estén a doble espacio. Puede ingresar algo como lo
siguiente en el shell interactivo:
>>> import csv
>>> csvFile = open ('ejemplo.tsv', 'w', nueva línea = '')
u >>> csvWriter = csv.writer (csvFile, delimitador = '\ t', lineterminator = '\ n \ n')
>>> csvWriter.writerow (['manzanas', 'naranjas', 'uvas'])
24
>>> csvWriter.writerow (['' huevos ',' tocino ',' jamón '])
17
>>> csvWriter.writerow ([' 'spam', 'spam', 'spam', 'spam', 'spam', 'spam'])
32
>>> csvFile.close ()
324 Capítulo 14
Esto cambia los caracteres delimitadores y de terminación de línea en su
archivo. El delimitador es el carácter que aparece entre celdas en una fila. Por
defecto, el delimitador para un archivo CSV es una coma. El terminador de línea es el
carácter que aparece al final de una fila. Por defecto, el terminador de línea
es una nueva línea. Puede cambiar los caracteres a diferentes valores utilizando los
argumentos de palabras clave delimitador y lineterminator con csv.writer ().
Pasar delimeter = '\ t' y lineterminator = '\ n \ n' u cambia el carácter
entre las celdas a una pestaña y el carácter entre las filas a dos nuevas líneas.
Luego llamamos a escritorow () tres veces para darnos tres filas.
Esto produce un archivo llamado example.tsv con el siguiente contenido:
manzanas naranjas uvas
huevos tocino jamón
spam spam spam spam spam spam
Ahora que nuestras celdas están separadas por pestañas, estamos usando la extensión de archivo
.tsv , para valores separados por pestañas.
Proyecto: eliminar el encabezado de los archivos cSV
Digamos que tiene el aburrido trabajo de eliminar la primera línea de varios cientos de
archivos CSV. Tal vez los esté introduciendo en un proceso automatizado que
requiere solo los datos y no los encabezados en la parte superior de las columnas. Puede
abrir cada archivo en Excel, eliminar la primera fila y volver a guardar el archivo, pero
eso llevaría horas. Escribamos un programa para hacerlo en su lugar.
El programa deberá abrir cada archivo con la extensión .csv en el
directorio de trabajo actual, leer el contenido del archivo CSV y reescribir
el contenido sin la primera fila en un archivo del mismo nombre. Esto
reemplazará los contenidos antiguos del archivo CSV con los nuevos contenidos sin cabeza.
w A rning Como siempre, siempre que escriba un programa que modifique archivos, asegúrese de
hacer una copia de seguridad de los
archivos, primero en caso de que su programa no funcione de la manera esperada. No
desea borrar accidentalmente sus archivos originales.
En un nivel alto, el programa debe hacer lo siguiente:

• Encuentre todos los archivos CSV en el directorio de trabajo actual. • Lea el contenido completo
de cada archivo. • Escriba el contenido, omitiendo la primera línea, en un nuevo archivo
CSV.

A nivel de código, esto significa que el programa deberá hacer lo siguiente:

• Recorra una lista de archivos de os.listdir (), omitiendo los archivos que no son CSV. • Cree un
objeto CSV Reader y lea el contenido del archivo, utilizando

el atributo line_num para descubrir qué línea omitir.


• Cree un objeto Escritor CSV y escriba los datos leídos en el nuevo archivo.
Trabajar con archivos CSV y datos JSON 325
Para este proyecto, abra una nueva ventana del editor de archivos y
guárdela como removeCsvHeader.py .
Paso 1: Recorrer cada archivo CSV
Lo primero que debe hacer su programa es recorrer una lista de todos los
nombres de archivos CSV para el directorio de trabajo actual. Haga que su removeCsvHeader.py
se vea
así:
#! python3
# removeCsvHeader.py - Elimina el encabezado de todos los archivos CSV en el # directorio de
trabajo actual
.
importar csv, os
os.makedirs ('headerRemoved', exist_ok = True)
# Recorrer cada archivo en el directorio de trabajo actual.
para csvFilename en os.listdir ('.'):
si no es csvFilename.endswith ('. csv'):
continúas # saltas archivos que no son csv
print ('Eliminando el encabezado de' + csvFilename + '...')
# TODO: Lea el archivo CSV en (omitiendo la primera fila).
# TODO: escriba el archivo CSV.
La llamada os.makedirs () creará una carpeta headerRemoved donde
se escribirán todos los archivos CSV sin cabeza . Un bucle for en os.listdir ('.') Lo lleva a la mitad
, pero recorrerá todos los archivos en el directorio de trabajo, por lo que
deberá agregar un código al comienzo del bucle que omita los nombres de archivo que no ' t
termina
con .csv. La instrucción continue u hace que el bucle for pase al siguiente
nombre de archivo cuando se encuentra con un archivo que no es CSV.
Solo para que haya algo de salida a medida que se ejecuta el programa, imprima un mensaje
que indique en qué archivo CSV está trabajando el programa. Luego, agregue algunos comentarios
TODO
para lo que el resto del programa debe hacer.
Paso 2: leer el archivo CSV
El programa no elimina la primera línea del archivo CSV. Más bien,
crea una nueva copia del archivo CSV sin la primera línea. Como el
nombre de archivo de la copia es el mismo que el nombre de archivo original, la copia sobrescribirá
el
original.
El programa necesitará una forma de rastrear si se está reproduciendo actualmente en
la primera fila. Agregue lo siguiente para eliminarCsvHeader.py.
#! python3
# removeCsvHeader.py - Elimina el encabezado de todos los archivos CSV en el # directorio de
trabajo actual
.
- cortar -
326 Capítulo 14
# Lea el archivo CSV en (omitiendo la primera fila).
csvRows = []
csvFileObj = abierto (csvFilename)
readerObj = csv.reader (csvFileObj)
para la fila en readerObj:
if readerObj.line_num == 1:
continue # skip first row
csvRows.append (row) csvFileObj.clpend ( fila)
csvFileObj.clpend
# TODO: escriba el archivo CSV.
El atributo line_num del objeto Reader se puede usar para determinar qué
línea en el archivo CSV está leyendo actualmente. Otro bucle for recorrerá
las filas devueltas desde el objeto CSV Reader, y todas las filas, excepto la primera,
se agregarán a csvRows.
A medida que el bucle for itera sobre cada fila, el código verifica si
readerObj.line_num está establecido en 1. Si es así, ejecuta un continuo para avanzar a la
siguiente fila sin agregarlo a csvRows. Para cada fila posterior, la
condición siempre será False, y la fila se agregará a csvRows.
Paso 3: escriba el archivo CSV sin la primera fila
Ahora que csvRows contiene todas las filas excepto la primera fila, la lista debe
escribirse en un archivo CSV en la carpeta headerRemoved. Agregue lo siguiente
para eliminarCsvHeader.py :
#! python3
# removeCsvHeader.py - Elimina el encabezado de todos los archivos CSV en el
# directorio de trabajo actual .
- cortar -
# Recorrer cada archivo en el directorio de trabajo actual.
u para csvFilename en os.listdir ('.'):
si no es csvFilename.endswith ('. csv'):
continuar # omitir archivos no CSV
- cortar -
# Escriba el archivo CSV.
csvFileObj = abierto (os.path.join ('headerRemoved', csvFilename), 'w',
newline = '')
csvWriter = csv.writer (csvFileObj)
para la fila en csvRows:
csvWriter.writerow (fila)
csvFileObj.cl
El objeto CSV Writer escribirá la lista en un archivo CSV en headerRemoved
usando csvFilename (que también usamos en el lector CSV). Esto sobrescribirá
el archivo original.
Trabajar con archivos CSV y datos JSON 327
Una vez que creamos el objeto Writer, recorremos las sublistas almacenadas en
csvRows y escribimos cada sublista en el archivo.
Después de que se ejecuta el código, el bucle for externo u pasará al siguiente
nombre de archivo desde os.listdir ('.'). Cuando finalice ese ciclo, el programa estará
completo.
Para probar su programa, descargue removeCsvHeader.zip de http: // nostarch
.com / automatestuff / y descomprímalo en una carpeta. Ejecute
el programa removeCsvHeader.py en esa carpeta. La salida se verá así:
Extracción de cabeza desde NAICS_data_1048.csv ...
Extracción de cabeza desde NAICS_data_1218.csv ...
- SNIP -
Extracción de cabeza desde NAICS_data_9834.csv ...
Extracción de cabeza desde NAICS_data_9986.csv ...
Este programa debe imprimir un nombre de archivo cada vez que elimina la primera línea
de un archivo CSV.
Ideas para programas similares
Los programas que podría escribir para archivos CSV son similares a los que
podría escribir para archivos Excel, ya que ambos son archivos de hoja de cálculo. Puede
escribir programas para hacer lo siguiente:

• Compare datos entre diferentes filas en un archivo CSV o entre múltiples archivos CSV.

• Copie datos específicos de un archivo CSV a un archivo de Excel, o viceversa. • Compruebe si


hay datos no válidos o errores de formato en los archivos CSV y alerta al

usuario de estos errores.


• Leer datos de un archivo CSV como entrada para sus programas Python.
JSon y APis
JavaScript Object Notation es una forma popular de formatear datos como una sola
cadena legible por humanos. JSON es la forma nativa en que los programas JavaScript
escriben sus estructuras de datos y generalmente se asemeja a lo
que produciría la función pprint () de Python . No necesita saber JavaScript para
trabajar con datos con formato JSON.
Aquí hay un ejemplo de datos formateados como JSON:
{"nombre": "Zophie", "isCat": verdadero,
"miceCaught": 0, "napsTaken": 37.5,
"felineIQ": nulo}
Es útil saber JSON, porque muchos sitios web ofrecen contenido JSON como
una forma de que los programas interactúen con el sitio web. Esto se conoce como proporcionar
una interfaz de programación de aplicaciones (API) . Acceder a una API es lo mismo
328 Capítulo 14
como acceder a cualquier otra página web a través de una URL. La diferencia es que los datos
devueltos por una API están formateados (con JSON, por ejemplo) para máquinas;
Las API no son fáciles de leer para las personas.
Muchos sitios web hacen que sus datos estén disponibles en formato JSON. Facebook,
Twitter, Yahoo, Google, Tumblr, Wikipedia, Flickr, Data.gov, Reddit, IMDb,
Rotten Tomatoes, LinkedIn y muchos otros sitios populares ofrecen API para que los
programas los utilicen. Algunos de estos sitios requieren registro, que casi
siempre es gratuito. Tendrá que encontrar documentación sobre qué URL
debe solicitar su programa para obtener los datos que desea, así como el
formato general de las estructuras de datos JSON que se devuelven. Esta documentación
debe ser provista por cualquier sitio que ofrezca la API; si tienen
una página de "Desarrolladores", busque la documentación allí.
Con las API, puede escribir programas que hagan lo siguiente:
• Raspe los datos sin procesar de los sitios web. (Acceder a las API suele ser más conveniente que
descargar páginas web y analizar HTML con Beautiful Soup).
• Descargue automáticamente nuevas publicaciones de una de sus cuentas de redes sociales y
publíquelas en otra cuenta. Por ejemplo, podría tomar sus publicaciones de Tumblr y publicarlas en
Facebook.
• Cree una "enciclopedia de películas" para su colección personal de películas extrayendo datos de
IMDb, Rotten Tomatoes y Wikipedia y colocándolos en un solo archivo de texto en su
computadora.
Puede ver algunos ejemplos de API JSON en los recursos en http: //
nostarch.com/automatestuff/ .
el módulo json El módulo json de
Python maneja todos los detalles de la traducción entre una cadena
con datos JSON y valores de Python para las funciones json.loads () y json.dumps ()
. JSON no puede almacenar todo tipo de valor de Python. Puede contener valores
de solo los siguientes tipos de datos: cadenas, enteros, flotantes, booleanos, listas,
diccionarios y NoneType. JSON no puede representar objetos específicos de Python,
como objetos File, CSV Reader o Writer, Regex o Selenium
WebElement.
Lectura de JSON con la función load ()
Para traducir una cadena que contenga datos JSON a un valor de Python, páselo a
la función json.loads (). (El nombre significa "cadena de carga", no "cargas").
Ingrese lo siguiente en el shell interactivo:
>>> stringOfJsonData = '{"name": "Zophie", "isCat": true, "miceCaught": 0,
"felineIQ": null}'
>>> import json
>>> jsonDataAsPythonValue = json.loads (stringOfJsonData)
>>> jsonDataAsPythonValue
{'isCat': True, 'miceCaught': 0, 'name': 'Zophie', 'felineIQ': None}
Trabajar con archivos CSV y datos JSON 329
Después de importar el módulo json, puede llamar a load () y pasarle una
cadena de datos JSON. Tenga en cuenta que las cadenas JSON siempre usan comillas dobles. Se
devolverá que los datos como un diccionario de Python. Los diccionarios de Python no están
ordenados, por lo que los pares clave-valor pueden aparecer en un orden diferente cuando
imprime jsonDataAsPythonValue.
Escribir JSON con la función dumps ()
La función json.dumps () (que significa "volcar cadena", no "volcar")
traducirá un valor de Python en una cadena de datos con formato JSON. Ingrese lo
siguiente en el shell interactivo:
>>> pythonValue = {'isCat': True, 'miceCaught': 0, 'name': 'Zophie',
'felineIQ': None}
>>> import json
>>> stringOfJsonData = json.dumps (pythonValue)
>> > stringOfJsonData
'{"isCat": verdadero, "felineIQ": nulo, "miceCaught": 0, "nombre": "Zophie"}'
El valor solo puede ser uno de los siguientes tipos de datos básicos de Python: diccionario
, lista, entero, flotante, cadena, booleano o ninguno.
Proyecto: obtener datos meteorológicos actuales
Verificar el clima parece bastante trivial: abra su navegador web, haga clic en la
barra de direcciones, escriba la URL de un sitio web meteorológico (o busque uno y luego
haga clic en el enlace), espere a que se cargue la página, busque más allá de todos los anuncios, y
así sucesivamente.
En realidad, hay muchos pasos aburridos que podría omitir si tuviera un programa
que descargara el pronóstico del tiempo para los próximos días y lo imprimiera
como texto sin formato. Este programa utiliza el módulo de solicitudes del Capítulo 11 para
descargar datos de la Web.
En general, el programa hace lo siguiente:

• Lee la ubicación solicitada desde la línea de comando. • Descarga datos meteorológicos JSON de
OpenWeatherMap.org. • Convierte la cadena de datos JSON en una estructura de datos
Python. • Imprime el clima para hoy y los próximos dos días.

Entonces el código deberá hacer lo siguiente:

• Unir cadenas en sys.argv para obtener la ubicación. • Llame a request.get () para descargar los
datos del clima. • Llame a json.loads () para convertir los datos JSON a una estructura de datos
Python. • Imprima el pronóstico del tiempo.

Para este proyecto, abra una nueva ventana del editor de archivos y
guárdela como quickWeather.py .
330 Capítulo 14
Paso 1: Obtener ubicación desde el argumento de la línea de comando
La entrada para este programa vendrá desde la línea de comando. Haga que
quickWeather.py se vea así:
#! python3
# quickWeather.py - Imprime el clima para una ubicación desde la línea de comando.
importar json, solicitudes, sys
# Calcular ubicación a partir de argumentos de línea de comando.
if len (sys.argv) <2:
print ('Uso: quickWeather.py location')
sys.exit ()
location = '' .join (sys.argv [1:])
# TODO: descargue los datos JSON de la API de OpenWeatherMap.org.
# TODO: Cargue datos JSON en una variable de Python.
En Python, los argumentos de la línea de comandos se almacenan en la lista sys.argv.
Después de la #! shebang line y declaraciones de importación, el programa verificará
que haya más de un argumento de línea de comando. (Recuerde que sys.argv
siempre tendrá al menos un elemento, sys.argv [0], que contiene el
nombre de archivo del script de Python ). Si solo hay un elemento en la lista, el usuario no
proporcionó una ubicación en el línea de comando y se le proporcionará un mensaje de "uso"
al usuario antes de que finalice el programa.
Los argumentos de la línea de comando se dividen en espacios. El argumento de la línea de
comando
San Francisco, CA haría que sys.argv mantenga ['quickWeather.py', 'San',
'Francisco', 'CA']. Por lo tanto, llame al método join () para unir todas las cadenas
excepto la primera en sys.argv. Almacene esta cadena unida en una ubicación denominada variable
.
Paso 2: descargue los datos JSON
OpenWeatherMap.org proporciona información meteorológica en tiempo real en
formato JSON. Su programa simplemente tiene que descargar la página en
http://api.openweathermap.org/data/2.5/forecast/daily?q=<Location>&cnt=3 ,
donde <Location> es el nombre de la ciudad cuyo clima desea . Agregue
lo siguiente a quickWeather.py .
#! python3
# quickWeather.py - Imprime el clima para una ubicación desde la línea de comando.
- cortar -
# Descargue los datos JSON de la API de OpenWeatherMap.org.
url = 'http: //api.openweathermap.org/data/2.5/forecast/daily? q =% s & cnt = 3'%
(ubicación)
response = request.get (url)
response.raise_for_status ()
# TODO: Cargue datos JSON en una variable de Python.
Trabajar con archivos CSV y datos JSON 331
Tenemos ubicación de nuestros argumentos de línea de comando. Para crear la URL a la
que queremos acceder, utilizamos el marcador de posición% s e insertamos cualquier cadena que
esté
almacenada en ese lugar en la cadena de URL. Almacenamos el resultado en
url y pasamos url a request.get (). La
llamada request.get () devuelve un objeto de respuesta , que puede comprobar si hay errores
llamando a raise_for_status (). Si no se produce ninguna
excepción, el texto descargado estará en respuesta.text.
Paso 3: Cargue datos JSON e imprima el clima
La variable de miembro de.text.text contiene una gran cadena de
datos con formato JSON . Para convertir esto a un valor de Python, llame a la función json.loads
(). Los
datos JSON se verán así:
{'ciudad': {'coord': {'lat': 37.7771, 'lon': -122.42},
'país': 'Estados Unidos de América',
'id': '5391959',
'nombre': 'San Francisco ',
' población ': 0},
' cnt ': 3,
' bacalao ':' 200 ',
' lista ': [{' nubes ': 0,
' deg ': 233,
' dt ': 1402344000,
' humedad ': 58,
' presión ': 1012.23,
' velocidad ': 1.96,
' temp ': {' día ': 302.29,
' eve ': 296.46,
' max ': 302.29,
' min ': 289.77,
' mañana ': 294.59 ,
'night': 289.77},
'weather': [{'description': 'sky is clear',
'icon': '01d',
- snip -
Puede ver estos datos pasando weatherData a pprint.pprint (). Es posible que
desee consultar http://openweathermap.org/ para obtener más documentación sobre el significado
de
estos campos. Por ejemplo, la documentación en línea le dirá que
el 302.29 después del "día" es la temperatura diurna en Kelvin, no en grados Celsius o
Fahrenheit.
Las descripciones meteorológicas que desea están después de 'principal' y 'descripción'.
Para imprimirlos cuidadosamente, agregue lo siguiente a quickWeather.py .
! python3
# quickWeather.py - Imprime el clima para una ubicación desde la línea de comando.
- cortar -
# Cargar datos JSON en una variable de Python.
weatherData = json.loads (response.text)
332 Capítulo 14
# Imprimir descripciones del clima.
u w = weatherData ['lista']
print ('Clima actual en% s:'% (ubicación))
print (w [0] ['weather'] [0] ['main'], '-', w [0] ['weather'] [0 ] ['descripción'])
print ()
print ('Mañana:')
print (w [1] ['weather'] [0] ['main'], '-', w [1] ['weather'] [0] ['descripción'])
print ()
print ('Pasado mañana:')
print (w [2] ['weather'] [0] ['main'], '-', w [2] [ 'clima'] [0] ['descripción'])
Observe cómo el código almacena weatherData ['list'] en la variable w para ahorrarle
algo de tipeo u. Utiliza w [0], w [1] yw [2] para recuperar los diccionarios
de hoy, mañana y pasado mañana, respectivamente.
Cada uno de estos diccionarios tiene una clave de "clima", que contiene un valor de lista.
Está interesado en el primer elemento de la lista, un diccionario anidado con varias
teclas más, en el índice 0. Aquí imprimimos los valores almacenados en las teclas 'principal' y
'descripción', separados por un guión.
Cuando este programa se ejecuta con el argumento de línea de comando
quickWeather.py San Francisco, CA, la salida se ve así:
Tiempo actual en San Francisco, California:
despejado - el cielo está despejado
Mañana:
nubes - pocas nubes
Pasado mañana:
despejado - el cielo está despejado
(¡El clima es una de las razones por las que me gusta vivir en San Francisco!)
Ideas para programas similares El
acceso a datos meteorológicos puede formar la base de muchos tipos de programas. Puede
crear programas similares para hacer lo siguiente:
• Recoja pronósticos del tiempo para varios campamentos o rutas de senderismo para ver cuál
tendrá el mejor clima.
• Programe un programa para verificar periódicamente el clima y enviarle una alerta de heladas si
necesita mover sus plantas en el interior. (El Capítulo 15 cubre la programación y el Capítulo 16
explica cómo enviar correos electrónicos).
• Obtenga datos meteorológicos de múltiples sitios para mostrarlos todos a la vez, o calcule y
muestre el promedio de las predicciones meteorológicas múltiples.
Trabajar con archivos CSV y datos JSON 333
Resumen
CSV y JSON son formatos comunes