100% encontró este documento útil (2 votos)
2K vistas244 páginas

Piensa en Python: 2ª Edición

Este documento es la segunda edición del libro "Think Python" que enseña a pensar como un científico de computación. El autor originalmente escribió el libro para una clase de programación en Java pero luego fue traducido a Python. El libro ha sido actualizado y mejorado con más ejercicios y secciones a lo largo de varias ediciones.

Cargado por

marco caniza
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
100% encontró este documento útil (2 votos)
2K vistas244 páginas

Piensa en Python: 2ª Edición

Este documento es la segunda edición del libro "Think Python" que enseña a pensar como un científico de computación. El autor originalmente escribió el libro para una clase de programación en Java pero luego fue traducido a Python. El libro ha sido actualizado y mejorado con más ejercicios y secciones a lo largo de varias ediciones.

Cargado por

marco caniza
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Machine Translated by Google

Piensa  en  Python

Cómo  pensar  como  un  científico  informático

2.ª  edición,  versión  2.4.0
Machine Translated by Google
Machine Translated by Google

Piensa  en  Python

Cómo  pensar  como  un  científico  informático

2.ª  edición,  versión  2.4.0

allen  downey

Prensa  de  té  verde
Needham,  Massachusetts
Machine Translated by Google

Derechos  de  autor  ©  2015  Allen  Downey.

Prensa  de  té  verde
9  Washburn  Ave
Needham  MA  02492

Se  otorga  permiso  para  copiar,  distribuir  y/o  modificar  este  documento  bajo  los  términos  de  la  licencia  Creative  Commons  
Attribution­NonCommercial  3.0  Unported,  que  está  disponible  en
.

La  forma  original  de  este  libro  es  el  código  fuente  de  LATEX.  La  compilación  de  esta  fuente  LATEX  tiene  el  efecto  de  
generar  una  representación  independiente  del  dispositivo  de  un  libro  de  texto,  que  se  puede  convertir  a  otros  formatos  e  
imprimir.

La  fuente  LATEX  para  este  libro  está  disponible  en
Machine Translated by Google

Prefacio

La  extraña  historia  de  este  libro.
En  enero  de  1999  me  estaba  preparando  para  dar  una  clase  de  introducción  a  la  programación  en  Java.  Lo  
había  enseñado  tres  veces  y  me  estaba  frustrando.  La  tasa  de  fracaso  en  la  clase  era  demasiado  alta  e,  incluso  
para  los  estudiantes  que  tenían  éxito,  el  nivel  general  de  rendimiento  era  demasiado  bajo.

Uno  de  los  problemas  que  vi  fueron  los  libros.  Eran  demasiado  grandes,  con  demasiados  detalles  innecesarios  
sobre  Java  y  sin  suficiente  orientación  de  alto  nivel  sobre  cómo  programar.  Y  todos  sufrieron  el  efecto  de  la  
trampilla:  comenzarían  con  facilidad,  avanzarían  gradualmente  y  luego,  en  algún  lugar  alrededor  del  Capítulo  
5,  se  desmoronarían.  Los  estudiantes  obtendrían  demasiado  material  nuevo,  demasiado  rápido,  y  yo  pasaría  
el  resto  del  semestre  recogiendo  las  piezas.

Dos  semanas  antes  del  primer  día  de  clases,  decidí  escribir  mi  propio  libro.  Mis  objetivos  eran:

•  Que  sea  breve.  Es  mejor  para  los  estudiantes  leer  10  páginas  que  no  leer  50  páginas.

•  Tenga  cuidado  con  el  vocabulario.  Traté  de  minimizar  la  jerga  y  definir  cada  término  al  principio
usar.

•  Construya  gradualmente.  Para  evitar  trampas,  tomé  los  temas  más  difíciles  y  los  dividí  en  una  serie  de  
pequeños  pasos.

•  Concéntrese  en  la  programación,  no  en  el  lenguaje  de  programación.  Incluí  el  subconjunto  útil  mínimo  de  
Java  y  omití  el  resto.

Necesitaba  un  título,  así  que  por  capricho  elegí  Cómo  pensar  como  un  científico  informático.

Mi  primera  versión  fue  tosca,  pero  funcionó.  Los  estudiantes  leyeron  y  entendieron  lo  suficiente  como  para  que  
yo  pudiera  dedicar  tiempo  de  clase  a  los  temas  difíciles,  los  temas  interesantes  y  (lo  más  importante)  dejar  que  
los  estudiantes  practicaran.

Lancé  el  libro  bajo  la  Licencia  de  Documentación  Libre  GNU,  que  permite  a  los  usuarios  copiar,  modificar  y  
distribuir  el  libro.

Lo  que  sucedió  después  es  la  parte  interesante.  Jeff  Elkner,  profesor  de  secundaria  en  Virginia,  adoptó  mi  libro  
y  lo  tradujo  a  Python.  Me  envió  una  copia  de  su  traducción  y  tuve  la  experiencia  inusual  de  aprender  Python  
leyendo  mi  propio  libro.  Como  Green  Tea  Press,  publiqué  la  primera  versión  de  Python  en  2001.

En  2003  comencé  a  enseñar  en  Olin  College  y  pude  enseñar  Python  por  primera  vez.  El  contraste  con  Java  
fue  sorprendente.  Los  estudiantes  lucharon  menos,  aprendieron  más,  trabajaron  en  proyectos  más  interesantes  
y,  en  general,  se  divirtieron  mucho  más.
Machine Translated by Google

vi Capítulo  0.  Prefacio

Desde  entonces  he  seguido  desarrollando  el  libro,  corrigiendo  errores,  mejorando  algunos  de  los  ejemplos  y  
añadiendo  material,  especialmente  ejercicios.

El  resultado  es  este  libro,  ahora  con  el  título  menos  grandioso  Think  Python.  Algunos  de  los  cambios
son:

•  Agregué  una  sección  sobre  depuración  al  final  de  cada  capítulo.  Estas  secciones  presentan  técnicas  
generales  para  encontrar  y  evitar  errores,  y  advertencias  sobre  caídas  en  boxes  de  Python.

•  Agregué  más  ejercicios,  desde  pruebas  breves  de  comprensión  hasta  algunos  proyectos  sustanciales.  
La  mayoría  de  los  ejercicios  incluyen  un  enlace  a  mi  solución.

•  Agregué  una  serie  de  estudios  de  casos:  ejemplos  más  largos  con  ejercicios,  soluciones  y  dis
cusión

•  Amplié  la  discusión  de  planes  de  desarrollo  de  programas  y  patrones  de  diseño  básicos.

•  Agregué  apéndices  sobre  depuración  y  análisis  de  algoritmos.

La  segunda  edición  de  Think  Python  tiene  estas  nuevas  características:

•  El  libro  y  todo  el  código  de  soporte  se  han  actualizado  a  Python  3.

•  Agregué  algunas  secciones  y  más  detalles  en  la  web  para  ayudar  a  los  principiantes  a  comenzar  a  
ejecutar  Python  en  un  navegador,  para  que  no  tenga  que  lidiar  con  la  instalación  de  Python  hasta  que  
lo  desee.

•  Para  el  Capítulo  4.1,  cambié  de  mi  propio  paquete  de  gráficos  Turtle,  llamado  Swampy,  a  uno  que  es  
módulo  de  Python  más  estándar, , más  fácil  de  instalar  y  más  potente.

•  Agregué  un  nuevo  capítulo  llamado  "The  Goodies",  que  presenta  algunos
Funciones  de  Python  que  no  son  estrictamente  necesarias,  pero  a  veces  útiles.

Espero  que  disfrutes  trabajando  con  este  libro  y  que  te  ayude  a  aprender  a  programar  y  pensar  como  un  
informático,  al  menos  un  poco.

Allen  B  Downey

Colegio  Olín

Expresiones  de  gratitud

Muchas  gracias  a  Jeff  Elkner,  quien  tradujo  mi  libro  de  Java  a  Python,  lo  que  puso  en  marcha  este  proyecto  y  
me  presentó  lo  que  resultó  ser  mi  lenguaje  favorito.

Gracias  también  a  Chris  Meyers,  quien  contribuyó  con  varias  secciones  a  Cómo  pensar  como  un  científico  
informático.

Gracias  a  la  Free  Software  Foundation  por  desarrollar  la  licencia  de  documentación  libre  de  GNU,  que  me  
ayudó  a  hacer  posible  mi  colaboración  con  Jeff  y  Chris,  y  a  Creative  Commons  por  la  licencia  que  estoy  
usando  ahora.
Machine Translated by Google

viii

Gracias  a  los  editores  de  Lulu  que  trabajaron  en  Cómo  pensar  como  un  científico  informático.

Gracias  a  los  editores  de  O'Reilly  Media  que  trabajaron  en  Think  Python.

Gracias  a  todos  los  estudiantes  que  trabajaron  con  versiones  anteriores  de  este  libro  y  a  todos  los  
colaboradores  (mencionados  a  continuación)  que  enviaron  correcciones  y  sugerencias.

Lista  de  colaboradores

Más  de  100  lectores  perspicaces  y  reflexivos  han  enviado  sugerencias  y  correcciones  en  los  últimos  años.  
Sus  contribuciones  y  entusiasmo  por  este  proyecto  han  sido  de  gran  ayuda.

Si  tiene  una  sugerencia  o  corrección,  envíe  un  correo  electrónico  a  Si   .
realizo  un  cambio  en  función  de  sus  comentarios,  lo  agregaré  a  la  lista  de  colaboradores  (a  menos  que  
solicite  ser  omitido).

Si  incluye  al  menos  parte  de  la  oración  en  la  que  aparece  el  error,  eso  me  facilita  la  búsqueda.  Los  números  
de  página  y  sección  también  están  bien,  pero  no  es  tan  fácil  trabajar  con  ellos.  ¡Gracias!

•  Lloyd  Hugh  Allen  envió  una  corrección  a  la  Sección  8.4.

•  Yvon  Boulianne  envió  una  corrección  de  un  error  semántico  en  el  Capítulo  5.

•  Fred  Bremmer  presentó  una  corrección  en  la  Sección  2.1.

•  Jonah  Cohen  escribió  los  scripts  de  Perl  para  convertir  el  código  fuente  de  LaTeX  de  este  libro  en  hermosos
HTML.

•  Michael  Conlon  envió  una  corrección  gramatical  en  el  Capítulo  2  y  una  mejora  en  el  estilo  en
Capítulo  1,  e  inició  la  discusión  sobre  los  aspectos  técnicos  de  los  intérpretes.

•  Benoît  Girard  envió  una  corrección  a  un  error  humorístico  en  la  Sección  5.6.

,
•  Courtney  Gleason  y  Katherine  Smith  escribieron,  que  se  utilizó  como  estudio  
de  caso  en  una  versión  anterior  
del  libro.  Su  programa  ahora  se  puede  encontrar  en  el  sitio  web.

•  Lee  Harr  envió  más  correcciones  de  las  que  tenemos  espacio  para  enumerar  aquí  y,  de  hecho,  debería  figurar  
como  uno  de  los  principales  editores  del  texto.

•  James  Kaylin  es  un  estudiante  que  usa  el  texto.  Ha  presentado  numerosas  correcciones.

•  David  Kershaw  arregló  el  roto función  en  la  Sección  3.10.

•  Eddie  Lam  ha  enviado  numerosas  correcciones  a  los  Capítulos  1,  2  y  3.  También  arregló  el  Makefile  para  que  
cree  un  índice  la  primera  vez  que  se  ejecuta  y  nos  ayudó  a  configurar  un  esquema  de  control  de  versiones.

•  Man­Yong  Lee  envió  una  corrección  al  código  de  ejemplo  en  la  Sección  2.4.

•  David  Mayo  señaló  que  la  palabra  "inconscientemente"  en  el  Capítulo  1  debía  cambiarse  a
"de  modo  subconsciente".

•  Chris  McAloon  envió  varias  correcciones  a  las  Secciones  3.9  y  3.10.

•  Matthew  J.  Moelter  ha  sido  colaborador  durante  mucho  tiempo  y  envió  numerosas  correcciones  y
sugerencias  al  libro.
Machine Translated by Google

viii Capítulo  0.  Prefacio

•  Simon  Dicon  Montford  informó  que  faltaba  una  definición  de  función  y  varios  errores  tipográficos  en  el  Capítulo  3.  
También  encontró  errores  en  el función  en  el  Capítulo  13.

•  John  Ouzts  corrigió  la  definición  de  "valor  de  retorno"  en  el  Capítulo  3.

•  Kevin  Parks  envió  valiosos  comentarios  y  sugerencias  sobre  cómo  mejorar  la  distribución
del  libro.

•  David  Pool  envió  un  error  tipográfico  en  el  glosario  del  Capítulo  1,  así  como  amables  palabras  de  aliento.

•  Michael  Schmitt  envió  una  corrección  al  capítulo  sobre  archivos  y  excepciones.

•  Robin  Shaw  señaló  un  error  en  la  Sección  13.1,  donde  la  función  printTime  se  usó  en  un
ejemplo  sin  ser  definido.

•  Paul  Sleigh  encontró  un  error  en  el  Capítulo  7  y  un  error  en  el  script  Perl  de  Jonah  Cohen  que  genera
HTML  de  LaTeX.

•  Craig  T.  Snydal  está  probando  el  texto  en  un  curso  en  la  Universidad  Drew.  Ha  aportado  varios
valiosas  sugerencias  y  correcciones.

•  Ian  Thomas  y  sus  alumnos  están  usando  el  texto  en  un  curso  de  programación.  Son  los  primeros  en  probar  los  
capítulos  de  la  segunda  mitad  del  libro  y  han  hecho  numerosas  correcciones  y  sugerencias.

•  Keith  Verheyden  envió  una  corrección  en  el  Capítulo  3.

•  Peter  Winstanley  nos  hizo  saber  acerca  de  un  error  de  larga  data  en  nuestro  latín  en  el  Capítulo  3.

•  Chris  Wrobel  hizo  correcciones  al  código  en  el  capítulo  sobre  E/S  de  archivos  y  excepciones.

•  Moshe  Zadka  ha  hecho  contribuciones  invaluables  a  este  proyecto.  Además  de  escribir  el  primer  borrador  del  
capítulo  sobre  Diccionarios,  brindó  orientación  continua  en  las  primeras  etapas  del  libro.

•  Christoph  Zwerschke  envió  varias  correcciones  y  sugerencias  pedagógicas,  y  explicó  el
diferencia  entre  gleich  y  selbe.

•  James  Mayer  nos  envió  una  gran  cantidad  de  errores  ortográficos  y  tipográficos,  incluidos  dos  en  el
lista  de  contribuyentes.

•  Hayden  McAfee  detectó  una  incoherencia  potencialmente  confusa  entre  dos  ejemplos.

•  Ángel  Arnal  es  parte  de  un  equipo  internacional  de  traductores  que  trabajan  en  la  versión  en  español  de
el  texto.  También  ha  encontrado  varios  errores  en  la  versión  en  inglés.

•  Tauhidul  Hoque  y  Lex  Berezhny  crearon  las  ilustraciones  del  Capítulo  1  y  mejoraron  muchas
de  las  otras  ilustraciones.

•  La  Dra.  Michele  Alzetta  detectó  un  error  en  el  Capítulo  8  y  envió  algunos  comunicados  pedagógicos  interesantes.
comentarios  y  sugerencias  sobre  Fibonacci  y  Old  Maid.

•  Andy  Mitchell  detectó  un  error  tipográfico  en  el  Capítulo  1  y  un  ejemplo  roto  en  el  Capítulo  2.

•  Kalin  Harvey  sugirió  una  aclaración  en  el  Capítulo  7  y  detectó  algunos  errores  tipográficos.

•  Christopher  P.  Smith  detectó  varios  errores  tipográficos  y  nos  ayudó  a  actualizar  el  libro  para  Python  2.2.

•  David  Hutchins  detectó  un  error  tipográfico  en  el  Prólogo.

•  Gregor  Lingl  está  enseñando  Python  en  una  escuela  secundaria  en  Viena,  Austria.  Él  está  trabajando  en  un  Ger
man  tradujo  el  libro,  y  detectó  un  par  de  errores  graves  en  el  capítulo  5.
Machine Translated by Google

ix

•  Julie  Peters  detectó  un  error  tipográfico  en  el  Prefacio.

•  Florin  Oprina  envió  una  mejora  en , una  corrección  en , y  un  buen  error  tipográfico.

•  DJ  Webre  sugirió  una  aclaración  en  el  Capítulo  3.

•  Ken  encontró  un  puñado  de  errores  en  los  capítulos  8,  9  y  11.

•  Ivo  Wever  detectó  un  error  tipográfico  en  el  Capítulo  5  y  sugirió  una  aclaración  en  el  Capítulo  3.

•  Curtis  Yanko  sugirió  una  aclaración  en  el  Capítulo  2.

•  Ben  Logan  envió  varios  errores  tipográficos  y  problemas  con  la  traducción  del  libro  a  HTML.

•  Jason  Armstrong  vio  la  palabra  que  faltaba  en  el  Capítulo  2.

•  Louis  Cordier  notó  un  lugar  en  el  Capítulo  16  donde  el  código  no  coincidía  con  el  texto.

•  Brian  Cain  sugirió  varias  aclaraciones  en  los  Capítulos  2  y  3.

•  Rob  Black  envió  un  montón  de  correcciones,  incluidos  algunos  cambios  para  Python  2.2.

•  Jean­Philippe  Rey  de  École  Centrale  Paris  envió  varios  parches,  incluidas  algunas  actualizaciones
para  Python  2.2  y  otras  mejoras  bien  pensadas.

•  Jason  Mader  de  la  Universidad  George  Washington  hizo  una  serie  de  sugerencias  útiles  y  cor
recciones

•  Jan  Gundtofte­Bruun  nos  recordó  que  “un  error”  es  un  error.

•  Abel  David  y  Alexis  Dinno  nos  recordaron  que  el  plural  de  “matrix”  es  “matrices”,  no  “matrices”.  Este  error  
estuvo  en  el  libro  durante  años,  pero  dos  lectores  con  las  mismas  iniciales  lo  reportaron  el  mismo  día.  Extraño.

•  Charles  Thayer  nos  animó  a  deshacernos  de  los  puntos  y  comas  que  habíamos  puesto  al  final  de  algunas  
declaraciones  ya  limpiar  nuestro  uso  de  "argumento"  y  "parámetro".

•  Roger  Sperberg  señaló  una  lógica  retorcida  en  el  Capítulo  3.

•  Sam  Bull  señaló  un  párrafo  confuso  en  el  Capítulo  2.

•  Andrew  Cheung  señaló  dos  instancias  de  "uso  antes  de  def".

•  C.  Corey  Capel  detectó  la  palabra  que  faltaba  en  el  Tercer  Teorema  de  Depuración  y  un  error  tipográfico  en
Capítulo  4.

•  Alessandra  ayudó  a  aclarar  algunas  confusiones  sobre  las  tortugas.

•  Wim  Champagne  encontró  un  cerebro­o  en  un  ejemplo  de  diccionario.

•  Douglas  Wright  señaló  un  problema  con  la  división  del  piso  en .

•  Jared  Spindor  encontró  algunos  desechos  al  final  de  una  oración.

•  Lin  Peiheng  envió  una  serie  de  sugerencias  muy  útiles.

•  Ray  Hagtvedt  envió  dos  errores  y  uno  no  del  todo.

•  Torsten  Hübsch  señaló  una  inconsistencia  en  Swampy.

•  Inga  Petuhhov  corrigió  un  ejemplo  en  el  Capítulo  14.

•  Arne  Babenhauserheide  envió  varias  correcciones  útiles.
Machine Translated by Google

X Capítulo  0.  Prefacio

•  Mark  E.  Casida  es  bueno  para  detectar  palabras  repetidas.

•  Scott  Tyler  llenó  uno  que  faltaba.  Y  luego  envió  un  montón  de  correcciones.

•  Gordon  Shephard  envió  varias  correcciones,  todas  en  correos  electrónicos  separados.

•  Andrés  Turner ted  un  error  en  el  Capítulo  8.

•  Adam  Hobart  solucionó  un  problema  con  la  división  del  piso  en .

•  Daryl  Hammond  y  Sarah  Zimmerman  señalaron  que  expuse  que  Zim  detectó  un  error   demasiado  temprano.  Y

tipográfico.

•  George  Sass  encontró  un  error  en  una  sección  de  Depuración.

•  Brian  Bingham  sugirió  el  Ejercicio  11.5.

•  Leah  Engelbert­Fenton  señaló  que  usé como  nombre  de  variable,  contrariamente  a  mi  propio  
consejo.  Y  luego  encontré  un  montón  de  errores  tipográficos  y  un  "uso  antes  de  la  definición".

•  Joe  Funke  detectó  un  error  tipográfico.

•  Chao­chao  Chen  encontró  una  inconsistencia  en  el  ejemplo  de  Fibonacci.

•  Jeff  Paine  conoce  la  diferencia  entre  espacio  y  spam.

•  Lubos  Pintes  envió  un  error  tipográfico.

•  Gregg  Lind  y  Abigail  Heithoff  sugirieron  el  ejercicio  14.3.

•  Max  Hailperin  ha  enviado  una  serie  de  correcciones  y  sugerencias.  Max  es  uno  de  los  autores  de  las  extraordinarias  
Abstracciones  Concretas,  que  tal  vez  quieras  leer  cuando  termines  con  este  libro.

•  Chotipat  Pornavalai  encontró  un  error  en  un  mensaje  de  error.

•  Stanislaw  Antol  envió  una  lista  de  sugerencias  muy  útiles.

•  Eric  Pashman  envió  varias  correcciones  para  los  capítulos  4–11.

•  Miguel  Azevedo  encontró  algunos  errores  tipográficos.

•  Jianhua  Liu  envió  una  larga  lista  de  correcciones.

•  Nick  King  encontró  una  palabra  que  faltaba.

•  Martin  Zuther  envió  una  larga  lista  de  sugerencias.

•  Adam  Zimmerman  encontró  una  inconsistencia  en  mi  caso  de  una  "instancia"  y  varios  otros
errores

•  Ratnakar  Tiwari  sugirió  una  nota  al  pie  que  explica  los  triángulos  degenerados.

•  Anurag  Goel  sugirió  otra  solución  para y  envió  algunas  correcciones  adicionales
ciones.  Y  sabe  cómo  deletrear  a  Jane  Austen.

•  Kelli  Kratzer  detectó  uno  de  los  errores  tipográficos.

•  Mark  Griffiths  señaló  un  ejemplo  confuso  en  el  Capítulo  3.

•  Roydan  Ongie  encontró  un  error  en  mi  método  de  Newton.

•  Patryk  Wolowiec  me  ayudó  con  un  problema  en  la  versión  HTML.
Machine Translated by Google

xi

•  Mark  Chonofsky  me  habló  de  una  nueva  palabra  clave  en  Python  3.

•  Russell  Coleman  me  ayudó  con  mi  geometría.

•  Nam  Nguyen  encontró  un  error  tipográfico  y  señaló  que  usé  el  patrón  Decorator  pero  no  los  hombres.
ción  por  su  nombre.

•  Stéphane  Morin  envió  varias  correcciones  y  sugerencias.

•  Paul  Stoop  corrigió  un  error  tipográfico  en .

•  Eric  Bronner  señaló  una  confusión  en  la  discusión  del  orden  de  las  operaciones.

•  Alexandros  Gezerlis  estableció  un  nuevo  estándar  para  el  número  y  la  calidad  de  las  sugerencias  que  presentó.  
¡Estamos  profundamente  agradecidos!

•  Gray  Thomas  conoce  su  derecha  de  su  izquierda.

•  Giovanni  Escobar  Sosa  envió  una  larga  lista  de  correcciones  y  sugerencias.

•  Daniel  Neilson  corrigió  un  error  sobre  el  orden  de  las  operaciones.

•  Will  McGinnis  señaló  que se  definió  de  manera  diferente  en  dos  lugares.

•  Frank  Hecker  señaló  un  ejercicio  que  estaba  subespecificado  y  algunos  enlaces  rotos.

•  Animesh  B  me  ayudó  a  aclarar  un  ejemplo  confuso.

•  Martin  Caspersen  encontró  dos  errores  de  redondeo.

•  Gregor  Ulm  envió  varias  correcciones  y  sugerencias.

•  Dimitrios  Tsirigkas  me  sugirió  aclarar  un  ejercicio.

•  Carlos  Tafur  envió  una  página  de  correcciones  y  sugerencias.

•  Martin  Nordsletten  encontró  un  error  en  la  solución  de  un  ejercicio.

•  Sven  Hoexter  señaló  que  una  variable  llamada sombrea  una  función  incorporada.

•  Stephen  Gregory  señaló  el  problema  con en  Phyton  3.

•  Ishwar  Bhat  corrigió  mi  declaración  del  último  teorema  de  Fermat.

•  Andrea  Zanella  tradujo  el  libro  al  italiano  y  envió  una  serie  de  correcciones  a  lo  largo  del
forma.

•  Muchas,  muchas  gracias  a  Melissa  Lewis  y  Luciano  Ramalho  por  sus  excelentes  comentarios  y  sugerencias  sobre  la  
segunda  edición.

•  Gracias  a  Harry  Percival  de  PythonAnywhere  por  su  ayuda  para  que  las  personas  comenzaran  a  ejecutar  Python  en  un  
navegador.

•  Xavier  Van  Aubel  hizo  varias  correcciones  útiles  en  la  segunda  edición.

•  William  Murray  corrigió  mi  definición  de  división  de  piso.

•  Per  Starbäck  me  puso  al  día  sobre  saltos  de  línea  universales  en  Python  3.

•  Laurent  Rosenfeld  y  Mihaela  Rotaru  tradujeron  este  libro  al  francés.  En  el  camino,  ellos
enviado  muchas  correcciones  y  sugerencias.

Además,  las  personas  que  detectaron  errores  tipográficos  o  hicieron  correcciones  incluyen  a  Czeslaw  Czapla,  Dale  
Wil  son,  Francesco  Carlo  Cimini,  Richard  Fursa,  Brian  McGhie,  Lokesh  Kumar  Makani,  Matthew  Shultz,  Viet  Le,  Victor  
Simeone,  Lars  OD  Christensen,  Swarup  Sahoo,  Alix  Etienne ,  Kuang  He,  Wei  Huang,  Karen  Barber  y  Eric  Ransom.
Machine Translated by Google

xi Capítulo  0.  Prefacio
Machine Translated by Google

Contenido

Prefacio v

1  El  camino  del  programa 1

1.1  ¿Qué  es  un  programa? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2  Ejecutando  Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.3  El  primer  programa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  3

1.4  Operadores  aritméticos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  3

1.5  Valores  y  tipos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.6  Lenguajes  formales  y  naturales. . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.7  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  6

1.8  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.9 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2  Variables,  expresiones  y  sentencias 9

2.1  Declaraciones  de  cesión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  9

2.2  Nombres  de  variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  9

2.3  Expresiones  y  declaraciones. . . . . . . . . . . . . . . . . . . . . . . . . . .  10

2.4 Modo  guión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.5  Orden  de  las  operaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.6 Operaciones  con  cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.7  Comentarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.8  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  13

2.9  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.10  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14


Machine Translated by Google

xiv Contenido

3  funciones 17

3.1  Llamadas  a  funciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3.2  Funciones  matemáticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  18

3.3  Composición. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.4  Adición  de  nuevas  funciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.5 Definiciones  y  usos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  20

3.6  Flujo  de  ejecución. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.7  Parámetros  y  argumentos. . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.8 Las  variables  y  los  parámetros  son  locales. . . . . . . . . . . . . . . . . . . . . . . 22

3.9  Diagramas  de  pila. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  23

3.10  Funciones  fructíferas  y  funciones  nulas. . . . . . . . . . . . . . . . . . . . . . 24

3.11  ¿Por  qué  funciones? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

3.12  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  25

3.13  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  25

3.14  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  26

4  Estudio  de  caso:  diseño  de  interfaz 29

4.1  El  módulo  tortuga. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  29

4.2  Repetición  simple. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  30

4.3 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  31

4.4  Encapsulación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  32

4.5  Generalización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  32

4.6 Diseño  de  interfaz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  33

4.7  Refactorización. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  34

4.8  Un  plan  de  desarrollo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  35

4.9  cadena  de  documentación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  35

4.10  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  36

4.11  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  36

4.12  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  37


Machine Translated by Google

Contenido XV

5  Condicionales  y  recursión 39

5.1  División  de  piso  y  módulo. . . . . . . . . . . . . . . . . . . . . . . . . . .  39

5.2  Expresiones  booleanas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  40

5.3  Operadores  lógicos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  40

5.4  Ejecución  condicional. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

5.5  Ejecución  alternativa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

5.6  Condicionales  encadenados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

5.7  Condicionales  anidados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

5.8  Recursividad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  43

5.9  Diagramas  de  pila  para  funciones  recursivas. . . . . . . . . . . . . . . . . . . . . 44

5.10  Recurrencia  infinita. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

5.11  Entrada  de  teclado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  45

5.12  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  46

5.13  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

5.14  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

6  funciones  fructíferas 51

6.1  Valores  devueltos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  51

6.2  Desarrollo  incremental. . . . . . . . . . . . . . . . . . . . . . . . . . . .  52

6.3  Composición. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  54

6.4  Funciones  booleanas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  54

6.5  Más  recursividad. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  55

6.6  Acto  de  fe. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  57

6.7  Un  ejemplo  más. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  57

6.8  Tipos  de  cheques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  58

6.9  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  59

6.10  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  60

6.11  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  60


Machine Translated by Google

xvi Contenido

7  Iteración 63

7.1  Reasignación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  63

7.2  Actualización  de  variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  64

7.3  El declaración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  64

7.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  66

7.5  Raíces  cuadradas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  66

7.6  Algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  67

7.7  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  68

7.8  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  68

7.9 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  69

8  cuerdas 71

8.1  Una  cadena  es  una  secuencia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

8.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

8.3 transversal  con  un bucle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

8.4 Rebanadas  de  cuerda. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  73

8.5 Las  cadenas  son  inmutables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

8.6  Búsqueda. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

8.7  Bucle  y  conteo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  75

8.8 Métodos  de  cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  75

8.9  El  operador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  76

8.10  Comparación  de  cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

8.11  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

8.12  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  79

8.13  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  79

9  Estudio  de  caso:  juego  de  palabras 83

9.1  Leer  listas  de  palabras. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  83

9.2 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  84

9.3  Buscar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  85

9.4  Bucles  con  índices. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  86

9.5  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  87

9.6  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  87

9.7 ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  88


Machine Translated by Google

Contenido xvii

10  listas 89

10.1  Una  lista  es  una  secuencia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  89

10.2  Las  listas  son  mutables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  90

10.3  Recorriendo  una  lista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  91

10.4  Operaciones  de  lista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  91

10.5  Sectores  de  lista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  91

10.6  Métodos  de  lista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  92

10.7  Mapear,  filtrar  y  reducir. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  93

10.8  Eliminación  de  elementos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  94

10.9  Listas  y  cadenas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  94

10.10  Objetos  y  valores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  95

10.11  Alias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  96

10.12  Lista  de  argumentos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  97

10.13  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  98

10.14  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  100

10.15  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  100

11  diccionarios 103

11.1  Un  diccionario  es  un  mapeo. . . . . . . . . . . . . . . . . . . . . . . . . . . .  103

11.2  Diccionario  como  colección  de  contadores. . . . . . . . . . . . . . . . . . . . . .  104

11.3  Bucles  y  diccionarios. . . . . . . . . . . . . . . . . . . . . . . . . . . . .  106

11.4  Búsqueda  inversa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  106

11.5  Diccionarios  y  listas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  107

11.6  Notas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  109

11.7  Variables  globales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  110

11.8  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

11.9  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112

11.10  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  113


Machine Translated by Google

xviii Contenido

12  tuplas 115

12.1  Las  tuplas  son  inmutables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  115

12.2  Asignación  de  tuplas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  116

12.3  Tuplas  como  valores  de  retorno. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

12.4  Tuplas  de  argumentos  de  longitud  variable. . . . . . . . . . . . . . . . . . . . . . . .  118

12.5  Listas  y  tuplas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  118

12.6  Diccionarios  y  tuplas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  120

12.7  Secuencias  de  secuencias. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

12.8  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

12.9  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

12.10  Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  123

13  Estudio  de  caso:  selección  de  estructura  de  datos 125

13.1  Análisis  de  frecuencia  de  palabras. . . . . . . . . . . . . . . . . . . . . . . . . . . . .  125

13.2  Números  aleatorios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  126

13.3  Histograma  de  palabras. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

13.4  Palabras  más  comunes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  128

13.5  Parámetros  opcionales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  129

13.6  Resta  de  diccionario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  129

13.7  Palabras  aleatorias. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  130

13.8  Análisis  de  Markov. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  130

13.9  Estructuras  de  datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  132

13.10  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  133

13.11  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  134

13.12  Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  134

14  archivos 137

14.1  Persistencia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  137

14.2  Leer  y  escribir. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  137

14.3  Operador  de  formato. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  138

14.4  Nombres  de  archivos  y  rutas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  139

14.5  Captura  de  excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  140


Machine Translated by Google

Contenido xix

14.6  Bases  de  datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

14.7  Decapado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

14.8  Tuberías . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

14.9  Módulos  de  escritura. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  143

14.10  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

14.11  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  145

14.12  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  145

15  Clases  y  objetos 147

15.1  Tipos  definidos  por  el  programador. . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

15.2  Atributos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  148

15.3  Rectángulos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  149

15.4  Instancias  como  valores  de  retorno. . . . . . . . . . . . . . . . . . . . . . . . . . . .  150

15.5  Los  objetos  son  mutables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  151

15.6  Copia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  151

15.7  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  152

15.8  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  153

15.9  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  154

16  Clases  y  funciones 155

16.1  Tiempo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  155

16.2  Funciones  puras. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  156

16.3  Modificadores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  157

16.4  Creación  de  prototipos  versus  planificación. . . . . . . . . . . . . . . . . . . . . . . . . . .  158

16.5  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  159

16.6  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  160

16.7  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  160

17  Clases  y  métodos 161

17.1  Características  orientadas  a  objetos. . . . . . . . . . . . . . . . . . . . . . . . . . . . .  161

17.2  Objetos  de  impresión. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  162

17.3  Otro  ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  163


Machine Translated by Google

XX Contenido

17.4  Un  ejemplo  más  complicado. . . . . . . . . . . . . . . . . . . . . . . . . .  164

17.5  El  método  init. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  164

17.6  El método . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  165

17.7  Sobrecarga  del  operador. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  165

17.8  Despacho  basado  en  tipos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  166

17.9  Polimorfismo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  167

17.10  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  168

17.11  Interfaz  e  implementación. . . . . . . . . . . . . . . . . . . . . . . . . .  169

17.12  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  169

17.13  Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  170

18  Herencia 171

18.1  Objetos  de  tarjeta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

18.2  Atributos  de  clase. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

18.3  Comparación  de  tarjetas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  173

18.4  Cubiertas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

18.5  Impresión  de  la  baraja. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

18.6  Añadir,  eliminar,  barajar  y  clasificar. . . . . . . . . . . . . . . . . . . . . . . . . .  175

18.7  Herencia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  176

18.8  Diagramas  de  clase. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177

18.9  Depuración. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  178

18.10  Encapsulación  de  datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  179

18.11  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  180

18.12  Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  181

19  Las  golosinas 183

19.1  Expresiones  condicionales. . . . . . . . . . . . . . . . . . . . . . . . . . . . .  183

19.2  Lista  de  comprensiones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  184

19.3  Expresiones  generadoras. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  185

19.4 y . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  185

19.5  Conjuntos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  186

19.6  Contadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  187


Machine Translated by Google

Contenido xxx

19.7  dictamen  predeterminado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  188

19.8  Tuplas  con  nombre. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  189

19.9  Recopilación  de  argumentos  de  palabras  clave. . . . . . . . . . . . . . . . . . . . . . . . . . . . .  190

19.10  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  191

19.11  Ejercicios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  192

Una  depuración 193

A.1  Errores  de  sintaxis. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  193

A.2  Errores  de  tiempo  de  ejecución. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  195

A.3  Errores  semánticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  198

B  Análisis  de  Algoritmos 201

B.1  Orden  de  crecimiento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  202

B.2  Análisis  de  las  operaciones  básicas  de  Python. . . . . . . . . . . . . . . . . . . . . .  204

B.3  Análisis  de  algoritmos  de  búsqueda. . . . . . . . . . . . . . . . . . . . . . . . . .  205

B.4  Tablas  hash. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  206

B.5  Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  209


Machine Translated by Google

XXII Contenido
Machine Translated by Google

Capítulo  1

El  camino  del  programa

El  objetivo  de  este  libro  es  enseñarte  a  pensar  como  un  informático.  Esta  forma  de  pensar  combina  
algunas  de  las  mejores  características  de  las  matemáticas,  la  ingeniería  y  las  ciencias  naturales.
Al  igual  que  los  matemáticos,  los  informáticos  utilizan  lenguajes  formales  para  denotar  ideas  
(específicamente  cálculos).  Al  igual  que  los  ingenieros,  diseñan  cosas,  ensamblan  componentes  en  
sistemas  y  evalúan  las  compensaciones  entre  alternativas.  Al  igual  que  los  científicos,  observan  el  
comportamiento  de  sistemas  complejos,  formulan  hipótesis  y  prueban  predicciones.

La  habilidad  más  importante  para  un  informático  es  la  resolución  de  problemas.  La  resolución  de  
problemas  significa  la  capacidad  de  formular  problemas,  pensar  creativamente  en  soluciones  y  expresar  
una  solución  con  claridad  y  precisión.  Resulta  que  el  proceso  de  aprender  a  programar  es  una  excelente  
oportunidad  para  practicar  las  habilidades  de  resolución  de  problemas.  Es  por  eso  que  este  capítulo  se  
llama,  “El  camino  del  programa”.

En  un  nivel,  aprenderá  a  programar,  una  habilidad  útil  en  sí  misma.  En  otro  nivel,  utilizará  la  programación  
como  un  medio  para  un  fin.  A  medida  que  avanzamos,  ese  final  se  hará  más  claro.

1.1  ¿Qué  es  un  programa?
Un  programa  es  una  secuencia  de  instrucciones  que  especifica  cómo  realizar  un  cálculo.  El  cálculo  
puede  ser  algo  matemático,  como  resolver  un  sistema  de  ecuaciones  o  encontrar  las  raíces  de  un  
polinomio,  pero  también  puede  ser  un  cálculo  simbólico,  como  buscar  y  reemplazar  texto  en  un  
documento  o  algo  gráfico,  como  procesar  una  imagen  o  reproduciendo  un  video

Los  detalles  se  ven  diferentes  en  diferentes  idiomas,  pero  aparecen  algunas  instrucciones  básicas  en  
casi  todos  los  idiomas:

entrada:  obtenga  datos  del  teclado,  un  archivo,  la  red  o  algún  otro  dispositivo.

salida:  Mostrar  datos  en  la  pantalla,  guardarlos  en  un  archivo,  enviarlos  a  través  de  la  red,  etc.

matemáticas:  Realice  operaciones  matemáticas  básicas  como  la  suma  y  la  multiplicación.

ejecución  condicional:  compruebe  ciertas  condiciones  y  ejecute  el  código  apropiado.
Machine Translated by Google

2 Capítulo  1.  El  camino  del  programa

repetición:  Realizar  alguna  acción  repetidamente,  generalmente  con  alguna  variación.

Lo  creas  o  no,  eso  es  prácticamente  todo  lo  que  hay  que  hacer.  Todos  los  programas  que  hayas  usado,  sin  
importar  cuán  complicados  sean,  se  componen  de  instrucciones  que  se  parecen  mucho  a  estas.
Entonces,  puede  pensar  en  la  programación  como  el  proceso  de  dividir  una  tarea  grande  y  compleja  en  
subtareas  cada  vez  más  pequeñas  hasta  que  las  subtareas  sean  lo  suficientemente  simples  como  para  
realizarlas  con  una  de  estas  instrucciones  básicas.

1.2  Ejecutando  Python
Uno  de  los  desafíos  de  comenzar  con  Python  es  que  es  posible  que  deba  instalar  Python  y  el  software  
relacionado  en  su  computadora.  Si  está  familiarizado  con  su  sistema  operativo,  y  especialmente  si  se  siente  
cómodo  con  la  interfaz  de  línea  de  comandos,  no  tendrá  problemas  para  instalar  Python.  Pero  para  los  
principiantes,  puede  ser  doloroso  aprender  sobre  administración  de  sistemas  y  programación  al  mismo  tiempo.

Para  evitar  ese  problema,  le  recomiendo  que  comience  ejecutando  Python  en  un  navegador.  Más  tarde,  
cuando  se  sienta  cómodo  con  Python,  le  haré  sugerencias  para  instalar  Python  en  su  computadora.

Hay  varias  páginas  web  que  puede  usar  para  ejecutar  Python.  Si  ya  tiene  un  favorito,  continúe  y  utilícelo.  De  
lo  contrario,  recomiendo  PythonAnywhere.  Proporciono  instrucciones  detalladas  para  comenzar  en
.

Hay  dos  versiones  de  Python,  llamadas  Python  2  y  Python  3.  Son  muy  similares,  así  que  si  aprendes  una,  es  
fácil  cambiar  a  la  otra.  De  hecho,  solo  hay  algunas  diferencias  que  encontrará  como  principiante.  Este  libro  
está  escrito  para  Python  3,  pero  incluyo  algunas  notas  sobre  Python  2.

El  intérprete  de  Python  es  un  programa  que  lee  y  ejecuta  código  de  Python.  Según  su  entorno,  puede  iniciar  el  
intérprete  haciendo  clic  en  un  icono  o  escribiendo
en  una  línea  de  comando.  Cuando  se  inicia,  debería  ver  un  resultado  como  este:

Las  primeras  tres  líneas  contienen  información  sobre  el  intérprete  y  el  sistema  operativo  en  el  que  se  ejecuta,  
por  lo  que  podría  ser  diferente  para  usted.  Pero  debe  verificar  que  el  número  de  versión,  que  se  encuentra  en  
este  ejemplo,  comience  con  3,  lo  que  indica  que  está  ejecutando  Python  3.  Si  comienza  con  2,  está  ejecutando  
(lo  adivinó)  Python  2.

La  última  línea  es  un  mensaje  que  indica  que  el  intérprete  está  listo  para  que  ingrese  el  código.  Si  escribe  una  
línea  de  código  y  pulsa  Intro,  el  intérprete  muestra  el  resultado:

Ahora  estás  listo  para  empezar.  De  aquí  en  adelante,  asumo  que  sabe  cómo  iniciar  el  intérprete  de  Python  y  
ejecutar  el  código.
Machine Translated by Google

1.3.  el  primer  programa 3

1.3  El  primer  programa
Tradicionalmente,  el  primer  programa  que  escribes  en  un  nuevo  idioma  se  llama  "¡Hola,  mundo!"  porque  
todo  lo  que  hace  es  mostrar  las  palabras  "¡Hola,  mundo!".  En  Python,  se  ve  así:

Este  es  un  ejemplo  de  una  declaración  de  impresión,  aunque  en  realidad  no  imprime  nada  en  papel.  Muestra  
un  resultado  en  la  pantalla.  En  este  caso,  el  resultado  son  las  palabras.

Las  comillas  en  el  programa  marcan  el  principio  y  el  final  del  texto  a  mostrar;  no  aparecen  en  el  resultado.

Los  paréntesis  indican  que es  una  función  Llegaremos  a  las  funciones  en  el  Capítulo  3.

En  Python  2,  la  declaración  de  impresión  es  ligeramente  diferente;  no  es  una  función,  por  lo  que  no  usa  
paréntesis.

Esta  distinción  tendrá  más  sentido  pronto,  pero  eso  es  suficiente  para  comenzar.

1.4  Operadores  aritméticos
Después  de  “Hello,  World”,  el  siguiente  paso  es  la  aritmética.  Python  proporciona  operadores,  que  son  
símbolos  especiales  que  representan  cálculos  como  la  suma  y  la  multiplicación.

Los  operadores,   , y  realizar  sumas,  restas  y  multiplicaciones,  como  en  la  siguiente
dando  ejemplos:

El  operador  realiza  la  división:

Tal  vez  se  pregunte  por  qué  el  resultado  es en  lugar  de . Lo  explicaré  en  la  siguiente  sección.

Finalmente,  el  operador  realiza  la  exponenciación;  es  decir,  eleva  un  número  a  una  potencia:

En  algunos  otros  lenguajes,  se  usa  para  la  exponenciación,  pero  en  Python  es  un  operador  bit  a  bit  llamado  
XOR.  Si  no  estás  familiarizado  con  los  operadores  bit  a  bit,  el  resultado  te  sorprenderá:

No  cubriré  los  operadores  bit  a  bit  en  este  libro,  pero  puede  leer  sobre  ellos  en
.
Machine Translated by Google

4 Capítulo  1.  El  camino  del  programa

1.5  Valores  y  tipos
Un  valor  es  una  de  las  cosas  básicas  con  las  que  trabaja  un  programa,  como  una  letra  o  un  número.  Algunos  
valores  que  hemos  visto  hasta  ahora  son, ,y .

Estos  valores  pertenecen  a  diferentes  tipos:  es  un  número   es  un  número  de  punto  flotante,  y
entero,  es  una  cadena,  se  llama  así  porque  las  letras  que  contiene  están  encadenadas.

Si  no  está  seguro  de  qué  tipo  tiene  un  valor,  el  intérprete  puede  decirle:

En  estos  resultados,  la  palabra  “clase”  se  utiliza  en  el  sentido  de  una  categoría;  un  tipo  es  una  categoría  de  
valores.

No  es  sorprendente  que  los  números  enteros  pertenezcan  al  tipo  al   ,  las  cadenas  pertenecen  a y  punto  flotante


que  pertenecen  los  números. .

¿Qué  pasa  con  valores  como  y   ?  Parecen  números,  pero  están  entre  comillas.
marcas  como  cadenas?

Son  cuerdas.

Cuando  escribe  un  número  entero  grande,  puede  sentirse  tentado  a  usar  comas  entre  grupos  de  dígitos,  
como  en .  Este  no  es  un  número  entero  legal  en  Python,  pero  es  legal:

¡Eso  no  es  lo  que  esperábamos  en  absoluto!  Python  interpreta  como  una  secuencia  de  enteros  separados  por  
comas.  Aprenderemos  más  sobre  este  tipo  de  secuencia  más  adelante.

1.6  Lenguajes  formales  y  naturales
Los  lenguajes  naturales  son  los  idiomas  que  hablan  las  personas,  como  el  inglés,  el  español  y  el  francés.
No  fueron  diseñados  por  personas  (aunque  la  gente  trata  de  imponerles  algún  orden);  
evolucionaron  naturalmente.

Los  lenguajes  formales  son  lenguajes  diseñados  por  personas  para  aplicaciones  específicas.  
Por  ejemplo,  la  notación  que  usan  los  matemáticos  es  un  lenguaje  formal  que  es  particularmente  
bueno  para  denotar  relaciones  entre  números  y  símbolos.  Los  químicos  usan  un  lenguaje  formal  
para  representar  la  estructura  química  de  las  moléculas.  Y  más  importante:

Los  lenguajes  de  programación  son  lenguajes  formales  que  han  sido  diseñados  para  
expresar  cálculos.
Machine Translated by Google

1.6.  lenguajes  formales  y  naturales 5

Los  lenguajes  formales  tienden  a  tener  reglas  de  sintaxis  estrictas  que  rigen  la  estructura  de  las  declaraciones.
Por  ejemplo,  en  matemáticas,  la  declaración  3  +  3  =  6  tiene  una  sintaxis  correcta,  pero  3+  =  3$6  no.  En  
química,  H2O  es  una  fórmula  sintácticamente  correcta,  pero  2Zz  no  lo  es.

Las  reglas  de  sintaxis  vienen  en  dos  sabores,  pertenecientes  a  tokens  y  estructura.  Los  tokens  son  los  
elementos  básicos  del  lenguaje,  como  palabras,  números  y  elementos  químicos.  Uno  de  los  problemas  con  3+  
=  3$6  es  que  $  no  es  un  token  legal  en  matemáticas  (al  menos  que  yo  sepa).  Del  mismo  modo,  2Zz  no  es  
legal  porque  no  hay  ningún  elemento  con  la  abreviatura  Zz.

El  segundo  tipo  de  regla  de  sintaxis  se  refiere  a  la  forma  en  que  se  combinan  los  tokens.  La  ecuación  3  + /3  
es  ilegal  porque  aunque  +  y /  son  fichas  legales,  no  puedes  tener  una  después  de  la  otra.  De  manera  similar,  
en  una  fórmula  química,  el  subíndice  viene  después  del  nombre  del  elemento,
no  antes.

Esta  es  una  oración  en  inglés  bien  estructurada  con  tokens  no  válidos.  Esta  oración  tiene  todos  los  tokens  
válidos,  pero  una  estructura  no  válida.

Cuando  lees  una  oración  en  inglés  o  una  declaración  en  un  lenguaje  formal,  tienes  que  descifrar  la  estructura  
(aunque  en  un  lenguaje  natural  lo  haces  inconscientemente).  Este  proceso  se  denomina  análisis.

Aunque  los  lenguajes  formales  y  naturales  tienen  muchas  características  en  común  (tokens,  estructura  y  
sintaxis),  existen  algunas  diferencias:

Ambigüedad:  Los  lenguajes  naturales  están  llenos  de  ambigüedad,  que  las  personas  manejan  usando  pistas  
contextuales  y  otra  información.  Los  lenguajes  formales  están  diseñados  para  ser  casi  o  completamente  
inequívocos,  lo  que  significa  que  cualquier  declaración  tiene  exactamente  un  significado,  
independientemente  del  contexto.

redundancia:  para  compensar  la  ambigüedad  y  reducir  los  malentendidos,  los  lenguajes  naturales  emplean  
mucha  redundancia.  Como  resultado,  a  menudo  son  detallados.  Los  lenguajes  formales  son  menos  
redundantes  y  más  concisos.

literalidad:  Los  lenguajes  naturales  están  llenos  de  modismos  y  metáforas.  Si  digo,  “Se  cayó  el  centavo”,  
probablemente  no  haya  ningún  centavo  ni  nada  cayendo  (esta  expresión  significa  que  alguien  entendió  
algo  después  de  un  período  de  confusión).  Los  lenguajes  formales  significan  exactamente  lo  que  dicen.

Debido  a  que  todos  crecemos  hablando  idiomas  naturales,  a  veces  es  difícil  adaptarse  a  los  idiomas  formales.  
La  diferencia  entre  lenguaje  formal  y  natural  es  como  la  diferencia  entre  poesía  y  prosa,  pero  más:

Poesía:  Las  palabras  se  usan  tanto  por  sus  sonidos  como  por  su  significado,  y  todo  el  poema  en  conjunto  crea  
un  efecto  o  una  respuesta  emocional.  La  ambigüedad  no  solo  es  común,  sino  que  a  menudo  es  
deliberada.

Prosa:  El  significado  literal  de  las  palabras  es  más  importante,  y  la  estructura  aporta  más  significado.  La  prosa  
es  más  susceptible  de  análisis  que  la  poesía,  pero  sigue  siendo  a  menudo  ambigua.

Programas:  El  significado  de  un  programa  de  computadora  es  inequívoco  y  literal,  y  puede  ser
entendido  completamente  por  el  análisis  de  los  tokens  y  la  estructura.
Machine Translated by Google

6 Capítulo  1.  El  camino  del  programa

Los  lenguajes  formales  son  más  densos  que  los  lenguajes  naturales,  por  lo  que  lleva  más  tiempo  leerlos.
Además,  la  estructura  es  importante,  por  lo  que  no  siempre  es  mejor  leer  de  arriba  a  abajo,  de  izquierda  a  
derecha.  En  su  lugar,  aprenda  a  analizar  el  programa  en  su  cabeza,  identificando  las  fichas  e  interpretando  la  
estructura.  Finalmente,  los  detalles  importan.  Pequeños  errores  de  ortografía  y  puntuación,  que  puedes  evitar  en  
los  lenguajes  naturales,  pueden  marcar  una  gran  diferencia  en  un  lenguaje  formal.

1.7  Depuración
Los  programadores  cometen  errores.  Por  caprichosas  razones,  los  errores  de  programación  se  denominan  bugs  
y  el  proceso  de  rastrearlos  se  denomina  depuración.

La  programación,  y  especialmente  la  depuración,  a  veces  provoca  emociones  fuertes.  Si  está  luchando  con  un  
error  difícil,  puede  sentirse  enojado,  abatido  o  avergonzado.

Existe  evidencia  de  que  las  personas  responden  naturalmente  a  las  computadoras  como  si  fueran  personas.  
Cuando  funcionan  bien,  pensamos  en  ellos  como  compañeros  de  equipo,  y  cuando  son  obstinados  o  groseros,  
les  respondemos  de  la  misma  manera  que  respondemos  a  las  personas  groseras  y  obstinadas  (Reeves  y  Nass,  
The  Media  Equation:  How  People  Treat  Computers,  Television,  y  nuevos  medios  como  personas  y  lugares  reales).

Prepararse  para  estas  reacciones  podría  ayudarlo  a  lidiar  con  ellas.  Un  enfoque  es  pensar  en  la  computadora  
como  un  empleado  con  ciertas  fortalezas,  como  velocidad  y  precisión,  y  debilidades  particulares,  como  falta  de  
empatía  e  incapacidad  para  comprender  el  panorama  general.

Tu  trabajo  es  ser  un  buen  gerente:  encuentra  formas  de  aprovechar  las  fortalezas  y  mitigar  las  debilidades.  Y  
encuentre  formas  de  usar  sus  emociones  para  abordar  el  problema,  sin  dejar  que  sus  reacciones  interfieran  con  
su  capacidad  para  trabajar  de  manera  efectiva.

Aprender  a  depurar  puede  ser  frustrante,  pero  es  una  habilidad  valiosa  que  es  útil  para  muchas  actividades  más  
allá  de  la  programación.  Al  final  de  cada  capítulo  hay  una  sección,  como  esta,  con  mis  sugerencias  para  la  
depuración.  ¡Espero  que  ayuden!

1.8  Glosario
resolución  de  problemas:  El  proceso  de  formular  un  problema,  encontrar  una  solución  y  expresar
ing  eso.

lenguaje  de  alto  nivel:  Un  lenguaje  de  programación  como  Python  que  está  diseñado  para  ser  fácil  para
humanos  a  leer  y  escribir.

lenguaje  de  bajo  nivel:  un  lenguaje  de  programación  que  está  diseñado  para  que  una  computadora  pueda  
ejecutarlo  fácilmente;  también  llamado  “lenguaje  de  máquina”  o  “lenguaje  ensamblador”.

portabilidad:  Una  propiedad  de  un  programa  que  puede  ejecutarse  en  más  de  un  tipo  de  computadora.

Intérprete:  Un  programa  que  lee  otro  programa  y  lo  ejecuta.

indicador:  Caracteres  que  muestra  el  intérprete  para  indicar  que  está  listo  para  tomar  entrada
del  usuario

programa:  Un  conjunto  de  instrucciones  que  especifica  un  cálculo.
Machine Translated by Google

1.9.  Ejercicios 7

declaración  de  impresión:  una  instrucción  que  hace  que  el  intérprete  de  Python  muestre  un  valor  en
la  pantalla.

operador:  un  símbolo  especial  que  representa  un  cálculo  simple  como  la  suma,  la  multiplicación  o  la  concatenación  
de  cadenas.

valor:  una  de  las  unidades  básicas  de  datos,  como  un  número  o  una  cadena,  que  manipula  un  programa.

tipo:  Una  categoría  de  valores.  Los  tipos  que  hemos  visto  hasta  ahora  son  enteros  (tipo)  y  cadenas   ),  flotante
números  de  punto  (tipo (tipo).

entero:  Un  tipo  que  representa  números  enteros.

punto  flotante:  un  tipo  que  representa  números  con  partes  fraccionarias.

cadena:  un  tipo  que  representa  secuencias  de  caracteres.

lenguaje  natural:  Cualquiera  de  los  lenguajes  que  habla  la  gente  que  evolucionó  naturalmente.

lenguaje  formal:  Cualquiera  de  los  lenguajes  que  la  gente  ha  diseñado  para  propósitos  específicos,  como  representar  
ideas  matemáticas  o  programas  de  computadora;  todos  los  lenguajes  de  programación  son  lenguajes  formales.

token:  Uno  de  los  elementos  básicos  de  la  estructura  sintáctica  de  un  programa,  análogo  a  un
palabra  en  un  lenguaje  natural.

sintaxis:  Las  reglas  que  gobiernan  la  estructura  de  un  programa.

analizar:  Examinar  un  programa  y  analizar  la  estructura  sintáctica.

bug:  Un  error  en  un  programa.

depuración:  El  proceso  de  encontrar  y  corregir  errores.

1.9  Ejercicios

Ejercicio  1.1.  Es  una  buena  idea  leer  este  libro  frente  a  una  computadora  para  que  pueda  probar  los  ejemplos  a  medida  
que  avanza.

Cada  vez  que  esté  experimentando  con  una  nueva  función,  debe  intentar  cometer  errores.  Por  ejemplo,  en  el  mensaje  
"¡Hola,  mundo!"  programa,  ¿qué  sucede  si  omite  una  de  las  comillas?  ¿Qué  pasa  si  omites  ambos?  ¿Qué  pasa  si  
escribes  mal?

Este  tipo  de  experimento  te  ayuda  a  recordar  lo  que  lees;  también  ayuda  cuando  está  programando,  porque  llega  a  
saber  qué  significan  los  mensajes  de  error.  Es  mejor  cometer  errores  ahora  ya  propósito  que  después  y  sin  querer.

1.  En  una  declaración  de  impresión,  ¿qué  sucede  si  omite  uno  de  los  paréntesis  o  ambos?

2.  Si  está  tratando  de  imprimir  una  cadena,  ¿qué  sucede  si  omite  una  de  las  comillas?
¿o  ambos?

3.  ¿Puedes  usar  un  signo  menos  para  hacer  un  número  negativo  como   .  Que  pasa  si  pones  un  plus
un  signo  antes  de  un  número?  Qué  pasa ?
Machine Translated by Google

8 Capítulo  1.  El  camino  del  programa

4.  En  notación  matemática,  los  ceros  iniciales  están  bien,  como  en .  ¿Qué  sucede  si  intentas  esto  en  Python?
Qué  pasa ?

5.  ¿Qué  pasa  si  tienes  dos  valores  sin  operador  entre  ellos?

Ejercicio  1.2.  Inicie  el  intérprete  de  Python  y  utilícelo  como  calculadora.

1.  ¿Cuántos  segundos  hay  en  42  minutos  42  segundos?

2.  ¿Cuántas  millas  hay  en  10  kilómetros?  Pista:  hay  1,61  kilómetros  en  una  milla.

3.  Si  corres  una  carrera  de  10  kilómetros  en  42  minutos  y  42  segundos,  ¿cuál  es  tu  ritmo  promedio  (tiempo  
por  milla  en  minutos  y  segundos)?  ¿Cuál  es  su  velocidad  promedio  en  millas  por  hora?
Machine Translated by Google

Capitulo  2

Variables,  expresiones  y
declaraciones

Una  de  las  características  más  poderosas  de  un  lenguaje  de  programación  es  la  capacidad  de  manipular  
variables.  Una  variable  es  un  nombre  que  hace  referencia  a  un  valor.

2.1  Declaraciones  de  cesión
Una  declaración  de  asignación  crea  una  nueva  variable  y  le  da  un  valor:

Este  ejemplo  hace  tres  asignaciones.  El  primero  asigna  una  cadena  a  una  nueva  variable  llamada ;  el  segundo  
da  el  entero  a ;  el  tercero  asigna  el  valor  (aproximado)  de
π  a .

Una  forma  común  de  representar  variables  en  papel  es  escribir  el  nombre  con  una  flecha  que  apunta  a  su  
valor.  Este  tipo  de  figura  se  llama  diagrama  de  estado  porque  muestra  en  qué  estado  se  encuentra  cada  una  
de  las  variables  (piense  en  ello  como  el  estado  mental  de  la  variable).  La  figura  2.1  muestra  el  resultado  del  
ejemplo  anterior.

2.2  Nombres  de  variables
Los  programadores  generalmente  eligen  nombres  significativos  para  sus  variables:  documentan  para  qué  se  
usa  la  variable.

mensaje 'Y  ahora  para  algo  completamente  diferente'
norte 17

Pi 3.1415926535897932

Figura  2.1:  Diagrama  de  estado.
Machine Translated by Google

10 Capítulo  2.  Variables,  expresiones  y  sentencias

Los  nombres  de  las  variables  pueden  ser  tan  largos  como  desee.  Pueden  contener  tanto  letras  como  
números,  pero  no  pueden  comenzar  con  un  número.  Es  legal  usar  letras  mayúsculas,  pero  es  convencional  
usar  solo  minúsculas  para  nombres  de  variables.

El  carácter  de  subrayado, ,  puede  aparecer  en  un  nombre.  A  menudo  se  usa  en  nombres  con  varias  palabras,  
como o .

Si  le  da  a  una  variable  un  nombre  ilegal,  obtendrá  un  error  de  sintaxis:

es  ilegal  porque  comienza  con  un  número.  un   es  ilegal  porque  contiene
carácter  ilegal, .  Pero  que  tiene  de  malo ?

Resulta  que  es  una  de  las  palabras  clave  de  Python.  El  intérprete  usa  palabras  clave  para  reconocer  la  
estructura  del  programa  y  no  se  pueden  usar  como  nombres  de  variables.

Python  3  tiene  estas  palabras  clave:

No  tienes  que  memorizar  esta  lista.  En  la  mayoría  de  los  entornos  de  desarrollo,  las  palabras  clave  se  
muestran  en  un  color  diferente;  si  intenta  usar  uno  como  nombre  de  variable,  lo  sabrá.

2.3  Expresiones  y  declaraciones
Una  expresión  es  una  combinación  de  valores,  variables  y  operadores.  Un  valor  en  sí  mismo  se  considera  
una  expresión,  al  igual  que  una  variable,  por  lo  que  las  siguientes  son  todas  expresiones  legales:

Cuando  escribe  una  expresión  en  el  indicador,  el  intérprete  la  evalúa ,  lo  que  significa  que  encuentra  el  valor  
de  la  expresión.  En  este  ejemplo,  tiene  el  valor  17  y  tiene  el  valor  42.

Una  declaración  es  una  unidad  de  código  que  tiene  un  efecto,  como  crear  una  variable  o  mostrar  un  valor.
Machine Translated by Google

2.4.  Modo  de  secuencia  de  comandos
11

La  primera  línea  es  una  declaración  de  asignación  que  da  un  valor  a .  La  segunda  línea  es  una  declaración  
de  impresión  que  muestra  el  valor  de .

Cuando  escribe  una  declaración,  el  intérprete  la  ejecuta ,  lo  que  significa  que  hace  lo  que  dice  la  
declaración.  En  general,  las  declaraciones  no  tienen  valores.

2.4  Modo  de  guión
Hasta  ahora  hemos  ejecutado  Python  en  modo  interactivo,  lo  que  significa  que  interactúas  directamente  
con  el  intérprete.  El  modo  interactivo  es  una  buena  manera  de  comenzar,  pero  si  trabaja  con  más  de  unas  
pocas  líneas  de  código,  puede  resultar  complicado.

La  alternativa  es  guardar  el  código  en  un  archivo  llamado  secuencia  de  comandos  y  luego  ejecutar  el  intérprete  en  modo  secuencia  
de  comandos  para  ejecutar  la  secuencia  de  comandos.  Por  convención,  los  scripts  de  Python  tienen  nombres  que  terminan  con .

Si  sabe  cómo  crear  y  ejecutar  un  script  en  su  computadora,  está  listo  para  comenzar.  De  lo  contrario,  
recomiendo  usar  PythonAnywhere  nuevamente.  He  publicado  instrucciones  para  ejecutar  en  modo  script  
en .

Debido  a  que  Python  proporciona  ambos  modos,  puede  probar  fragmentos  de  código  en  modo  interactivo  
antes  de  colocarlos  en  un  script.  Pero  existen  diferencias  entre  el  modo  interactivo  y  el  modo  script  que  
pueden  resultar  confusos.

Por  ejemplo,  si  está  utilizando  Python  como  calculadora,  puede  escribir

,
La  primera  línea  asigna  un  valor  a  pero  no  tiene   ningún  efecto  visible.  La  segunda  línea  es  una  expresión,  
por  lo  que  el  intérprete  la  evalúa  y  muestra  el  resultado.  Resulta  que  un  maratón  son  unos  42  kilómetros.

Pero  si  escribe  el  mismo  código  en  un  script  y  lo  ejecuta,  no  obtiene  ningún  resultado.  En  modo  script,  una  
expresión,  por  sí  misma,  no  tiene  ningún  efecto  visible.  Python  evalúa  la  expresión,  pero  no  muestra  el  
resultado.  Para  mostrar  el  resultado,  necesita  una  declaración  como  esta:

Este  comportamiento  puede  ser  confuso  al  principio.  Para  verificar  su  comprensión,  escriba  las  siguientes  
declaraciones  en  el  intérprete  de  Python  y  vea  lo  que  hacen:

Ahora  ponga  las  mismas  declaraciones  en  un  script  y  ejecútelo.  ¿Cuál  es  la  salida?  Modifique  el  script  
transformando  cada  expresión  en  una  declaración  de  impresión  y  luego  ejecútelo  nuevamente.

2.5  Orden  de  las  operaciones
Cuando  una  expresión  contiene  más  de  un  operador,  el  orden  de  evaluación  depende  del  orden  de  las  
operaciones.  Para  los  operadores  matemáticos,  Python  sigue  la  convención  matemática.  El  acrónimo  
PEMDAS  es  una  forma  útil  de  recordar  las  reglas:
Machine Translated by Google

12 Capítulo  2.  Variables,  expresiones  y  sentencias

•  Los  paréntesis  tienen  la  prioridad  más  alta  y  se  pueden  usar  para  forzar  que  una  expresión  se  
evalúe  en  el  orden  que  desee.  Dado  que  las  expresiones  entre  paréntesis  se  evalúan  primero,  
es  4  y  es  8.  También  puede  usar  paréntesis  para  hacer  que  una  expresión  sea  
más  fácil  de  leer,  incluso  si  no  cambia  el  resultado. ,

•  La  exponenciación  tiene  la  siguiente  prioridad  más  alta,  por  lo   es  9,  no  27,  y
que  es  18,  no  36.

•  La  multiplicación  y  la  división  tienen  mayor  prioridad  que  la  suma  y  la  resta.  es  5,  no  4,  y  es  8,  
Entonces
no  5.

•  Los  operadores  con  la  misma  precedencia  se  evalúan  de  izquierda  a  derecha  (excepto  
exponenciación).  Entonces,  en  la  expresión,  la  división  ,ocurre  primero  y  el  resultado  se  
multiplica  por .  Para  dividir  por  2π,  puedes  usar  paréntesis  o  escribir
.

No  trabajo  muy  duro  para  recordar  la  precedencia  de  los  operadores.  Si  no  puedo  decirlo  mirando  la  
expresión,  uso  paréntesis  para  que  sea  obvio.

2.6  Operaciones  con  cadenas

En  general,  no  puede  realizar  operaciones  matemáticas  en  cadenas,  incluso  si  las  cadenas  parecen  
números,  por  lo  que  las  siguientes  son  ilegales:

Pero  hay  dos  excepciones,  y .

El  operador  realiza  la  concatenación  de  cadenas,  lo  que  significa  que  une  las  cadenas  al  vincularlas  
de  extremo  a  extremo.  Por  ejemplo:

El  operador  también  trabaja  en  cadenas;  realiza  la  repetición.  Por  ejemplo,  si  uno  de   es
. los  valores  es  una  cadena,  el  otro  debe  ser  un  número  entero.

Este  uso  de  y  tiene  sentido  por  analogía  con  la  suma  y  la  multiplicación.  Así  como  equivale  a  ser  
lo  mismo  que  y  es.  Por  o,tro  
esperamos ,
lado,  hay  una  forma  significativa  en  la  que  la  concatenación  y  repetición  
de  cadenas  son  diferentes  de  la  suma  y  multiplicación  de  enteros.  ¿Puedes  pensar  en  una  propiedad  
que  tenga  la  suma  y  que  no  tenga  la  concatenación  de  cadenas?

2.7  Comentarios

A  medida  que  los  programas  se  hacen  más  grandes  y  complicados,  se  vuelven  más  difíciles  de  leer.  Los  
lenguajes  formales  son  densos  y,  a  menudo,  es  difícil  mirar  un  fragmento  de  código  y  descubrir  qué  está  
haciendo  o  por  qué.
Machine Translated by Google

2.8.  depuración 13

Por  esta  razón,  es  una  buena  idea  agregar  notas  a  sus  programas  para  explicar  en  lenguaje  natural  lo  que  está  
haciendo  el  programa.  Estas  notas  se  denominan  comentarios  y  comienzan  con  el  símbolo:

En  este  caso,  el  comentario  aparece  solo  en  una  línea.  También  puede  poner  comentarios  al  final  de  una  línea:

Se  ignora  todo,  desde  el  hasta  el  final  de  la  línea;  no  tiene  ningún  efecto  en  la  ejecución  del  programa.

Los  comentarios  son  más  útiles  cuando  documentan  características  no  obvias  del  código.  Es  razonable  suponer  
que  el  lector  puede  averiguar  qué  hace  el  código;  es  más  útil  explicar  por  qué.

Este  comentario  es  redundante  con  el  código  e  inútil:

Este  comentario  contiene  información  útil  que  no  está  en  el  código:

Los  buenos  nombres  de  variables  pueden  reducir  la  necesidad  de  comentarios,  pero  los  nombres  largos  pueden  dificultar  la  
lectura  de  expresiones  complejas,  por  lo  que  existe  una  compensación.

2.8  Depuración
Pueden  ocurrir  tres  tipos  de  errores  en  un  programa:  errores  de  sintaxis,  errores  de  tiempo  de  ejecución  y  errores  
semánticos.  Es  útil  distinguirlos  para  localizarlos  más  rápidamente.

Error  de  sintaxis:  “Sintaxis”  se  refiere  a  la  estructura  de  un  programa  y  las  reglas  sobre  esa  estructura.  Por  ejemplo,  
los  paréntesis  deben  venir  en  pares  coincidentes,  por  lo  que  es  legal,  pero  es  un  error  de  sintaxis.

Si  hay  un  error  de  sintaxis  en  cualquier  parte  de  su  programa,  Python  muestra  un  mensaje  de  error  y  se  
cierra,  y  no  podrá  ejecutar  el  programa.  Durante  las  primeras  semanas  de  su  carrera  como  programador,  
puede  pasar  mucho  tiempo  rastreando  errores  de  sintaxis.  A  medida  que  gane  experiencia,  cometerá  menos  
errores  y  los  encontrará  más  rápido.

Error  de  tiempo  de  ejecución:  el  segundo  tipo  de  error  es  un  error  de  tiempo  de  ejecución,  llamado  así  porque  el  
error  no  aparece  hasta  que  el  programa  ha  comenzado  a  ejecutarse.  Estos  errores  también  se  denominan  
excepciones  porque  suelen  indicar  que  ha  ocurrido  algo  excepcional  (y  malo).

Los  errores  de  tiempo  de  ejecución  son  raros  en  los  programas  simples  que  verá  en  los  primeros  capítulos,  
por  lo  que  puede  pasar  un  tiempo  antes  de  que  encuentre  uno.

Error  semántico:  el  tercer  tipo  de  error  es  el  “semántico”,  que  significa  relacionado  con  el  significado.
Si  hay  un  error  semántico  en  su  programa,  se  ejecutará  sin  generar  mensajes  de  error,  pero  no  hará  lo  
correcto.  Hará  otra  cosa.  Específicamente,  hará  lo  que  le  dijiste  que  hiciera.

Identificar  errores  semánticos  puede  ser  complicado  porque  requiere  que  trabajes  hacia  atrás  mirando  la  
salida  del  programa  y  tratando  de  averiguar  qué  está  haciendo.
Machine Translated by Google

14 Capítulo  2.  Variables,  expresiones  y  sentencias

2.9  Glosario
variable:  Un  nombre  que  se  refiere  a  un  valor.

asignación:  Una  declaración  que  asigna  un  valor  a  una  variable.

diagrama  de  estado:  Una  representación  gráfica  de  un  conjunto  de  variables  y  los  valores  a  los  que  se  refieren.

palabra  clave:  una  palabra  reservada  que  se  utiliza  para  analizar  un  programa;  no  puedes  usar  palabras  clave  como
, ,y como  nombres  de  variables.

operando:  Uno  de  los  valores  sobre  los  que  opera  un  operador.

expresión:  Una  combinación  de  variables,  operadores  y  valores  que  representa  una  sola  re
resultado

evaluar:  Simplificar  una  expresión  realizando  las  operaciones  para  producir  una  sola
valor.

declaración:  Una  sección  de  código  que  representa  un  comando  o  acción.  Hasta  ahora,  las  sentencias  
que  hemos  visto  son  asignaciones  y  sentencias  de  impresión.

ejecutar:  para  ejecutar  una  declaración  y  hacer  lo  que  dice.

modo  interactivo:  una  forma  de  usar  el  intérprete  de  Python  escribiendo  código  en  el  aviso.

modo  script:  una  forma  de  usar  el  intérprete  de  Python  para  leer  el  código  de  un  script  y  ejecutarlo.

script:  Un  programa  almacenado  en  un  archivo.

orden  de  operaciones:  Reglas  que  rigen  el  orden  en  que  se  evalúan  las  expresiones  que  involucran  
múltiples  operadores  y  operandos.

concatenar:  unir  dos  operandos  de  extremo  a  extremo.

comentario:  Información  en  un  programa  que  está  destinada  a  otros  programadores  (o  cualquiera  que  
lea  el  código  fuente)  y  no  tiene  efecto  en  la  ejecución  del  programa.

error  de  sintaxis:  Un  error  en  un  programa  que  hace  que  sea  imposible  de  analizar  (y  por  lo  tanto  im  
posible  de  interpretar).

excepción:  un  error  que  se  detecta  mientras  se  ejecuta  el  programa.

semántica:  El  significado  de  un  programa.

error  semántico:  un  error  en  un  programa  que  hace  que  haga  algo  diferente  de  lo  que  pretendía  el  
programador.

2.10  Ejercicios

Ejercicio  2.1.  Repitiendo  mi  consejo  del  capítulo  anterior,  cada  vez  que  aprenda  una  nueva  función,  debe  
probarla  en  modo  interactivo  y  cometer  errores  a  propósito  para  ver  qué  sale  mal.

•  Hemos  visto  que es  legal.  Qué  pasa ?
Machine Translated by Google

2.10.  Ejercicios 15

•  Qué  tal  si ?

•  En  algunos  idiomas,  cada  declaración  termina  con  un  punto  y  coma, .  ¿Qué  sucede  si  coloca  un  punto  y  coma  
al  final  de  una  declaración  de  Python?

•  ¿Qué  sucede  si  pone  un  punto  al  final  de  una  declaración?

•  En  notación  matemática  puedes  multiplicar  x  e  y  así:  xy.  ¿Qué  pasa  si  intentas  eso  en
¿Pitón?

Ejercicio  2.2.  Practique  usando  el  intérprete  de  Python  como  calculadora:

4  3  πr  
1.  El  volumen  de  una  esfera  de  radio  r  es 3 .  ¿Cuál  es  el  volumen  de  una  esfera  de  radio  5?

2.  Supón  que  el  precio  de  tapa  de  un  libro  es  $24.95,  pero  las  librerías  obtienen  un  40%  de  descuento.  El  envío  
cuesta  $3  por  la  primera  copia  y  75  centavos  por  cada  copia  adicional.  ¿Cuál  es  el  costo  total  al  por  mayor  
de  60  copias?

3.  Si  salgo  de  mi  casa  a  las  6:52  a.  m.  y  corro  1  milla  a  un  ritmo  suave  (8:15  por  milla),  luego  3  millas  a  un  ritmo  
lento  (7:12  por  milla)  y  1  milla  a  un  ritmo  suave  de  nuevo,  ¿a  qué  hora?  llego  a  casa  a  desayunar?
Machine Translated by Google

dieciséis
Capítulo  2.  Variables,  expresiones  y  sentencias
Machine Translated by Google

Capítulo  3

Funciones

En  el  contexto  de  la  programación,  una  función  es  una  secuencia  con  nombre  de  declaraciones  
que  realiza  un  cálculo.  Cuando  define  una  función,  especifica  el  nombre  y  la  secuencia  de  
declaraciones.  Más  tarde,  puede  "llamar"  a  la  función  por  su  nombre.

3.1  Llamadas  de  función

Ya  hemos  visto  un  ejemplo  de  una  llamada  de  función:

El  nombre  de  la  función  es .  La  expresión  entre  paréntesis  se  llama  argumento  de  la  función.  El  
resultado,  para  esta  función,  es  el  tipo  del  argumento.

Es  común  decir  que  una  función  “toma”  un  argumento  y  “devuelve”  un  resultado.  El  resultado  
también  se  denomina  valor  de  retorno.

Python  proporciona  funciones  que  convierten  valores  de  un  tipo  a  otro.  La  función  toma  cualquier  
valor  y  lo  convierte  en  un  número  entero,  si  puede,  o  se  queja  de  lo  contrario:

puede  convertir  valores  de  coma  flotante  en  enteros,  pero  no  redondea;  corta  la  parte  
fraccionaria:

convierte  enteros  y  cadenas  a  números  de  punto  flotante:
Machine Translated by Google

18 Capítulo  3.  Funciones

Finalmente, convierte  su  argumento  en  una  cadena:

3.2  Funciones  matemáticas

Python  tiene  un  módulo  matemático  que  proporciona  la  mayoría  de  las  funciones  matemáticas  familiares.  Un  
módulo  es  un  archivo  que  contiene  una  colección  de  funciones  relacionadas.

Antes  de  que  podamos  usar  las  funciones  en  un  módulo,  debemos  importarlo  con  un  estado  de  importación
mento:

Esta  declaración  crea  un  objeto  de  módulo  llamado  matemáticas.  Si  muestra  el  objeto  del  módulo,  obtendrá  
información  al  respecto:

El  objeto  del  módulo  contiene  las  funciones  y  variables  definidas  en  el  módulo.  Para  acceder  a  una  de  las  
funciones,  debe  especificar  el  nombre  del  módulo  y  el  nombre  de  la  función,  separados  por  un  punto  (también  
conocido  como  punto).  Este  formato  se  llama  notación  de  puntos.

El  primer  ejemplo  usa  that   para  calcular  una  relación  señal­ruido  en  decibelios  (suponiendo  que  
y  which  calcula  la  base  de   estén  definidos).  El  módulo  de  matemáticas  también  proporciona ,
logaritmos.

El  segundo  ejemplo  encuentra  el  seno  de .  El  nombre  de  la  variable  es  una  pista  de  que  las  
otras  funciones  trigonométricas  (, ,  etc.)  toman  argumentos  en  radianes.  A
convertir  de  grados  a  radianes,  dividir  por  180  y  multiplicar  por  π:

La  expresión  obtiene  la  variable  del  módulo  matemático.  Su  valor  es  una  aproximación  de  coma  flotante  de  
π,  con  una  precisión  de  unos  15  dígitos.

Si  sabes  trigonometría,  puedes  comprobar  el  resultado  anterior  comparándolo  con  la  raíz  cuadrada  de  dos,  
dividida  por  dos:
Machine Translated by Google

3.3.  Composición 19

3.3  Composición
Hasta  ahora,  hemos  visto  los  elementos  de  un  programa  (variables,  expresiones  y  sentencias)  de  forma  aislada,  sin  
hablar  de  cómo  combinarlos.

Una  de  las  características  más  útiles  de  los  lenguajes  de  programación  es  su  capacidad  para  tomar  pequeños  
bloques  de  construcción  y  componerlos .  Por  ejemplo,  el  argumento  de  una  función  puede  ser  cualquier  tipo  de  
expresión,  incluidos  los  operadores  aritméticos:

E  incluso  llamadas  a  funciones:

Casi  en  cualquier  lugar  donde  pueda  poner  un  valor,  puede  poner  una  expresión  arbitraria,  con  una  excepción:  el  
lado  izquierdo  de  una  declaración  de  asignación  tiene  que  ser  un  nombre  de  variable.  Cualquier  otra  expresión  en  
el  lado  izquierdo  es  un  error  de  sintaxis  (veremos  excepciones  a  esta  regla  más  adelante).

3.4  Agregar  nuevas  funciones
Hasta  ahora,  solo  hemos  estado  usando  las  funciones  que  vienen  con  Python,  pero  también  es  posible  agregar  
nuevas  funciones.  Una  definición  de  función  especifica  el  nombre  de  una  nueva  función  y  la  secuencia  de  
instrucciones  que  se  ejecutan  cuando  se  llama  a  la  función.

Aquí  hay  un  ejemplo:

es  una  palabra  clave  que  indica  que  se  trata  de  una  definición  de  función.  El  nombre  de  la  función  es .  Las  
reglas  para  los  nombres  de  funciones  son  las  mismas  que  para  los  nombres  de  variables:  letras,  números  y  guiones  
bajos  son  válidos,  pero  el  primer  carácter  no  puede  ser  un  número.  No  puede  usar  una  palabra  clave  como  nombre  
de  una  función  y  debe  evitar  tener  una  variable  y  una  función  con  el  mismo  nombre.

Los  paréntesis  vacíos  después  del  nombre  indican  que  esta  función  no  acepta  ningún  argumento.
mentos.

La  primera  línea  de  la  definición  de  la  función  se  llama  encabezado;  el  resto  se  llama  el  cuerpo.  El  encabezado  debe  
terminar  con  dos  puntos  y  el  cuerpo  debe  estar  sangrado.  Por  convención,  la  sangría  es  siempre  de  cuatro  espacios.  
El  cuerpo  puede  contener  cualquier  número  de  sentencias.

Las  cadenas  en  las  sentencias  de  impresión  están  encerradas  entre  comillas  dobles.  Las  comillas  simples  y  las  
comillas  dobles  hacen  lo  mismo;  la  mayoría  de  la  gente  usa  comillas  simples,  excepto  en  casos  como  este,  donde  
aparece  una  comilla  simple  (que  también  es  un  apóstrofo)  en  la  cadena.

Todas  las  comillas  (simples  y  dobles)  deben  ser  "comillas  rectas",  generalmente  ubicadas  junto  a  Enter  en  el  teclado.  
Las  “comillas  rizadas”,  como  las  de  esta  oración,  no  son  legales  en  Python.

Si  escribe  una  definición  de  función  en  modo  interactivo,  el  intérprete  imprime  puntos  ()  para  informarle  que  la  
definición  no  está  completa:
Machine Translated by Google

20 Capítulo  3.  Funciones

Para  finalizar  la  función,  debe  ingresar  una  línea  vacía.

La  definición  de  una  función  crea  un  objeto  de  función,  que  tiene  tipo :

La  sintaxis  para  llamar  a  la  nueva  función  es  la  misma  que  para  las  funciones  integradas:

Una  vez  que  haya  definido  una  función,  puede  usarla  dentro  de  otra  función.  Por  ejemplo,  para  repetir  el  
estribillo  anterior,  podríamos  escribir  una  función  llamada :

y  luego  llamar :

Pero  así  no  es  realmente  como  va  la  canción.

3.5  Definiciones  y  usos

Reuniendo  los  fragmentos  de  código  de  la  sección  anterior,  todo  el  programa  se  ve  así:

Este  programa  contiene  dos  definiciones  de  función:  y  las  definiciones  de  ción   .  Función

se  ejecutan  como  otras  declaraciones,  pero  el  efecto  es  crear  objetos  de  función.  Las  instrucciones  dentro  
de  la  función  no  se  ejecutan  hasta  que  se  llama  a  la  función  y  la  definición  de  la  función  no  genera  ningún  
resultado.
Machine Translated by Google

3.6.  Flujo  de  ejecución 21

Como  es  de  esperar,  debe  crear  una  función  antes  de  poder  ejecutarla.  En  otras  palabras,  la  definición  de  
la  función  debe  ejecutarse  antes  de  que  se  llame  a  la  función.

Como  ejercicio,  mueva  la  última  línea  de  este  programa  hacia  arriba,  para  que  la  llamada  a  la  función  
aparezca  antes  de  las  definiciones.  Ejecute  el  programa  y  vea  qué  mensaje  de  error  recibe.

Ahora  mueva  la  llamada  de  función  al  final  y  mueva  la  definición  de  después  de  la  
definición  de .  ¿Qué  sucede  cuando  ejecutas  este  programa?

3.6  Flujo  de  ejecución

Para  asegurarse  de  que  una  función  se  define  antes  de  su  primer  uso,  debe  conocer  el  orden  en  que  se  
ejecutan  las  sentencias,  lo  que  se  denomina  flujo  de  ejecución.

La  ejecución  siempre  comienza  en  la  primera  instrucción  del  programa.  Las  declaraciones  se  ejecutan  una  
a  la  vez,  en  orden  de  arriba  a  abajo.

Las  definiciones  de  función  no  alteran  el  flujo  de  ejecución  del  programa,  pero  recuerde  que  las  
declaraciones  dentro  de  la  función  no  se  ejecutan  hasta  que  se  llama  a  la  función.

Una  llamada  de  función  es  como  un  desvío  en  el  flujo  de  ejecución.  En  lugar  de  ir  a  la  siguiente  declaración,  
el  flujo  salta  al  cuerpo  de  la  función,  ejecuta  las  declaraciones  allí  y  luego  regresa  para  continuar  donde  lo  
dejó.

Eso  suena  bastante  simple,  hasta  que  recuerdas  que  una  función  puede  llamar  a  otra.  Mientras  se  
encuentra  en  medio  de  una  función,  es  posible  que  el  programa  deba  ejecutar  las  declaraciones  en  otra  
función.  Luego,  mientras  ejecuta  esa  nueva  función,  ¡el  programa  podría  tener  que  ejecutar  otra  función!

Afortunadamente,  Python  es  bueno  para  hacer  un  seguimiento  de  dónde  está,  por  lo  que  cada  vez  que  se  
completa  una  función,  el  programa  continúa  donde  se  quedó  en  la  función  que  la  llamó.  Cuando  llega  al  
final  del  programa,  termina.

En  resumen,  cuando  lees  un  programa,  no  siempre  quieres  leer  de  arriba  a  abajo.
A  veces  tiene  más  sentido  si  sigues  el  flujo  de  ejecución.

3.7  Parámetros  y  argumentos
Algunas  de  las  funciones  que  hemos  visto  requieren  argumentos.  Por  ejemplo,  cuando  llamas  pasas  un  
número  como  argumento.  Algunas  funciones  toman  más  de  uno  o  toman  dos,  la  base  y  el  
cemento: exponente.

Dentro  de  la  función,  los  argumentos  se  asignan  a  variables  llamadas  parámetros.  Aquí  hay  una  definición  
para  una  función  que  toma  un  argumento:

Esta  función  asigna  el  argumento  a  un  parámetro  llamado  llamado,   .  Cuando  la  función  es
imprime  el  valor  del  parámetro  (sea  cual  sea)  dos  veces.

Esta  función  funciona  con  cualquier  valor  que  se  pueda  imprimir.
Machine Translated by Google

22 Capítulo  3.  Funciones

Las  mismas  reglas  de  composición  que  se  aplican  a  las  funciones  integradas  también  se  aplican  a  las  funciones  
definidas  por  el  programador,  por  lo  que  podemos  usar  cualquier  tipo  de  expresión  como  argumento  para :

El  argumento  se  evalúa  antes  de  llamar  a  la  función,  por  lo  que  en  los  ejemplos  las  expresiones
y solo  se  evalúan  una  vez.

También  puede  usar  una  variable  como  argumento:

El  nombre  de  la  variable  que  pasamos  como  argumento  ()  no  tiene  nada  que  ver  con  el  nombre  del  
parámetro  ().  No  importa  cuál  fue  el  valor  llamado  en  casa  (en  la  persona  que  llama);  aquí  en  llamamos  
a  todos , .

3.8  Las  variables  y  los  parámetros  son  locales
Cuando  crea  una  variable  dentro  de  una  función,  es  local,  lo  que  significa  que  solo  existe  dentro  de  la  
función.  Por  ejemplo:

Esta  función  toma  dos  argumentos,  los  concatena  e  imprime  el  resultado  dos  veces.  Aquí  hay  un  
ejemplo  que  lo  usa:

Cuando   termina,  la  variable Esta  destruido.  Si  tratamos  de  imprimirlo,  obtenemos  un


excepción:
Machine Translated by Google

3.9.  diagramas  de  pila 23

línea  1 'Bing  tiddle'  'tiddle  
__principal__
línea  2 bang'.

parte  1 'Bing  tiddle'

gato_dos  veces parte  2 'tiddle  bang'.  'Bing  

gato tiddle  tiddle  bang'.

imprimir_dos  veces bruce 'Bing  tiddle  tiddle  bang'.

Figura  3.1:  Diagrama  de  pila.

Los  parámetros  también  son  locales.  Por  ejemplo,  fuera , no  hay  tal  cosa  como
.

3.9  Diagramas  de  pila
Para  realizar  un  seguimiento  de  qué  variables  se  pueden  usar  en  qué  lugar,  a  veces  es  útil  dibujar  un  diagrama  
de  pila.  Al  igual  que  los  diagramas  de  estado,  los  diagramas  de  pila  muestran  el  valor  de  cada  variable,  pero  
también  muestran  la  función  a  la  que  pertenece  cada  variable.

Cada  función  está  representada  por  un  marco.  Un  marco  es  un  cuadro  con  el  nombre  de  una  función  
al  lado  y  los  parámetros  y  variables  de  la  función  dentro.  El  diagrama  de  pila  para  el  ejemplo  anterior  
se  muestra  en  la  Figura  3.1.

Los  marcos  se  organizan  en  una  pila  que  indica  qué  función  llamó  a  cuál,  y  así  sucesivamente.  
,
En  este  ejemplo,  fue  llamado  por  y  fue  llamado  por,  que  es  un  nombre  
especial  para  el  marco  
,
superior.  Cuando   crea  una  variable  fuera  de  cualquier  función,  pertenece  a
.

Cada  parámetro  hace  referencia  al  mismo  valor  que  su  argumento  correspondiente.   tiene  el  
Entonces,  el  mismo  valor  
,que  tiene  el  mismo  valor  que  y , mismo  valor  que
.

Si  ocurre  un  error  durante  una  llamada  de  función,  Python  imprime  el  nombre  de  la  función,  el  
nombre  de  la  función  que  la  llamó  y  el  nombre  de  la  función  que  la  llamó,  todo  el  camino  de  
vuelta  a .

Por  ejemplo,  si  intenta  acceder  desde  dentro ,  obtienes  un :
Machine Translated by Google

24 Capítulo  3.  Funciones

Esta  lista  de  funciones  se  denomina  rastreo.  Le  dice  en  qué  archivo  de  programa  ocurrió  el  error,  en  qué  línea  y  
qué  funciones  se  estaban  ejecutando  en  ese  momento.  También  muestra  la  línea  de  código  que  provocó  el  error.

El  orden  de  las  funciones  en  el  rastreo  es  el  mismo  que  el  orden  de  los  marcos  en  el  diagrama  de  pila.  La  función  
que  se  está  ejecutando  actualmente  se  encuentra  en  la  parte  inferior.

3.10  Funciones  fructíferas  y  funciones  nulas

Algunas  de  las  funciones  que  hemos  utilizado,  como  las  funciones  matemáticas,  devuelven  resultados;  a  falta  de  
mejor  nombre,  las  llamo  funciones  fecundas.  Otras  funciones,  como ,  realizan  una  acción  pero  no  devuelven  un  
valor.  Se  llaman  funciones  nulas.

Cuando  llamas  a  una  función  fructífera,  casi  siempre  quieres  hacer  algo  con  el  resultado;  por  ejemplo,  puede  
asignarlo  a  una  variable  o  usarlo  como  parte  de  una  expresión:

Cuando  llama  a  una  función  en  modo  interactivo,  Python  muestra  el  resultado:

Pero  en  un  script,  si  llama  a  una  función  fructífera  por  sí  misma,  ¡el  valor  de  retorno  se  pierde  para  siempre!

Este  script  calcula  la  raíz  cuadrada  de  5,  pero  como  no  almacena  ni  muestra  el  resultado,  no  es  muy  útil.

Las  funciones  de  anulación  pueden  mostrar  algo  en  la  pantalla  o  tener  algún  otro  efecto,  pero  no  tienen  un  valor  de  
retorno.  Si  asigna  el  resultado  a  una  variable,  obtiene  un  valor  especial  llamado
.

El  tipo  de   no  es  lo  mismo  que  la  cadena .  Es  un  valor  especial  que  tiene  su  propio


valor:

Las  funciones  que  hemos  escrito  hasta  ahora  son  todas  nulas.  Comenzaremos  a  escribir  funciones  fructíferas  en  
unos  pocos  capítulos.

3.11  ¿Por  qué  funciones?

Puede  que  no  esté  claro  por  qué  vale  la  pena  dividir  un  programa  en  funciones.  Hay  varias  razones:
Machine Translated by Google

3.12.  depuración 25

•  La  creación  de  una  nueva  función  le  brinda  la  oportunidad  de  nombrar  un  grupo  de  declaraciones,  lo  
que  hace  que  su  programa  sea  más  fácil  de  leer  y  depurar.

•  Las  funciones  pueden  hacer  que  un  programa  sea  más  pequeño  al  eliminar  el  código  repetitivo.  
Posteriormente,  si  realiza  un  cambio,  solo  tiene  que  hacerlo  en  un  lugar.

•  Dividir  un  programa  largo  en  funciones  le  permite  depurar  las  partes  una  a  la  vez
y  luego  ensamblarlos  en  un  todo  funcional.

•  Las  funciones  bien  diseñadas  suelen  ser  útiles  para  muchos  programas.  Una  vez  que  escribe  y  depura  
uno,  puede  reutilizarlo.

3.12  Depuración
Una  de  las  habilidades  más  importantes  que  adquirirá  es  la  depuración.  Aunque  puede  ser  frustrante,  la  
depuración  es  una  de  las  partes  intelectualmente  más  ricas,  desafiantes  e  interesantes  de  la  programación.

En  cierto  modo,  la  depuración  es  como  un  trabajo  de  detective.  Te  enfrentas  a  pistas  y  tienes  que  inferir  los  
procesos  y  eventos  que  llevaron  a  los  resultados  que  ves.

La  depuración  también  es  como  una  ciencia  experimental.  Una  vez  que  tenga  una  idea  de  lo  que  va  mal,  
modifique  su  programa  y  vuelva  a  intentarlo.  Si  su  hipótesis  fue  correcta,  puede  predecir  el  resultado  de  la  
modificación  y  dar  un  paso  más  hacia  un  programa  que  funcione.  Si  su  hipótesis  fue  incorrecta,  debe  pensar  
en  una  nueva.  Como  señaló  Sherlock  Holmes:  “Cuando  has  eliminado  lo  imposible,  lo  que  quede,  por  
improbable  que  sea,  debe  ser  la  verdad”.  (A.  Conan  Doyle,  El  signo  de  los  cuatro)

Para  algunas  personas,  la  programación  y  la  depuración  son  lo  mismo.  Es  decir,  la  programación  es  el  
proceso  de  depuración  gradual  de  un  programa  hasta  que  hace  lo  que  quieres.  La  idea  es  que  debe  
comenzar  con  un  programa  que  funcione  y  hacer  pequeñas  modificaciones,  depurándolas  sobre  la  marcha.

Por  ejemplo,  Linux  es  un  sistema  operativo  que  contiene  millones  de  líneas  de  código,  pero  comenzó  como  
un  programa  simple  que  Linus  Torvalds  usó  para  explorar  el  chip  Intel  80386.  Según  Larry  Greenfield,  “Uno  
de  los  primeros  proyectos  de  Linus  fue  un  programa  que  cambiaría  entre  la  impresión  AAAA  y  BBBB.  Esto  
luego  evolucionó  a  Linux”.  (La  Guía  del  Usuario  de  Linux  Versión  Beta  1).

3.13  Glosario
función:  Una  secuencia  con  nombre  de  sentencias  que  realiza  alguna  operación  útil.  Las  funciones  pueden  
o  no  tomar  argumentos  y  pueden  o  no  producir  un  resultado.

definición  de  función:  una  declaración  que  crea  una  nueva  función,  especificando  su  nombre,  parámetros  y  
las  declaraciones  que  contiene.

objeto  de  función:  Un  valor  creado  por  una  definición  de  función.  El  nombre  de  la  función  es  una  variable  
que  hace  referencia  a  un  objeto  de  función.

encabezado:  La  primera  línea  de  una  definición  de  función.
Machine Translated by Google

26 Capítulo  3.  Funciones

cuerpo:  La  secuencia  de  sentencias  dentro  de  una  definición  de  función.

parámetro:  Un  nombre  usado  dentro  de  una  función  para  referirse  al  valor  pasado  como  argumento.

Llamada  de  función:  una  instrucción  que  ejecuta  una  función.  Consiste  en  el  nombre  de  la  función  seguido  de  una  
lista  de  argumentos  entre  paréntesis.

argumento:  un  valor  proporcionado  a  una  función  cuando  se  llama  a  la  función.  Este  valor  es  como
firmado  al  parámetro  correspondiente  en  la  función.

variable  local:  Una  variable  definida  dentro  de  una  función.  Una  variable  local  sólo  se  puede  utilizar
dentro  de  su  función.

valor  de  retorno:  El  resultado  de  una  función.  Si  se  utiliza  una  llamada  de  función  como  expresión,  el  valor  devuelto  
es  el  valor  de  la  expresión.

función  fructífera:  una  función  que  devuelve  un  valor.

función  nula:  una  función  que  siempre  devuelve .

:  Un  valor  especial  devuelto  por  funciones  nulas.

módulo:  Un  archivo  que  contiene  una  colección  de  funciones  relacionadas  y  otras  definiciones.

declaración  de  importación:  una  declaración  que  lee  un  archivo  de  módulo  y  crea  un  objeto  de  módulo.

objeto  de  módulo:  Un  valor  creado  por  un  definido   declaración  que  proporciona  acceso  a  los  valores
en  un  módulo.

notación  de  puntos:  la  sintaxis  para  llamar  a  una  función  en  otro  módulo  especificando  el  nombre  del  módulo  
seguido  de  un  punto  (punto)  y  el  nombre  de  la  función.

composición:  Usar  una  expresión  como  parte  de  una  expresión  más  grande,  o  una  declaración  como  parte  de  una  
declaración  más  grande.

Flujo  de  ejecución:  las  instrucciones  de  orden  se  ejecutan.

diagrama  de  pila:  una  representación  gráfica  de  una  pila  de  funciones,  sus  variables  y  la
valores  a  los  que  se  refieren.

marco:  un  cuadro  en  un  diagrama  de  pila  que  representa  una  llamada  de  función.  Contiene  el  local  vari
funciones  y  parámetros  de  la  función.

traceback:  Una  lista  de  las  funciones  que  se  están  ejecutando,  impresa  cuando  ocurre  una  excepción.

3.14  Ejercicios

Ejercicio  3.1.  Escriba  una  función  named  que  tome  una  cadena  named  como  parámetro  e  imprima  la  cadena  con  
suficientes  espacios  iniciales  para  que  la  última  letra  de  la  cadena  esté  en  la  columna  70  de  la  pantalla.

Sugerencia:  utilice  la  concatenación  y  repetición  de  cadenas.  Además,  Python  proporciona  una  función  integrada  llamada  
que  devuelve  la  longitud  de  una  cadena,  por  lo  que  el  valor  de  es  5.
Machine Translated by Google

3.14.  Ejercicios 27

Ejercicio  3.2.  Un  objeto  de  función  es  un  valor  que  puede  asignar  a  una  variable  o  pasar  como  argumento.  Por  ejemplo,  es  una  función  
que  toma  un  objeto  de  función  como  argumento  y  lo  llama  dos  veces:

dos  veces.
He  aquí  un  ejemplo  que  utiliza para  llamar  a  una  función  llamada

1.  Escriba  este  ejemplo  en  un  script  y  pruébelo.

2.  Modifique  para  que  tome  dos  argumentos,  un  objeto  de  función  y  un  valor,  y  llame  a  la  función  dos  veces,  pasando  el  valor  como  
argumento.

3.  Copie  la  definición  de desde  antes  en  este  capítulo  a  su  script.

4.  Utilice  la  versión  modificada  del  argumento. llamar dos  veces,  pasando como  un

5.  Defina  una  nueva  función  llamada  que  tome  un  objeto  de  función  y  un  valor  y  llame  a  la  función  cuatro  veces,  pasando  el  valor  
como  parámetro.  Debe  haber  solo  dos  declaraciones  en  el  cuerpo  de  esta  función,  no  cuatro.

Solución:   .

Ejercicio  3.3.  Nota:  este  ejercicio  debe  realizarse  utilizando  solo  las  declaraciones  y  otras  características  que  hemos  aprendido  hasta  
ahora.

1.  Escribe  una  función  que  dibuje  una  cuadrícula  como  la  siguiente:

Sugerencia:  para  imprimir  más  de  un  valor  en  una  línea,  puede  imprimir  una  secuencia  de  valores  separados  por  comas:

De  forma  predeterminada,  avanza  a  la  siguiente  línea,  pero  puede  anular  ese  comportamiento  y  poner  un  espacio  al  final,  así:
Machine Translated by Google

28 Capítulo  3.  Funciones

La  salida  de  estas  declaraciones  es  una   en  la  misma  línea.  El  resultado  de  la  próxima  impresión
declaración  que  comenzaría  en  la  siguiente  línea.

2.  Escribe  una  función  que  dibuje  una  cuadrícula  similar  con  cuatro  filas  y  cuatro  columnas.

Solución: .  Crédito:  este  ejercicio  se  basa  en  un  ejercicio  en  Oualline,  Practical  C  Programming,  Third  Edition,  O'Reilly  

Media,  1997.
Machine Translated by Google

Capítulo  4

Estudio  de  caso:  diseño  de  interfaz

Este  capítulo  presenta  un  caso  de  estudio  que  demuestra  un  proceso  para  diseñar  funciones  que  
funcionan  juntas.

Presenta  el  módulo,  que  le  permite  crear  imágenes  utilizando  gráficos  de  tortugas.
El  módulo  está  incluido  en  la  mayoría  de  las  instalaciones  de  Python,  pero  si  está  ejecutando  Python  
usando  PythonAnywhere,  no  podrá  ejecutar  los  ejemplos  de  tortugas  (al  menos  no  podía  cuando  
escribí  esto).

Si  ya  instaló  Python  en  su  computadora,  debería  poder  ejecutar  los  ejemplos.  De  lo  contrario,  ahora  
es  un  buen  momento  para  instalar.  He  publicado  instrucciones  en
.

Los  ejemplos  de  código  de  este  capítulo  están  disponibles  en
.

4.1  El  módulo  tortuga

Para  comprobar  si  tiene  la módulo,  abra  el  intérprete  de  Python  y  escriba

Cuando  ejecuta  este  código,  debería  crear  una  nueva  ventana  con  una  pequeña  flecha  que  representa
la  tortuga.  Cerrar  la  ventana.

Crear  un  archivo  llamado y  escriba  el  siguiente  código:

El  módulo  (con  una  't'  minúscula)  proporciona  una  función  llamada  (con  una  'T'  mayúscula)  que  crea  
un  objeto  Turtle,  que  asignamos  a  una  variable  llamada .  La  impresión  muestra  algo  como:
Machine Translated by Google

30 Capítulo  4.  Caso  de  estudio:  diseño  de  interfaz

Esto  significa  que se  refiere  a  un  objeto  con  tipo como  se  define  en  el  módulo .

le  dice  a  la  ventana  que  espere  a  que  el  usuario  haga  algo,  aunque  en  este  caso  el  usuario  no  tiene  
mucho  que  hacer  excepto  cerrar  la  ventana.

Una  vez  que  creas  una  tortuga,  puedes  llamar  a  un  método  para  moverla  por  la  ventana.  Un  método  es  similar  a  
una  función,  pero  usa  una  sintaxis  ligeramente  diferente.  Por  ejemplo,  para  mover  la  tortuga  hacia  adelante:

El  método,  está  asociado  con  el  objeto  de  tortuga  que  estamos  llamando  como   .  Llamar  a  un  método  es
hacer  una  solicitud:  estás  preguntando avanzar.

El  argumento  de  es  una  distancia  en  píxeles,  por  lo  que  el  tamaño  real  depende  de  su  pantalla.

Otros  métodos  a  los  que  puede  llamar  a  una  tortuga  son  moverse  hacia  atrás,  girar  a  la  izquierda  y  girar  a  la  
derecha.  El  argumento  a  favor  de  y  es  un  ángulo  en  grados.

Además,  cada  tortuga  sostiene  un  bolígrafo,  que  está  hacia  abajo  o  hacia  arriba;  si  el  bolígrafo  está  abajo,  la  
Tortuga  deja  un  rastro  cuando  se  mueve.  Los  métodos  y  representan  "pluma  arriba"  y  "pluma  abajo".

Para  dibujar  un  ángulo  recto,  agregue  estas  líneas  al  programa  (después  de  crear  y  antes  de  llamar
):

Cuando  ejecute  este  programa,  debería  ver  moverse  hacia  el  este  y  luego  hacia  el  norte,  dejando  atrás  dos  
segmentos  de  línea.

Ahora  modifica  el  programa  para  dibujar  un  cuadrado.  ¡No  continúes  hasta  que  lo  tengas  funcionando!

4.2  Repetición  simple
Lo  más  probable  es  que  hayas  escrito  algo  como  esto:

Podemos  hacer  lo  mismo  de  forma  más  concisa  con  a  y   declaración.  Agrega  este  ejemplo  a
ejecutarlo  de  nuevo:

Debería  ver  algo  como  esto:
Machine Translated by Google

4.3.  Ejercicios 31

Este  es  el  uso  más  simple  de  la  declaración;  veremos  más  adelante.  Pero  eso  debería  ser  suficiente  para  
permitirle  reescribir  su  programa  de  dibujo  de  cuadrados.  No  continúes  hasta  que  lo  hagas.
Aquí  hay  un enunciado  que  dibuja  un  cuadrado:

La  sintaxis  de  a   declaración  es  similar  a  una  definición  de  función.  Tiene  un  encabezado  que  termina
con  dos  puntos  y  cuerpo  sangrado.  El  cuerpo  puede  contener  cualquier  número  de  sentencias.

Una  declaración  también  se  denomina  bucle  porque  el  flujo  de  ejecución  se  ejecuta  a  través  del  cuerpo  
y  luego  vuelve  a  la  parte  superior.  En  este  caso,  se  ejecuta  el  cuerpo  cuatro  veces.

Esta  versión  es  en  realidad  un  poco  diferente  del  código  de  dibujo  de  cuadrados  anterior  porque  hace  
otro  giro  después  de  dibujar  el  último  lado  del  cuadrado.  El  turno  adicional  toma  más  tiempo,  pero  
simplifica  el  código  si  hacemos  lo  mismo  cada  vez  que  se  ejecuta  el  ciclo.  Esta  versión  también  tiene  
el  efecto  de  dejar  a  la  tortuga  en  la  posición  inicial,  mirando  en  la  dirección  inicial.

4.3  Ejercicios

La  siguiente  es  una  serie  de  ejercicios  usando  el  módulo.  Están  destinados  a  ser  divertidos,  pero  
también  tienen  un  punto.  Mientras  trabaja  en  ellos,  piense  cuál  es  el  punto.

Las  siguientes  secciones  tienen  soluciones  para  los  ejercicios,  así  que  no  busques  hasta  que  hayas  terminado  (o  al  
menos  lo  hayas  intentado).

1.  Escriba  una  función  llamada  que  tome  un  parámetro  llamado  debería  usar   , que  es  una  tortuga.  Él
la  tortuga  para  dibujar  un  cuadrado.
Escriba  una  llamada  de  función  que  pase  como  argumento  para  programar   , y  luego  ejecuta  el
nuevamente.

2.  Agregue  otro  parámetro,  denominado .  Modifique  el  , cauerpo  para  que  la  longitud  de  los  lados  sea  y  luego  
modifique  la  llamada  
, a  la  función  para  proporcionar  un  segundo  argumento.  Vuelva  a  ejecutar  el  programa.  
Pruebe  su  programa  con  un  rango  de  valores  para .

3.  Haz  una  copia  de y  cambie  el  nombre  a .  Agregue  otro  parámetro  llamado  y  modifique  
el  cuerpo  para  que  dibuje  un  polígono  regular  de  n  lados.  Pista:  Los  ángulos  exteriores  de  un  
polígono  regular  de  n  lados  son  360/n  grados.
4.  Escribe  una  función  llamada que  toma  como  parámetros  una  tortuga, ,  y  un  radio,  y  con  
que  dibuja  un  círculo  aproximado  llamando   una  longitud  y
número  de  lados.  Pruebe  su  función  con  un  rango  de  valores  de .
Pista:  calcula  la  circunferencia  del  círculo  y  asegúrate  de  que
.

5.  Haz  una  versión  más  general  de  llamado  que   que  toma  un  parámetro  adicional  está  
, determina  qué  fracción  de  un  círculo  dibujar.  debe   en  unidades  de  grados,
así  que  cuando , dibujar  un  círculo  completo.
Machine Translated by Google

32 Capítulo  4.  Caso  de  estudio:  diseño  de  interfaz

4.4  Encapsulación
El  primer  ejercicio  le  pide  que  coloque  su  código  de  dibujo  cuadrado  en  una  definición  de  función  y  luego  
llame  a  la  función,  pasando  la  tortuga  como  parámetro.  Aquí  hay  una  solución:

Las  declaraciones  más  internas,  y  están  sangradas  dos  veces  para  mostrar  que  están  dentro  de  la  está  al  
bucle,  que  está  dentro  de  la  definición  de  la  función.  La  siguiente  línea,   , ras  con
el  margen  izquierdo,  que  indica  el  final  de  ambos bucle  y  la  definición  de  la  función.

Dentro  de  la  función,  se  refiere  a  la  misma  tortuga , entonces tiene  el  mismo  efecto  que  


. En  ese  caso,  ¿por  qué  no  llamar  al  parámetro?  La  idea  es  que  puede  ser  cualquier  tortuga,  
, una  segunda  tortuga  y  pasarla  como  argumento  a
no  solo  para  poder  crear   :

Envolver  una  pieza  de  código  en  una  función  se  llama  encapsulación.  Uno  de  los  beneficios  de  la  
encapsulación  es  que  le  asigna  un  nombre  al  código,  que  sirve  como  una  especie  de  documentación.  Otra  
ventaja  es  que  si  reutiliza  el  código,  ¡es  más  conciso  llamar  a  una  función  dos  veces  que  copiar  y  pegar  el  
cuerpo!

4.5  Generalización
El  siguiente  paso  es  agregar  un parámetro  a .  Aquí  hay  una  solución:

Agregar  un  parámetro  a  una  función  se  llama  generalización  porque  hace  que  la  función  sea  más  general:  
en  la  versión  anterior,  el  cuadrado  siempre  tiene  el  mismo  tamaño;  en  esta  versión  puede  ser  de  cualquier  
tamaño.

El  siguiente  paso  es  también  una  generalización.  En  lugar  de  dibujar  cuadrados,   dibuja  regularmente
polígonos  con  cualquier  número  de  lados.  Aquí  hay  una  solución:
Machine Translated by Google

4.6.  Diseño  de  interfaz 33

Este  ejemplo  dibuja  un  polígono  de  7  lados  con  una  longitud  de  lado  de  70.

Si  está  utilizando  Python  2,  el  valor  de  la  solución   podría  estar  apagado  debido  a  la  división  de  enteros.  
simple  es  calcular  el  número  de   A .  porque  el  numerador  es  flotante
puntos,  el  resultado  es  un  punto  flotante.

Cuando  una  función  tiene  más  de  unos  pocos  argumentos  numéricos,  es  fácil  olvidar  cuáles  son  o  en  qué  orden  
deberían  estar.  En  ese  caso,  a  menudo  es  una  buena  idea  incluir  los  nombres  de  los  parámetros  en  la  lista  de  
argumentos:

Estos  se  denominan  argumentos  de  palabras  clave  porque  incluyen  los  nombres  de  los  parámetros  como  
"palabras  clave" (que  no  deben  confundirse  con  las  palabras  clave  de  Python  como  y ).

Esta  sintaxis  hace  que  el  programa  sea  más  legible.  También  es  un  recordatorio  sobre  cómo  funcionan  los  
argumentos  y  parámetros:  cuando  llama  a  una  función,  los  argumentos  se  asignan  al  parámetro
éteres.

4.6  Diseño  de  la  interfaz
El  siguiente  paso  es  escribir   , que  toma  un  radio, ,  como  parámetro.  Aquí  hay  un  simple  para  dibujar  
una  solución  que  use un  polígono  de  50  lados:

La  primera  línea  calcula  la  circunferencia  de  un  círculo  con  radio  usando  la  fórmula  2πr.
Ya  que  usamos  tenemos  que   , importar .  Por  convención,  normalmente  al  principio   las  declaraciones  son

del  guión.

es  el  número  de  segmentos  de  línea  en  nuestra  aproximación  de  un  círculo,  por  lo   es  la  longitud  
que  de  cada  segmento.  Por   dibuja  un  polígono  de  50  lados  que  se  aproxima  a  un  círculo  con
lo  tanto,  radio .

Una  limitación  de  esta  solución  es  que  es  una  constante,  lo  que  significa  que  para  círculos  muy  grandes,  los  
segmentos  de  línea  son  demasiado  largos,  y  para  círculos  pequeños,  perdemos  tiempo  dibujando  segmentos  
muy  pequeños.  Una  solución  sería  generalizar  la  función  tomando  como  parámetro.
Esto  le  daría  al  usuario  (quienquiera  que  llame)  más  control,  pero  la  interfaz  sería  menos  limpia.

La  interfaz  de  una  función  es  un  resumen  de  cómo  se  utiliza:  ¿cuáles  son  los  parámetros?  ¿Qué  hace  la  función?  
¿Y  cuál  es  el  valor  de  retorno?  Una  interfaz  es  "limpia"  si  permite  que  la  persona  que  llama  haga  lo  que  quiera  
sin  tener  que  lidiar  con  detalles  innecesarios.

En  este  ejemplo,  pertenece  a  la  interfaz  porque  especifica  el  círculo  que  se  dibujará.  es  menos  apropiado  porque  
se  refiere  a  los  detalles  de  cómo  se  debe  representar  el  círculo.

En  lugar  de  saturar  la  interfaz,  es  mejor  elegir  un  valor  apropiado  de  dependiendo  de
:
Machine Translated by Google

34 Capítulo  4.  Caso  de  estudio:  diseño  de  interfaz

Ahora,  el  número  de  segmentos  es  un  número  entero  cercano,  por  lo  que  la  longitud  de  cada  ,segmento  es  de  
aproximadamente  3,  que  es  lo  suficientemente  pequeño  para  que  los  círculos  se  vean  bien,  pero  lo  suficientemente  grande  
para  ser  eficiente  y  aceptable  para  círculos  de  cualquier  tamaño.

Sumar  3  a  garantiza  que  el  polígono  tiene  al  menos  3  lados.

4.7  Refactorización
Cuando  escribí   , pude  reutilizar porque  un  polígono  de  muchos  lados  es  un  bien  
aproximación  de  un  círculo.  Pero   no  es  tan  cooperativo;  no  podemos  usar o a
dibuja  un  arco.

Una  alternativa  es  comenzar  con  una  copia   y  transformarlo  en .  El  resultado


de  podría  verse  así:

La  segunda  mitad  de  esta  función  parece   , pero  no  podemos  reutilizar  sin  tomar  un  
cambiar  la  interfaz.  Podríamos  generalizar  pero   ángulo  como  tercer  argumento,  ¡ya  no  
luego  la   sería  un  nombre  apropiado!  En  cambio,  llamemos  al  más
función  general :

Ahora  podemos  reescribir y  para  usar :

Finalmente,  podemos  reescribir usar :
Machine Translated by Google

4.8.  un  plan  de  desarrollo 35

Este  proceso,  reorganizar  un  programa  para  mejorar  las  interfaces  y  facilitar  la  reutilización  del  código,  se  denomina  
refactorización.  En  este  caso,  nos  dimos  cuenta  de  que  había  un  código  similar  y  lo  "factorizamos"  en ,
.

Si  hubiéramos  planeado  con  anticipación,  podríamos  haber  escrito  primero  y  evitado  la  refactorización,  pero  a  
menudo  no  se  sabe  lo  suficiente  al  comienzo  de  un  proyecto  para  diseñar  todas  las  interfaces.
Una  vez  que  empiezas  a  codificar,  entiendes  mejor  el  problema.  A  veces,  la  refactorización  es  una  señal  de  que  
has  aprendido  algo.

4.8  Un  plan  de  desarrollo

Un  plan  de  desarrollo  es  un  proceso  para  escribir  programas.  El  proceso  que  utilizamos  en  este  estudio  de  caso  
es  "encapsulación  y  generalización".  Los  pasos  de  este  proceso  son:

1.  Comience  escribiendo  un  pequeño  programa  sin  definiciones  de  funciones.

2.  Una  vez  que  tenga  el  programa  funcionando,  identifique  una  parte  coherente  del  mismo,  encapsule  la  parte  
en  una  función  y  asígnele  un  nombre.

3.  Generalice  la  función  agregando  los  parámetros  apropiados.

4.  Repita  los  pasos  1  a  3  hasta  que  tenga  un  conjunto  de  funciones  operativas.  Copiar  y  pegar  trabajando
código  para  evitar  volver  a  escribir  (y  volver  a  depurar).

5.  Busque  oportunidades  para  mejorar  el  programa  refactorizando.  Por  ejemplo,  si  tiene  un  código  similar  en  
varios  lugares,  considere  factorizarlo  en  una  función  general  apropiada.

Este  proceso  tiene  algunos  inconvenientes,  veremos  alternativas  más  adelante,  pero  puede  ser  útil  si  no  sabe  de  
antemano  cómo  dividir  el  programa  en  funciones.  Este  enfoque  le  permite  diseñar  sobre  la  marcha.

4.9  cadena  de  documentación

Una  cadena  de  documentos  es  una  cadena  al  comienzo  de  una  función  que  explica  la  interfaz  ("doc"  es  la  
abreviatura  de  "documentación").  Aquí  hay  un  ejemplo:

Por  convención,  todas  las  cadenas  de  documentos  son  cadenas  entre  comillas  triples,  también  conocidas  como  cadenas  
de  varias  líneas  porque  las  comillas  triples  permiten  que  la  cadena  abarque  más  de  una  línea.
Machine Translated by Google

36 Capítulo  4.  Caso  de  estudio:  diseño  de  interfaz

Es  breve,  pero  contiene  la  información  esencial  que  alguien  necesitaría  para  usar  esta  función.  Explica  de  manera  
concisa  lo  que  hace  la  función  (sin  entrar  en  los  detalles  de  cómo  lo  hace).  Explica  qué  efecto  tiene  cada  parámetro  
en  el  comportamiento  de  la  función  y  de  qué  tipo  debe  ser  cada  parámetro  (si  no  es  obvio).

Escribir  este  tipo  de  documentación  es  una  parte  importante  del  diseño  de  la  interfaz.  Una  interfaz  bien  diseñada  
debe  ser  sencilla  de  explicar;  si  te  cuesta  explicar  alguna  de  tus  funciones,  quizás  la  interfaz  se  podría  mejorar.

4.10  Depuración
Una  interfaz  es  como  un  contrato  entre  una  función  y  una  persona  que  llama.  La  persona  que  llama  acepta  
proporcionar  ciertos  parámetros  y  la  función  acepta  realizar  cierto  trabajo.

Por  ejemplo,  requiere  cuatro  argumentos:  tiene  que  ser  una  tortuga;  tiene  que  ser  un  número  entero;  debe  ser  un  
número  positivo;  y  tiene  que  ser  un  número,  que  se  entiende  en  grados.

Estos  requisitos  se  denominan  condiciones  previas  porque  se  supone  que  se  cumplen  antes  de  que  la  función  
comience  a  ejecutarse.  Por  el  contrario,  las  condiciones  al  final  de  la  función  son  condiciones  posteriores.  Las  
condiciones  posteriores  incluyen  el  efecto  previsto  de  la  función  (como  dibujar  segmentos  de  línea)  y  cualquier  
efecto  secundario  (como  mover  la  tortuga  o  realizar  otros  cambios).

Las  condiciones  previas  son  responsabilidad  de  la  persona  que  llama.  Si  la  persona  que  llama  viola  una  condición  
previa  (¡debidamente  documentada!)  y  la  función  no  funciona  correctamente,  el  error  está  en  la  persona  que  llama,  
no  en  la  función.

Si  se  cumplen  las  condiciones  previas  y  no  las  poscondiciones,  el  error  está  en  la  función.
Si  sus  condiciones  previas  y  posteriores  son  claras,  pueden  ayudar  con  la  depuración.

4.11  Glosario
método:  una  función  que  está  asociada  con  un  objeto  y  se  llama  usando  la  notación  de  puntos.

loop:  Una  parte  de  un  programa  que  puede  ejecutarse  repetidamente.

encapsulación:  El  proceso  de  transformar  una  secuencia  de  sentencias  en  una  función  defi
nición

generalización:  El  proceso  de  reemplazar  algo  innecesariamente  específico  (como  un  número)  con  algo  
apropiadamente  general  (como  una  variable  o  parámetro).

argumento  de  palabra  clave:  un  argumento  que  incluye  el  nombre  del  parámetro  como  una  "clave
palabra".

interfaz:  una  descripción  de  cómo  usar  una  función,  incluido  el  nombre  y  las  descripciones  de  los  argumentos  y  el  
valor  de  retorno.

refactorización:  El  proceso  de  modificar  un  programa  de  trabajo  para  mejorar  las  interfaces  de  función  y  otras  
cualidades  del  código.

plan  de  desarrollo:  Un  proceso  para  escribir  programas.
Machine Translated by Google

4.12.  Ejercicios 37

Figura  4.1:  Flores  de  tortuga.

Figura  4.2:  Pasteles  de  tortuga.

docstring:  una  cadena  que  aparece  en  la  parte  superior  de  una  definición  de  función  para  documentar  la  función
interfaz  de  ción.

condición  previa:  un  requisito  que  debe  cumplir  la  persona  que  llama  antes  de  que  comience  una  función.

poscondición:  Un  requisito  que  debe  ser  satisfecho  por  la  función  antes  de  que  finalice.

4.12  Ejercicios

Ejercicio  4.1.  Descargue  el  código  de  este  capítulo  desde
.

1.  Dibuje  un  diagrama  de  pila  que  muestre  el  estado  del  programa  mientras  se  ejecuta
.  Puedes  hacer  la  aritmética  a  mano  o  sumar declaraciones  al  código.

2.  La  versión  de  en  la  Sección  4.7  no  es  muy  precisa  porque  la  aproximación  lineal  del  círculo  siempre  está  
fuera  del  círculo  verdadero.  Como  resultado,  la  tortuga  termina  a  unos  pocos  píxeles  del  destino  correcto.  
Mi  solución  muestra  una  forma  de  reducir  el  efecto  de  este  error.  Lea  el  código  y  vea  si  tiene  sentido  para  
usted.  Si  dibuja  un  diagrama,  puede  ver  cómo  funciona.
Ejercicio  4.2.  Escriba  un  conjunto  general  apropiado  de  funciones  que  puedan  dibujar  flores  como  en  la  figura  4.1.

Solución: , también  requiere
.
Ejercicio  4.3.  Escriba  un  conjunto  general  apropiado  de  funciones  que  puedan  dibujar  formas  como  en  la  figura  4.2.

Solución:   .
Ejercicio  4.4.  Las  letras  del  alfabeto  se  pueden  construir  a  partir  de  un  número  moderado  de  elementos  básicos,  
como  líneas  verticales  y  horizontales  y  algunas  curvas.  Diseñe  un  alfabeto  que  se  pueda  dibujar  con  un  número  
mínimo  de  elementos  básicos  y  luego  escriba  funciones  que  dibujen  las  letras.

Debe  escribir  una  función  para  cada  letra,  con  funciones  de  nombres   , ,  etc.,  y  pon  tu .  Puede  
en  un  archivo  llamado descargar  una  "máquina  de  escribir  tortuga"  para  
ayudarlo  a  probar  su  código.
Machine Translated by Google

38 Capítulo  4.  Caso  de  estudio:  diseño  de  interfaz

Puede  obtener  una  solución  de ;  también  requiere
.
Ejercicio  4.5.  Lea  sobre  espirales  en ;  luego  escriba  un  programa  que  dibuje  una  espiral  de  Arquímedes  (o  
uno  de  los  otros  tipos).  Solución:
.
Machine Translated by Google

Capítulo  5

Condicionales  y  recursión

El  tema  principal  de  este  capítulo  es  la  sentencia,  que  ejecuta  código  diferente  dependiendo  del  estado  del  
programa.  Pero  primero  quiero  presentar  dos  nuevos  operadores:  división  de  piso  y  módulo.

5.1  División  de  piso  y  módulo

El  operador  de  división  de  piso ,  divide  dos  números  y  los  redondea  a  un  número  entero.  Por  ejemplo,  
suponga  que  el  tiempo  de  ejecución  de  una  película  es  de  105  minutos.  Es  posible  que  desee  saber  cuánto  
tiempo  es  eso  en  horas.  La  división  convencional  devuelve  un  número  de  coma  flotante:

Pero  normalmente  no  escribimos  las  horas  con  puntos  decimales.  La  división  de  piso  devuelve  el  número  
entero  de  horas,  redondeando  hacia  abajo:

Para  obtener  el  resto,  podría  restar  una  hora  en  minutos:

Una  alternativa  es  utilizar  el  operador  de  módulo,  que  divide  dos  números  y  devuelve  el  resto.

El  operador  de  módulo  es  más  útil  de  lo  que  parece.  Por  ejemplo,  puede  verificar  si  un  número  es  divisible  
por  otro;  si  es  cero,  entonces  es  divisible  por .
Machine Translated by Google

40 Capítulo  5.  Condicionales  y  recursión

Además,  puede  extraer  el  dígito  o  dígitos  más  a  la  derecha  de  un  número.  Por  ejemplo,  produce  
el  dígito  más  a  la  derecha  de  (en  base  10).  De  manera  similar,  produce  los  dos  últimos  dígitos.

Si  está  utilizando  Python  2,  la  división  funciona  de  manera  diferente.  El  operador  de  división,  realiza  una  
división  mínima  si  ambos  operandos  son  enteros  y  una  división  de  punto  flotante  si  cualquiera  de  los  operandos  es
a .

5.2  Expresiones  booleanas
Una  expresión  booleana  es  una  expresión  que  es  verdadera  o  falsa.  Los  siguientes  ejemplos  usan  el  
operador ,  que  compara  
dos  operandos  y  produce  si  son  iguales  y  si  no:

y son  valores  especiales  que  pertenecen  al  tipo ;  no  son  cadenas:

El  operador  es  uno  de  los  operadores  relacionales;  los  otros  son:

Aunque  estas  operaciones  probablemente  le  resulten  familiares,  los  símbolos  de  Python  son  diferentes  
de  los  símbolos  matemáticos.  Un  error  común  es  usar  un  solo  signo  igual  ()  en  lugar  de  un  doble  signo  
igual  ().  Recuerda  que  es  un  operador  de  asignación  y  es  un  operador  relacional.  No  existe  tal  cosa  
como  o .

5.3  Operadores  lógicos
Hay  tres  operadores  lógicos:  operadores   , , y .  La  semántica  (significado)  de  estos  es  verdadera
es  similar  a  su  significado  en  inglés.  Por  ejemplo,  solo  si  es  mayor  que  
0  y  menor  que  10.

es  verdadero  si  una  o  ambas  condiciones  son  verdaderas,  es  decir,  si  el  número
es  divisible  por  2  o  3.

Por  último,   El  operador  niega  una  expresión  booleana,  por  lo  que es  cierto  si es

el  falso,  es  decir,  si  es  menor  o  igual  que .

Estrictamente  hablando,  los  operandos  de  los  operadores  lógicos  deberían  ser  expresiones  booleanas,  pero  
Python  no  es  muy  estricto.  Cualquier  número  distinto  de  cero  se  interpreta  como :
Machine Translated by Google

5.4.  ejecución  condicional 41

Esta  flexibilidad  puede  ser  útil,  pero  tiene  algunas  sutilezas  que  pueden  resultar  confusas.
Es  posible  que  desee  evitarlo  (a  menos  que  sepa  lo  que  está  haciendo).

5.4  Ejecución  condicional

Para  escribir  programas  útiles,  casi  siempre  necesitamos  la  capacidad  de  verificar  las  condiciones  y  cambiar  el  
comportamiento  del  programa  en  consecuencia.  Las  declaraciones  condicionales  nos  dan  esta  habilidad.  La  
forma  más  simple  es  la  declaración:

La  expresión  booleana  posterior  se  denomina  condición.  Si  es  verdadero,  se  ejecuta  la  instrucción  con  sangría.  
Si  no,  no  pasa  nada.

Las  declaraciones  tienen  la  misma  estructura  que  las  definiciones  de  función:  un  encabezado  seguido  de  un  
cuerpo  sangrado.  Las  declaraciones  como  esta  se  llaman  declaraciones  compuestas.

No  hay  límite  en  la  cantidad  de  declaraciones  que  pueden  aparecer  en  el  cuerpo,  pero  tiene  que  haber  al  menos  
una.  Ocasionalmente,  es  útil  tener  un  cuerpo  sin  declaraciones  (generalmente  como  un  guardián  del  código  que  
aún  no  ha  escrito).  En  ese  caso,  puede  usar  la  declaración,  que  no  hace  nada.

5.5  Ejecución  alternativa

Una  segunda  forma  de  la  declaración  es  "ejecución  alternativa",  en  la  que  hay  dos  posibilidades  y  la  condición  
determina  cuál  se  ejecuta.  La  sintaxis  se  ve  así:

Si  el  resto  cuando  se  divide  por  2  es  0,  entonces  sabemos  que  es  par  y  el  programa  muestra  un  mensaje  
apropiado.  Si  la  condición  es  falsa,  se  ejecuta  el  segundo  conjunto  de  sentencias.  Dado  que  la  condición  debe  
ser  verdadera  o  falsa,  se  ejecutará  exactamente  una  de  las  alternativas.  Las  alternativas  se  denominan  ramas,  
porque  son  ramas  en  el  flujo  de  ejecución.

5.6  Condicionales  encadenados

A  veces  hay  más  de  dos  posibilidades  y  necesitamos  más  de  dos  ramas.
Una  forma  de  expresar  un  cálculo  como  ese  es  un  condicional  encadenado:
Machine Translated by Google

42 Capítulo  5.  Condicionales  y  recursión

es  una  abreviatura  de  "else  if".  Nuevamente,  se  ejecutará  exactamente  una  rama.  No  hay  límite  de  
el  número  de  no   declaraciones.  Si  hay  una  cláusula,  tiene  que  estar  al  final,  pero  no
tiene  que  ser  uno.

Cada  condición  se  comprueba  en  orden.  Si  la  primera  es  falsa,  se  comprueba  la  siguiente,  y  así  sucesivamente.  
Si  uno  de  ellos  es  verdadero,  se  ejecuta  la  rama  correspondiente  y  finaliza  la  instrucción.  Incluso  si  más  de  una  
condición  es  verdadera,  solo  se  ejecuta  la  primera  rama  verdadera.

5.7  Condicionales  anidados
Un  condicional  también  se  puede  anidar  dentro  de  otro.  Podríamos  haber  escrito  el  ejemplo  en  la  sección  anterior  
así:

El  condicional  externo  contiene  dos  ramas.  La  primera  rama  contiene  una  declaración  simple.
La  segunda  rama  contiene  otra  declaración,  que  tiene  dos  ramas  propias.
Esas  dos  ramas  son  declaraciones  simples,  aunque  también  podrían  haber  sido  declaraciones  condicionales.

Aunque  la  sangría  de  las  declaraciones  hace  que  la  estructura  sea  aparente,  los  condicionales  anidados  se  
vuelven  difíciles  de  leer  muy  rápidamente.  Es  una  buena  idea  evitarlos  cuando
poder.

Los  operadores  lógicos  a  menudo  proporcionan  una  forma  de  simplificar  declaraciones  condicionales  anidadas.  
Por  ejemplo,  podemos  reescribir  el  siguiente  código  usando  un  solo  condicional:

La  declaración  se  ejecuta  solo  si  superamos  ambos  condicionales,  por  lo  que  podemos  obtener  el  mismo  efecto  
con  el operador:
Machine Translated by Google

5.8.  recursividad 43

Para  este  tipo  de  condición,  Python  ofrece  una  opción  más  concisa:

5.8  Recursividad
Es  legal  que  una  función  llame  a  otra;  también  es  legal  que  una  función  se  llame  a  sí  misma.  
Puede  que  no  sea  obvio  por  qué  eso  es  algo  bueno,  pero  resulta  ser  una  de  las  cosas  más  
mágicas  que  puede  hacer  un  programa.  Por  ejemplo,  observe  la  siguiente  función:

Si  es  0  o  negativo,  emite  la  palabra  "Blastoff!"  De  lo  contrario,  genera  una  salida  y  luego  se  llama  —a  sí  
una  función  llamada mismo—  pasándolo  como  un  argumento.

¿Qué  pasa  si  llamamos  a  esta  función  así?

La  ejecución  de  comienza  con  el  valor  3  y  luego   , y  dado  que  es  mayor  que  0,  genera  el
se  llama  a  sí  misma...

La  ejecución  de  comienza  con  la  salida  del   , y  como  es  mayor  que  0,
valor  2  y  luego  se  llama  a  sí  misma...
La  ejecución  de  comienza  con  0,  genera   , y  como  es  mayor
el  valor  1  y  luego  se  llama  a  sí  mismo...
La  ejecución  de  comienza  con  no  más  de   , y  puesto  que  es
0,  genera  la  palabra  "¡Blastoff!"  y  luego  regresa.

El eso  tiene   devoluciones.

El eso  tiene devoluciones.

El eso  tiene devoluciones.

Y  luego  estás  de  vuelta .  Entonces,  la  salida  total  se  ve  así:

Una  función  que  se  llama  a  sí  misma  es  recursiva;  el  proceso  de  ejecución  se  llama  recursividad.

Como  otro  ejemplo,  podemos  escribir  una  función  que  imprima  una  cadena  veces.
Machine Translated by Google

44 Capítulo  5.  Condicionales  y  recursión

__principal__

cuenta  regresiva norte 3

cuenta  regresiva norte 2

cuenta  regresiva norte 1

cuenta  regresiva norte
0

Figura  5.1:  Diagrama  de  pila.

Si  la  declaración  de  retorno  sale  de  la  función.  El  flujo  de  ejecución  vuelve  inmediatamente  a  la  persona  
que  llama  y  las  líneas  restantes  de  la  función  no  se  ejecutan.
El  resto  de  la  función  es  similar  a :  se  muestra  y  luego  se  llama  a  sí  mismo  para  
mostrar  n  −  1  veces  adicionales.  Entonces,  el  número  de  líneas  de  salida  es  lo  que  s, uma
a .

Para  ejemplos  simples  como  este,  probablemente  sea  más  fácil  usar  un  bucle.  Pero  veremos  ejemplos  más  
adelante  que  son  difíciles  de  escribir  con  un  bucle  y  fáciles  de  escribir  con  recursividad,  por  lo  que  es  bueno  
comenzar  temprano.

5.9  Diagramas  de  pila  para  funciones  recursivas
En  la  Sección  3.9,  usamos  un  diagrama  de  pila  para  representar  el  estado  de  un  programa  durante  una  llamada  
de  función.  El  mismo  tipo  de  diagrama  puede  ayudar  a  interpretar  una  función  recursiva.

Cada  vez  que  se  llama  a  una  función,  Python  crea  un  marco  para  contener  las  variables  y  parámetros  
locales  de  la  función.  Para  una  función  recursiva,  puede  haber  más  de  un  cuadro  en  la  pila  al  mismo  
tiempo.

La  Figura  5.1  muestra  un  diagrama  de  pila  para llamado  con .

Como  de  costumbre,  la  parte  superior  de  la  pila  es  el   .  Está  vacío  porque  no  lo  hicimos.
marco  para  crear  cualquier  variable  o  pasarle  argumentos.
Los  cuatro   los  marcos  tienen  diferentes  valores  para  el  parámetro.  La  parte  inferior  del  se  
se  apilan,  donde   , llama  el  caso  base.  No  hace  una  llamada  recursiva,  por  lo  que  no  hay
hay  más  fotogramas.

llamado  
Como  ejercicio,  dibuje  un  diagrama  de  pila  para  y .  Luego  e scriba  ucna  
onfunción  llamada  que  tome  un  
objeto  de  función  y  un  número,  como  argumentos,  y  que  llame  a  la  función  dada  veces.

5.10  Recurrencia  infinita

Si  una  recursión  nunca  llega  a  un  caso  base,  continúa  haciendo  llamadas  recursivas  para  siempre  y  el  
programa  nunca  termina.  Esto  se  conoce  como  recursividad  infinita  y  generalmente  no  es  una  buena  
idea.  Aquí  hay  un  programa  mínimo  con  una  recursividad  infinita:
Machine Translated by Google

5.11.  Entrada  de  teclado 45

En  la  mayoría  de  los  entornos  de  programación,  un  programa  con  recursividad  infinita  en  realidad  no  se  
ejecuta  para  siempre.  Python  informa  un  mensaje  de  error  cuando  se  alcanza  la  profundidad  de  recursión  máxima:

Este  rastreo  es  un  poco  más  grande  que  el  que  vimos  en  el  capítulo  anterior.  Cuando  ocurre  el  error,  
¡hay  1000  marcos  en  la  pila!

Si  encuentra  una  recursividad  infinita  por  accidente,  revise  su  función  para  confirmar  que  hay  un  caso  
base  que  no  realiza  una  llamada  recursiva.  Y  si  hay  un  caso  base,  verifique  si  tiene  la  garantía  de  
alcanzarlo.

5.11  Entrada  de  teclado
Los  programas  que  hemos  escrito  hasta  ahora  no  aceptan  ninguna  entrada  del  usuario.  Simplemente  hacen  
lo  mismo  cada  vez.

Python  proporciona  una  función  integrada  llamada  que  detiene  el  programa  y  espera  a  que  el  usuario  
o y  devuelve  
escriba  algo.  Cuando  el  usuario  presiona,  el  programa  se  reanuda   , lo  que  el  usuario  escribió  
como  una  cadena.  En  Python  2,  la  misma  función  se  llama
.

Antes  de  obtener  información  del  usuario,  es  una  buena  idea  imprimir  un  aviso  que  le  diga  al  usuario  qué  
escribir. puede  tomar  un  aviso  como  argumento:  

La  secuencia  al  final  del  indicador  representa  una  nueva  línea,  que  es  un  carácter  especial  que  provoca  
un  salto  de  línea.  Es  por  eso  que  la  entrada  del  usuario  aparece  debajo  del  aviso.

Si  espera  que  el  usuario  escriba  un  número  entero,  puede  intentar  convertir  el  valor  de  retorno  a :
Machine Translated by Google

46 Capítulo  5.  Condicionales  y  recursión

Pero  si  el  usuario  escribe  algo  que  no  sea  una  cadena  de  dígitos,  obtendrá  un  error:

Veremos  cómo  manejar  este  tipo  de  error  más  adelante.

5.12  Depuración
Cuando  ocurre  un  error  de  sintaxis  o  de  tiempo  de  ejecución,  el  mensaje  de  error  contiene  mucha  
información,  pero  puede  ser  abrumador.  Las  partes  más  útiles  suelen  ser:

•  Qué  tipo  de  error  fue,  y

•  Dónde  ocurrió.

Los  errores  de  sintaxis  suelen  ser  fáciles  de  encontrar,  pero  hay  algunas  trampas.  Los  errores  de  espacios  en  blanco  
pueden  ser  complicados  porque  los  espacios  y  las  pestañas  son  invisibles  y  estamos  acostumbrados  a  ignorarlos.

En  este  ejemplo,  el  problema  es  que  la  segunda  línea  está  sangrada  por  un  espacio.  Pero  el  error  que  
mensaje  al  problema   , es  engañoso.  En  general,  los  mensajes  de  error  indican  dónde  apunta  el  
que  se  descubrió,  pero  el  error  real  puede  estar  antes  en  el  código,  a  veces  en  una  línea  anterior.

Lo  mismo  ocurre  con  los  errores  de  tiempo  de  ejecución.  Suponga  que  está  tratando  de  calcular  una  
relación  señal­ruido  en  decibelios.  La  fórmula  es  SNRdb  =  10  log10(Pseñal/Pruido).  En  Python,  podrías  
escribir  algo  como  esto:

Cuando  ejecuta  este  programa,  obtiene  una  excepción:

El  mensaje  de  error  indica  la  línea  5,  pero  no  hay  nada  de  malo  en  esa  línea.  Para  encontrar  el  error  
real,  puede  ser  útil  imprimir  el  valor  que  resulta  ser  0.  El  problema  e,stá  en  la  línea  4,  que  usa  división  
de  piso  en  lugar  de  división  de  punto  flotante.

Debe  tomarse  el  tiempo  para  leer  los  mensajes  de  error  cuidadosamente,  pero  no  asuma  que  todo  lo  
que  dicen  es  correcto.
Machine Translated by Google

5.13.  Glosario 47

5.13  Glosario
división  de  piso:  Un  operador,  denotado , que  divide  dos  números  y  redondea  hacia  abajo  
(hacia  el  infinito  negativo)  a  un  número  entero.

operador  de  módulo:  un  operador,  indicado  con  un  signo  de  porcentaje  (),  que  funciona  con  
números  enteros  y  devuelve  el  resto  cuando  un  número  se  divide  por  otro.

expresión  booleana:  una  expresión  cuyo  valor  es o .

operador  relacional:  Uno  de  los  operadores  que  compara  sus  operandos: , , , , ,y
.

operador  lógico:  Uno  de  los  operadores  que  combina  expresiones  booleanas: , , y
.

sentencia  condicional:  Una  sentencia  que  controla  el  flujo  de  ejecución  dependiendo  de  alguna
condición.

condición:  La  expresión  booleana  en  una  declaración  condicional  que  determina  qué
carreras  de  rama.

declaración  compuesta:  una  declaración  que  consta  de  un  encabezado  y  un  cuerpo.  El  encabezado  termina
con  dos  puntos  (:).  El  cuerpo  está  sangrado  en  relación  con  el  encabezado.

rama:  Una  de  las  secuencias  alternativas  de  sentencias  en  una  sentencia  condicional.
Condicional  encadenado:  una  declaración  condicional  con  una  serie  de  ramas  alternativas.

Condicional  anidado:  una  declaración  condicional  que  aparece  en  una  de  las  ramas  de  otra  
declaración  condicional.

declaración  de  retorno:  una  declaración  que  hace  que  una  función  finalice  inmediatamente  y  regrese  a  la
llamador.

recursividad:  El  proceso  de  llamar  a  la  función  que  se  está  ejecutando  actualmente.

caso  base:  una  rama  condicional  en  una  función  recursiva  que  no  realiza  una  llamada  recursiva.

recursión  infinita:  Una  recursión  que  no  tiene  un  caso  base,  o  nunca  lo  alcanza.  Evento
aliado,  una  recursividad  infinita  provoca  un  error  de  tiempo  de  ejecución.

5.14  Ejercicios

Ejercicio  5.1.  El  módulo  proporciona  una  función,  también  denominada  hora   , que  devuelve  la  corriente
media  de  Greenwich  en  "la  época",  que  es  una  hora  arbitraria  utilizada  como  punto  de  referencia.  En  los  sistemas  
UNIX,  la  época  es  el  1  de  enero  de  1970.

Escriba  un  script  que  lea  la  hora  actual  y  la  convierta  en  una  hora  del  día  en  horas,  minutos  y  
segundos,  más  el  número  de  días  desde  la  época.
Machine Translated by Google

48 Capítulo  5.  Condicionales  y  recursión

Ejercicio  5.2.  El  último  teorema  de  Fermat  dice  que  no  hay  números  enteros  positivos  a,  b  y  c  tales  que

n  
un +  segundo
norte
n  =  c

para  cualquier  valor  de  n  mayor  que  2.

1.  Escribe  una  función  llamada   que  toma  cuatro  parámetros—, , y  y


cheques  para  ver  si  se  cumple  el  teorema  de  Fermat.  Si  n  es  mayor  que  2  y

a norte

+  segundo
norte
=  do norte

el  programa  debería  imprimir,  "¡Santo  cielo,  Fermat  estaba  equivocado!"  De  lo  contrario,  el  programa  
debería  imprimir  "No,  eso  no  funciona".

,
2.  Escriba  una  función  que  solicite  al  usuario  que  ingrese  valores  para ,  y  números   , los  convierte  en
enteros,  y  los  use  para  verificar  si  violan  el  teorema  de  Fermat.

Ejercicio  5.3.  Si  le  dan  tres  palos,  es  posible  que  pueda  o  no  colocarlos  en  un  triángulo.
Por  ejemplo,  si  uno  de  los  palos  mide  12  pulgadas  de  largo  y  los  otros  dos  miden  una  pulgada  de  largo,  no  podrá  
hacer  que  los  palos  cortos  se  junten  en  el  medio.  Para  tres  longitudes  cualesquiera,  hay  una  prueba  simple  para  
ver  si  es  posible  formar  un  triángulo:

Si  alguna  de  las  tres  longitudes  es  mayor  que  la  suma  de  las  otras  dos,  entonces  no  se  puede  
formar  un  triángulo.  De  lo  contrario,  puedes.  (Si  la  suma  de  dos  longitudes  es  igual  a  la  tercera,  
forman  lo  que  se  llama  un  triángulo  "degenerado").

1.  Escriba  una  función  llamada  que  tome  tres  números  enteros  como  argumentos  y  que  imprima  "Sí"  o  "No",  
dependiendo  de  si  puede  o  no  formar  un  triángulo  con  palos  con  las  longitudes  dadas.

2.  Escriba  una  función  que  solicite  al  usuario  que  ingrese  tres  longitudes  de  palo,  las  convierta  en  números  enteros,
y  usos para  comprobar  si  los  palos  con  las  longitudes  dadas  pueden  formar  un  triángulo.

Ejercicio  5.4.  ¿Cuál  es  la  salida  del  siguiente  programa?  Dibuje  un  diagrama  de  pila  que  muestre  el  estado  del  
programa  cuando  imprime  el  resultado.

1.  ¿Qué  pasaría  si  llamaras  a  esta  función  así: ?

2.  Escriba  una  cadena  de  documentación  que  explique  todo  lo  que  alguien  necesitaría  saber  para  usar  esta  
función  (y  nada  más).

Los  siguientes  ejercicios  utilizan  el   módulo,  descrito  en  el  Capítulo  4:
Ejercicio  5.5.  Lea  la  siguiente  función  y  vea  si  puede  averiguar  lo  que  hace  (vea  los  ejemplos  en  el  Capítulo  4).  
Luego  ejecútelo  y  vea  si  lo  hizo  bien.
Machine Translated by Google

5.14.  Ejercicios 49

Figura  5.2:  Una  curva  de  Koch.

Ejercicio  5.6.  La  curva  de  Koch  es  un  fractal  que  se  parece  a  la  figura  5.2.  Para  dibujar  una  curva  de  Koch  con  longitud  x,  todo  lo  que  
tienes  que  hacer  es

1.  Dibuja  una  curva  de  Koch  con  longitud  x/3.

2.  Gire  a  la  izquierda  60  grados.

3.  Dibujar  una  curva  de  Koch  con  longitud  x/3.

4.  Gire  a  la  derecha  120  grados.

5.  Dibuja  una  curva  de  Koch  con  longitud  x/3.

6.  Gire  a  la  izquierda  60  grados.

7.  Dibuja  una  curva  de  Koch  con  longitud  x/3.

La  excepción  es  si  x  es  menor  que  3:  en  ese  caso,  puedes  dibujar  una  línea  recta  con  longitud  x.

1.  Escribe  una  función  llamada que  toma  como  parámetros  una  tortuga  y  una  longitud,  y  que  utiliza  el
tortuga  para  dibujar  una  curva  de  Koch  con  la  longitud  dada.

2.  Escribe  una  función  llamada  copo   que  dibuja  tres  curvas  de  Koch  para  hacer  el  contorno  de  un
de  nieve.

Solución: .

3.  La  curva  de  Koch  se  puede  generalizar  de  varias  formas.  Vea  ejemplos  e  
implemente  su  favorito.
Machine Translated by Google

50 Capítulo  5.  Condicionales  y  recursión
Machine Translated by Google

Capítulo  6

Funciones  fructíferas

Muchas  de  las  funciones  de  Python  que  hemos  usado,  como  las  funciones  matemáticas,  producen  
valores  de  retorno.  Pero  todas  las  funciones  que  hemos  escrito  son  nulas:  tienen  un  efecto,  como  
imprimir  un  valor  o  mover  una  tortuga,  pero  no  tienen  un  valor  de  retorno.  En  este  capítulo  aprenderás  a  
escribir  funciones  fructíferas.

6.1  Valores  devueltos

Llamar  a  la  función  genera  un  valor  de  retorno,  que  normalmente  asignamos  a  una  variable  o  usamos  
como  parte  de  una  expresión.

Las  funciones  que  hemos  escrito  hasta  ahora  son  nulas.  Hablando  casualmente,  no  tienen  valor  de  
retorno;  más  precisamente,  su  valor  de  retorno  es .

En  este  capítulo,  (finalmente)  vamos  a  escribir  funciones  fructíferas.  El  primer  ejemplo  es  el  que   ,
devuelve  el  área  de  un  círculo  con  el  radio  dado:

Hemos  visto  que   declaración  anterior,  pero  en  una  función  fructífera  la declaración


incluye  una  expresión.  Esta  declaración  significa:  "Regrese  inmediatamente  de  esta  función  y  use  la  
siguiente  expresión  como  valor  de  retorno".  La  expresión  puede  ser  arbitrariamente  complicada,  por  lo  
que  podríamos  haber  escrito  esta  función  de  manera  más  concisa:

Por  otro  lado,  las  variables  temporales  como  pueden  facilitar  la  depuración.

A  veces  es  útil  tener  varias  declaraciones  de  retorno,  una  en  cada  rama  de  un  condicional:
Machine Translated by Google

52 Capítulo  6.  Funciones  fructíferas

Dado  que  estos Las  declaraciones  están  en  un  condicional  alternativo,  solo  se  ejecuta  uno.

Tan  pronto  como  se  ejecuta  una  declaración  de  devolución,  la  función  finaliza  sin  ejecutar  ninguna  
declaración  posterior.  El  código  que  aparece  después  de  una  instrucción,  o  cualquier  otro  lugar  al  que  nunca  
llegue  el  flujo  de  ejecución,  se  denomina  código  muerto.

En  una  función  fructífera,  es  una  buena  idea  asegurarse  de  que  todos  los  caminos  posibles  a  través  del  
programa  lleguen  a  una  declaración.  Por  ejemplo:

Esta  función  es  incorrecta  porque  si  pasa  a  ser  0,  ninguna  de  las  condiciones  es  verdadera  y  la  
función  termina  sin  llegar  a  una  declaración.  Si  el  flujo  de  ejecución  llega  al  final  de  una  función,  el  
valor  devuelto  es  que  no  es  el  valor  absoluto  
, de  0.

Por  cierto,  Python  proporciona  una  función  integrada  llamada que  calcula  valores  absolutos.

Como  ejercicio,  escribe   función  que  toma  dos  valores,  y , y  vuelve  si


, si , un  y  si .

6.2  Desarrollo  incremental
A  medida  que  escribe  funciones  más  grandes,  es  posible  que  dedique  más  tiempo  a  la  depuración.

Para  lidiar  con  programas  cada  vez  más  complejos,  es  posible  que  desee  probar  un  proceso  
llamado  desarrollo  incremental.  El  objetivo  del  desarrollo  incremental  es  evitar  largas  sesiones  de  
depuración  agregando  y  probando  solo  una  pequeña  cantidad  de  código  a  la  vez.

Como  ejemplo,  suponga  que  desea  encontrar  la  distancia  entre  dos  puntos,  dada  por  las  
coordenadas  (x1,  y1)  y  (x2,  y2).  Por  el  teorema  de  Pitágoras,  la  distancia  es:

distancia  =  (x2  −  x1) 2 +  (y2  −  y1) 2
El  primer  paso  es  considerar  cómo  debería  verse  una  función  en  Python.  En  otras  palabras,  ¿cuáles  
son  las  entradas  (parámetros)  y  cuál  es  la  salida  (valor  de  retorno)?

En  este  caso,  las  entradas  son  dos  puntos,  que  puedes  representar  usando  cuatro  números.  El  
valor  devuelto  es  la  distancia  representada  por  un  valor  de  coma  flotante.

Inmediatamente  puede  escribir  un  esquema  de  la  función:
Machine Translated by Google

6.2.  Desarrollo  incremental 53

Obviamente,  esta  versión  no  calcula  distancias;  siempre  devuelve  cero.  Pero  es  sintácticamente  
correcto  y  funciona,  lo  que  significa  que  puedes  probarlo  antes  de  complicarlo  más.

Para  probar  la  nueva  función,  llámela  con  argumentos  de  ejemplo:

Elegí  estos  valores  para  que  la  distancia  horizontal  sea  3  y  la  distancia  vertical  sea  4;  así  el  
resultado  es  5,  la  hipotenusa  de  un  triángulo  rectángulo  3­4­5.  Al  probar  una  función,  es  útil  
saber  la  respuesta  correcta.
En  este  punto,  hemos  confirmado  que  la  función  es  sintácticamente  correcta  y  podemos  
comenzar  a  agregar  código  al  cuerpo.  Un  siguiente  paso  razonable  es  encontrar  las  diferencias  
x2  −  x1  e  y2  −  y1.  La  próxima  versión  almacena  esos  valores  en  variables  temporales  y  los  imprime.

y
Si  la  función  funciona,  debería  mostrarse.  Si  es  así,  sabemos   .
que  la  función  
obtiene  los  
argumentos  correctos  y  realiza  el  primer  cálculo  correctamente.  Si  no,  solo  hay  unas  pocas  
líneas  para  verificar.
A  continuación  calculamos  la  suma  de  los  cuadrados  de  y :

Nuevamente,  ejecutaría  el  programa  en  esta  etapa  y  verificaría  la  salida  (que  debería  ser  25).  
Finalmente,  puede  usar  para  calcular  y  devolver  el  resultado:

Si  eso  funciona  correctamente,  ya  está.  De  lo  contrario,  es  posible  que  desee  imprimir  el  valor  de  antes  
de  la  declaración  de  devolución.

La  versión  final  de  la  función  no  muestra  nada  cuando  se  ejecuta;  solo  devuelve  un  valor.  Las  
declaraciones  que  escribimos  son  útiles  para  la  depuración,  pero  una  vez  que  la  función  
funcione,  debe  eliminarlas.  Este  tipo  de  código  se  llama  andamiaje  porque  es  útil  para  construir  
el  programa  pero  no  es  parte  del  producto  final.
Cuando  comience,  debe  agregar  solo  una  línea  o  dos  de  código  a  la  vez.  A  medida  que  adquiera  más  
experiencia,  es  posible  que  se  encuentre  escribiendo  y  depurando  fragmentos  más  grandes.  De  cualquier  
manera,  el  desarrollo  incremental  puede  ahorrarle  mucho  tiempo  de  depuración.

Los  aspectos  clave  del  proceso  son:
Machine Translated by Google

54 Capítulo  6.  Funciones  fructíferas

1.  Comience  con  un  programa  de  trabajo  y  realice  pequeños  cambios  incrementales.  En  cualquier  momento,  si
hay  un  error,  debe  tener  una  buena  idea  de  dónde  está.

2.  Use  variables  para  contener  valores  intermedios  para  que  pueda  mostrarlos  y  verificarlos.

3.  Una  vez  que  el  programa  esté  funcionando,  es  posible  que  desee  eliminar  algunos  de  
los  andamios  o  consolidar  varias  declaraciones  en  expresiones  compuestas,  pero  solo  
si  no  dificulta  la  lectura  del  programa.

Como  ejercicio,  use  el  desarrollo  incremental  para  escribir  una  función  que  devuelva  la  longitud  de  la  
hipotenusa  de  un  triángulo  rectángulo  dadas  las  longitudes  de  los  otros  dos  catetos  como  argumentos.  
Registre  cada  etapa  del  proceso  de  desarrollo  a  medida  que  avanza.

6.3  Composición
Como  ya  debería  esperar,  puede  llamar  a  una  función  desde  otra.  Como  ejemplo,  
escribiremos  una  función  que  toma  dos  puntos,  el  centro  del  círculo  y  un  punto  en  el  
perímetro,  y  calcula  el  área  del  círculo.

Suponga  que  el  punto  central  está  almacenado  en  las  variables  y  ,y  el  punto  del  perímetro  
está  en  y .  El  primer  paso  es  encontrar  el  radio  del  círculo,  que  es  la  distancia  entre  los  dos  
puntos.  Acabamos  de  escribir  una  función, , eso  hace  eso:

El  siguiente  paso  es  encontrar  el  área  de  un  círculo  con  ese  radio;  acabamos  de  escribir  eso,  también:

Encapsulando  estos  pasos  en  una  función,  obtenemos:

y el  desarrollo  y  la  depuración,  pero  una  vez  que  el  programa  
Las  variables  temporales  son  útiles  para  
está  funcionando,  podemos  hacerlo  más  conciso  componiendo  las  llamadas  a  funciones:

6.4  Funciones  booleanas
Las  funciones  pueden  devolver  valores  booleanos,  lo  que  suele  ser  conveniente  para  ocultar  pruebas  complicadas  
en  funciones  secundarias.  Por  ejemplo:
Machine Translated by Google

6.5.  Más  recursividad 55

Es  común  dar  nombres  de  funciones  booleanas  que  suenen  como  preguntas  de  sí/no;  devuelve  cualquiera  
para  indicar  si  es  divisible  
o por .

Aquí  hay  un  ejemplo:

El  resultado  del  operador  es  un  booleano,  por  lo  que  podemos  escribir  la  función  de  manera  más  concisa  
devolviéndola  directamente:

Las  funciones  booleanas  se  utilizan  a  menudo  en  declaraciones  condicionales:

Puede  ser  tentador  escribir  algo  como:

Pero  la  comparación  adicional  es  innecesaria.

Como  ejercicio,  escribe  una  función que  regresa si  x  ≤  y  ≤  z  o


de  lo  contrario.

6.5  Más  recursividad
Solo  hemos  cubierto  un  pequeño  subconjunto  de  Python,  pero  es  posible  que  le  interese  saber  que  este  
subconjunto  es  un  lenguaje  de  programación  completo,  lo  que  significa  que  todo  lo  que  se  puede  calcular  se  
puede  expresar  en  este  lenguaje.  Cualquier  programa  que  se  haya  escrito  podría  reescribirse  usando  solo  
las  características  del  lenguaje  que  ha  aprendido  hasta  ahora  (en  realidad,  necesitaría  algunos  comandos  
para  controlar  dispositivos  como  el  mouse,  discos,  etc.,  pero  eso  es  todo).

Demostrar  esa  afirmación  es  un  ejercicio  no  trivial  realizado  por  primera  vez  por  Alan  Turing,  uno  de  los  
primeros  científicos  informáticos  (algunos  dirían  que  era  matemático,  pero  muchos  de  los  primeros  científicos  
informáticos  comenzaron  como  matemáticos).  En  consecuencia,  se  conoce  como  la  Tesis  de  Turing.  Para  
una  discusión  más  completa  (y  precisa)  de  la  tesis  de  Turing,  recomiendo  el  libro  de  Michael  Sipser  
Introducción  a  la  teoría  de  la  computación.

Para  darle  una  idea  de  lo  que  puede  hacer  con  las  herramientas  que  ha  aprendido  hasta  ahora,  evaluaremos  
algunas  funciones  matemáticas  definidas  recursivamente.  Una  definición  recursiva  es  similar  a  una  definición  
circular,  en  el  sentido  de  que  la  definición  contiene  una  referencia  a  la  cosa  que  se  define.  Una  definición  
verdaderamente  circular  no  es  muy  útil:

vorpal:  Un  adjetivo  usado  para  describir  algo  que  es  vorpal.

Si  vio  esa  definición  en  el  diccionario,  es  posible  que  se  moleste.  Por  otro  lado,  si  buscó  la  definición  de  la  
función  factorial,  denotada  con  el  símbolo !,  podría  obtener  algo  como  esto:

0!  =  1

¡norte!  =  n(n  −  1)!
Machine Translated by Google

56 Capítulo  6.  Funciones  fructíferas

Esta  definición  dice  que  el  factorial  de  0  es  1,  y  el  factorial  de  cualquier  otro  valor,  n,  es  n  multiplicado  
por  el  factorial  de  n  −  1.

¡Así  que  3!  es  3  por  2!,  que  es  2  por  1!,  que  es  1  por  0!.  ¡Poniéndolo  todo  junto,  3!  es  igual  a  3  por  2  
por  1  por  1,  que  es  6.

Si  puede  escribir  una  definición  recursiva  de  algo,  puede  escribir  un  programa  Python  para  evaluarlo.  
El  primer  paso  es  decidir  cuáles  deben  ser  los  parámetros.  En  este  caso  debe  quedar  claro  que  toma  
un  número  entero:

Si  el  argumento  resulta  ser  0,  todo  lo  que  tenemos  que  hacer  es  devolver  1:

De  lo  contrario,  y  esta  es  la  parte  interesante,  tenemos  que  hacer  una  llamada  recursiva  para  
encontrar  el  factorial  de  n  −  1  y  luego  multiplicarlo  por  n:

El  flujo  de  ejecución  de  este  programa  es  similar  al  flujo  de  lo  que   en  la  Sección  5.8.  Si
llamamos  con  el  valor  3:

Como  3  no  es  0,  tomamos  la  segunda  rama  y  calculamos  el  factorial  de ...

Como  2  no  es  0,  tomamos  la  segunda  rama  y  calculamos  el  factorial  de ...

Como  1  no  es  0,  tomamos  la  segunda  rama  y  calculamos  el  factorial  de
...

Dado  que  0  es  igual  a  0,  tomamos  la  primera  rama  y  devolvemos  1  
sin  realizar  más  llamadas  recursivas.

El  valor  devuelto,  1,  se  multiplica  por  n,  que  es  1,  y  se  devuelve  el  resultado.

El  valor  devuelto,  1,  se  multiplica  por  n,  que  es  2,  y  se  devuelve  el  resultado.

El  valor  de  retorno  (2)  se  multiplica  por  n,  que  es  3,  y  el  resultado,  6,  se  convierte  en  el  valor  de  
retorno  de  la  llamada  de  función  que  inició  todo  el  proceso.

La  figura  6.1  muestra  cómo  se  ve  el  diagrama  de  pila  para  esta  secuencia  de  llamadas  a  funciones.

Los  valores  devueltos  se  muestran  pasando  de  vuelta  a  la  pila.  En  cada  marco,  el  valor  devuelto  es  
el  valor  del  cual  es  el  producto  d, e  y .

En  el  último  cuadro,  las  variables  locales   y no  existen,  porque  la  rama
que  las  crean  no  se  ejecutan.
Machine Translated by Google

6.6.  Salto  de  fe 57

__principal__
6
factorial norte 3  recursivo 2 resultado 6

2
factorial norte 2 recursivo 1 resultado 2

1
factorial norte 1 recursivo 1 resultado 1

1
factorial norte
0

Figura  6.1:  Diagrama  de  pila.

6.6  Acto  de  fe
Seguir  el  flujo  de  ejecución  es  una  forma  de  leer  programas,  pero  puede  volverse  abrumador  
rápidamente.  Una  alternativa  es  lo  que  yo  llamo  el  “salto  de  fe”.  Cuando  llega  a  una  llamada  de  
función,  en  lugar  de  seguir  el  flujo  de  ejecución,  asume  que  la  función  funciona  correctamente  y  
devuelve  el  resultado  correcto.

De  hecho,  ya  está  practicando  este  acto  de  fe  cuando  utiliza  las  funciones  integradas.  Cuando  llama  
o
a ,  no  examina  los  cuerpos  
de  esas  funciones.  Simplemente  asume  que  funcionan  porque  las  
personas  que  escribieron  las  funciones  integradas  eran  buenos  programadores.

Lo  mismo  es  cierto  cuando  llamas  a  una  de  tus  propias  funciones.  Por  ejemplo,  en  la  Sección  6.4,  
escribimos  una  función  llamada  que  determina  si  un  número  es  divisible  por  otro.  Una  vez  que  nos  
hayamos  convencido  de  que  esta  función  es  correcta,  examinando  el  código  y  probando,  podemos  
usar  la  función  sin  volver  a  mirar  el  cuerpo.

Lo  mismo  ocurre  con  los  programas  recursivos.  Cuando  llegue  a  la  llamada  recursiva,  en  lugar  de  
seguir  el  flujo  de  ejecución,  debe  suponer  que  la  llamada  recursiva  funciona  (devuelve  el  resultado  
correcto)  y  luego  pregúntese:  "Suponiendo  que  puedo  encontrar  el  factorial  de  n  −  1,  ¿ puedo  
calcular  el  factorial  de  n?  Está  claro  que  puedes,  multiplicando  por  n.

Por  supuesto,  es  un  poco  extraño  asumir  que  la  función  funciona  correctamente  cuando  no  has  
terminado  de  escribirla,  ¡pero  por  eso  se  llama  un  acto  de  fe!

6.7  Un  ejemplo  más
Después   , el  ejemplo  más  común  de  una  función  matemática  definida  recursivamente
de  ción  es , que  tiene  la  siguiente  definición  (ver
):

fibonacci(0)  =  0  
fibonacci(1)  =  1  
fibonacci(n)  =  fibonacci(n  −  1)  +  fibonacci(n  −  2)

Traducido  a  Python,  se  ve  así:
Machine Translated by Google

58 Capítulo  6.  Funciones  fructíferas

Si  intenta  seguir  el  flujo  de  ejecución  aquí,  incluso  para  valores  bastante  pequeños  de  n,  su  cabeza  explota.  
Pero  de  acuerdo  con  el  acto  de  fe,  si  asume  que  las  dos  llamadas  recursivas  funcionan  correctamente,  
entonces  está  claro  que  obtiene  el  resultado  correcto  al  sumarlas.

6.8  Tipos  de  comprobación

¿Qué  pasa  si  llamamos? y  darle  1.5  como  argumento?

Parece  una  recursividad  infinita.  ¿Como  puede  ser?  La  función  tiene  un  caso  base:  cuando .  Pero  si  no  es  
un  número  entero,  podemos  perder  el  caso  base  y  repetir  para  siempre.

En  la  primera  llamada  recursiva,  el  valor  de  es  0,5.  En  el  siguiente,  es  ­0.5.  A  partir  de  ahí,  se  vuelve  más  
pequeño  (más  negativo),  pero  nunca  será  0.

Tenemos  dos  opciones.  Podemos  intentar  generalizar  la  función  para  que  funcione  con  números  de  punto  
flotante,  o  podemos  comprobar  el  tipo  de  su  argumento.  La  primera  opción  se  llama  función  gamma  y  está  un  
poco  más  allá  del  alcance  de  este  libro.  Así  que  vamos  a  por  el  segundo.

Podemos  usar  la  función  incorporada  para  verificar  el  tipo  del  argumento.  Mientras  estamos  en  eso,  también  
podemos  asegurarnos  de  que  el  argumento  sea  positivo:

El  primer  caso  base  maneja  números  no  enteros;  el  segundo  maneja  enteros  negativos.  En  ambos  casos,  el  
programa  imprime  un  mensaje  de  error  y  regresa  para  indicar  que  algo  salió  mal:
Machine Translated by Google

6.9.  depuración 59

Si  superamos  ambas  comprobaciones,  sabemos  que  n  es  un  número  entero  no  negativo,  por  lo  que  podemos  
probar  que  la  recursividad  termina.

Este  programa  demuestra  un  patrón  a  veces  llamado  guardián.  Los  dos  primeros  condicionales  actúan  como  
guardianes,  protegiendo  el  código  que  sigue  de  valores  que  podrían  causar  un  error.  Los  guardianes  permiten  
probar  la  exactitud  del  código.

En  la  Sección  11.4  veremos  una  alternativa  más  flexible  a  la  impresión  de  un  mensaje  de  error:  generar  una  
excepción.

6.9  Depuración
Dividir  un  programa  grande  en  funciones  más  pequeñas  crea  puntos  de  control  naturales  para  la  depuración.
Si  una  función  no  funciona,  hay  tres  posibilidades  a  considerar:

•  Hay  algo  mal  con  los  argumentos  que  recibe  la  función;  una  condición  previa
es  violado

•  Hay  algún  problema  con  la  función;  se  viola  una  poscondición.

•  Hay  algún  problema  con  el  valor  de  retorno  o  la  forma  en  que  se  utiliza.

Para  descartar  la  primera  posibilidad,  puede  agregar  una  declaración  al  comienzo  de  la  función  y  mostrar  los  
valores  de  los  parámetros  (y  tal  vez  sus  tipos).  O  puede  escribir  código  que  compruebe  explícitamente  las  
condiciones  previas.

Si  los  parámetros  se  ven  bien,  agregue  una  declaración  antes  de  cada  declaración  y  muestre  el  valor  de  retorno.  
Si  es  posible,  verifique  el  resultado  a  mano.  Considere  llamar  a  la  función  con  valores  que  faciliten  la  verificación  
del  resultado  (como  en  la  Sección  6.2).

Si  la  función  parece  estar  funcionando,  mire  la  llamada  a  la  función  para  asegurarse  de  que  el  valor  devuelto  se  
esté  usando  correctamente  (¡o  no  se  esté  usando!).

Agregar  declaraciones  de  impresión  al  principio  y  al  final  de  una  función  puede  ayudar  a  que  el  flujo  de  ejecución  
sea  más  visible.  Por  ejemplo,  aquí  hay  una  versión  de  declaraciones  con  impresión:

es  una  cadena  de  caracteres  de  espacio  que  controla  la  sangría  de  la  salida.  Aquí  está  el  resultado  de
:
Machine Translated by Google

60 Capítulo  6.  Funciones  fructíferas

Si  está  confundido  acerca  del  flujo  de  ejecución,  este  tipo  de  salida  puede  ser  útil.  Se  necesita  algo  de  tiempo  para  
desarrollar  un  andamiaje  eficaz,  pero  un  poco  de  andamiaje  puede  ahorrar  una  gran  cantidad  de  depuración.

6.10  Glosario
variable  temporal:  una  variable  utilizada  para  almacenar  un  valor  intermedio  en  un  cálculo  complejo
ción

código  muerto:  Parte  de  un  programa  que  nunca  se  puede  ejecutar,  a  menudo  porque  aparece  después  de  un
declaración.

desarrollo  incremental:  un  plan  de  desarrollo  de  programa  destinado  a  evitar  la  depuración  por
agregando  y  probando  solo  una  pequeña  cantidad  de  código  a  la  vez.

scaffolding:  Código  que  se  utiliza  durante  el  desarrollo  del  programa,  pero  no  es  parte  de  la  final
versión.

guardián:  un  patrón  de  programación  que  usa  una  declaración  condicional  para  verificar  y
dle  circunstancias  que  podrían  causar  un  error.

6.11  Ejercicios

Ejercicio  6.1.  Dibuje  un  diagrama  de  pila  para  el  siguiente  programa.  ¿Qué  imprime  el  programa?
Machine Translated by Google

6.11.  Ejercicios 61

Ejercicio  6.2.  La  función  de  Ackermann,  A(m,  n),  se  define:

n  +  1 si  m  =  0  
A(m,  n)  = A(m  −  1,  1) si  m  >  0  y  n  =  0  
A(m  −  1,  A(m,  n  −  1))  si  m  >  0  y  n  >  0.

Ver .  Escriba  una  función  llamada  que  evalúe  la  función  de  Ackermann.  Usa  tu  función  para  evaluar  cuál  
debería  ser  125.  ¿Qué  sucede  con  valores  más  grandes  de  y ?  Solución: ,

.
Ejercicio  6.3.  Un  palíndromo  es  una  palabra  que  se  escribe  igual  al  derecho  y  al  revés,  como  "noon"  y  "redivider".  
Recursivamente,  una  palabra  es  un  palíndromo  si  la  primera  y  la  última  letra  son  iguales  y  la  del  medio  es  un  
palíndromo.

Las  siguientes  son  funciones  que  toman  un  argumento  de  cadena  y  devuelven  la  primera,  la  última  y  la  letra  del  medio:

Veremos  cómo  funcionan  en  el  Capítulo  8.

1.  Escriba  estas  funciones  en  un  archivo  llamado  y  pruébelas.  ¿Qué  pasa  si  llamas  con  una  cadena  de  dos  
letras?  ¿Una  carta?  ¿Qué  pasa  con  la  cadena  vacía,  que  está  escrita  y  no  contiene  letras?

2.  Escribe  una  función  llamada   que  toma  un  argumento  de  cadena  y  devuelve  si  es  lo  
es  un  palíndromo  y  para   contrario.  Recuerda  que  puedes  usar  la  función  incorporada
verificar  la  longitud  de  una  cadena.

Solución:   .
Ejercicio  6.4.  Un  número,  a,  es  una  potencia  de  b  si  es  divisible  por  b  y  a/b  es  una  potencia  de  b.  Escriba  una  
función  llamada  que  tome  parámetros  y  devuelva  si  es  una  potencia  de .  Nota:  tendrás  que  pensar  en  el  caso  
base.
Ejercicio  6.5.  El  máximo  común  divisor  (MCD)  de  a  y  b  es  el  número  más  grande  que  divide  a  ambos  sin  resto.

Una  forma  de  encontrar  el  MCD  de  dos  números  se  basa  en  la  observación  de  que  si  r  es  el  resto  cuando  a  se  
divide  entre  b,  entonces  mcd(a,  b)  =  mcd(b,r).  Como  caso  base,  podemos  usar  mcd(a,  0)  =  a.

Escribe  una  función  llamada que  toma  parámetros  y  devuelve  su  máximo  común  divisor.

Crédito:  Este  ejercicio  se  basa  en  un  ejemplo  de  la  Estructura  e  Interpretación  de  Programas  de  Computadora  
de  Abelson  y  Sussman.
Machine Translated by Google

62 Capítulo  6.  Funciones  fructíferas
Machine Translated by Google

Capítulo  7

Iteración

Este  capítulo  trata  sobre  la  iteración,  que  es  la  capacidad  de  ejecutar  un  bloque  de  sentencias  repetidamente.
Vimos  una  especie  de  iteración,  usando  recursividad,  en  la  Sección  5.8.  Vimos  otro  tipo,  usando  un  bucle,  en  
la  Sección  4.2.  En  este  capítulo  veremos  otro  tipo  más,  usando  una  instrucción.
Pero  primero  quiero  hablar  un  poco  más  sobre  la  asignación  de  variables.

7.1  Reasignación
Como  habrá  descubierto,  es  legal  realizar  más  de  una  asignación  a  la  misma  variable.  Una  nueva  asignación  
hace  que  una  variable  existente  se  refiera  a  un  nuevo  valor  (y  deje  de  referirse  al  valor  anterior).

La  primera  vez  que  mostramos ,  su  valor  es  5;  la  segunda  vez,  su  valor  es  7.

La  figura  7.1  muestra  cómo  se  ve  la  reasignación  en  un  diagrama  de  estado.

En  este  punto  quiero  abordar  una  fuente  común  de  confusión.  Debido  a  que  Python  usa  el  signo  igual  ()  para  
la  asignación,  es  tentador  interpretar  una  declaración  como  una  proposición  matemática   como  matemático

de  igualdad;  es  decir,  la  afirmación  de  que  y  son  iguales.  Pero  esta  interpretación  es  incorrecta.

Primero,  la  igualdad  es  una  relación  simétrica  y  la  asignación  no  lo  es.  Por  ejemplo,  en  matemáticas,  si  a  =  
7  entonces  7  =  a.  Pero  en  Python,  la  declaración  es es  legal  y
no.

Además,  en  matemáticas,  una  proposición  de  igualdad  es  verdadera  o  falsa  para  todos  los  tiempos.  Si  a  =  b  
ahora,  entonces  a  siempre  será  igual  a  b.  En  Python,  una  declaración  de  asignación  puede  hacer  que  dos  
variables  sean  iguales,  pero  no  tienen  por  qué  permanecer  así:
Machine Translated by Google

64 Capítulo  7.  Iteración

5
X
7

Figura  7.1:  Diagrama  de  estado.

La  tercera  línea  cambia  el  valor  de  pero  no  cambia  el  valor  de  más  largo  igual. , por  lo  que  no  son

La  reasignación  de  variables  suele  ser  útil,  pero  debe  usarla  con  precaución.  Si  los  valores  de  las  
variables  cambian  con  frecuencia,  el  código  puede  resultar  difícil  de  leer  y  depurar.

7.2  Actualización  de  variables
Un  tipo  común  de  reasignación  es  una  actualización,  donde  el  nuevo  valor  de  la  variable  depende  
del  antiguo.

Esto  significa  "obtener  el  valor  actual  de , agregue  uno  y  luego  actualice  con  el  nuevo  valor  ".

Si  intenta  actualizar  una  variable  que  no  existe,  obtiene  un  error,  porque  Python  evalúa  el  lado  
derecho  antes  de  asignar  un  valor  a:

Antes  de  que  pueda  actualizar  una  variable,  debe  inicializarla ,  generalmente  con  una  asignación  
simple:

Actualizar  una  variable  sumando  1  se  denomina  incremento;  restar  1  se  llama  decremento.

7.3  El declaración
Las  computadoras  se  utilizan  a  menudo  para  automatizar  tareas  repetitivas.  Repetir  tareas  idénticas  o  
similares  sin  cometer  errores  es  algo  que  las  computadoras  hacen  bien  y  las  personas  mal.  En  un  
programa  de  computadora,  la  repetición  también  se  llama  iteración.

y
Ya  hemos  visto  dos  funciones,  que  iteran  usando  recursividad. ,
Debido  a  que  la  iteración  es  tan  común,  Python  proporciona  funciones  de  lenguaje  para  que  sea  más  fácil.  
Una  es  la  declaración  que  vimos  en  la  Sección  4.2.  Volveremos  a  eso  más  tarde.

otro  es  el declaración.  Aquí  hay  una  versión  de que  usa  un declaración:


Machine Translated by Google

7.3.  El declaración sesenta  y  cinco

Casi  se  puede  leer  el  comunicado  como  si  fuera  inglés.  Significa:  “Mientras  sea  mayor  que  0,  
muestra  el  valor  de  y  luego  disminuye .  Cuando  llegue  a  0,  muestre  la  palabra

Más  formalmente,  aquí  está  el  flujo  de  ejecución  para  un declaración:

1.  Determinar  si  la  condición  es  verdadera  o  falsa.

2.  Si  es  falso,  salga  de  la declaración  y  continuar  la  ejecución  en  la  próxima  declaración.

3.  Si  la  condición  es  verdadera,  ejecute  el  cuerpo  y  luego  regrese  al  paso  1.

Este  tipo  de  flujo  se  llama  bucle  porque  el  tercer  paso  vuelve  a  la  parte  superior.

El  cuerpo  del  ciclo  debe  cambiar  el  valor  de  una  o  más  variables  para  que  la  condición  se  vuelva  
falsa  eventualmente  y  el  ciclo  termine.  De  lo  contrario,  el  bucle  se  repetirá  para  siempre,  lo  que  
se  denomina  bucle  infinito.  Una  fuente  inagotable  de  diversión  para  los  informáticos  es  la  
observación  de  que  las  instrucciones  del  champú,  "Hacer  espuma,  enjuagar,  repetir",  son  un  
bucle  infinito.
En  el  caso  de  podemos  probar  
, que  el  ciclo  termina:  si  es  cero  o  negativo,  el  ciclo  nunca  se  ejecuta.  De  lo  
contrario,  se  vuelve  más  pequeño  cada  vez  que  pasa  por  el  bucle,  por  lo  que  eventualmente  tenemos  que  
llegar  a  0.

Para  algunos  otros  bucles,  no  es  tan  fácil  saberlo.  Por  ejemplo:

La  condición  para  este  ciclo  es   , por  lo  que  el  bucle  continuará  hasta  que  sea , que  hace


la  condición  falsa.

Cada  vez  que  pasa  por  el  ciclo,  el  programa  genera  el  valor  de  y  luego  verifica  si  es  par  o  impar.  
Si  es  par,  se  divide  por  2.  Si  es  impar,  el  valor  de  se  reemplaza  por  es  3,  los  valores  resultantes  
.  Por  ejemplo,  si  el  argumento  pasado  es  3,   de
10,  5,  16,  8,  4,  2,  1.

Dado  que  a  veces  aumenta  ya  veces  disminuye,  no  hay  una  prueba  obvia  de  que  alguna  vez  
,
llegue  a  1  o  de  que  el  programa  finalice.  Para  algunos  valores  particulares  de  podemos   probar  la  
terminación.  Por  ejemplo,  si  el  valor  inicial  es  una  potencia  de  dos,  será  par  cada  vez  que  pase  
por  el  ciclo  hasta  que  llegue  a  1.  El  ejemplo  anterior  termina  con  tal  secuencia,  comenzando  con  
16.

La  pregunta  difícil  es  si  podemos  probar  que  este  programa  termina  para  todos  los  valores  
positivos  de .  ¡Hasta  ahora,  nadie  ha  podido  probarlo  o  refutarlo!  (Ver
.)
Machine Translated by Google

66 Capítulo  7.  Iteración

Como  ejercicio,  reescriba  la  recursividad   de  la  Sección  5.8  usando  iteración  en  lugar  de
de  la  función.

7.4
A  veces  no  sabes  que  es  hora  de  terminar  un  ciclo  hasta  que  llegas  a  la  mitad  del  cuerpo.
En  ese  caso,  puede  usar  la  declaración  para  salir  del  bucle.

Por  ejemplo,  suponga  que  desea  recibir  información  del  usuario  hasta  que  escriba: .  Tú  podrías

La  condición  del  bucle  es , lo  cual  siempre  es  cierto,  por  lo  que  el  ciclo  se  ejecuta  hasta  que  llega  al  descanso
declaración.

Cada  vez  que  pasa,  le  indica  al  usuario  un  paréntesis  angular.  Si  el  usuario  escribe , la  
instrucción  sale  del  bucle.  De  lo  contrario,  el  programa  repite  lo  que  el  usuario  escriba  y  vuelve  al  
principio  del  bucle.  Aquí  hay  una  ejecución  de  muestra:

Esta  forma  de  escribir  bucles  es  común  porque  puede  verificar  la  condición  en  cualquier  lugar  del  bucle  
(no  solo  en  la  parte  superior)  y  puede  expresar  la  condición  de  parada  afirmativamente  ("detenerse  
cuando  esto  suceda")  en  lugar  de  negativamente  ("continuar  hasta  que  eso  suceda  ”).

7.5  Raíces  cuadradas
Los  bucles  se  usan  a  menudo  en  programas  que  calculan  resultados  numéricos  comenzando  con  una  
respuesta  aproximada  y  mejorándola  iterativamente.

Por  ejemplo,  una  forma  de  calcular  raíces  cuadradas  es  el  método  de  Newton.  Suponga  que  quiere  saber  
la  raíz  cuadrada  de  a.  Si  comienza  con  casi  cualquier  estimación,  x,  puede  calcular  una  mejor  estimación  
con  la  siguiente  fórmula:

x  +  a/xy  
= 2

Por  ejemplo,  si  a  es  4  y  x  es  3:
Machine Translated by Google

7.6.  Algoritmos 67

El  resultado  está  más  cerca  de  la  respuesta  correcta  (√  4  =  2).  Si  repetimos  el  proceso  con  la  nueva  estimación,  
se  acerca  aún  más:

Después  de  algunas  actualizaciones  más,  la  estimación  es  casi  exacta:

En  general,  no  sabemos  de  antemano  cuántos  pasos  se  necesitan  para  llegar  a  la  respuesta  correcta,  pero  
sabemos  cuándo  llegamos  allí  porque  la  estimación  deja  de  cambiar:

Cuando  podemos  
, parar.  Aquí  hay  un  ciclo  que  comienza  con  una  estimación  inicial,  y  la  mejora  hasta  que  deja  
de  cambiar:

Para  la  mayoría  de  los  valores  esto  funciona  bien,  pero  en  general  es  peligroso  probar  la  igualdad.
Los  valores  de  punto  flotante  son  solo  aproximadamente  correctos:  la  mayoría  de  los  números  racionales,  como  1/3,  y  
los  números  irracionales,  como  √  2,  no  se  pueden  representar  exactamente  con  un .

En  lugar  de  comprobar  si  y  son  exactamente  iguales,  es  más  seguro  utilizar  la  función  integrada  para  calcular  el  
ción valor  absoluto,  o  la  magnitud,  de  la  diferencia  entre  ellos:

Dónde tiene  un  valor  como eso  determina  qué  tan  cerca  está  lo  suficientemente  cerca.

7.6  Algoritmos
El  método  de  Newton  es  un  ejemplo  de  algoritmo:  es  un  proceso  mecánico  para  resolver  una  categoría  de  
problemas  (en  este  caso,  calcular  raíces  cuadradas).
Machine Translated by Google

68 Capítulo  7.  Iteración

Para  entender  qué  es  un  algoritmo,  puede  ser  útil  comenzar  con  algo  que  no  sea  un  algoritmo.  Cuando  
aprendiste  a  multiplicar  números  de  un  solo  dígito,  probablemente  memorizaste  la  tabla  de  multiplicar.  En  efecto,  
memorizaste  100  soluciones  específicas.  Ese  tipo  de  conocimiento  no  es  algorítmico.

Pero  si  eras  "perezoso",  es  posible  que  hayas  aprendido  algunos  trucos.  Por  ejemplo,  para  encontrar  el  producto  
de  n  y  9,  puedes  escribir  n  −  1  como  el  primer  dígito  y  10  −  n  como  el  segundo  dígito.
Este  truco  es  una  solución  general  para  multiplicar  cualquier  número  de  un  solo  dígito  por  9.  ¡Eso  es  un  algoritmo!

De  manera  similar,  las  técnicas  que  aprendiste  para  la  suma  con  acarreo,  la  resta  con  préstamo  y  la  división  
larga  son  todos  algoritmos.  Una  de  las  características  de  los  algoritmos  es  que  no  requieren  ninguna  inteligencia  
para  llevarse  a  cabo.  Son  procesos  mecánicos  en  los  que  cada  paso  se  sigue  del  anterior  de  acuerdo  con  un  
conjunto  simple  de  reglas.

Ejecutar  algoritmos  es  aburrido,  pero  diseñarlos  es  interesante,  intelectualmente  desafiante  y  una  parte  central  
de  las  ciencias  de  la  computación.

Algunas  de  las  cosas  que  la  gente  hace  de  forma  natural,  sin  dificultad  ni  pensamiento  consciente,  son  las  más  
difíciles  de  expresar  algorítmicamente.  Comprender  el  lenguaje  natural  es  un  buen  ejemplo.
Todos  lo  hacemos,  pero  hasta  ahora  nadie  ha  sido  capaz  de  explicar  cómo  lo  hacemos,  al  menos  no  en  forma  
de  algoritmo.

7.7  Depuración
A  medida  que  comience  a  escribir  programas  más  grandes,  es  posible  que  dedique  más  tiempo  a  la  depuración.  
Más  código  significa  más  posibilidades  de  cometer  un  error  y  más  lugares  para  que  los  errores  se  escondan.

Una  forma  de  reducir  el  tiempo  de  depuración  es  "depuración  por  bisección".  Por  ejemplo,  si  hay  100  líneas  en  
su  programa  y  las  verifica  una  a  la  vez,  tomaría  100  pasos.

En  su  lugar,  trate  de  dividir  el  problema  por  la  mitad.  Busque  en  la  mitad  del  programa,  o  cerca  de  él,  un  valor  
intermedio  que  pueda  verificar.  Agregue  una  declaración  (o  algo  más  que  tenga  un  efecto  verificable)  y  ejecute  
el  programa.

Si  la  verificación  del  punto  medio  es  incorrecta,  debe  haber  un  problema  en  la  primera  mitad  del  programa.
Si  es  correcto,  el  problema  está  en  la  segunda  mitad.

Cada  vez  que  realiza  una  comprobación  como  esta,  reduce  a  la  mitad  el  número  de  líneas  que  tiene  que  buscar.
Después  de  seis  pasos  (que  son  menos  de  100),  tendrá  una  o  dos  líneas  de  código,  al  menos  en  teoría.

En  la  práctica,  no  siempre  está  claro  cuál  es  el  “medio  del  programa”  y  no  siempre  es  posible  comprobarlo.  No  
tiene  sentido  contar  líneas  y  encontrar  el  punto  medio  exacto.  En  su  lugar,  piense  en  lugares  del  programa  
donde  puede  haber  errores  y  lugares  donde  es  fácil  marcar.  A  continuación,  elija  un  lugar  donde  crea  que  las  
posibilidades  de  que  el  error  esté  antes  o  después  de  la  comprobación  son  aproximadamente  las  mismas.

7.8  Glosario
reasignación:  Asignar  un  nuevo  valor  a  una  variable  que  ya  existe.
Machine Translated by Google

7.9.  Ejercicios 69

actualizar:  Una  asignación  donde  el  nuevo  valor  de  la  variable  depende  del  anterior.

inicialización:  una  asignación  que  da  un  valor  inicial  a  una  variable  que  se  actualizará.

incremento:  una  actualización  que  aumenta  el  valor  de  una  variable  (a  menudo  en  uno).

decremento:  Una  actualización  que  disminuye  el  valor  de  una  variable.

iteración:  ejecución  repetida  de  un  conjunto  de  declaraciones  utilizando  una  llamada  de  función  recursiva
o  un  bucle.

bucle  infinito:  Un  bucle  en  el  que  la  condición  de  terminación  nunca  se  cumple.

algoritmo:  Un  proceso  general  para  resolver  una  categoría  de  problemas.

7.9  Ejercicios

Ejercicio  7.1.  Copie  el  bucle  de  la  Sección  7.5  y  encapsúlelo  en  una  función  llamada  que  toma  como  
parámetro,  elige  un  valor  razonable  de  y  devuelve  una  estimación  de  la  raíz  cuadrada  de
.

Para  probarlo,  escribe  una  función  llamada que  imprime  una  tabla  como  esta:

La  primera  columna  es  un  número,  a;  la  segunda  columna  es  la  raíz  cuadrada  de  a  calculada  con   ;
la  tercera  columna  es  la  raíz  cuadrada  calculada  por ;  la  cuarta  columna  es  el  valor  absoluto  de  la  diferencia  
entre  las  dos  estimaciones.
Ejercicio  7.2.  La  función  incorporada  toma  una  cadena  y  la  evalúa  usando  el  intérprete  de  Python.  Por  
ejemplo:

Escriba  una  función  llamada  que  solicite  iterativamente  al  usuario,  tome  la  entrada  resultante  y  la  evalúe  
,
usando  e  imprima  el  resultado.

Debe  continuar  hasta  que  el  usuario  ingrese   , y  luego  devolver  el  valor  de  la  última  expresión  que
evaluado.
Machine Translated by Google

70 Capítulo  7.  Iteración

Ejercicio  7.3.  El  matemático  Srinivasa  Ramanujan  encontró  una  serie  infinita  que  puede  usarse  para  generar  una  
aproximación  numérica  de  1/π:

1 2  √  2 ∞ (4k)!(1103  +  26390k)  ∑  
=
π 9801k  (k!)  43964k
=0

Escribe  una  función   que  usa  esta  fórmula  para  calcular  y  devolver  una  estimación  del  bucle  
llamada  π.  Debería  usar  un para  calcular  los  términos  de  la  suma  hasta  que  el  último  término  sea  menor  que
(que  es  la  notación  de  Python  para  10−15).  Puedes  comprobar  el  resultado  comparándolo  con .

Solución: .
Machine Translated by Google

Capítulo  8

Instrumentos  de  cuerda

Las  cadenas  no  son  como  los  números  enteros,  flotantes  y  booleanos.  Una  cadena  es  una  secuencia,  lo  
que  significa  que  es  una  colección  ordenada  de  otros  valores.  En  este  capítulo,  verá  cómo  acceder  a  los  
caracteres  que  forman  una  cadena  y  aprenderá  algunos  de  los  métodos  que  proporcionan  las  cadenas.

8.1  Una  cadena  es  una  secuencia
Una  cadena  es  una  secuencia  de  caracteres.  Puede  acceder  a  los  caracteres  de  uno  en  uno  con  el  
operador  de  paréntesis:

La  segunda  instrucción  selecciona  el  carácter  número  1  de y  lo  asigna  a .

La  expresión  entre  paréntesis  se  llama  índice.  El  índice  indica  qué  carácter  de  la  secuencia  desea  
(de  ahí  el  nombre).

Pero  es  posible  que  no  obtenga  lo  que  espera:

Para  la  mayoría  de  las  personas,  la  primera   es , no .  Pero  para  los  informáticos,  la
letra  del  índice  es  un  desplazamiento  desde  el  principio  de  la  cadena  y  el  desplazamiento  de  la  primera  letra  es  cero.

También  lo  es  la  letra  0  ("cero­eth")   , es  la  1ª  letra  ("one­eth"),  y  es  la  2ª
de  la  letra  ("dos­eth").

Como  índice  puede  utilizar  una  expresión  que  contenga  variables  y  operadores:
Machine Translated by Google

72 Capítulo  8.  Cuerdas

Pero  el  valor  del  índice  tiene  que  ser  un  número  entero.  De  lo  contrario  obtienes:

8.2

es  una  función  integrada  que  devuelve  el  número  de  caracteres  en  una  cadena:

Para  obtener  la  última  letra  de  una  cadena,  es  posible  que  tenga  la  tentación  de  probar  algo  como  esto:

La  razón  del  índice  6.  Como  comenzamos  
es  que  an  o  
contar   desde  
en cero,  las  seis  letras  están  numeradas  del  0  al  
hay  letra  
5.  Para  obtener  el  último  carácter,  debe  restar  1  de
:

O  puede  usar  índices  negativos,  que  cuentan  hacia  atrás  desde  el  final  de  la  cadena.  produce  la  última  
letra,  produce  la  penúltima  y  así  sucesivamente.  expresión

8.3  Recorrido  con  un bucle
Una  gran  cantidad  de  cálculos  implican  procesar  una  cadena  de  un  carácter  a  la  vez.  A  menudo  
comienzan  desde  el  principio,  seleccionan  cada  personaje  por  turno,  le  hacen  algo  y  continúan  hasta  el  
final.  Este  patrón  de  procesamiento  se  llama  recorrido.  Una  forma  de  escribir  un  recorrido  es  con  un
bucle:

Este  bucle  atraviesa  la  cadena  y  muestra  cada  letra  en  una  línea  por  sí  misma.  La  condición  del  ciclo  es  
, así  que  
igual  a  la  longitud  de  la  cadena,   la   condición  es  falsa  y  el  cuerpo  del  ciclo  no  se  ejecuta.  El  último  carácter  
cuando

al  que  se  accede  es  el  que  tiene  el  índice,  que  es  el  último  carácter  de  la  cadena.
,

Como  ejercicio,  escriba  una  función  que  tome  una  cadena  como  argumento  y  muestre  las  letras  al  revés,  
una  por  línea.

Otra  forma  de  escribir  un  recorrido  es  con  un bucle:
Machine Translated by Google

8.4.  Rebanadas  de  cuerda 73

fruta ' '


plátano
índice  0  1  2  3  4  5  6

Figura  8.1:  Índices  de  corte.

Cada  vez  que  se  recorre  el  bucle,  el  siguiente  carácter  de  la  cadena  se  asigna  a  la  variable
.  El  bucle  continúa  hasta  que  no  quedan  caracteres.

El  siguiente  ejemplo  muestra  cómo  usar  la  concatenación  (suma  de  cadenas)  y  un  bucle  para  generar  una  serie  
abecedaria  (es  decir,  en  orden  alfabético).  En  el  libro  de  Robert  McCloskey  Abran  paso  a  los  patitos,  los  nombres  
de  los  patitos  son  Jack,  Kack,  Lack,  Mack,  Nack,  Ouack,  Pack  y  Quack.  Este  ciclo  genera  estos  nombres  en  orden:

La  salida  es:

Por  supuesto,  eso  no  es  del  todo  correcto  porque  "Ouack"  y  "Quack"  están  mal  escritos.  Como  ejercicio,  modifique  
el  programa  para  corregir  este  error.

8.4  Cortes  de  cuerda
Un  segmento  de  una  cuerda  se  llama  rebanada.  Seleccionar  un  segmento  es  similar  a  seleccionar  un  personaje:

El  operador  devuelve  la  parte  de  la  cadena  del  carácter  "n­ésimo"  al  carácter  "m­ésimo",  incluido  el  primero  pero  
excluyendo  el  último.  Este  comportamiento  es  contradictorio,  pero  podría  ayudar  imaginar  los  índices  apuntando  
entre  los  caracteres,  como  en  la  Figura  8.1.

Si  omite  el  primer  índice  (antes  de  los  dos  puntos),  el  segmento  comienza  al  principio  de  la  cadena.
Si  omite  el  segundo  índice,  el  segmento  va  al  final  de  la  cadena:
Machine Translated by Google

74 Capítulo  8.  Cuerdas

Si  el  primer  índice  es  mayor  o  igual  que  el  segundo,  el  resultado  es  una  cadena  vacía,  representada  por  
dos  comillas:

Una  cadena  vacía  no  contiene  caracteres  y  tiene  una  longitud  de  0,  pero  aparte  de  eso,  es  igual  que  
cualquier  otra  cadena.

Continuando  con  este  ejemplo,  ¿qué  piensas ¿medio?  Pruébalo  y  verás.

8.5  Las  cadenas  son  inmutables
Es  tentador  usar  el  operador  en  el  lado  izquierdo  de  una  asignación,  con  la  intención  de  cambiar  un  carácter  
en  una  cadena.  Por  ejemplo:

El  "objeto"  en  este  caso  es  la  cadena  y  el  "elemento"  es  el  carácter  que  intentaste  asignar.
Por  ahora,  un  objeto  es  lo  mismo  que  un  valor,  pero  refinaremos  esa  definición  más  adelante  (Sección  10.10).

El  motivo  del  error  es  que  las  cadenas  son  inmutables,  lo  que  significa  que  no  puede  cambiar  una  cadena  
existente.  Lo  mejor  que  puede  hacer  es  crear  una  nueva  cadena  que  sea  una  variación  de  la  original:

Este  ejemplo  concatena  una  nueva  primera  letra  en  una  porción  de   .  No  tiene  efecto  sobre  el
la  cadena  original.

8.6  Búsqueda
¿Qué  hace  la  siguiente  función?
Machine Translated by Google

8.7.  Bucle  y  contando 75

el  carácter   es  el  inverso  del  operador.  En  lugar  de  tomar  un  índice  y  extraer  En  cierto  sentido,  
correspondiente,  toma  un  carácter  y  encuentra  el  índice  donde  aparece  ese  carácter.  Si  no  se  encuentra  
el  carácter,  la  función  devuelve .

Este  es  el  primer  ejemplo  que  hemos  visto  de  una  sentencia  dentro  de  un  bucle.  Si  la  
, función  sale  del  ciclo  y  regresa  inmediatamente.

Si  el  carácter  no  aparece  en  la  cadena,  el  programa  sale  del  ciclo  normalmente  y  vuelve
vueltas

Este  patrón  de  cálculo  (atravesar  una  secuencia  y  volver  cuando  encontramos  lo  que  buscamos)  se  
denomina  búsqueda .

Como  ejercicio,  modificar   por  lo  que  tiene  un  tercer  parámetro,  el  índice  en donde  se


debería  empezar  a  buscar.

8.7  Bucle  y  conteo
El  siguiente  programa  cuenta  el  número  de  veces  que  aparece  la  letra  en  una  cadena:

Este  programa  demuestra  otro  patrón  de  cálculo  llamado  contador.  La  variable  se  inicializa  a  0  y  luego  
se  incrementa  cada  vez  que  se  encuentra  an.  Cuando  el  bucle  sale,  contiene  el  resultado:  el  
número  total  de  's.

Como  ejercicio,  encapsule  este  código  en  una  función  denominada   , y  generalizarlo  de  modo  que
que  acepte  la  cadena  y  la  letra  como  argumentos.

Luego,  reescriba  la  función  para  que,  en  lugar  de  recorrer  la  cadena,  use  la  versión  de  tres  parámetros  
de  la  sección  anterior.

8.8  Métodos  de  cadena
Las  cadenas  proporcionan  métodos  que  realizan  una  variedad  de  operaciones  útiles.  Un  método  es  
similar  a  una  función,  toma  argumentos  y  devuelve  un  valor,  pero  la  sintaxis  es  diferente.  Por  ejemplo,  
el  método  toma  una  cadena  y  devuelve  una  nueva  cadena  con  todas  las  letras  mayúsculas.

En  lugar  de  la  sintaxis  de  la  función , utiliza  la  sintaxis  del  método .
Machine Translated by Google

76 Capítulo  8.  Cuerdas

Esta  forma  de  notación  de  puntos  especifica  el  nombre  del  método,  la   , y  el  nombre  del.  Los  
cadena  a  la  que  aplicar  el  método,   paréntesis  vacíos  indican  que  este  método
no  toma  argumentos.

Una  llamada  de  método  se  denomina  invocación;  en  este  caso,  diríamos  que  estamos  invocando
en .

Resulta  que  hay  un  método  de  cadena  llamado  función  que   que  es  notablemente  similar  a  la
escribimos:

En  este  ejemplo,  invocamos en y  pasar  la  letra  que  buscamos  como  param
éter

En  realidad,   el  método  es  más  general  que  nuestra  función;  puede  encontrar  subcadenas,  no  solo
los  personajes:

De  forma   comienza  al  principio  de  la  cadena,  pero  puede  tomar  un  segundo  argumento,  el
predeterminada,  indexe  donde  debería  comenzar:

Este  es  un  ejemplo  de  un  argumento  opcional;   también  puede  tomar  un  tercer  argumento,  el  índice
donde  debe  parar:

Esta  búsqueda  falla  porque  no  aparece  en  el  rango  de  índice  desde  hasta  sin  incluir . ,
La  búsqueda  hasta  el  segundo  índice,  pero  sin  incluirlo,  es  coherente  con  el  operador  de  división.

8.9  El  operador
La  palabra  es  un  operador  booleano  que  toma  dos  cadenas  y  devuelve  peras  como   si  la  primera  ap
una  subcadena  en  la  segunda:

Por  ejemplo,  la  siguiente  función  imprime  todas  las  letras  de que  también  aparecen  en
:
Machine Translated by Google

8.10.  Comparación  de  cadenas 77

Con  nombres  de  variables  bien  elegidos,  Python  a  veces  se  lee  como  inglés.  Podría  leer  este  ciclo,  "para  (cada)  
letra  en  (la  primera)  palabra,  si  (la)  letra  (aparece)  en  (la  segunda)  palabra,  imprima  (la)  letra".

Esto  es  lo  que  obtienes  si  comparas  manzanas  y  naranjas:

8.10  Comparación  de  cadenas

Los  operadores  relacionales  trabajan  en  cadenas.  Para  ver  si  dos  cadenas  son  iguales:

Otras  operaciones  relacionales  son  útiles  para  poner  palabras  en  orden  alfabético:

Python  no  maneja  las  letras  mayúsculas  y  minúsculas  de  la  misma  manera  que  la  gente.  Todas  las  letras  
mayúsculas  vienen  antes  que  todas  las  letras  minúsculas,  así  que:

Una  forma  común  de  abordar  este  problema  es  convertir  cadenas  a  un  formato  estándar,  como  minúsculas,  antes  
de  realizar  la  comparación.  Tenlo  en  cuenta  en  caso  de  que  tengas  que  defenderte  de  un  hombre  armado  con  
una  piña.

8.11  Depuración

Cuando  usa  índices  para  recorrer  los  valores  en  una  secuencia,  es  complicado  obtener  el  comienzo  y  el  final  
correctos  del  recorrido.  Aquí  hay  una  función  que  se  supone  que  compara  dos  palabras  y  regresa
si  una  de  las  palabras  es  el  reverso  de  la  otra,  pero  contiene  dos  errores:
Machine Translated by Google

78 Capítulo  8.  Cuerdas

La  primera  instrucción  comprueba  si  las  palabras  tienen  la  misma  longitud.  Si  no,  podemos  regresar  
inmediatamente.  De  lo  contrario,  para  el  resto  de  la  función,  podemos  suponer  que  las  palabras
son  de  la  misma  longitud.  Este  es  un  ejemplo  del  patrón  de  tutor  en  la  Sección  6.8.
y  son  índices:  las  poligonales   adelante  mientras  atraviesa hacia  atrás.  Si  
encuentran  dos  letras  que  no  coinciden,  podemos   nosotros  inmediatamente.  Si  pasamos  por  el
.
devolver  el  bucle  completo  y  todas  las  letras  coinciden,  volvemos

Si  probamos  esta  función  con  las  palabras  "pots"  y  "stop",  esperamos  el  valor  de  retorno   ,
pero  obtenemos  un  IndexError:

Para  depurar  este  tipo  de  error,  mi  primer  movimiento  es  imprimir  los  valores  de  los  índices  
inmediatamente  antes  de  la  línea  donde  aparece  el  error.

Ahora,  cuando  vuelvo  a  ejecutar  el  programa,  obtengo  más  información:

La  primera  vez  que  pasa  por  el  bucle,  el  valor  de  es  4,  que  está  fuera  del  rango  de  la  cadena.  El  
índice  del  último  carácter  es  3,  por  lo  que  el  valor  inicial  de  debe  ser
.

Si  soluciono  ese  error  y  vuelvo  a  ejecutar  el  programa,  obtengo:

Esta  vez  obtenemos  la  respuesta  correcta,  pero  parece  que  el  ciclo  solo  se  ejecutó  tres  veces,  lo  cual  es  
sospechoso.  Para  tener  una  mejor  idea  de  lo  que  está  sucediendo,  es  útil  dibujar  un  diagrama  de  estado.
Durante  la  primera  iteración,  el  marco  para  se  muestra  en  la  Figura  8.2.

Me  tomé  una  licencia  al  ordenar  las  variables  en  el  cuadro  y  agregar  líneas  de  puntos  para  mostrar  
que  los  valores  de  e  indican  los  caracteres  en y .

Comenzando  con  este  diagrama,  ejecute  el  programa  en  papel,  cambiando  los  valores  de  y  
durante  cada  iteración.  Encuentre  y  corrija  el  segundo  error  en  esta  función.
Machine Translated by Google

8.12.  Glosario 79

palabra1 palabra  'ollas'2 'detener'

i 0 j 3

Figura  8.2:  Diagrama  de  estado.

8.12  Glosario
objeto:  Algo  a  lo  que  una  variable  puede  referirse.  Por  ahora,  puede  usar  "objeto"  y  "valor"  indistintamente.

secuencia:  Una  colección  ordenada  de  valores  donde  cada  valor  es  identificado  por  un  número  entero
índice.

item:  Uno  de  los  valores  en  una  secuencia.

índice:  un  valor  entero  utilizado  para  seleccionar  un  elemento  en  una  secuencia,  como  un  carácter  en  una  cadena.
En  Python,  los  índices  comienzan  desde  0.

rebanada:  una  parte  de  una  cadena  especificada  por  un  rango  de  índices.

cadena  vacía:  una  cadena  sin  caracteres  y  de  longitud  0,  representada  por  dos  comillas
marcas.

inmutable:  la  propiedad  de  una  secuencia  cuyos  elementos  no  se  pueden  cambiar.

atravesar:  iterar  a  través  de  los  elementos  en  una  secuencia,  realizando  una  operación  similar  en
cada.

búsqueda:  Un  patrón  de  recorrido  que  se  detiene  cuando  encuentra  lo  que  está  buscando.

contador:  una  variable  utilizada  para  contar  algo,  generalmente  inicializada  a  cero  y  luego  incrementada
mentalizado

invocación:  Una  declaración  que  llama  a  un  método.

argumento  opcional:  un  argumento  de  función  o  método  que  no  es  obligatorio.

8.13  Ejercicios

Ejercicio  8.1.  Lea  la  documentación  de  los  métodos  de  cadena  en .  Es  
posible  que  desee  experimentar  con  algunos  de  ellos  
para  asegurarse  de  que  entiende  cómo  funcionan. y que  son  particularmente  útiles.

La  documentación  utiliza  una  sintaxis  que  puede  resultar  confusa. Por  ejemplo,  entre  
, paréntesis  indique  argumentos  opcionales.  Entonces  es  obligatorio,  pero  
,
es  opcional,  y  si  lo  incluye,  entonces  es  opcional.
Ejercicio  8.2.  Hay  un  método  de  cadena  llamado  que  es  similar  a  la  función  de  la  Sección  8.7.
Lea  la  documentación  de  este  método  y  escriba  una  invocación  que  cuente  el  número  de  's  en
.
Ejercicio  8.3.  Un  segmento  de  cadena  puede  tomar  un  tercer  índice  que  especifica  el  "tamaño  de  paso";  es  decir,  el  
número  de  espacios  entre  caracteres  sucesivos.  Un  tamaño  de  paso  de  2  significa  cualquier  otro  carácter;  3  significa  
cada  tercio,  etc.
Machine Translated by Google

80 Capítulo  8.  Cuerdas

Un  tamaño  de  paso  de  ­1  recorre  la  palabra  hacia  atrás,  por  lo  que  el  segmento genera  una  cadena  invertida.

Usa  este  modismo  para  escribir  una  versión  de  una  línea  del  Ejercicio  6.3.
Ejercicio  8.4.  Todas  las  siguientes  funciones  están  destinadas  a  verificar  si  una  cadena  contiene  letras  minúsculas,  pero  al  
menos  algunas  de  ellas  son  incorrectas.  Para  cada  función,  describa  lo  que  realmente  hace  la  función  (asumiendo  que  el  
parámetro  es  una  cadena).

Ejercicio  8.5.  Un  cifrado  César  es  una  forma  débil  de  encriptación  que  implica  "rotar"  cada  letra  en  un  número  fijo  de  lugares.  
Rotar  una  letra  significa  cambiarla  por  el  alfabeto,  volviendo  al  principio  si  es  necesario,  de  modo  que  'A'  rotada  por  3  es  'D'  y  
'Z'  rotada  por  1  es  'A'.

Para  rotar  una  palabra,  rota  cada  letra  en  la  misma  cantidad.  Por  ejemplo,  "cheer"  rotado  por  7  es  "jolly"  y  "melon"  rotado  por  
­10  es  "cubed".  En  la  película  2001:  A  Space  Odyssey,  la  computadora  de  la  nave  se  llama  HAL,  que  es  IBM  rotada  por  ­1.

Escriba  una  función  llamada  que  tome  una  cadena  y  un  entero  como  parámetros  y  devuelva  una  nueva  cadena  que  contenga  
las  letras  de  la  cadena  original  rotadas  por  la  cantidad  dada.

Es  posible  que  desee  utilizar  la  función  integrada , que  convierte  un  carácter  en  un  código  numérico,  y
Machine Translated by Google

8.13.  Ejercicios 81

, que  convierte  códigos  numéricos  en  caracteres.  Las  letras  del  alfabeto  se  codifican  en  orden  
alfabético,  por  ejemplo:

Porque  es  la  segunda  letra  del  alfabeto.  Pero  cuidado:  los  códigos  numéricos  de  las  letras  mayúsculas  
son  diferentes.

Los  chistes  potencialmente  ofensivos  en  Internet  a  veces  se  codifican  en  ROT13,  que  es  un  cifrado  
César  con  rotación  13.  Si  no  se  ofende  fácilmente,  encuentre  y  decodifique  algunos  de  ellos.  Solución:
.
Machine Translated by Google

82 Capítulo  8.  Cuerdas
Machine Translated by Google

Capítulo  9

Estudio  de  caso:  juego  de  palabras

Este  capítulo  presenta  el  segundo  caso  de  estudio,  que  consiste  en  resolver  acertijos  de  palabras  
buscando  palabras  que  tengan  ciertas  propiedades.  Por  ejemplo,  encontraremos  los  palíndromos  más  
largos  en  inglés  y  buscaremos  palabras  cuyas  letras  aparezcan  en  orden  alfabético.  Y  presentaré  otro  
plan  de  desarrollo  del  programa:  la  reducción  a  un  problema  previamente  resuelto.

9.1  Lectura  de  listas  de  palabras

Para  los  ejercicios  de  este  capítulo  necesitamos  una  lista  de  palabras  en  inglés.  Hay  muchas  listas  de  
palabras  disponibles  en  la  Web,  pero  la  más  adecuada  para  nuestro  propósito  es  una  de  las  listas  de  
palabras  recopiladas  y  aportadas  al  dominio  público  por  Grady  Ward  como  parte  del  proyecto  Moby  lexi  
con  (ver ).  Es  una  lista  de  113.809  crucigramas  oficiales;  es  decir,  palabras  que  se  consideran  válidas  
en  crucigramas  y  otros  juegos  de  palabras.  En  la  colección  Moby,  el  nombre  del  archivo  es ;  puede  
descargar  una  copia,  con  el  nombre  más  simple  de
, .

Este  archivo  está  en  texto  sin  formato,  por  lo  que  puede  abrirlo  con  un  editor  de  texto,  pero  también  puede  leerlo  
desde  Python.  La  función  incorporada  toma  el  nombre  del  archivo  como  parámetro  y  devuelve  un  objeto  de  
archivo  que  puede  usar  para  leer  el  archivo.

es  un  nombre  común  para  un  objeto  de  archivo  utilizado  para  la  entrada.  El  objeto  de  archivo  proporciona  
métodos  para  leer,  incluso  en  una   , varios  que  leen  los  caracteres  del  archivo  hasta  que  obtiene
nueva  línea  y  devuelve  el  resultado  como  una  cadena:

La  primera  palabra  en  esta  lista  en  particular  es  “aa”,  que  es  una  especie  de  lava.  La  secuencia  
representa  el  carácter  de  nueva  línea  que  separa  esta  palabra  de  la  siguiente.

El  objeto  de  archivo  realiza  un  seguimiento  de  dónde  se  encuentra  en  el  archivo,  por  lo  que  si  llama   de  nuevo,  obtienes
a  la  siguiente  palabra:
Machine Translated by Google

84 Capítulo  9.  Estudio  de  caso:  juego  de  palabras

La  siguiente  palabra  es  "aah",  que  es  una  palabra  perfectamente  legítima,  así  que  deja  de  mirarme  así.  O,  si  lo  
que  le  molesta  es  el  carácter  de  nueva  línea,  podemos  deshacernos  de  él  con  el  método  de  cadena
:

También  puede  usar  un  objeto  de  archivo  como  parte  de   bucle.  Este  programa  lee y
una  impresión  de  cada  palabra,  una  por  línea:

9.2  Ejercicios

Hay  soluciones  a  estos  ejercicios  en  la  siguiente  sección.  Al  menos  debe  intentar  cada  uno  antes  de  leer  las  
soluciones.
Ejercicio  9.1.  Escriba  un  programa  que  lea   e  imprime  solo  las  palabras  con  más  de  20
caracteres  (sin  contar  los  espacios  en  blanco).
Ejercicio  9.2.  En  1939  Ernest  Vincent  Wright  publicó  una  novela  de  50.000  palabras  llamada  Gadsby  que  no  
contiene  la  letra  "e".  Dado  que  la  "e"  es  la  letra  más  común  en  inglés,  no  es  fácil  de  hacer.

De  hecho,  es  difícil  construir  un  pensamiento  solitario  sin  usar  ese  símbolo  tan  común.  Es  lento  al  principio,  pero  
con  precaución  y  horas  de  entrenamiento  se  puede  ir  ganando  facilidad.

Está  bien,  me  detendré  ahora.

Escribe  una  función   que  regresa si  la  palabra  dada  no  tiene  la  letra  "e"  en


llamada.

Escriba  un  programa  que  lea   e  imprime  solo  las  palabras  que  no  tienen  "e".  Calcular  el
el  porcentaje  de  palabras  en  la  lista  que  no  tienen  "e".
Ejercicio  9.3.  Escriba  una  función  llamada  que  tome  una  palabra  y  una  cadena  de  letras  prohibidas,  y  que  
regrese  si  la  palabra  no  usa  ninguna  de  las  letras  prohibidas.

Escriba  un  programa  que  solicite  al  usuario  que  ingrese  una  cadena  de  letras  prohibidas  y  luego  imprima  la  
cantidad  de  palabras  que  no  contienen  ninguna  de  ellas.  ¿Puedes  encontrar  una  combinación  de  5  letras  
prohibidas  que  excluya  la  menor  cantidad  de  palabras?
Ejercicio  9.4.  Escriba  una  función  llamada  que  tome  una  palabra  y  una  cadena  de  letras,  y  que  regrese  si  la  
palabra  contiene  solo  letras  en  la  lista.  ¿Puedes  hacer  una  oración  usando  solo  las  letras?  Aparte  de  "Hoe  
alfalfa"?
Ejercicio  9.5.  Escriba  una  función  llamada  que  tome  una  palabra  y  una  cadena  de  letras  requeridas,  y  que  
regrese  si  la  palabra  usa  todas  las  letras  requeridas  al  menos  una  vez.  ¿Cuántas  palabras  hay  que  usan  todas  
las  vocales?  Qué  tal  si ?
Ejercicio  9.6.  Escriba  una  función  llamada  que  devuelva  si  las  letras  de  una  palabra  aparecen  en  orden  alfabético  
(las  letras  dobles  están  bien).  ¿Cuántas  palabras  abecedarias  hay?
Machine Translated by Google

9.3.  Buscar 85

9.3  Buscar
Todos  los  ejercicios  de  la  sección  anterior  tienen  algo  en  común;  se  pueden  resolver  con  el  patrón  de  
búsqueda  que  vimos  en  la  Sección  8.6.  El  ejemplo  más  simple  es:

El  bucle  atraviesa  los  caracteres  en . Si  encontramos  la  letra  “e”,  podemos  inmediatamente;  
devolver de  lo  contrario,  tenemos  que  ir  a  la  siguiente  letra.  Si  salimos  del  ciclo  normalmente,  eso  significa  
que  no  encontramos  una  "e",  por  lo  que  regresamos .

Podría  escribir  esta  función  de  manera  más  concisa  usando  el  operador,  pero  comencé  con  esta  versión  
porque  demuestra  la  lógica  del  patrón  de  búsqueda.

es  una  versión  más  general  de pero  tiene  la  misma  estructura:

podemos  volver tan  pronto  como  encontremos  una  carta  prohibida;  si  llegamos  al  final  del  bucle,
regresamos .

es  similar  excepto  que  el  sentido  de  la  condición  se  invierte:

En  lugar  de  una  lista  de  letras  prohibidas,  tenemos  una  lista  de  letras  disponibles.  Si  encontramos  una  letra  en
eso  no  esta  en , podemos  volver .

es  similar  excepto  que  invertimos  el  papel  de  la  palabra  y  la  cadena  de  letras:

En  lugar  de  recorrer  las  letras  en  las   , el  bucle  atraviesa  las  letras  requeridas.  Si  alguno  de  los
letras  requeridas  que  no  aparecen  en  la  palabra,  podemos  regresar .

Si  realmente  estuvieras  pensando  como  un  científico  informático,  habrías  reconocido  que  era  una  instancia  
de  un  problema  previamente  resuelto  y  habrías  escrito:

Este  es  un  ejemplo  de  un  plan  de  desarrollo  de  programa  llamado  reducción  a  un  problema  previamente  
resuelto,  lo  que  significa  que  usted  reconoce  el  problema  en  el  que  está  trabajando  como  una  instancia  de  
un  problema  resuelto  y  aplica  una  solución  existente.
Machine Translated by Google

86 Capítulo  9.  Estudio  de  caso:  juego  de  palabras

9.4  Bucles  con  índices
Escribí  las  funciones  en  la  sección  anterior  con  caracteres  en   bucles  porque  solo  necesitaba  el
las  cadenas;  No  tuve  que  hacer  nada  con  los  índices.

En   tenemos  que  comparar  letras  adyacentes,  lo  cual  es  un  poco  complicado  con  un
bucle:

Una  alternativa  es  usar  la  recursividad:

Otra  opción  es  utilizar  un bucle:

El  ciclo  comienza  en  y  termina  cuando .  Cada  vez  que  pasa  por  el  bucle,  compara  el  i­ésimo  carácter  (que  
puede  considerar  como  el  carácter  actual)  con  el  i  +  1°  carácter  (que  puede  considerar  como  el  siguiente).

Si  el  siguiente  carácter  es  menor  que  (alfabéticamente  anterior)  al  actual,  entonces  hemos  descubierto  una  
ruptura  en  la  tendencia  abecedaria  y  volvemos .

Si  llegamos  al  final  del  ciclo  sin  encontrar  una  falla,  entonces  la  palabra  pasa  la  prueba.  Para  convencerse  de  
que  el  ciclo  termina  correctamente,  considere  un  ejemplo  como .  La  longitud  de  la  palabra  es  6,  por  lo  que  la  
última  vez  que  se  ejecuta  el  ciclo  es  cuando  es  4,  que  es  el  índice  del  penúltimo  carácter.  En  la  última  iteración,  
compara  el  penúltimo  carácter  con  el  último,  que  es  lo  que  queremos.

Aquí  hay  una  versión  del   (ver  Ejercicio  6.3)  que  utiliza  dos  índices;  uno  comienza  en
principio  y  sube;  el  otro  comienza  al  final  y  va  hacia  abajo.
Machine Translated by Google

9.5.  depuración 87

O  podríamos  reducir  a  un  problema  previamente  resuelto  y  escribir:

Usando de  la  Sección  8.11.

9.5  Depuración
Probar  programas  es  difícil.  Las  funciones  de  este  capítulo  son  relativamente  fáciles  de  probar  porque  puede  comprobar  
los  resultados  a  mano.  Aun  así,  es  entre  difícil  e  imposible  elegir  un  conjunto  de  palabras  que  prueben  todos  los  
posibles  errores.

Tomando  como  ejemplo,  hay  dos  casos  obvios  para  verificar:  las  palabras  que  tienen  una  'e'  deben  regresar  y  las  
palabras  que  no  deben  regresar.  
, No  deberías  tener  problemas  para  encontrar  uno  de  cada  uno.

Dentro  de  cada  caso,  hay  algunos  subcasos  menos  obvios.  Entre  las  palabras  que  tienen  una  "e",  debe  probar  palabras  
con  una  "e"  al  principio,  al  final  y  en  algún  lugar  en  el  medio.  Debe  probar  palabras  largas,  palabras  cortas  y  palabras  
muy  cortas,  como  la  cadena  vacía.  La  cadena  vacía  es  un  ejemplo  de  un  caso  especial,  que  es  uno  de  los  casos  no  
obvios  donde  a  menudo  acechan  los  errores.

Además  de  los  casos  de  prueba  que  genera,  también  puede  probar  su  programa  con  una  lista  de  palabras  como .  Al  
escanear  la  salida,  es  posible  que  pueda  detectar  errores,  pero  tenga  cuidado:  puede  detectar  un  tipo  de  error  (palabras  
que  no  deben  incluirse,  pero  lo  están)  y  no  otro  (palabras  que  deben  incluirse,  pero  no  lo  están) .

En  general,  las  pruebas  pueden  ayudarlo  a  encontrar  errores,  pero  no  es  fácil  generar  un  buen  conjunto  de  casos  de  
prueba,  e  incluso  si  lo  hace,  no  puede  estar  seguro  de  que  su  programa  sea  correcto.  Según  un  legendario  informático:

Las  pruebas  de  programas  se  pueden  usar  para  mostrar  la  presencia  de  errores,  ¡pero  nunca  para  
mostrar  su  ausencia!

—Edsger  W.  Dijkstra

9.6  Glosario
objeto  de  archivo:  un  valor  que  representa  un  archivo  abierto.

reducción  a  un  problema  previamente  resuelto:  una  forma  de  resolver  un  problema  expresándolo
como  una  instancia  de  un  problema  previamente  resuelto.

caso  especial:  un  caso  de  prueba  que  es  atípico  o  no  obvio  (y  es  menos  probable  que  se  maneje  de  forma  incorrecta).
correctamente).
Machine Translated by Google

88 Capítulo  9.  Estudio  de  caso:  juego  de  palabras

9.7  Ejercicios

Ejercicio  9.7.  Esta  pregunta  se  basa  en  un  Puzzler  que  se  transmitió  en  el  programa  de  radio  Car  Talk  (
):

Dame  una  palabra  con  tres  letras  dobles  consecutivas.  Te  daré  un  par  de  palabras  que  casi  califican,  
pero  no  lo  hacen.  Por  ejemplo,  la  palabra  comité,  comité.  Estaría  genial  salvo  por  la  'i'  que  se  cuela  
por  ahí.  O  Mississippi:  Mississi  ppi.  Si  pudieras  eliminar  esos  i's,  funcionaría.  Pero  hay  una  palabra  
que  tiene  tres  pares  consecutivos  de  letras  y  que  yo  sepa,  esta  puede  ser  la  única  palabra.

Por  supuesto,  probablemente  haya  500  más,  pero  solo  puedo  pensar  en  uno.  ¿Que  es  la  palabra?

Escribe  un  programa  para  encontrarlo.   .
Solución:  Ejercicio  9.8.  Aquí  hay  otro  Car  Talk  Puzzler  ( ):

“Estaba  conduciendo  por  la  carretera  el  otro  día  y  me  fijé  en  mi  cuentakilómetros.
Como  la  mayoría  de  los  odómetros,  muestra  seis  dígitos,  solo  en  millas  enteras.  Entonces,  si  mi  auto  tuviera  
300,000  millas,  por  ejemplo,  vería  3­0­0­0­0­0.

“Ahora,  lo  que  vi  ese  día  fue  muy  interesante.  Noté  que  los  últimos  4  dígitos  eran  palindrómicos;  es  
decir,  se  leen  igual  hacia  adelante  que  hacia  atrás.  Por  ejemplo,  5­4­4­5  es  un  palíndromo,  por  lo  que  
mi  cuentakilómetros  podría  haber  indicado  3­1­5­4­4­5.

“Una  milla  después,  los  últimos  5  números  eran  palindrómicos.  Por  ejemplo,  podría  haber  leído  
3­6­5­4­5­6.  Una  milla  después  de  eso,  los  4  de  los  6  números  del  medio  eran  palindrómicos.  ¿Y  estás  
listo  para  esto?  ¡Una  milla  después,  los  6  eran  palindrómicos!

“La  pregunta  es,  ¿qué  había  en  el  odómetro  cuando  miré  por  primera  vez?”

Escriba  un  programa  en  Python  que  pruebe  todos  los  números  de  seis  dígitos  e  imprima  cualquier  número  que  
satisfaga  estos  requisitos.   .
Solución:  Ejercicio  9.9.  Aquí  hay  otro  Car  Talk  Puzzler  que  puedes  resolver  con  una  búsqueda  (
):

“Recientemente  tuve  una  visita  con  mi  mamá  y  nos  dimos  cuenta  de  que  los  dos  dígitos  que  forman  
mi  edad  cuando  se  invierten  dan  como  resultado  su  edad.  Por  ejemplo,  si  ella  tiene  73  años,  yo  tengo  
37.  Nos  preguntamos  con  qué  frecuencia  ha  sucedido  esto  a  lo  largo  de  los  años,  pero  nos  distrajimos  
con  otros  temas  y  nunca  encontramos  una  respuesta.

“Cuando  llegué  a  casa  me  di  cuenta  de  que  los  dígitos  de  nuestras  edades  han  sido  reversibles  seis  
veces  hasta  ahora.  También  me  di  cuenta  de  que,  si  teníamos  suerte,  volvería  a  suceder  en  unos  
años,  y  si  realmente  teníamos  suerte,  sucedería  una  vez  más  después  de  eso.  En  otras  palabras,  
habría  sucedido  8  veces  en  total.  Entonces  la  pregunta  es,  ¿cuántos  años  tengo  ahora?”

Escriba  un  programa  en  Python  que  busque  soluciones  para  este  rompecabezas.  Sugerencia:  es  posible  que  encuentre  el  método  
de  cadena útil.

Solución: .
Machine Translated by Google

Capítulo  10

Liza

Este  capítulo  presenta  uno  de  los  tipos  integrados  más  útiles  de  Python,  las  listas.  También  aprenderá  más  sobre  los  
objetos  y  lo  que  puede  suceder  cuando  tiene  más  de  un  nombre  para  el  mismo  objeto.

10.1  Una  lista  es  una  secuencia

Al  igual  que  una  cadena,  una  lista  es  una  secuencia  de  valores.  En  una  cadena,  los  valores  son  caracteres;  en  una  
lista,  pueden  ser  de  cualquier  tipo.  Los  valores  de  una  lista  se  denominan  elementos  o,  a  veces,  elementos.

Hay  varias  formas  de  crear  una  nueva  lista;  la  más  sencilla  es  encerrar  los  elementos  entre  corchetes  ( y ):

El  primer  ejemplo  es  una  lista  de  cuatro  enteros.  El  segundo  es  una  lista  de  tres  cadenas.  Los  elementos  de  una  lista  
no  tienen  que  ser  del  mismo  tipo.  La  siguiente  lista  contiene  una  cadena,  un  flotante,  un  entero  y  (¡vaya!)  otra  lista:

Una  lista  dentro  de  otra  lista  está  anidada.

Una  lista  que  no  contiene  elementos  se  denomina  lista  vacía;  puede  crear  uno  con  corchetes  vacíos, .

Como  era  de  esperar,  puede  asignar  valores  de  lista  a  las  variables:
Machine Translated by Google

90 Capítulo  10.  Listas

lista

quesos 0 'Queso  Cheddar'

1 'Queso  Edam'

2 'Gouda'

lista

números 0 42
1 123
5

lista

vacío

Figura  10.1:  Diagrama  de  estado.

10.2  Las  listas  son  mutables
La  sintaxis  para  acceder  a  los  elementos  de  una  lista  es  la  misma  que  para  acceder  a  los  
caracteres  de  una  cadena:  el  operador  de  paréntesis.  La  expresión  entre  corchetes  especifica  el  índice.
Recuerda  que  los  índices  empiezan  en  0:

A  diferencia  de  las  cadenas,  las  listas  son  mutables.  Cuando  el  operador  de  paréntesis  aparece  en  el  
lado  izquierdo  de  una  asignación,  identifica  el  elemento  de  la  lista  que  se  asignará.

El  elemento  uno­ésimo  de , que  antes  era  123,  ahora  es  5.

La  figura  10.1  muestra  el  diagrama  de  estado   , y .

para  las  listas  están  representadas  por  cuadros  con  la  palabra  "lista"  afuera  y  los  elementos  de  la  lista  
se  refieren  a  una  lista  con  tres  elementos  indexados  0,  1  y  2. contiene
adentro.  dos  elementos;  el  diagrama  muestra  que  el  valor  del  segundo  elemento  ha  sido  
reasignado  de  123  a  5.  se  refiere  a  una  lista  sin  elementos.

Los  índices  de  lista  funcionan  de  la  misma  manera  que  los  índices  de  cadena:

•  Cualquier  expresión  entera  se  puede  utilizar  como  índice.

•  Si  intenta  leer  o  escribir  un  elemento  que  no  existe,  obtiene  un  •  Si  un   .

índice  tiene  un  valor  negativo,  cuenta  hacia  atrás  desde  el  final  de  la  lista.

El  operador  también  trabaja  en  listas.
Machine Translated by Google

10.3.  Atravesando  una  lista 91

10.3  Recorriendo  una  lista

La  forma  más  común  de  recorrer  los  elementos  de  una  lista  es  con  lo   bucle.  la  sintaxis  es
mismo  que  para  las  cadenas:

Esto  funciona  bien  si  solo  necesita  leer  los  elementos  de  la  lista.  Pero  si  desea  escribir  o  actualizar  
los  elementos,  necesita  los  índices.  Una  forma  común  de  hacerlo  es  combinar  las  funciones  
integradas y :

Este  bucle  atraviesa  la  lista  y  actualiza  cada  elemento.  devuelve  el  número  de  elementos  de  la  
lista.  devuelve  una  lista  de  índices  de  0  a  n  −  1,  donde  n  es  la  longitud  de  la  lista.
Cada  vez  que  pasa  por  el  ciclo  obtiene  el  índice  del  siguiente  elemento.  La  declaración  de  
asignación  en  el  cuerpo  se  usa  para  leer  el  valor  antiguo  del  elemento  y  para  asignar  el  nuevo  valor.

Un  bucle  sobre  una  lista  vacía  nunca  ejecuta  el  cuerpo:

Aunque  una  lista  puede  contener  otra  lista,  la  lista  anidada  sigue  contando  como  un  solo  elemento.  La  
longitud  de  esta  lista  es  de  cuatro:

10.4  Operaciones  de  lista

El  operador  concatena  listas:

El  operador  repite  una  lista  un  número  determinado  de  veces:

El  primer  ejemplo  se  repite   cuatro  veces.  El  segundo  ejemplo  repite  la  lista.
tres  veces.

10.5  Sectores  de  lista

El  operador  de  corte  también  funciona  en  listas:
Machine Translated by Google

92 Capítulo  10.  Listas

Si  omite  el  primer  índice,  el  segmento  comienza  al  principio.  Si  omites  el  segundo,  el  corte  va  hasta  el  final.  
Entonces,  si  omite  ambos,  el  segmento  es  una  copia  de  la  lista  completa.

Dado  que  las  listas  son  mutables,  a  menudo  es  útil  hacer  una  copia  antes  de  realizar  operaciones  que  
modifiquen  las  listas.

Un  operador  de  división  en  el  lado  izquierdo  de  una  tarea  puede  actualizar  varios  elementos:

10.6  Métodos  de  lista

Python  proporciona  métodos  que  operan  en  listas.  Por  ejemplo,  al  final  de   agrega  un  nuevo  elemento
una  lista:

toma  una  lista  como  argumento  y  agrega  todos  los  elementos:

Este  ejemplo  no  se  modifica.

ordena  los  elementos  de  la  lista  de  menor  a  mayor:

La  mayoría  de  los  métodos  de  lista  son  nulos;  modifican  la  lista  y   . Si  accidentalmente  escribes
regresan,  te  decepcionará  el  resultado.
Machine Translated by Google

10.7.  Mapear,  filtrar  y  reducir 93

10.7  Mapear,  filtrar  y  reducir
Para  sumar  todos  los  números  en  una  lista,  puede  usar  un  ciclo  como  este:

se  inicializa  en  0.  Cada  vez  que  pasa  por  el  ciclo,  obtiene  un  elemento  de  la  lista.
El  operador  proporciona  una  forma  breve  de  actualizar  una  variable.  Esta  tarea  aumentada
declaración,

es  equivalente  a

A  medida  que  se  ejecuta  el  bucle,  acumula  la  suma  de  los  elementos;  una  variable  utilizada  de  esta  manera  a  
veces  se  denomina  acumulador.

Sumar  los  elementos  de  una  lista  es  una  operación  tan  común  que  Python  la  proporciona  como  una  función  
integrada, :

Una  operación  como  esta  que  combina  una  secuencia  de  elementos  en  un  solo  valor  a  veces  se  denomina  
reducir.

A  veces  desea  recorrer  una  lista  mientras  crea  otra.  Por  ejemplo,  la  siguiente  función  toma  una  lista  de  
cadenas  y  devuelve  una  nueva  lista  que  contiene  cadenas  en  mayúsculas:

se  inicializa  con  una  lista  vacía;  cada  vez  que  recorremos  el  bucle,  añadimos  el  siguiente  elemento.  
Entonces es  otro  tipo  de  acumulador.

Una  operación  como   a  veces  se  denomina  mapa  porque  "mapea"  una  función )  en  cada  
(en  este  caso  el  método uno  de  los  elementos  de  una  secuencia.

Otra  operación  común  es  seleccionar  algunos  de  los  elementos  de  una  lista  y  devolver  una  sublista.
Por  ejemplo,  la  siguiente  función  toma  una  lista  de  cadenas  y  devuelve  una  lista  que  contiene  solo  las  cadenas  
en  mayúsculas:
Machine Translated by Google

94 Capítulo  10.  Listas

es  un  método  de  cadena  que  devuelve si  la  cadena  contiene  solo  letras  mayúsculas.

Una  operación  como   se  llama  filtro  porque  selecciona  algunos  de  los  elementos  y
filtra  las  demás.

Las  operaciones  de  lista  más  comunes  se  pueden  expresar  como  una  combinación  de  mapa,  filtro  y  reducción.

10.8  Eliminación  de  elementos
Hay  varias  formas  de  eliminar  elementos  de  una  lista.  Si  conoce  el  índice  del  elemento  que  desea,  puede  usar:

modifica  la  lista  y  devuelve  el  elemento  que  se  eliminó.  Si  no  proporciona  un
index,  borra  y  devuelve  el  último  elemento.

Si  no  necesita  el  valor  eliminado,  puede  usar  el operador:

Si  conoce  el  elemento  que  desea  eliminar  (pero  no  el  índice),  puede  usar :

El  valor  de  retorno  de es .

Para  eliminar  más  de  un  elemento,  puede  utilizar con  un  índice  de  corte:

Como  de  costumbre,  el  segmento  selecciona  todos  los  elementos  hasta  el  segundo  índice,  pero  sin  incluirlo.

10.9  Listas  y  cadenas
Una  cadena  es  una  secuencia  de  caracteres  y  una  lista  es  una  secuencia  de  valores,  pero  una  lista  de  caracteres  
no  es  lo  mismo  que  una  cadena.  Para  convertir  de  una  cadena  a  una  lista  de  caracteres,  puede  usar :
Machine Translated by Google

10.10.  Objetos  y  valores 95

a 'banana' a
'banana'
b 'banana' b

Figura  10.2:  Diagrama  de  estado.

Porque   es  el  nombre  de  una  función  incorporada,  debe  evitar  usarla  como  una  variable
nombre.  También  lo  evito  porque  se  parece  demasiado  a .  Entonces  es  por  eso  que  uso .

La  función  divide  una  cadena  en  letras  individuales.  Si  desea  dividir  una  cadena  en  palabras,  puede  usar  el  
método:

Un  argumento  opcional  llamado  delimitador  especifica  qué  caracteres  usar  como  aries  vinculados  a  palabras.  
El  siguiente  ejemplo  utiliza  un  guión  como  delimitador:

es  el  inverso  de .  Toma  una  lista  de  cadenas  y  concatena  los  elementos.  es  un  método  de  
cadena,  por  lo  que  debe  invocarlo  en  el  delimitador  y  pasar  la  lista  como  parámetro:

En  este  caso,  el  delimitador  es  un  carácter  de  espacio,  por  lo  que  pone  un  espacio  entre  palabras.  Para  
concatenar  cadenas  sin  espacios,  puede  usar  la  cadena  vacía, ,  como  delimitador.

10.10  Objetos  y  valores
Si  ejecutamos  estas  sentencias  de  asignación:

Lo  sabemos  y  ambos  se  refieren  a  una  cadena,  pero  no  sabemos  si  se  refieren  a  la  misma  cadena.  Hay  dos  
estados  posibles,  que  se  muestran  en  la  figura  10.2.

En  un  caso,  y  se  refieren  a  dos  objetos  diferentes  que  tienen  el  mismo  valor.  En  el  segundo  caso,  se  refieren  al  
mismo  objeto.

Para  verificar  si  dos  variables  se  refieren  al  mismo  objeto,  puede  usar  el  operador.
Machine Translated by Google

96 Capítulo  10.  Listas

a [1,  2,  3]  
b [1,  2,  3]

Figura  10.3:  Diagrama  de  estado.

a
[ 1,  2,  3 ]
b

Figura  10.4:  Diagrama  de  estado.

En  este  ejemplo,  Python  solo  creó  un  objeto  de  cadena  y  ambos  se  refieren  a  él.  Pero  cuando  creas  dos  listas,  
obtienes  dos  objetos:

Entonces,  el  diagrama  de  estado  se  parece  a  la  figura  10.3.

En  este  caso  diríamos  que  las  dos  listas  son  equivalentes,  porque  tienen  los  mismos  elementos,  pero  no  
idénticas,  porque  no  son  el  mismo  objeto.  Si  dos  objetos  son  idénticos,  también  son  equivalentes,  pero  si  son  
equivalentes,  no  necesariamente  son  idénticos.

Hasta  ahora,  hemos  estado  usando  "objeto"  y  "valor"  indistintamente,  pero  es  más  preciso  decir  que  un  objeto  
tiene  un  valor.  Si  evalúas,  obtienes  un  objeto  de  lista  cuyo  valor  es  una  secuencia  de  enteros.  Si  otra  lista  tiene  
los  mismos  elementos,  decimos  que  tiene  el  mismo  valor,  pero  no  es  el  mismo  objeto.

10.11  Alias
Si  se  refiere  a  un  objeto  y  le  asignas , entonces  ambas  variables  se  refieren  al  mismo  objeto:

El  diagrama  de  estado  se  parece  a  la  figura  10.4.

La  asociación  de  una  variable  con  un  objeto  se  denomina  referencia.  En  este  ejemplo,  hay  dos  referencias  al  
mismo  objeto.

Un  objeto  con  más  de  una  referencia  tiene  más  de  un  nombre,  por  lo  que  decimos  que  el  objeto  tiene  un  alias.

Si  el  objeto  con  alias  es  mutable,  los  cambios  realizados  con  un  alias  afectan  al  otro:
Machine Translated by Google

10.12.  Listar  argumentos 97

lista
__principal__ letras
0 'a'

1 'b'
eliminar_cabeza t
2 'C'

Figura  10.5:  Diagrama  de  pila.

Aunque  este  comportamiento  puede  ser  útil,  es  propenso  a  errores.  En  general,  es  más  seguro  evitar  la  
creación  de  alias  cuando  se  trabaja  con  objetos  mutables.

Para  objetos  inmutables  como  cadenas,  el  alias  no  es  un  gran  problema.  En  este  ejemplo:

Casi  nunca  hace  una  diferencia  si  y  se  refieren  a  la  misma  cadena  o  no.

10.12  Argumentos  de  lista
Cuando  pasa  una  lista  a  una  función,  la  función  obtiene  una  referencia  a  la  lista.  Si  la  función  modifica  
la  lista,  la  persona  que  llama  ve  el  cambio.  Por  ejemplo,  elimina  el  primer  elemento  de  una  lista:

Así  es  como  se  usa:

El  parámetro  y  la  variable  se  parece   son  alias  para  el  mismo  objeto.  El  diagrama  de  pila
a  la  figura  10.5.

Como  la  lista  es  compartida  por  dos  marcos,  la  dibujé  entre  ellos.

Es  importante  distinguir  entre  operaciones  que  modifican  listas  y  operaciones  que  crean  nuevas  listas.  
Por  ejemplo,  el  método  modifica  una  lista,  pero  el  operador  crea  una  nueva  lista.

Aquí  hay  un  ejemplo  usando :
Machine Translated by Google

98 Capítulo  10.  Listas

El  valor  de  retorno  de es .

Aquí  hay  un  ejemplo  usando  el  operador:

El  resultado  del  operador  es  una  nueva  lista  y  la  lista  original  no  cambia.

Esta  diferencia  es  importante  cuando  escribe  funciones  que  se  supone  que  modifican  listas.
Por  ejemplo,  esta  función  no  elimina  el  encabezado  de  una  lista:

El  operador  de  división  crea  una  nueva  lista  y  la  asignación  hace  referencia  a  ella,  pero  eso  no  afecta  a  la  
persona  que  llama.

Al  comienzo  de  una   , y  consulte  la  misma  lista.  Al  final  se  refiere
nueva  lista,  pero  aún  se  refiere  a  la  lista  original  sin  modificar.

Una  alternativa  es  escribir  una  función  que  cree  y  devuelva  una  nueva  lista.  Por  ejemplo,  devuelve  todos  
menos  el  primer  elemento  de  una  lista:

Esta  función  deja  la  lista  original  sin  modificar.  Así  es  como  se  usa:

10.13  Depuración
El  uso  descuidado  de  listas  (y  otros  objetos  mutables)  puede  llevar  a  largas  horas  de  depuración.  Aquí  hay  
algunas  trampas  comunes  y  formas  de  evitarlas:

1.  La  mayoría  de  los  métodos  de  lista  modifican  el  argumento  y  devuelven .  Esto  es  lo  contrario  de  los  
métodos  de  cadena,  que  devuelven  una  nueva  cadena  y  dejan  el  original  en  paz.

Si  está  acostumbrado  a  escribir  código  de  cadena  como  este:

Es  tentador  escribir  un  código  de  lista  como  este:
Machine Translated by Google

10.13.  depuración 99

Porque devoluciones , la  próxima  operación  que  realice  es  probable  que  falle.

Antes  de  usar  métodos  y  operadores  de  lista,  debe  leer  la  documentación  detenidamente  y  
luego  probarlos  en  modo  interactivo.

2.  Elija  un  idioma  y  quédese  con  él.

Parte  del  problema  con  las  listas  es  que  hay  demasiadas  formas  de  hacer  las  cosas.  Por  ejemplo,  
, asignación  
para  eliminar  un  elemento  de  una  lista,  puede  utilizar  o  incluso  una   , d,e  sector.

Para  agregar  un  elemento,  puede  usar  es   método  o  el  operador.  Asumiendo  que
una  lista  y  es  un  elemento  de  lista,  estos  son  correctos:

Y  estos  están  mal:

Pruebe  cada  uno  de  estos  ejemplos  en  modo  interactivo  para  asegurarse  de  que  entiende  lo  que  
hacen.  Tenga  en  cuenta  que  solo  el  último  provoca  un  error  de  tiempo  de  ejecución;  los  otros  
tres  son  legales,  pero  hacen  lo  incorrecto.

3.  Haga  copias  para  evitar  la  creación  de  alias.

Si  desea  utilizar  un  método  como  ese  que  modifica  el  argumento,  pero  también  necesita  
conservar  la  lista  original,  puede  hacer  una  copia.

En  este  ejemplo,  también  podría  usar  la  lista  ordenada  de   , que  devuelve  un  nuevo,
funciones  incorporada  y  dejar  el  original  solo.
Machine Translated by Google

100 Capítulo  10.  Listas

10.14  Lista  del  glosario:  Una  

secuencia  de  valores.

elemento:  Uno  de  los  valores  en  una  lista  (u  otra  secuencia),  también  llamados  elementos.

lista  anidada:  Una  lista  que  es  un  elemento  de  otra  lista.

acumulador:  una  variable  utilizada  en  un  bucle  para  sumar  o  acumular  un  resultado.

asignación  aumentada:  una  declaración  que  actualiza  el  valor  de  una  variable  usando  una  ópera
como .

reducir:  Un  patrón  de  procesamiento  que  atraviesa  una  secuencia  y  acumula  los  elementos  en
un  solo  resultado.

mapa:  Un  patrón  de  procesamiento  que  atraviesa  una  secuencia  y  realiza  una  operación  en  cada
elemento.

filtro:  Un  patrón  de  procesamiento  que  recorre  una  lista  y  selecciona  los  elementos  que  satisfacen
criterio.

objeto:  Algo  a  lo  que  una  variable  puede  referirse.  Un  objeto  tiene  un  tipo  y  un  valor.

equivalente:  Que  tiene  el  mismo  valor.

idéntico:  Ser  el  mismo  objeto  (lo  que  implica  equivalencia).

referencia:  La  asociación  entre  una  variable  y  su  valor.

aliasing:  una  circunstancia  en  la  que  dos  o  más  variables  se  refieren  al  mismo  objeto.

delimitador:  un  carácter  o  cadena  que  se  utiliza  para  indicar  dónde  debe  dividirse  una  cadena.

10.15  Ejercicios

Puedes  descargar  soluciones  a  estos  ejercicios  desde
.
Ejercicio  10.1.  Escriba  una  función  llamada  que  tome  una  lista  de  listas  de  números  enteros  y  sume  los  
elementos  de  todas  las  listas  anidadas.  Por  ejemplo:

Ejercicio  10.2.  Escriba  una  función  llamada  que  tome  una  lista  de  números  y  devuelva  la  suma  acumulativa;  es  
decir,  una  nueva  lista  donde  el  i­ésimo  elemento  es  la  suma  de  los  primeros  i  +  1  elementos  de  la  lista  original.  
Por  ejemplo:

Ejercicio  10.3.  Escriba  una  función  llamada  que  tome  una  lista  y  devuelva  una  nueva  lista  que  contenga  todos  los  
elementos  menos  el  primero  y  el  último.  Por  ejemplo:
Machine Translated by Google

10.15.  Ejercicios 101

Ejercicio  10.4.  Escriba  una  función  llamada  que  tome  una  lista,  la  modifique  eliminando  el  primer  y  el  último  elemento  y  
devuelva .  Por  ejemplo:

Ejercicio  10.5.  Escriba  una  función  llamada  si   que  toma  una  lista  como  parámetro  y  devuelve  lo  
la  lista  está  ordenada  en  orden  ascendente  y contrario.  Por  ejemplo:

Ejercicio  10.6.  Dos  palabras  son  anagramas  si  puedes  reorganizar  las  letras  de  una  para  deletrear  la  otra.
Escriba  una  función  llamada  que  tome  dos  cadenas  y  devuelva  si  son  anagramas.
Ejercicio  10.7.  Escriba  una  función  llamada  que  tome  una  lista  y  regrese  si  hay  algún  elemento  que  aparece  más  de  una  
vez.  No  debe  modificar  la  lista  original.
Ejercicio  10.8.  Este  ejercicio  pertenece  a  la  llamada  Paradoja  del  Cumpleaños,  sobre  la  cual  puedes  leer
en .

Si  hay  23  estudiantes  en  tu  clase,  ¿cuál  es  la  probabilidad  de  que  dos  de  ellos  tengan  el  mismo  cumpleaños?
Puede  estimar  esta  probabilidad  generando  muestras  aleatorias  de  23  cumpleaños  y  buscando  coincidencias.  Sugerencia:  
puede  generar  cumpleaños  aleatorios  con  la  función  en  el  módulo.

Puede  descargar  mi  solución  del  Ejercicio   .

10.9.  Escriba  una  función  que  lea  el  archivo  por  palabra.   y  construye  una  lista  con  un  método  de  

Escribe  dos  versiones  de  esta  función,  una  usando  el  modismo elemento  y  el  otro  usando
.  ¿Cuál  tarda  más  en  correr?  ¿Por  qué?

Solución:   .

Ejercicio  10.10.  Para  verificar  si  una  palabra  está  en  la  lista  de  palabras,  puede  usar  sería  lento   operador,  pero
porque  busca  las  palabras  en  orden.

Debido  a  que  las  palabras  están  en  orden  alfabético,  podemos  acelerar  las  cosas  con  una  búsqueda  de  bisección  
(también  conocida  como  búsqueda  binaria),  que  es  similar  a  lo  que  hace  cuando  busca  una  palabra  en  el  diccionario  (el  
libro,  no  la  estructura  de  datos) .  Comienza  en  el  medio  y  verifica  si  la  palabra  que  está  buscando  viene  antes  de  la  
palabra  en  el  medio  de  la  lista.  Si  es  así,  busque  la  primera  mitad  de  la  lista  de  la  misma  manera.  De  lo  contrario,  busca  
la  segunda  mitad.

De  cualquier  manera,  cortas  el  espacio  de  búsqueda  restante  a  la  mitad.  Si  la  lista  de  palabras  tiene  113.809  palabras,  
se  necesitarán  unos  17  pasos  para  encontrar  la  palabra  o  concluir  que  no  está  allí.

Escribe  una  función  llamada   que  toma  una  lista  ordenada  y  un  valor  objetivo  y  devuelve  si  no   si
la  palabra  está  en  la  lista  y lo  es.

O  puede  leer  la  documentación  del ¡Módulo  y  utilízalo!  Solución:
.

Ejercicio  10.11.  Dos  palabras  son  un  "par  inverso"  si  cada  una  es  el  reverso  de  la  otra.  Escriba  un  programa  que  
encuentre  todos  los  pares  inversos  en  la  lista  de  palabras.  Solución:
.

Ejercicio  10.12.  Dos  palabras  se  “entrelazan”  si  al  tomar  letras  alternas  de  cada  una  se  forma  una  nueva  palabra.  Por  
ejemplo,  "zapato"  y  "frío"  se  entrelazan  para  formar  "escolarizado".  Solución:
Machine Translated by Google

102 Capítulo  10.  Listas

.  Crédito:  Este  ejercicio  está  inspirado  en  un  ejemplo  en
.

1.  Escriba  un  programa  que  encuentre  todos  los  pares  de  palabras  que  se  entrelazan.  Pista:  ¡no  enumeres  todos  los  pares!

2.  ¿Puedes  encontrar  alguna  palabra  que  esté  entrelazada  en  tres  direcciones?  es  decir,  cada  tercera  letra  forma  
una  palabra,  a  partir  de  la  primera,  segunda  o  tercera?
Machine Translated by Google

Capítulo  11

Diccionarios

Este  capítulo  presenta  otro  tipo  incorporado  llamado  diccionario.  Los  diccionarios  son  una  de  las  mejores  
características  de  Python;  son  los  componentes  básicos  de  muchos  algoritmos  eficientes  y  elegantes.

11.1  Un  diccionario  es  un  mapeo
Un  diccionario  es  como  una  lista,  pero  más  general.  En  una  lista,  los  índices  deben  ser  números  enteros;  
en  un  diccionario  pueden  ser  (casi)  cualquier  tipo.

Un  diccionario  contiene  una  colección  de  índices,  que  se  denominan  claves,  y  una  colección  de  valores.  
Cada  clave  está  asociada  con  un  único  valor.  La  asociación  de  una  clave  y  un  valor  se  denomina  par  clave­
valor  o,  a  veces,  elemento.

En  lenguaje  matemático,  un  diccionario  representa  una  asignación  de  claves  a  valores,  por  lo  que  también  
puede  decir  que  cada  clave  "se  asigna"  a  un  valor.  Como  ejemplo,  construiremos  un  diccionario  que  mapea  
palabras  de  inglés  a  español,  por  lo  que  las  claves  y  los  valores  son  todas  cadenas.

La  función  crea  un  nuevo  diccionario  sin  elementos.  Debido  a  que  es  una  función   es  el  nombre  de  un
incorporada,  debe  evitar  usarla  como  nombre  de  variable.

Los  corchetes  ondulados  representan  un  diccionario  vacío.  Para  agregar  elementos  al  diccionario,  puede  
usar  corchetes:

Esta  línea  crea  un  elemento  que  se  asigna  desde  la  clave  hasta  el  valor . Si  volvemos  a  
imprimir  el  diccionario,  vemos  un  par  clave­valor  con  dos  puntos  entre  la  clave  y  el  valor:

Este  formato  de  salida  es  también  un  formato  de  entrada.  Por  ejemplo,  puede  crear  un  nuevo  diccionario  
con  tres  elementos:
Machine Translated by Google

104 Capítulo  11.  Diccionarios

Pero  si  imprimes ,  te  sorprenderías:

El  orden  de  los  pares  clave­valor  puede  no  ser  el  mismo.  Si  escribe  el  mismo  ejemplo  en  su  
computadora,  es  posible  que  obtenga  un  resultado  diferente.  En  general,  el  orden  de  los  elementos  en  
un  diccionario  es  impredecible.

Pero  eso  no  es  un  problema  porque  los  elementos  de  un  diccionario  nunca  se  indexan  con  índices  
enteros.  En  su  lugar,  utiliza  las  teclas  para  buscar  los  valores  correspondientes:

La  clave siempre  se  asigna  al  valor así  que  el  orden  de  los  artículos  no  importa.

Si  la  clave  no  está  en  el  diccionario,  obtendrá  una  excepción:

La  función  funciona  en  diccionarios;  devuelve  el  número  de  pares  clave­valor:

El  operador  también  trabaja  con  diccionarios;  te  dice  si  algo  aparece  como  una  clave  en  el  diccionario  
(aparecer  como  un  valor  no  es  lo  suficientemente  bueno).

Para  ver  si  algo  aparece  como  valor  en  un  diccionario,  puedes  usar  el  método
, que  devuelve  una  colección  de  valores,  y  luego  usa  el  operador:

El  operador  utiliza  diferentes  algoritmos  para  listas  y  diccionarios.  Para  las  listas,  busca  los  elementos  de  la  
lista  en  orden,  como  en  la  Sección  8.6.  A  medida  que  la  lista  se  hace  más  larga,  el  tiempo  de  búsqueda  se  
hace  más  largo  en  proporción  directa.

Los  diccionarios  de  Python  usan  una  estructura  de  datos  llamada  tabla  hash  que  tiene  una  propiedad  
notable:  el  operador  tarda  aproximadamente  la  misma  cantidad  de  tiempo  sin  importar  cuántos  elementos  
haya  en  el  diccionario.  Explico  cómo  es  eso  posible  en  la  Sección  B.4,  pero  es  posible  que  la  explicación  
no  tenga  sentido  hasta  que  haya  leído  algunos  capítulos  más.

11.2  Diccionario  como  colección  de  fichas
Suponga  que  le  dan  una  cadena  y  desea  contar  cuántas  veces  aparece  cada  letra.
Hay  varias  formas  de  hacerlo:
Machine Translated by Google

11.2.  Diccionario  como  colección  de  contadores 105

1.  Podrías  crear  26  variables,  una  para  cada  letra  del  alfabeto.  Luego  podría  recorrer  la  cadena  
y,  para  cada  carácter,  incrementar  el  contador  correspondiente,  probablemente  usando  un  
condicional  encadenado.

2.  Podrías  crear  una  lista  con  26  elementos.  Luego,  podría  convertir  cada  carácter  en  un  número  
(usando  la  función  integrada),  usar  el  número  como  un  índice  en  la  lista  e  incrementar  el  
contador  apropiado.

3.  Podrías  crear  un  diccionario  con  caracteres  como  claves  y  contadores  como  los  valores  
correspondientes.  La  primera  vez  que  vea  un  carácter,  agregaría  un  elemento  al  diccionario.
Después  de  eso,  incrementaría  el  valor  de  un  elemento  existente.

Cada  una  de  estas  opciones  realiza  el  mismo  cálculo,  pero  cada  una  de  ellas  implementa  ese  
cálculo  de  una  manera  diferente.

Una  implementación  es  una  forma  de  realizar  un  cálculo;  algunas  implementaciones  son  mejores  
que  otras.  Por  ejemplo,  una  ventaja  de  la  implementación  del  diccionario  es  que  no  tenemos  que  
saber  de  antemano  qué  letras  aparecen  en  la  cadena  y  solo  tenemos  que  dejar  espacio  para  las  
letras  que  aparecen.

Así  es  como  se  vería  el  código:

El  nombre  de  la  función  es  (o   , que  es  un  término  estadístico  para  una  colección  de  contadores
frecuencias).

La  primera  línea  de  la  función  crea  un  diccionario  vacío.  El  lazo  atraviesa  la  cuerda.
Cada  vez  que  recorremos  el  bucle,  si  el  carácter  no  está  en  el  diccionario,  creamos  un  nuevo  
elemento  con  clave  y  el  valor  inicial  1  (ya  que  hemos  visto  esta  letra  una  vez).  Si  ya  está  en  el  
diccionario  incrementamos .

Así  es  como  funciona:

El  histograma  indica  que  las  letras y aparecer  una  vez; Aparece  dos  veces  y


pronto.

Los  diccionarios  tienen  un  método   que  toma  una  clave  y  un  valor  predeterminado.  Si  la  
llamado  aparece  en  el   clave  devuelve  el  valor  correspondiente;  de  lo  contrario,  devuelve  el
diccionario,  valor  predeterminado.  Por  ejemplo:
Machine Translated by Google

106 Capítulo  11.  Diccionarios

Como  ejercicio,  utilice   escribir de  forma  más  concisa.  Deberías  poder  eliminar


la  sentencia.

11.3  Bucles  y  diccionarios
Si  usa  un  diccionario  en  una  declaración,  atraviesa  las  claves  del  diccionario.  Por  ejemplo,  imprime  
cada  clave  y  el  valor  correspondiente:

Así  es  como  se  ve  la  salida:

Una  vez  más,  las  claves  no  están  en  ningún  orden  en  particular.  Para  recorrer  las  teclas  en  orden  ordenado,  puede  
usar  la  función  incorporada :

11.4  Búsqueda  inversa
Dado  un  diccionario  y  una  clave,  es  fácil  encontrar  el  valor  correspondiente.  La   .  Este
operación  se  denomina  búsqueda .

Pero,  ¿y  si  lo  tienes  y  lo  quieres  encontrar?  Tiene  dos  problemas:  primero,  puede  haber  más  de  una  
clave  que  se  asigna  al  valor.  Dependiendo  de  la  aplicación,  es  posible  que  pueda  elegir  una,  o  puede  
que  tenga  que  hacer  una  lista  que  las  contenga  todas.  En  segundo  lugar,  no  existe  una  sintaxis  simple  
para  realizar  una  búsqueda  inversa;  tienes  que  buscar

Aquí  hay  una  función  que  toma  un  valor  y  devuelve  la  primera  clave  que  se  asigna  a  ese  valor:
Machine Translated by Google

11.5.  diccionarios  y  listas 107

Esta  función  es  otro  ejemplo  más  del  patrón  de  búsqueda,  pero  utiliza  una  función  que  no  hemos  
visto  antes, .  La  declaración  de  aumento  provoca  una  excepción;  en  este  caso,  provoca  una  
, excepción  integrada  que  se  usa  para  indicar  que  una  operación  de  búsqueda  falló.

Si  llegamos  al  final  del  bucle,  eso  significa  que  no  aparece  en  el  diccionario  como  un  valor,  por  lo  que  
generamos  una  excepción.

Aquí  hay  un  ejemplo  de  una  búsqueda  inversa  exitosa:

Y  uno  fallido:

El  efecto  cuando  genera  una  excepción  es  el  mismo  que  cuando  Python  genera  una:  imprime  un  
seguimiento  y  un  mensaje  de  error.

Cuando  genera  una  excepción,  puede  proporcionar  un  mensaje  de  error  detallado  como  argumento  
opcional.  Por  ejemplo:

Una  búsqueda  inversa  es  mucho  más  lenta  que  una  búsqueda  directa;  si  tiene  que  hacerlo  a  menudo,  
o  si  el  diccionario  crece,  el  rendimiento  de  su  programa  se  verá  afectado.

11.5  Diccionarios  y  listas

Las  listas  pueden  aparecer  como  valores  en  un  diccionario.  Por  ejemplo,  si  le  dan  un  diccionario  
que  asigna  letras  a  frecuencias,  es  posible  que  desee  invertirlo;  es  decir,  cree  un  diccionario  que  
mapee  desde  frecuencias  hasta  letras.  Dado  que  puede  haber  varias  letras  con  la  misma  
frecuencia,  cada  valor  en  el  diccionario  invertido  debe  ser  una  lista  de  letras.

Aquí  hay  una  función  que  invierte  un  diccionario:
Machine Translated by Google

108 Capítulo  11.  Diccionarios

dictar dictar lista

historia 'a' 1 inversión 1 0 'a'

'pag' 1 1 'pag'

'r' 2 2 't'
't' 1 3 'o'
'o' 1
lista

2 0 'r'

Figura  11.1:  Diagrama  de  estado.

Cada  vez  que  pasa  por  el  bucle,  obtiene  una  clave  de  y  obtiene  el  valor  correspondiente.
ignifica  que  no  lo  h, emos  visto  antes,  creamos  un  nuevo  elemento  y  no  lo  inicializamos  con  
Si  eso  sun  
singleton  (una  lista  que  contiene  un  solo  elemento).  De  lo  contrario,  hemos  visto  este  valor  antes,  
por  lo  que  agregamos  la  clave  correspondiente  a  la  lista.

Aquí  hay  un  ejemplo:

. se  representa  como  un  cuadro  
y Un  diccionario  
La  figura  11.1  es  un  diagrama  de  estado  que  muestra  
con  el  tipo  encima  y  los  pares  clave­valor  dentro.  Si  los  valores  son  enteros,  flotantes  o  cadenas,  los  
dibujo  dentro  del  cuadro,  pero  generalmente  dibujo  listas  fuera  del  cuadro,  solo  para  simplificar  el  
diagrama.

Las  listas  pueden  ser  valores  en  un  diccionario,  como  muestra  este  ejemplo,  pero  no  pueden  ser  claves.  Esto  
es  lo  que  sucede  si  lo  intentas:

Mencioné  anteriormente  que  un  diccionario  se  implementa  usando  una  tabla  hash  y  eso  significa  que  
las  claves  tienen  que  ser  hashable.

Un  hash  es  una  función  que  toma  un  valor  (de  cualquier  tipo)  y  devuelve  un  número  entero.  Los  diccionarios  
usan  estos  números  enteros,  llamados  valores  hash,  para  almacenar  y  buscar  pares  clave­valor.

Este  sistema  funciona  bien  si  las  claves  son  inmutables.  Pero  si  las  claves  son  mutables,  como  las  
listas,  suceden  cosas  malas.  Por  ejemplo,  cuando  crea  un  par  clave­valor,  Python  procesa  la  clave  
y  la  almacena  en  la  ubicación  correspondiente.  Si  modifica  la  clave  y  luego  la  vuelve  a  codificar,  iría  
a  una  ubicación  diferente.  En  ese  caso,  es  posible  que  tenga  dos  entradas  para  la  misma  clave  o  
que  no  pueda  encontrar  una  clave.  De  cualquier  manera,  el  diccionario  no  funcionaría  correctamente.

Es  por  eso  que  las  claves  tienen  que  ser  hashable  y  por  qué  los  tipos  mutables  como  las  listas  no  lo  son.  
La  forma  más  sencilla  de  sortear  esta  limitación  es  utilizar  tuplas,  que  veremos  en  el  próximo  capítulo.
Machine Translated by Google

11.6.  Notas 109

fibonacci
norte 4

fibonacci fibonacci
norte 3 norte 2

fibonacci fibonacci fibonacci fibonacci


norte 2 norte 1 norte 1 norte 0

fibonacci fibonacci
norte 1 norte
0

Figura  11.2:  Gráfico  de  llamadas.

Dado  que  los  diccionarios  son  mutables,  no  se  pueden  usar  como  claves,  pero  se  pueden  usar  como  valores.

11.6  Notas
Si  jugó  con  la  función  de  la  Sección  6.7,  es  posible  que  haya  notado  que  cuanto  mayor  sea  el  argumento  
que  proporcione,  más  tiempo  tardará  en  ejecutarse  la  función.  Además,  el  tiempo  de  ejecución  aumenta  
rápidamente.

Para  entender  por  qué,  considere  la  figura  11.2,  que  muestra  el  gráfico  de  llamadas  para con
:

Un  gráfico  de  llamadas  muestra  un  conjunto  de  marcos  de  función,  con  líneas  que  conectan  cada  marco  con  los  
con con  y .
marcos  de  las  funciones  a  las  que  llama.  En  la  parte  superior  del  gráfico,  llamadas  
A  su  vez,  con  con  y .  Etcétera. llamadas

Cuente  cuántas  veces   y son  llamados.  Este  es  un  ineficiente
soluciona  el  problema,  y  empeora  a  medida  que  la  discusión  se  hace  más  grande.

Una  solución  es  realizar  un  seguimiento  de  los  valores  que  ya  se  han  calculado  almacenándolos  en  un  
diccionario.  Un  valor  previamente  calculado  que  se  almacena  para  su  uso  posterior  se  denomina  memo.
Aquí  hay  una  versión  "memorizada"  de :

es  un  diccionario  que  realiza  un  seguimiento  de  los  números  de  Fibonacci  que  ya  conocemos.  Comienza
con  dos  elementos:  0  se  asigna  a  0  y  1  se  asigna  a  1.
Machine Translated by Google

110 Capítulo  11.  Diccionarios

Cada  vez  que  se  llama,  comprueba  si  el  resultado  ya  .está  allí,  puede  volver  inmediatamente.  De  lo  
contrario,  debe  calcular  el  nuevo  valor,  agregarlo  al  diccionario  y  devolverlo.

Si  ejecuta  esta  versión  de  es   y  compárelo  con  el  original,  encontrará  que
mucho  más  rápido.

11.7  Variables  globales

En  el  ejemplo  anterior,  se  crea  fuera  de  la  función,  por  lo  que  pertenece  al  marco  especial  llamado .  Las  
variables  en  a  veces  se  denominan  globales  porque  se  puede  acceder  a  ellas  desde  cualquier  función.  
A  diferencia  de  las  variables  locales,  que  desaparecen  cuando  finaliza  su  función,  las  variables  globales  
persisten  de  una  llamada  de  función  a  la  siguiente.

Es  común  usar  variables  globales  para  banderas;  es  decir,  variables  booleanas  que  indican  ("bandera")  
si  una  condición  es  verdadera.  Por  ejemplo,  algunos  programas  usan  un  indicador   a
llamado  control  del  nivel  de  detalle  en  la  salida:

Si  intenta  reasignar  una  variable  global,  puede  que  se  sorprenda.  Se  supone  que  el  siguiente  ejemplo  
realiza  un  seguimiento  de  si  se  ha  llamado  a  la  función:

Pero  si  lo  ejecuta  verá  que  el  valor  de no  cambia  El  problema  es  ese .  
La  variable  local  desaparece  
crea  una  ncueva   variable  
uando   local  
finaliza   llamada
la  función  
y  no  tiene  ningún  efecto  sobre  la  variable  
global.

Para  reasignar  una  variable  global  dentro  de  una  función,  debe  declarar  la  variable  global  antes  de  
usarla:

La  declaración  global  le  dice  al  intérprete  algo  como,  “En  esta  función,  cuando  digo  me  refiero  a  la  
, variable  global;  no  crees  uno  local”.

Aquí  hay  un  ejemplo  que  intenta  actualizar  una  variable  global:

Si  lo  ejecutas  obtienes:
Machine Translated by Google

11.8.  depuración 111

Python  asume  que  es  local  y,  bajo  esa  suposición,  lo  está  leyendo  antes  de  escribirlo.  La  solución,  de  nuevo,  
es  declarar global.

Si  una  variable  global  hace  referencia  a  un  valor  mutable,  puede  modificar  el  valor  sin  declarar  la  variable:

Entonces  puede  agregar,  eliminar  y  reemplazar  elementos  de  una  lista  global  o  diccionario,  pero  si  desea  
reasignar  la  variable,  debe  declararla:

Las  variables  globales  pueden  ser  útiles,  pero  si  tiene  muchas  y  las  modifica  con  frecuencia,  pueden  dificultar  
la  depuración  de  programas.

11.8  Depuración
A  medida  que  trabaja  con  conjuntos  de  datos  más  grandes,  puede  volverse  difícil  depurar  imprimiendo  y  
verificando  la  salida  a  mano.  Estas  son  algunas  sugerencias  para  depurar  grandes  conjuntos  de  datos:

Reducir  la  entrada:  si  es  posible,  reduzca  el  tamaño  del  conjunto  de  datos.  Por  ejemplo,  si  el  programa  lee  
un  archivo  de  texto,  comience  solo  con  las  primeras  10  líneas  o  con  el  ejemplo  más  pequeño  que  
pueda  encontrar.  Puede  editar  los  archivos  o  (mejor)  modificar  el  programa  para  que  lea  solo  las  
primeras  líneas.

Si  hay  un  error,  puede  reducirlo  al  valor  más  pequeño  que  manifieste  el  error  y  luego  aumentarlo  
gradualmente  a  medida  que  encuentre  y  corrija  los  errores.

Verifique  resúmenes  y  tipos:  en  lugar  de  imprimir  y  verificar  todo  el  conjunto  de  datos,  considere  imprimir  
resúmenes  de  los  datos:  por  ejemplo,  la  cantidad  de  elementos  en  un  diccionario  o  el  total  de  una  lista  
de  números.

Una  causa  común  de  errores  de  tiempo  de  ejecución  es  un  valor  que  no  es  del  tipo  correcto.  Para  
depurar  este  tipo  de  error,  suele  ser  suficiente  imprimir  el  tipo  de  un  valor.

Escribir  autocomprobaciones:  a  veces  puede  escribir  código  para  comprobar  si  hay  errores  automáticamente.  
Por  ejemplo,  si  está  calculando  el  promedio  de  una  lista  de  números,  puede  verificar  que  el  resultado  
no  sea  mayor  que  el  elemento  más  grande  de  la  lista  ni  menor  que  el  más  pequeño.
Esto  se  denomina  "control  de  cordura"  porque  detecta  resultados  que  son  "locos".

Otro  tipo  de  verificación  compara  los  resultados  de  dos  cálculos  diferentes  para  ver  si  son  consistentes.  
Esto  se  llama  una  "verificación  de  consistencia".
Machine Translated by Google

112 Capítulo  11.  Diccionarios

Formatee  la  salida:  Formatear  la  salida  de  depuración  puede  facilitar  la  detección  de  un  error.  Vimos  un  ejemplo  en  
la  Sección  6.9.  Otra  herramienta  que  puede  resultarle  útil  es  el  módulo,  que  proporciona  una  función  que  
muestra  los  tipos  incorporados  en  un  formato  más  legible  para  los  humanos  (significa  “letra  bonita”).

Una  vez  más,  el  tiempo  que  dedica  a  construir  andamios  puede  reducir  el  tiempo  que  dedica  a  la  depuración.

11.9  Glosario
Mapeo:  Una  relación  en  la  que  cada  elemento  de  un  conjunto  corresponde  a  un  elemento  de
otro  conjunto

diccionario:  Un  mapeo  de  claves  a  sus  valores  correspondientes.

par  clave­valor:  La  representación  del  mapeo  de  una  clave  a  un  valor.

elemento:  en  un  diccionario,  otro  nombre  para  un  par  clave­valor.

clave:  un  objeto  que  aparece  en  un  diccionario  como  la  primera  parte  de  un  par  clave­valor.

valor:  un  objeto  que  aparece  en  un  diccionario  como  la  segunda  parte  de  un  par  clave­valor.  Esto  es
más  específico  que  nuestro  uso  anterior  de  la  palabra  "valor".

implementación:  Una  forma  de  realizar  un  cálculo.

hashtable:  el  algoritmo  utilizado  para  implementar  los  diccionarios  de  Python.

función  hash:  una  función  utilizada  por  una  tabla  hash  para  calcular  la  ubicación  de  una  clave.

hashable:  un  tipo  que  tiene  una  función  hash.  Los  tipos  inmutables  como  enteros,  flotantes  y  cadenas  son  hashable;  
los  tipos  mutables  como  listas  y  diccionarios  no  lo  son.

búsqueda:  una  operación  de  diccionario  que  toma  una  clave  y  encuentra  el  valor  correspondiente.

búsqueda  inversa:  Una  operación  de  diccionario  que  toma  un  valor  y  encuentra  una  o  más  claves  que
mapearlo.

declaración  de  aumento:  una  declaración  que  (deliberadamente)  genera  una  excepción.

singleton:  Una  lista  (u  otra  secuencia)  con  un  solo  elemento.

gráfico  de  llamada:  un  diagrama  que  muestra  cada  marco  creado  durante  la  ejecución  de  un  programa,
con  una  flecha  de  cada  llamador  a  cada  destinatario.

memo:  Un  valor  calculado  almacenado  para  evitar  cálculos  futuros  innecesarios.

variable  global:  una  variable  definida  fuera  de  una  función.  Se  puede  acceder  a  las  variables  globales
de  cualquier  función.

declaración  global:  una  declaración  que  declara  un  nombre  de  variable  global.

bandera:  una  variable  booleana  utilizada  para  indicar  si  una  condición  es  verdadera.

declaración:  Una  declaración  como que  le  dice  al  intérprete  algo  sobre  una  variable.
Machine Translated by Google

11.10.  Ejercicios 113

11.10  Ejercicios

Ejercicio  11.1.  Escriba  una  función  que  lea  las  palabras  y  las  almacene  como  claves  en  un  diccionario.  No  importa  
cuáles  sean  los  valores.  Luego  puede  usar  el  operador  como  una  forma  rápida  de  verificar  si  una  cadena  está  en  el  
diccionario.

Si  hizo  el  ejercicio  10.10,  puede  comparar  la  velocidad  de  esta  implementación  con  el  operador  de  lista  y  la  búsqueda  
de  bisección.
Ejercicio  11.2.  Lea  la  documentación  del  método  de  diccionario  versión  más   y  úsalo  para  escribir  un
concisa  de .  Solución:
.
Ejercicio  11.3.  Memorice  la  función  de  Ackermann  del  ejercicio  6.2  y  vea  si  la  memorización  hace  posible  evaluar  la  
función  con  argumentos  más  grandes.  Pista:  no.  Solución:
.
Ejercicio  11.4.  Si  hiciste  el  ejercicio  10.7,  ya  tienes  una  función  llamada  que  toma  una  lista  como  parámetro  y  
regresa  si  hay  algún  objeto  que  aparece  más  de  una  vez  en  la  lista.

Use  un  diccionario  para  escribir  una  versión  más  rápida  y  simple  de .  Solución:
.
Ejercicio  11.5.  Dos  palabras  son  "rotar  pares"  si  puedes  rotar  una  de  ellas  y  obtener  la  otra  (ver
en  el  ejercicio  8.5).

Escriba  un  programa  que  lea  una  lista  de  palabras  y  encuentre  todos  los  pares  rotativos.  Solución:
.
Ejercicio  11.6.  Aquí  hay  otro  Puzzler  de  Car  Talk  (
):

Esto  fue  enviado  por  un  tipo  llamado  Dan  O'Leary.  Recientemente  se  encontró  con  una  palabra  
común  de  una  sílaba  y  cinco  letras  que  tiene  la  siguiente  propiedad  única.  Cuando  quitas  la  primera  
letra,  las  letras  restantes  forman  un  homófono  de  la  palabra  original,  es  decir,  una  palabra  que  suena  
exactamente  igual.  Reemplace  la  primera  letra,  es  decir,  vuelva  a  colocarla  y  elimine  la  segunda  letra  
y  el  resultado  es  otro  homófono  de  la  palabra  original.  Y  la  pregunta  es,  ¿cuál  es  la  palabra?

Ahora  les  voy  a  dar  un  ejemplo  que  no  funciona.  Veamos  la  palabra  de  cinco  letras,  'wrack'.  WRACK,  
sabes  que  te  gusta  'retorcer  con  dolor'.  Si  elimino  la  primera  letra,  me  queda  una  palabra  de  cuatro  
letras,  'RACK'.  Como  en,  '¡Santa  vaca,  viste  el  estante  en  ese  dólar!  ¡Debe  haber  sido  un  nueve  
puntos!  Es  un  homófono  perfecto.  Si  vuelves  a  poner  la  'w'  y  quitas  la  'r',  te  queda  la  palabra  'wack',  
que  es  una  palabra  real,  pero  no  es  un  homófono  de  las  otras  dos  palabras.

Pero  hay,  sin  embargo,  al  menos  una  palabra  que  Dan  y  nosotros  conocemos,  que  producirá  dos  
homófonos  si  elimina  cualquiera  de  las  dos  primeras  letras  para  formar  dos  nuevas  palabras  de  cuatro  
letras.  La  pregunta  es,  ¿cuál  es  la  palabra?

Puede  usar  el  diccionario  del  ejercicio  11.1  para  verificar  si  una  cadena  está  en  la  lista  de  palabras.

Para  verificar  si  dos  palabras  son  homófonas,  puede  usar  el  diccionario  de  pronunciación  CMU.  Puedes  descargarlo  
desde o  de
y  también  puede  descargar  que  
, proporciona  una  función  llamada que  lee  el  
diccionario  de  pronunciación  y  devuelve  un  diccionario  de  Python  que  asigna  cada  palabra  a  una  cadena  que  
describe  su  pronunciación  principal.
Machine Translated by Google

114 Capítulo  11.  Diccionarios

Escriba  un  programa  que  enumere  todas  las  palabras  que  resuelven  el  rompecabezas.  Solución:
.
Machine Translated by Google

Capítulo  12

tuplas

Este  capítulo  presenta  un  tipo  incorporado  más,  la  tupla,  y  luego  muestra  cómo  las  listas,  los  diccionarios  y  las  
tuplas  funcionan  juntos.  También  presento  una  función  útil  para  las  listas  de  argumentos  de  longitud  variable,  los  
operadores  de  recopilación  y  dispersión.

Una  nota:  no  hay  consenso  sobre  cómo  pronunciar  "tupla".  Algunas  personas  dicen  "tuh  ple",  que  rima  con  
"supple".  Pero  en  el  contexto  de  la  programación,  la  mayoría  de  la  gente  dice  "demasiado",  que  rima  con  "cuádruple".

12.1  Las  tuplas  son  inmutables
Una  tupla  es  una  secuencia  de  valores.  Los  valores  pueden  ser  de  cualquier  tipo  y  están  indexados  por  números  
enteros,  por  lo  que,  en  ese  sentido,  las  tuplas  se  parecen  mucho  a  las  listas.  La  diferencia  importante  es  que  las  tuplas
son  inmutables.

Sintácticamente,  una  tupla  es  una  lista  de  valores  separados  por  comas:

Aunque  no  es  necesario,  es  común  encerrar  las  tuplas  entre  paréntesis:

Para  crear  una  tupla  con  un  solo  elemento,  debe  incluir  una  coma  final:

Un  valor  entre  paréntesis  no  es  una  tupla:

Otra  forma  de  crear  una  tupla  es  la  función  integrada  una  tupla  vacía: .  Sin  argumento,  crea
Machine Translated by Google

116 Capítulo  12.  Tuplas

Si  el  argumento  es  una  secuencia  (cadena,  lista  o  tupla),  el  resultado  es  una  tupla  con  los  elementos  de  
la  secuencia:

Porque es  el  nombre  de  una  función  incorporada,  debe  evitar  usarla  como  una  variable
nombre.

La  mayoría  de  los  operadores  de  listas  también  funcionan  con  tuplas.  El  operador  de  paréntesis  indexa  un  elemento:

Y  el  operador  de  corte  selecciona  un  rango  de  elementos.

Pero  si  intenta  modificar  uno  de  los  elementos  de  la  tupla,  obtiene  un  error:

Debido  a  que  las  tuplas  son  inmutables,  no  puede  modificar  los  elementos.  Pero  puedes  reemplazar  una  
tupla  por  otra:

Esta  declaración  crea  una  nueva  tupla  y  luego  hace  referencia  a  ella.

Los  operadores  relacionales  trabajan  con  tuplas  y  otras  secuencias;  Python  comienza  comparando  el  
primer  elemento  de  cada  secuencia.  Si  son  iguales,  pasa  a  los  siguientes  elementos,  y  así  sucesivamente,  
hasta  encontrar  elementos  que  difieren.  Los  elementos  posteriores  no  se  consideran  (incluso  si  son  
realmente  grandes).

12.2  Asignación  de  tuplas
A  menudo  es  útil  intercambiar  los  valores  de  dos  variables.  Con  las  asignaciones  convencionales,  debe  
utilizar  una  variable  temporal.  Por  ejemplo,  para  intercambiar  y:

Esta  solución  es  engorrosa;  la  asignación  de  tuplas  es  más  elegante:
Machine Translated by Google

12.3.  Tuplas  como  valores  de  retorno 117

El  lado  izquierdo  es  una  tupla  de  variables;  el  lado  derecho  es  una  tupla  de  expresiones.  Cada  valor  se  asigna  a  
su  respectiva  variable.  Todas  las  expresiones  del  lado  derecho  se  evalúan  antes  que  cualquiera  de  las  
asignaciones.

El  número  de  variables  a  la  izquierda  y  el  número  de  valores  a  la  derecha  tiene  que  ser  el
mismo:

Más  generalmente,  el  lado  derecho  puede  ser  cualquier  tipo  de  secuencia  (cadena,  lista  o  tupla).  Por  ejemplo,  
para  dividir  una  dirección  de  correo  electrónico  en  un  nombre  de  usuario  y  un  dominio,  podría  escribir:

El  valor  de  retorno  del   es  una  lista  con  dos  elementos;  el  primer  elemento  se  asigna  a
, segundo  al .

12.3  Tuplas  como  valores  de  retorno

Estrictamente  hablando,  una  función  solo  puede  devolver  un  valor,  pero  si  el  valor  es  una  tupla,  el  efecto  es  el  
mismo  que  devolver  múltiples  valores.  Por  ejemplo,  si  desea  dividir  dos  números  enteros  y  calcular  el  cociente  y  
el  resto,  no  es  eficiente  calcular  y  luego .  Es  mejor  calcular  ambos  al  mismo  tiempo.

La  función  incorporada  toma  dos  argumentos  y  devuelve  una  tupla  de  dos  valores,  el  cociente  y  el  resto.  Puede  
almacenar  el  resultado  como  una  tupla:

O  use  la  asignación  de  tuplas  para  almacenar  los  elementos  por  separado:

Aquí  hay  un  ejemplo  de  una  función  que  devuelve  una  tupla:

y  son  funciones  integradas  que  encuentran  los  elementos  más  grandes  y  más  pequeños  de  una  secuencia.  
calcula  ambos  y  devuelve  una  tupla  de  dos  valores.
Machine Translated by Google

118 Capítulo  12.  Tuplas

12.4  Tuplas  de  argumento  de  longitud  variable

Las  funciones  pueden  tomar  un  número  variable  de  argumentos.  Un  nombre  de  parámetro  que  comienza  con  toma  
reúne  argumentos  en  una  tupla.  Por  ejemplo,  y  los  imprime: cualquier  número  de  argumentos

El  parámetro  de  recopilación  puede  tener  el  nombre  que  desee,  pero  la   es  convencional.  Así  es  cómo
función  funciona:

El  complemento  de  reunir  es  dispersar.  Si  tiene  una  secuencia  de  valores  y  desea  pasarla  a  una  función  como  múltiples  
argumentos,  puede  usar  el  operador.  Por  ejemplo,  toma  exactamente  dos  argumentos;  no  funciona  con  una  
tupla:

Pero  si  dispersas  la  tupla,  funciona:

Muchas  de  las  funciones  integradas  utilizan  tuplas  de  argumentos  de  longitud  variable.  Por  ejemplo,  y  puede  tomar  
cualquier  número  de  argumentos:

Pero no  es.

Como  ejercicio,  escribe  una  función  llamada   que  toma  cualquier  número  de  argumentos  y
devuelve  su  suma.

12.5  Listas  y  tuplas

es  una  función  integrada  que  toma  dos  o  más  secuencias  y  las  intercala.  El  nombre  de  la  función  hace  referencia  
a  una  cremallera,  que  intercala  dos  filas  de  dientes.

Este  ejemplo  comprime  una  cadena  y  una  lista:

El  resultado  es  un  objeto  zip  que  sabe  cómo  iterar  a  través  de  los  pares.  El  uso  más  común  de  bucle:
está  en  un
Machine Translated by Google

12.5.  Listas  y  tuplas 119

Un  objeto  zip  es  un  tipo  de  iterador,  que  es  cualquier  objeto  que  itera  a  través  de  una  secuencia.
Los  iteradores  son  similares  a  las  listas  en  algunos  aspectos,  pero  a  diferencia  de  las  listas,  no  puede  usar  un  índice  para  
seleccionar  un  elemento  de  un  iterador.

Si  desea  usar  operadores  y  métodos  de  lista,  puede  usar  un  objeto  zip  para  hacer  una  lista:

El  resultado  es  una  lista  de  tuplas;  en  este  ejemplo,  cada  tupla  contiene  un  carácter  de  la  cadena  y  el  
elemento  correspondiente  de  la  lista.

Si  las  secuencias  no  tienen  la  misma  longitud,  el  resultado  tiene  la  longitud  de  la  más  corta.

Puede  utilizar  la  asignación  de  tuplas  en  un bucle  para  recorrer  una  lista  de  tuplas:

Cada  vez  que  pasa  por  el  bucle,  Python  selecciona  la  siguiente  tupla  de  la  lista  y  le  asigna  el  elemento
mentos  a y .  La  salida  de  este  bucle  es:

Si  combina  y  tupla  la  a,signación,  obtiene  un  idioma  útil  para  atravesar  dos  (o  más)  secuencias  al  
mismo  tiempo.  Por  ejemplo,  and  y  devuelve  si  hay  un  índice   toma  dos  secuencias,
tal  que , :

Si  necesita  recorrer  los  elementos  de  una  secuencia  y  sus  índices,  puede  usar  la  función  incorporada
:

El  resultado  de  es  un  objeto  de  enumeración,  que  itera  una  secuencia  de  pares;  cada  par  contiene  un  
índice  (a  partir  de  0)  y  un  elemento  de  la  secuencia  dada.  En  este  ejemplo,  la  salida  es

De  nuevo.
Machine Translated by Google

120 Capítulo  12.  Tuplas

12.6  Diccionarios  y  tuplas
Los  diccionarios  tienen  un  método  llamado   que  devuelve  una  secuencia  de  tuplas,  donde  cada
tupla  que  es  un  par  clave­valor.

El  resultado  es   objeto,  que  es  un  iterador  que  itera  los  pares  clave­valor.  Haces  un  
una  lata  usarlo  en  un bucle  así:

Como  cabría  esperar  de  un  diccionario,  los  elementos  no  están  en  ningún  orden  en  particular.

Yendo  en  la  otra  dirección,  puede  usar  una  lista  de  tuplas  para  inicializar  un  nuevo  diccionario:

Combinatorio con produce  una  forma  concisa  de  crear  un  diccionario:

El  método  del  diccionario   también  toma  una  lista  de  tuplas  y  las  agrega,  como  pares  clave­valor,
a  un  diccionario  existente.

Es  común  usar  tuplas  como  claves  en  los  diccionarios  (principalmente  porque  no  puede  usar  
listas).  Por  ejemplo,  un  directorio  telefónico  podría  asignar  pares  de  apellido  y  nombre  a  números  
de  teléfono.  Suponiendo  que  hemos  definido  podríamos   , y
escribir: ,

La  expresión  entre  paréntesis  es  una  tupla.  Podríamos  usar  la  asignación  de  tuplas  para  recorrer  este  
diccionario.

Este  ciclo  atraviesa  las  claves  en   , que  son  tuplas.  Asigna  los  elementos  de  cada  uno  
tupla  hacia  y , y  luego  imprime  el  nombre  y  número  de  teléfono  correspondiente.

Hay  dos  formas  de  representar  tuplas  en  un  diagrama  de  estado.  La  versión  más  detallada  
muestra  los  índices  y  elementos  tal  como  aparecen  en  una  lista.  Por  ejemplo,  la  tupla  aparecería  
como  en  la  Figura  12.1.

Pero  en  un  diagrama  más  grande,  es  posible  que  desee  omitir  los  detalles.  Por  ejemplo,  un  diagrama  
de  la  guía  telefónica  podría  aparecer  como  en  la  figura  12.2.

Aquí  las  tuplas  se  muestran  usando  la  sintaxis  de  Python  como  una  abreviatura  gráfica.  El  número  
de  teléfono  en  el  diagrama  es  la  línea  de  quejas  de  la  BBC,  así  que  por  favor  no  llame.
Machine Translated by Google

12.7.  Secuencias  de  secuencias 121

tupla
0 'Clese'
1 'John'

Figura  12.1:  Diagrama  de  estado.

dictar

('Clese',  'Juan') '08700  100  222'
('Chapman',  'Graham') '08700  100  222'
('Inactivo',  'Eric') '08700  100  222'
('Gilliam',  'Terry') '08700  100  222'
('Jones',  'Terry') '08700  100  222'
('Palin',  'Michael') '08700  100  222'

Figura  12.2:  Diagrama  de  estado.

12.7  Secuencias  de  secuencias
Me  he  centrado  en  las  listas  de  tuplas,  pero  casi  todos  los  ejemplos  de  este  capítulo  también  funcionan  
con  listas  de  listas,  tuplas  de  tuplas  y  tuplas  de  listas.  Para  evitar  enumerar  las  posibles  combinaciones,  
a  veces  es  más  fácil  hablar  de  secuencias  de  secuencias.

En  muchos  contextos,  los  diferentes  tipos  de  secuencias  (cadenas,  listas  y  tuplas)  se  pueden  usar  
indistintamente.  Entonces,  ¿cómo  debería  elegir  uno  sobre  los  demás?

Para  empezar  con  lo  obvio,  las  cadenas  están  más  limitadas  que  otras  secuencias  porque  los  
elementos  tienen  que  ser  caracteres.  También  son  inmutables.  Si  necesita  la  capacidad  de  cambiar  
los  caracteres  en  una  cadena  (en  lugar  de  crear  una  nueva  cadena),  es  posible  que  desee  utilizar  una  
lista  de  caracteres  en  su  lugar.

Las  listas  son  más  comunes  que  las  tuplas,  principalmente  porque  son  mutables.  Pero  hay  algunos  
casos  en  los  que  podría  preferir  tuplas:

1.  En  algunos  contextos,   declaración,  es  sintácticamente  más  simple  crear  una  tupla
como  una  lista.

2.  Si  desea  utilizar  una  secuencia  como  clave  de  diccionario,  debe  utilizar  un  tipo  inmutable
como  una  tupla  o  cadena.

3.  Si  está  pasando  una  secuencia  como  argumento  a  una  función,  el  uso  de  tuplas  reduce  el
posibilidad  de  un  comportamiento  inesperado  debido  a  la  formación  de  alias.

,
Debido  a  que  las  tuplas  son  inmutables,  no  proporcionan  métodos  como  y  que  modifican  las  listas  
,
existentes.  Pero  Python  proporciona  la  función  integrada  que  toma  cualquier  secuencia  
y  devuelve  
una  nueva  lista  con  los  mismos  elementos  ordenados,  y  que  toma  una  secuencia  y   ,
devuelve  un  iterador  que  recorre  la  lista  en  orden  inverso.
Machine Translated by Google

122 Capítulo  12.  Tuplas

12.8  Depuración
Listas,  diccionarios  y  tuplas  son  ejemplos  de  estructuras  de  datos;  en  este  capítulo  estamos  empezando  a  ver  
estructuras  de  datos  compuestas,  como  listas  de  tuplas  o  diccionarios  que  contienen  tuplas  como  claves  y  listas  como  
valores.  Las  estructuras  de  datos  compuestas  son  útiles,  pero  son  propensas  a  lo  que  yo  llamo  errores  de  forma;  es  
decir,  errores  causados  cuando  una  estructura  de  datos  tiene  el  tipo,  tamaño  o  estructura  incorrectos.  Por  ejemplo,  si  
espera  una  lista  con  un  número  entero  y  le  doy  un  número  entero  simple  (no  en  una  lista),  no  funcionará.

Para  ayudar  a  depurar  este  tipo  de  errores,  he  escrito  un  módulo  llamado  que  proporciona  una  función,  también  
llamado  que  toma  cualquier  tipo  de  estructura  de  datos  como  ,argumento  y  devuelve  una  cadena  que  resume  su  
forma.  Puedes  descargarlo  desde

Aquí  está  el  resultado  de  una  lista  simple:

Un  programa  más  elegante  podría  escribir  "lista  de  3  enteros",  pero  era  más  fácil  no  tratar  con  plurales.
Aquí  hay  una  lista  de  listas:

Si  los  elementos  de  la  lista  no  son  del  mismo  tipo,  escriba: los  agrupa,  en  orden,  por

Aquí  hay  una  lista  de  tuplas:

Y  aquí  hay  un  diccionario  con  3  elementos  que  asignan  números  enteros  a  cadenas.

Si  tiene  problemas  para  realizar  un  seguimiento  de  sus  estructuras  de  datos, poder  ayudar.

12.9  Glosario
tupla:  Una  secuencia  inmutable  de  elementos.

asignación  de  tupla:  Una  asignación  con  una  secuencia  en  el  lado  derecho  y  una  tupla  de  variables  en  el  izquierdo.  
El  lado  derecho  se  evalúa  y  luego  sus  elementos  se  asignan  a  las  variables  de  la  izquierda.
Machine Translated by Google

12.10.  Ejercicios 123

reunir:  una  operación  que  recopila  múltiples  argumentos  en  una  tupla.

dispersión:  Una  operación  que  hace  que  una  secuencia  se  comporte  como  múltiples  argumentos.

objeto  zip:  El  resultado  de  llamar  a  una  secuencia  de  función  integrada   ;  un  objeto  que  itera  a  través  de  un
de  tuplas.

iterador:  un  objeto  que  puede  iterar  a  través  de  una  secuencia,  pero  que  no  proporciona  métodos  ni  operadores  de  lista.

estructura  de  datos:  una  colección  de  valores  relacionados,  a  menudo  organizados  en  listas,  diccionarios,  tuplas,
etc.

error  de  forma:  un  error  causado  porque  un  valor  tiene  la  forma  incorrecta;  es  decir,  el  tipo  equivocado
o  tamaño.

12.10  Ejercicios

Ejercicio  12.1.  Escriba  una  función  llamada  que  tome  una  cadena  e  imprima  las  letras  en  orden  decreciente  de  frecuencia.  
Encuentre  muestras  de  texto  de  varios  idiomas  diferentes  y  vea  cómo  la  frecuencia  de  las  letras  varía  entre  los  idiomas.  
Compare  sus  resultados  con  las  tablas  en .  Solución:

Ejercicio  12.2.  ¡Más  anagramas!

1.  Escriba  un  programa  que  lea  una  lista  de  palabras  de  un  archivo  (vea  la  Sección  9.1)  e  imprima  todos  los  conjuntos  de
palabras  que  son  anagramas.

Aquí  hay  un  ejemplo  de  cómo  se  vería  la  salida:

Sugerencia:  es  posible  que  desee  crear  un  diccionario  que  mapee  desde  una  colección  de  letras  a  una  lista  de  
palabras  que  se  pueden  deletrear  con  esas  letras.  La  pregunta  es,  ¿cómo  puedes  representar  la  colección  de  letras  
de  una  manera  que  pueda  usarse  como  clave?

2.  Modifique  el  programa  anterior  para  que  imprima  primero  la  lista  de  anagramas  más  larga,  luego  la  segunda  más  
larga  y  así  sucesivamente.

3.  En  Scrabble,  un  "bingo"  es  cuando  juegas  las  siete  fichas  en  tu  estante,  junto  con  una  letra  en  el  tablero,  para  formar  
una  palabra  de  ocho  letras.  ¿Qué  colección  de  8  letras  forma  la  mayor  cantidad  posible  de  bingos?

Solución: .

Ejercicio  12.3.  Dos  palabras  forman  un  “par  de  metátesis”  si  puedes  transformar  una  en  la  otra  intercambiando  dos  letras;  
por  ejemplo,  "conversar"  y  "conservar".  Escriba  un  programa  que  encuentre  todos  los  pares  de  metátesis  en  el  diccionario.  
Sugerencia:  no  pruebe  todos  los  pares  de  palabras  y  no  pruebe  todos  los  intercambios  posibles.  Solución: .  Crédito:  Este  
ejercicio  está  inspirado  en  un  ejemplo  en
.
Machine Translated by Google

124 Capítulo  12.  Tuplas

Ejercicio  12.4.  Aquí  hay  otro  Car  Talk  Puzzler  ( ):

¿Cuál  es  la  palabra  inglesa  más  larga,  que  sigue  siendo  una  palabra  inglesa  válida,  ya  que  eliminas  
sus  letras  una  a  la  vez?

Ahora,  las  letras  se  pueden  quitar  de  cualquier  extremo  o  del  medio,  pero  no  se  puede  reorganizar  
ninguna  de  las  letras.  Cada  vez  que  sueltas  una  letra,  terminas  con  otra  palabra  en  inglés.  Si  haces  
eso,  eventualmente  terminarás  con  una  letra  y  esa  también  será  una  palabra  en  inglés,  una  que  se  
encuentra  en  el  diccionario.  quiero  saber  cual  es  la  palabra  mas  larga  y  cuantas  letras  tiene

Te  voy  a  dar  un  pequeño  ejemplo  modesto:  Sprite.  ¿De  acuerdo?  Empiezas  con  sprite,  le  quitas  una  
letra,  una  del  interior  de  la  palabra,  le  quitas  la  r,  y  nos  queda  la  palabra  despecho,  luego  le  quitamos  
la  e  al  final,  nos  queda  escupir ,  le  quitamos  la  s,  nos  queda  pit,  it,  y  yo.

Escriba  un  programa  para  encontrar  todas  las  palabras  que  se  pueden  reducir  de  esta  manera  y  luego  encuentre  la  más  larga.

Este  ejercicio  es  un  poco  más  desafiante  que  la  mayoría,  así  que  aquí  hay  algunas  sugerencias:

1.  Es  posible  que  desee  escribir  una  función  que  tome  una  palabra  y  calcule  una  lista  de  todas  las  palabras  que
se  puede  formar  quitando  una  letra.  Estos  son  los  “hijos”  de  la  palabra.

2.  Recursivamente,  una  palabra  es  reducible  si  alguno  de  sus  hijos  es  reducible.  Como  caso  base,  puede
considere  la  cadena  vacía  reducible.

, palabras  de  una  sola  letra.  Por  lo  tanto,  es  posible  que  desee  
3.  La  lista  de  palabras  que  proporcioné  no  contiene  
agregar  "I",  "a"  y  la  cadena  vacía.

4.  Para  mejorar  el  rendimiento  de  su  programa,  es  posible  que  desee  memorizar  las  palabras  que  se  sabe  que  
son  reducibles.

Solución: .
Machine Translated by Google

Capítulo  13

Estudio  de  caso:  selección  de  
estructura  de  datos

En  este  punto,  ha  aprendido  acerca  de  las  estructuras  de  datos  centrales  de  Python  y  ha  visto  algunos  de  
los  algoritmos  que  las  usan.  Si  desea  saber  más  sobre  algoritmos,  este  podría  ser  un  buen  momento  para  
leer  el  Capítulo  B.  Pero  no  es  necesario  que  lo  lea  antes  de  continuar;  Puedes  leerlo  siempre  que  estés  
interesado.

Este  capítulo  presenta  un  estudio  de  caso  con  ejercicios  que  le  permiten  pensar  en  elegir  estructuras  de  
datos  y  practicar  su  uso.

13.1  Análisis  de  frecuencia  de  palabras
Como  de  costumbre,  al  menos  debería  intentar  los  ejercicios  antes  de  leer  mis  soluciones.
Ejercicio  13.1.  Escriba  un  programa  que  lea  un  archivo,  divida  cada  línea  en  palabras,  elimine  los  espacios  en  
blanco  y  la  puntuación  de  las  palabras  y  las  convierta  a  minúsculas.

Sugerencia:   módulo  proporciona  una  cadena  llamada , que  contiene  espacio,  tabulador,  


la  línea,  etc.,  y   nuevo  que  contiene  los  caracteres  de  puntuación.  Vamos  a  ver  si  podemos  hacer
Python  juran:

Además,  podría  considerar  usar  los  métodos  de  cadena   , y )   .
Ejercicio  13.2.  Vaya  a  Proyecto  Gutenberg  (libro   y  descarga  tu  favorito
sin  derechos  de  autor  en  formato  de  texto  sin  formato.

Modifique  su  programa  del  ejercicio  anterior  para  leer  el  libro  que  descargó,  omita  la  información  del  
encabezado  al  principio  del  archivo  y  procese  el  resto  de  las  palabras  como  antes.

Luego  modifique  el  programa  para  contar  el  número  total  de  palabras  en  el  libro  y  el  número  de  veces  que  
se  usa  cada  palabra.

Escribe  el  número  de  palabras  diferentes  usadas  en  el  libro.  Compara  diferentes  libros  de  diferentes  autores,  
escritos  en  diferentes  épocas.  ¿Qué  autor  utiliza  el  vocabulario  más  extenso?
Machine Translated by Google

126 Capítulo  13.  Estudio  de  caso:  selección  de  estructura  de  datos

Ejercicio  13.3.  Modifique  el  programa  del  ejercicio  anterior  para  imprimir  las  20  palabras  más  utilizadas  en  el  libro.

Ejercicio  13.4.  Modifique  el  programa  anterior  para  leer  una  lista  de  palabras  (vea  la  Sección  9.1)  y  luego  imprima  
todas  las  palabras  del  libro  que  no  están  en  la  lista  de  palabras.  ¿Cuántos  de  ellos  son  errores  tipográficos?  ¿Cuántas  
de  ellas  son  palabras  comunes  que  deberían  estar  en  la  lista  de  palabras  y  cuántas  de  ellas  son  realmente  oscuras?

13.2  Números  aleatorios
Dadas  las  mismas  entradas,  la  mayoría  de  los  programas  de  computadora  generan  las  mismas  salidas  cada  vez,  
por  lo  que  se  dice  que  son  deterministas.  El  determinismo  suele  ser  algo  bueno,  ya  que  esperamos  que  el  mismo  
cálculo  arroje  el  mismo  resultado.  Sin  embargo,  para  algunas  aplicaciones,  queremos  que  la  computadora  sea  
impredecible.  Los  juegos  son  un  ejemplo  obvio,  pero  hay  más.

Hacer  que  un  programa  sea  verdaderamente  no  determinista  resulta  difícil,  pero  hay  maneras  de  hacer  que  al  menos  
parezca  no  determinista.  Una  de  ellas  es  utilizar  algoritmos  que  generen  números  pseudoaleatorios .  Los  números  
pseudoaleatorios  no  son  verdaderamente  aleatorios  porque  se  generan  mediante  un  cálculo  determinista,  pero  con  
solo  mirar  los  números  es  casi  imposible  distinguirlos  de  los  aleatorios.

El  módulo  proporciona  funciones  que  generan  números  pseudoaleatorios  (a  los  que  simplemente  llamaré  "aleatorios"  
de  ahora  en  adelante).

La  función devuelve  un  flotante  aleatorio  entre  0,0  y  1,0  (incluido  0,0  pero  no  1,0). ,  obtienes  el  
Cada  vez  que  llamas  a   siguiente  número  en  una  serie  larga.  Para  ver  una  muestra,  ejecute
este  bucle:

La  función  toma  los  parámetros  y  y  (incluidos  ambos). y  devuelve  un  entero  entre

Para  elegir  un  elemento  de  una  secuencia  al  azar,  puede  utilizar :

El  módulo  también  proporciona  funciones  para  generar  valores  aleatorios  a  partir  de  distribuciones  
continuas,  incluidas  gaussianas,  exponenciales,  gamma  y  algunas  más.
Ejercicio  13.5.  Escriba  una  función  llamada  que  tome  un  histograma  como  se  define  en  la  Sección  11.2  y  devuelva  
un  valor  aleatorio  del  histograma,  elegido  con  probabilidad  en  proporción  a  la  frecuencia.  Por  ejemplo,  para  este  
histograma:
Machine Translated by Google

13.3.  Histograma  de  palabras 127

su  función  debe  volver con  probabilidad  2/3  y con  probabilidad  1/3.

13.3  Histograma  de  palabras

Debe  intentar  los  ejercicios  anteriores  antes  de  continuar.  Puede  descargar  mi  solución  desde .  también  
necesitarás
.

Aquí  hay  un  programa  que  lee  un  archivo  y  construye  un  histograma  de  las  palabras  en  el  archivo:

Este  programa  lee , que  contiene  el  texto  de  Emma  de  Jane  Austen.

recorre  las  líneas  del  archivo,  pasándolas  una  a  la  vez  a .  El  histograma  se  utiliza  como  
acumulador.

usa  el  método  de  cadena  para  reemplazar  los  guiones  con  espacios  antes  de  usar  para  
dividir  la  línea  en  una  lista  de  cadenas.  Recorre  la  lista  de  palabras  y  usos
y  las   para  eliminar  la  puntuación  y  convertir  a  minúsculas.  (Es  una  forma  abreviada  de  decir  eso  y
cadenas  se  "convierten";  recuerde  que  las  cadenas  son  inmutables,  por  lo  que  los  métodos  como  
devolver  nuevas  cadenas).

actualiza  el  histograma  creando  un  nuevo  elemento  o  incrementando  un
Finalmente,  uno  existente.

Para  contar  el  número  total  de  palabras  en  el  archivo,  podemos  sumar  las  frecuencias  en  el  histograma:
Machine Translated by Google

128 Capítulo  13.  Estudio  de  caso:  selección  de  estructura  de  datos

La  cantidad  de  palabras  diferentes  es  solo  la  cantidad  de  elementos  en  el  diccionario:

Aquí  hay  un  código  para  imprimir  los  resultados:

Y  los  resultados:

13.4  Palabras  más  comunes
Para  encontrar  las  palabras  más  comunes,  podemos  hacer  una  lista  de  tuplas,  donde  cada  tupla  contiene  una  palabra  y  
su  frecuencia,  y  ordenarla.

La  siguiente  función  toma  un  histograma  y  devuelve  una  lista  de  tuplas  de  frecuencia  de  palabra:

En  cada  tupla,  la  frecuencia  aparece  primero,  por  lo  que  la  lista  resultante  se  ordena  por  frecuencia.  Aquí  hay  un  bucle  
que  imprime  las  diez  palabras  más  comunes:

Utilizo  el  argumento  de  palabra  clave  para  indicar  que  se  utilice  un  carácter  de  tabulación  como  "separador",  en  lugar  de  
un  espacio,  de  modo  que  la  segunda  columna  esté  alineada.  Estos  son  los  resultados  de  Emma:

Este  código  se  puede  simplificar  usando  el  ous,   parámetro  de  la función.  si  eres  curi


puede  leer  sobre  él  en .
Machine Translated by Google

13.5.  Parámetros  opcionales 129

13.5  Parámetros  opcionales
Hemos  visto  funciones  y  métodos  incorporados  que  toman  argumentos  opcionales.  También  es  posible  escribir  
funciones  definidas  por  el  programador  con  argumentos  opcionales.  Por  ejemplo,  aquí  hay  una  función  que  
imprime  las  palabras  más  comunes  en  un  histograma

El  primer  parámetro  es  obligatorio;  el  segundo  es  opcional.  El  valor  predeterminado  de es  10

Si  solo  proporciona  un  argumento:

obtiene  el  valor  predeterminado.  Si  proporcionas  dos  argumentos:

obtiene  el  valor  del  argumento  en  su  lugar.  En  otras  palabras,  el  argumento  opcional  sobre
monta  el  valor  predeterminado.

Si  una  función  tiene  parámetros  requeridos  y  opcionales,  todos  los  parámetros  requeridos  deben  ir  primero,  
seguidos  de  los  opcionales.

13.6  Resta  de  diccionario
Encontrar  las  palabras  del  libro  que  no  están  en  la  lista  de  palabras  es  un  problema  que  puede  reconocer  como  
resta  de  conjuntos;  es  decir,  queremos  encontrar  todas  las  palabras  de  un  conjunto  (las  palabras  del  libro)  que  no  
están  en  el  otro  (las  palabras  de  la  lista).

toma  diccionarios  y  devuelve  un  nuevo  diccionario  que  contiene  todos  los .  Como  realmente  no  nos  
claves  de  eso  no  están  en  Ninguno. importan  los  valores,  los  configuramos  todos

Para  encontrar  las  palabras  en  el  libro  que  no  están  en   , nosotros  podemos  usar para  construir

un  histograma  para , y  luego  restar:

Estos  son  algunos  de  los  resultados  de  Emma:
Machine Translated by Google

130 Capítulo  13.  Estudio  de  caso:  selección  de  estructura  de  datos

Algunas  de  estas  palabras  son  nombres  y  posesivos.  Otros,  como  “rencontre”,  ya  no  son  de  uso  común.  ¡Pero  
algunas  son  palabras  comunes  que  realmente  deberían  estar  en  la  lista!
Ejercicio  13.6.  Python  proporciona  una  estructura  de  datos  llamada  que  proporciona  muchas  operaciones  de  
conjuntos  comunes.  Puede  leer  sobre  ellos  en  la  Sección  19.5,  o  leer  la  documentación  en
.

Escribe  un  programa  que  use  la  resta  de  conjuntos  para  encontrar  palabras  en  el  libro  que  no  están  en  la  lista  de  palabras.
Solución: .

13.7  Palabras  aleatorias

Para  elegir  una  palabra  aleatoria  del  histograma,  el  algoritmo  más  simple  es  construir  una  lista  con  múltiples  
copias  de  cada  palabra,  de  acuerdo  con  la  frecuencia  observada,  y  luego  elegir  de  la  lista:

El  método  de   crea  una  lista  con  la   copias  de  la  cadena .  El


expresión  es  similar  a excepción  de  que  el  argumento  es  una  secuencia.

Este  algoritmo  funciona,  pero  no  es  muy  eficiente;  cada  vez  que  elige  una  palabra  al  azar,  se  reconstruye  la  lista,  
que  es  tan  grande  como  el  libro  original.  Una  mejora  obvia  es  crear  la  lista  una  vez  y  luego  hacer  varias  
selecciones,  pero  la  lista  sigue  siendo  grande.

Una  alternativa  es:

1.  Uso para  obtener  una  lista  de  las  palabras  en  el  libro.

2.  Construya  una  lista  que  contenga  la  suma  acumulada  de  las  frecuencias  de  las  palabras  (vea  el  Ejercicio  
10.2).  El  último  elemento  de  esta  lista  es  el  número  total  de  palabras  del  libro,  n.

3.  Elige  un  número  aleatorio  del  1  al  n.  Use  una  búsqueda  de  bisección  (vea  el  ejercicio  10.10)  para  encontrar  
el  índice  donde  se  insertaría  el  número  aleatorio  en  la  suma  acumulada.

4.  Use  el  índice  para  encontrar  la  palabra  correspondiente  en  la  lista  de  palabras.

Ejercicio  13.7.  Escriba  un  programa  que  use  este  algoritmo  para  elegir  una  palabra  al  azar  del  libro.
Solución: .

13.8  Análisis  de  Markov
Si  elige  palabras  del  libro  al  azar,  puede  tener  una  idea  del  vocabulario,  pero  probablemente  no  obtendrá  una  
oración:
Machine Translated by Google

13.8.  análisis  de  Markov 131

Una  serie  de  palabras  al  azar  rara  vez  tiene  sentido  porque  no  hay  relación  entre  las  palabras  sucesivas.  Por  
ejemplo,  en  una  oración  real,  esperaría  que  un  artículo  como  "el"  fuera  seguido  por  un  adjetivo  o  un  sustantivo,  y  
probablemente  no  por  un  verbo  o  adverbio.

Una  forma  de  medir  este  tipo  de  relaciones  es  el  análisis  de  Markov,  que  caracteriza,  para  una  secuencia  dada  
de  palabras,  la  probabilidad  de  que  aparezcan  las  siguientes  palabras.  Por  ejemplo,  la  canción  Eric,  the  Half  a  
Bee  comienza:

Media  abeja,  filosóficamente,  
Debe,  ipso  facto,  la  mitad  no  ser.
Pero  la  mitad  de  la  abeja  tiene  que  
ser  Vis  a  vis,  su  entidad.  ¿Ves?

Pero,  ¿puede  decirse  que  una  
abeja  es  o  no  una  abeja  entera  
cuando  la  mitad  de  la  abeja  no  es  
abeja  debido  a  alguna  herida  antigua?

En  este  texto,  la  frase  "la  mitad  de"  siempre  va  seguida  de  la  palabra  "abeja",  pero  la  frase  "la  abeja"  puede  ir  
seguida  de  "tiene"  o  "es".

El  resultado  del  análisis  de  Markov  es  un  mapeo  de  cada  prefijo  (como  "la  mitad  de"  y  "la  abeja")  a  todos  los  
sufijos  posibles  (como  "tiene"  y  "es").

Dada  esta  asignación,  puede  generar  un  texto  aleatorio  comenzando  con  cualquier  prefijo  y  eligiendo  al  azar  
entre  los  posibles  sufijos.  A  continuación,  puede  combinar  el  final  del  prefijo  y  el  nuevo  sufijo  para  formar  el  
siguiente  prefijo  y  repetir.

Por  ejemplo,  si  comienza  con  el  prefijo  "Half  a",  entonces  la  siguiente  palabra  tiene  que  ser  "bee",  porque  el  prefijo  
solo  aparece  una  vez  en  el  texto.  El  siguiente  prefijo  es  "una  abeja",  por  lo  que  el  siguiente  sufijo  podría  ser  
"filosóficamente",  "ser"  o  "debido".

En  este  ejemplo,  la  longitud  del  prefijo  siempre  es  dos,  pero  puede  realizar  un  análisis  de  Markov  con  cualquier  
longitud  de  prefijo.
Ejercicio  13.8.  Análisis  de  Markov:

1.  Escriba  un  programa  para  leer  un  texto  de  un  archivo  y  realizar  un  análisis  de  Markov.  El  resultado  debería  
ser  un  diccionario  que  mapee  desde  prefijos  a  una  colección  de  posibles  sufijos.  La  colección  puede  ser  
una  lista,  una  tupla  o  un  diccionario;  depende  de  usted  hacer  una  elección  adecuada.  Puede  probar  su  
programa  con  la  longitud  de  prefijo  dos,  pero  debe  escribir  el  programa  de  una  manera  que  facilite  probar  
otras  longitudes.

2.  Agregue  una  función  al  programa  anterior  para  generar  texto  aleatorio  basado  en  el  análisis  de  Markov.
Aquí  hay  un  ejemplo  de  Emma  con  prefijo  de  longitud  2:  Él  

fue  muy  inteligente,  ya  sea  por  dulzura  o  por  estar  enojado,  avergonzado  o  solo  divertido,  ante  
tal  golpe.  ¿Nunca  había  pensado  en  Hannah  hasta  que  nunca  estuviste  destinado  para  mí?  —
No  puedo  pronunciar  discursos,  Emma:  —pronto  se  cortó  todo—.

Para  este  ejemplo,  dejé  la  puntuación  adjunta  a  las  palabras.  El  resultado  es  casi  sintácticamente  correcto,  
pero  no  del  todo.  Semánticamente,  casi  tiene  sentido,  pero  no  del  todo.

¿Qué  sucede  si  aumenta  la  longitud  del  prefijo?  ¿Tiene  más  sentido  el  texto  aleatorio?
Machine Translated by Google

132 Capítulo  13.  Estudio  de  caso:  selección  de  estructura  de  datos

3.  Una  vez  que  su  programa  esté  funcionando,  es  posible  que  desee  probar  una  combinación:  si  
combina  texto  de  dos  o  más  libros,  el  texto  aleatorio  que  genere  combinará  el  vocabulario  y  las  
frases  de  las  fuentes  de  maneras  interesantes.

Crédito:  Este  estudio  de  caso  se  basa  en  un  ejemplo  de  Kernighan  y  Pike,  The  Practice  of  Pro  gramming,  
Addison­Wesley,  1999.

Debe  intentar  este  ejercicio  antes  de  continuar;  entonces  puedes  descargar  mi  solución  de
.  también  necesitarás
.

13.9  Estructuras  de  datos
Usar  el  análisis  de  Markov  para  generar  texto  aleatorio  es  divertido,  pero  también  hay  un  punto  en  este  
ejercicio:  la  selección  de  la  estructura  de  datos.  En  tu  solución  a  los  ejercicios  anteriores,  tuviste  que  elegir:

•  Cómo  representar  los  prefijos.

•  Cómo  representar  la  colección  de  posibles  sufijos.

•  Cómo  representar  el  mapeo  de  cada  prefijo  a  la  colección  de  posibles  sufijos.

El  último  es  fácil:  un  diccionario  es  la  opción  obvia  para  un  mapeo  de  claves  a  valores  correspondientes.

Para  los  prefijos,  las  opciones  más  obvias  son  cadena,  lista  de  cadenas  o  tupla  de  cadenas.

Para  los  sufijos,  una  opción  es  una  lista;  otro  es  un  histograma  (diccionario).

¿Cómo  debes  elegir?  El  primer  paso  es  pensar  en  las  operaciones  que  necesitará  implementar  para  cada  
estructura  de  datos.  Para  los  prefijos,  debemos  poder  eliminar  palabras  del  principio  y  agregarlas  al  final.  
Por  ejemplo,  si  el  prefijo  actual  es  "Half  a",  y  la  siguiente  palabra  es  "bee",  debe  poder  formar  el  siguiente  
prefijo,  "a  bee".

Su  primera  opción  podría  ser  una  lista,  ya  que  es  fácil  agregar  y  eliminar  elementos,  pero  también  debemos  
poder  usar  los  prefijos  como  claves  en  un  diccionario,  de  modo  que  descarte  las  listas.  Con  las  tuplas,  no  
puede  agregar  ni  eliminar,  pero  puede  usar  el  operador  de  suma  para  formar  una  nueva  tupla:

,
toma  una  tupla  de  palabras  y  una  cadena,   , tupla  que  tiene  todas  las  palabras  
y  forma  una  nueva  
excepto  la  primera  y  se  agrega  al  final.

Para  la  recopilación  de  sufijos,  las  operaciones  que  debemos  realizar  incluyen  agregar  un  nuevo  sufijo  (o  
aumentar  la  frecuencia  de  uno  existente)  y  elegir  un  sufijo  aleatorio.

Agregar  un  nuevo  sufijo  es  igualmente  fácil  para  la  implementación  de  la  lista  o  el  histograma.  Elegir  un  
elemento  aleatorio  de  una  lista  es  fácil;  elegir  de  un  histograma  es  más  difícil  de  hacer  de  manera  eficiente  
(vea  el  ejercicio  13.7).

Hasta  ahora  hemos  estado  hablando  principalmente  sobre  la  facilidad  de  implementación,  pero  hay  otros  
factores  a  considerar  al  elegir  estructuras  de  datos.  Uno  es  el  tiempo  de  ejecución.  A  veces  hay  una  razón  
teórica  para  esperar  que  una  estructura  de  datos  sea  más  rápida  que  otra;  por  ejemplo,  mencioné  que
Machine Translated by Google

13.10.  depuración 133

el  operador  es  más  rápido  para  diccionarios  que  para  listas,  al  menos  cuando  el  número  de  elementos  es  grande.

Pero  a  menudo  no  se  sabe  de  antemano  qué  implementación  será  más  rápida.  Una  opción  es  implementar  
ambos  y  ver  cuál  es  mejor.  Este  enfoque  se  llama  evaluación  comparativa.
Una  alternativa  práctica  es  elegir  la  estructura  de  datos  que  sea  más  fácil  de  implementar  y  luego  ver  si  es  lo  
suficientemente  rápida  para  la  aplicación  prevista.  Si  es  así,  no  hay  necesidad  de  continuar.  Si  no,  hay  
herramientas,  como  el  módulo,  que  pueden  identificar  los  lugares  en  un  programa  que  toman  la  mayor  parte  del  
tiempo.

El  otro  factor  a  considerar  es  el  espacio  de  almacenamiento.  Por  ejemplo,  usar  un  histograma  para  la  colección  
de  sufijos  puede  ocupar  menos  espacio  porque  solo  tiene  que  almacenar  cada  palabra  una  vez,  sin  importar  
cuántas  veces  aparezca  en  el  texto.  En  algunos  casos,  ahorrar  espacio  también  puede  hacer  que  su  programa  
se  ejecute  más  rápido  y,  en  casos  extremos,  es  posible  que  su  programa  no  se  ejecute  en  absoluto  si  se  queda  
sin  memoria.  Pero  para  muchas  aplicaciones,  el  espacio  es  una  consideración  secundaria  después  del  tiempo  
de  ejecución.

Una  reflexión  final:  en  esta  discusión,  he  dado  a  entender  que  debemos  usar  una  estructura  de  datos  tanto  para  
el  análisis  como  para  la  generación.  Pero  dado  que  se  trata  de  fases  separadas,  también  sería  posible  utilizar  
una  estructura  para  el  análisis  y  luego  convertirla  en  otra  estructura  para  la  generación.
Esto  sería  una  ganancia  neta  si  el  tiempo  ahorrado  durante  la  generación  excediera  el  tiempo  dedicado  a  la  
conversión.

13.10  Depuración
Cuando  está  depurando  un  programa,  y  especialmente  si  está  trabajando  en  un  error  grave,  hay  cinco  cosas  
que  puede  probar:

Lectura:  examina  tu  código,  léelo  para  ti  mismo  y  comprueba  que  dice  lo  que
quise  decir.

Ejecución:  experimente  haciendo  cambios  y  ejecutando  diferentes  versiones.  A  menudo,  si  muestra  lo  correcto  
en  el  lugar  correcto  del  programa,  el  problema  se  vuelve  obvio,  pero  a  veces  tiene  que  construir  un  
andamiaje.

Rumiar:  ¡ Tómate  un  tiempo  para  pensar!  ¿Qué  tipo  de  error  es:  sintaxis,  tiempo  de  ejecución  o  semántico?  
¿Qué  información  puede  obtener  de  los  mensajes  de  error  o  de  la  salida  del  programa?  ¿Qué  tipo  de  
error  podría  causar  el  problema  que  estás  viendo?  ¿Qué  fue  lo  último  que  cambió,  antes  de  que  
apareciera  el  problema?

Dulzura:  si  le  explicas  el  problema  a  otra  persona,  a  veces  encuentras  la  respuesta  antes  de  terminar  de  hacer  
la  pregunta.  A  menudo  no  necesitas  a  la  otra  persona;  podrías  simplemente  hablar  con  un  patito  de  goma.  
Y  ese  es  el  origen  de  la  conocida  estrategia  llamada  depuración  del  patito  de  goma.  No  estoy  inventando  
esto;  ver
.

Retiro:  en  algún  momento,  lo  mejor  que  puede  hacer  es  retroceder,  deshaciendo  los  cambios  recientes,  hasta  
que  vuelva  a  tener  un  programa  que  funcione  y  que  entienda.  Entonces  puedes  empezar  a  reconstruir.
Machine Translated by Google

134 Capítulo  13.  Estudio  de  caso:  selección  de  estructura  de  datos

Los  programadores  principiantes  a  veces  se  atascan  en  una  de  estas  actividades  y  se  olvidan  de  las  demás.  Cada  
actividad  viene  con  su  propio  modo  de  falla.

Por  ejemplo,  leer  su  código  puede  ayudar  si  el  problema  es  un  error  tipográfico,  pero  no  si  el  problema  es  un  
malentendido  conceptual.  Si  no  entiende  lo  que  hace  su  programa,  puede  leerlo  100  veces  y  nunca  ver  el  error,  
porque  el  error  está  en  su  cabeza.

Ejecutar  experimentos  puede  ayudar,  especialmente  si  ejecuta  pruebas  pequeñas  y  simples.  Pero  si  ejecuta  
experimentos  sin  pensar  o  leer  su  código,  puede  caer  en  un  patrón  que  llamo  "programación  de  caminata  aleatoria",  
que  es  el  proceso  de  hacer  cambios  aleatorios  hasta  que  el  programa  hace  lo  correcto.  No  hace  falta  decir  que  la  
programación  de  caminata  aleatoria  puede  llevar  mucho  tiempo.

Tienes  que  tomarte  un  tiempo  para  pensar.  La  depuración  es  como  una  ciencia  experimental.  Debe  tener  al  menos  
una  hipótesis  sobre  cuál  es  el  problema.  Si  hay  dos  o  más  posibilidades,  trate  de  pensar  en  una  prueba  que  elimine  
una  de  ellas.

Pero  incluso  las  mejores  técnicas  de  depuración  fallarán  si  hay  demasiados  errores  o  si  el  código  que  está  tratando  
de  corregir  es  demasiado  grande  y  complicado.  A  veces  la  mejor  opción  es  retirarse,  simplificando  el  programa  
hasta  llegar  a  algo  que  funcione  y  que  entiendas.

Los  programadores  principiantes  a  menudo  son  reacios  a  retirarse  porque  no  soportan  borrar  una  línea  de  código  
(incluso  si  está  mal).  Si  te  hace  sentir  mejor,  copia  tu  programa  en  otro  archivo  antes  de  empezar  a  desmontarlo.  
Luego  puede  copiar  las  piezas  de  nuevo  una  a  la  vez.

Encontrar  un  error  difícil  requiere  leer,  correr,  reflexionar  y,  a  veces,  retirarse.  Si  te  quedas  atascado  en  una  de  
estas  actividades,  prueba  las  otras.

13.11  Glosario
determinista:  Perteneciente  a  un  programa  que  hace  lo  mismo  cada  vez  que  se  ejecuta,  dadas  las  mismas  entradas.

pseudoaleatorio:  Perteneciente  a  una  secuencia  de  números  que  parece  ser  aleatoria,  pero  es  generada  por  un  
programa  determinista.

valor  predeterminado:  el  valor  dado  a  un  parámetro  opcional  si  no  se  proporciona  ningún  argumento.

override:  para  reemplazar  un  valor  predeterminado  con  un  argumento.

evaluación  comparativa:  el  proceso  de  elegir  entre  estructuras  de  datos  implementando  alternativas  y  probándolas  
en  una  muestra  de  las  posibles  entradas.

Depuración  de  patitos  de  goma:  Depuración  explicando  su  problema  a  un  objeto  inanimado  como  un  patito  de  
goma.  Articular  el  problema  puede  ayudarte  a  resolverlo,  incluso  si  el  patito  de  goma  no  conoce  Python.

13.12  Ejercicios

Ejercicio  13.9.  El  “rango”  de  una  palabra  es  su  posición  en  una  lista  de  palabras  ordenadas  por  frecuencia:  la  
palabra  más  común  tiene  el  rango  1,  la  segunda  más  común  tiene  el  rango  2,  etc.
Machine Translated by Google

13.12.  Ejercicios 135

La  ley  de  Zipf  describe  una  relación  entre  los  rangos  y  las  frecuencias  de  las  palabras  en  los  lenguajes  naturales  
( ).  En  concreto,  predice  que  la  frecuencia,  f ,  de  la  palabra  con  rango  r  es:

f  =  cr−s

donde  s  y  c  son  parámetros  que  dependen  del  idioma  y  del  texto.  Si  tomas  el  logaritmo  de  ambos  lados  de  esta  
ecuación,  obtienes:

log  f  =  log  c  −  slog  r

Entonces,  si  graficas  log  f  versus  log  r,  deberías  obtener  una  línea  recta  con  pendiente  −s  e  interceptar  log  c.

Escriba  un  programa  que  lea  un  texto  de  un  archivo,  cuente  la  frecuencia  de  las  palabras  e  imprima  una  línea  para  
cada  palabra,  en  orden  descendente  de  frecuencia,  con  log  f  y  log  r.  Utilice  el  programa  de  gráficos  de  su  elección  
para  trazar  los  resultados  y  verifique  si  forman  una  línea  recta.  ¿Puedes  estimar  el  valor  de  s?

Solución:   .  Para  ejecutar  mi  solución,  necesita  la  
el  módulo  ting   trama.  Si  instaló  Anaconda,  ya  tiene ;  de  lo  contrario,  tú
podría  tener  que  instalarlo.
Machine Translated by Google

136 Capítulo  13.  Estudio  de  caso:  selección  de  estructura  de  datos
Machine Translated by Google

capitulo  14

archivos

Este  capítulo  presenta  la  idea  de  los  programas  “persistentes”  que  mantienen  los  datos  en  almacenamiento  permanente  
y  muestra  cómo  usar  diferentes  tipos  de  almacenamiento  permanente,  como  archivos  y  bases  de  datos.

14.1  Persistencia
La  mayoría  de  los  programas  que  hemos  visto  hasta  ahora  son  transitorios  en  el  sentido  de  que  se  ejecutan  durante  un  
breve  período  de  tiempo  y  producen  algún  resultado,  pero  cuando  finalizan,  sus  datos  desaparecen.  Si  ejecuta  el  
programa  de  nuevo,  comienza  con  una  pizarra  limpia.

Otros  programas  son  persistentes:  se  ejecutan  durante  mucho  tiempo  (o  todo  el  tiempo);  mantienen  al  menos  algunos  
de  sus  datos  en  almacenamiento  permanente  (un  disco  duro,  por  ejemplo);  y  si  se  apagan  y  se  reinician,  continúan  
donde  lo  dejaron.

Ejemplos  de  programas  persistentes  son  los  sistemas  operativos,  que  se  ejecutan  casi  siempre  que  una  computadora  
está  encendida,  y  los  servidores  web,  que  se  ejecutan  todo  el  tiempo,  esperando  que  lleguen  solicitudes  a  la  red.

Una  de  las  formas  más  sencillas  para  que  los  programas  mantengan  sus  datos  es  leyendo  y  escribiendo  archivos  de  
texto.  Ya  hemos  visto  programas  que  leen  archivos  de  texto;  en  este  capítulo  veremos  programas  que  los  escriben.

Una  alternativa  es  almacenar  el  estado  del  programa  en  una  base  de  datos.  En  este  capítulo  presentaré  una  base  de  
datos  simple  y  un  módulo, , que  facilita  el  almacenamiento  de  datos  del  programa.

14.2  Leer  y  escribir
Un  archivo  de  texto  es  una  secuencia  de  caracteres  almacenada  en  un  medio  permanente  como  un  disco  duro,  una  
memoria  flash  o  un  CD­ROM.  Vimos  cómo  abrir  y  leer  un  archivo  en  la  Sección  9.1.

Para  escribir  un  archivo,  debe  abrirlo  con  el  modo  como  segundo  parámetro:
Machine Translated by Google

138 Capítulo  14.  Archivos

Si  el  archivo  ya  existe,  abrirlo  en  modo  de  escritura  borra  los  datos  antiguos  y  comienza  de  nuevo,  ¡así  que  tenga  
cuidado!  Si  el  archivo  no  existe,  se  crea  uno  nuevo.

devuelve  un  objeto  de  archivo  que  proporciona  métodos  para  trabajar  con  el  archivo.  El
método  pone  datos  en  el  archivo.

El  valor  devuelto  es  el  número  de  caracteres  que  se  escribieron.  El  objeto  de  archivo  realiza  un  seguimiento  de  
dónde  está,  por  lo  que  si  vuelve  a  llamar,  agrega  los  nuevos  datos  al  final  del  archivo.

Cuando  haya  terminado  de  escribir,  debe  cerrar  el  archivo.

Si  no  cierra  el  archivo,  se  cerrará  cuando  finalice  el  programa.

14.3  Operador  de  formato
El  argumento  de  tener   tiene  que  ser  una  cadena,  así  que  si  queremos  poner  otros  valores  en  un  archivo,
que  convertirlos  en  cadenas.  La  forma  más  fácil  de  hacerlo  es  con:

Una  alternativa  es  utilizar  el  operador  de  formato, .  Cuando  se  aplica  a  números  enteros,  es  el  operador  de  módulo.  
Pero  cuando  el  primer  operando  es  una  cadena,  es  el  operador  de  formato.

El  primer  operando  es  la  cadena  de  formato,  que  contiene  una  o  más  secuencias  de  formato,  que  especifican  cómo  
se  formatea  el  segundo  operando.  El  resultado  es  una  cadena.

Por  ejemplo,  la  secuencia  de  formato  ted   significa  que  el  segundo  operando  debe  tener  formato
como  un  entero  decimal:

El  resultado  es  la  cadena. , que  no  debe  confundirse  con  el  valor  entero.

Una  secuencia  de  formato  puede  aparecer  en  cualquier  lugar  de  la  cadena,  por  lo  que  puede  incrustar  un  valor  en  
una  oración:

Si  hay  más  de  una  secuencia  de  formato  en  la  cadena,  el  segundo  argumento  debe  ser  una  tupla.  Cada  secuencia  
de  formato  se  empareja  con  un  elemento  de  la  tupla,  en  orden.

El  siguiente  ejemplo  usa  ber  y  para   para  formatear  un  entero, para  dar  formato  a  un  número  de  punto  flotante


formatear  una  cadena:
Machine Translated by Google

14.4.  Nombres  de  archivos  y  rutas 139

El  número  de  elementos  en  la  tupla  tiene  que  coincidir  con  el  número  de  secuencias  de  formato  en  la  
cadena.  Además,  los  tipos  de  los  elementos  deben  coincidir  con  las  secuencias  de  formato:

En  el  primer  ejemplo,  no  hay  suficientes  elementos;  en  el  segundo,  el  elemento  es  del  tipo  incorrecto.

Para  obtener  más  información  sobre  el  operador  de  formato,  consulte
. Una  alternativa  más  poderosa  es
el  método  de  formato  de  cadena,  sobre  el  que  puede  leer  en
.

14.4  Nombres  de  archivos  y  rutas

Los  archivos  se  organizan  en  directorios  (también  llamados  "carpetas").  Cada  programa  en  ejecución  
tiene  un  "directorio  actual",  que  es  el  directorio  predeterminado  para  la  mayoría  de  las  operaciones.  Por  
ejemplo,  cuando  abre  un  archivo  para  leerlo,  Python  lo  busca  en  el  directorio  actual.

El  módulo  proporciona  funciones  para  trabajar  con  archivos  y  directorios  ("os"  significa  "sistema  operativo").
devuelve  el  nombre  del  directorio  actual:

significa  "directorio  de  trabajo  actual".  El  resultado  en  este  ejemplo  es  cuál  es   ,
el  directorio  de  inicio  de  un  usuario  llamado .

Una  cadena  como que  identifica  un  archivo  o  directorio  se  llama  ruta.

Un  nombre  de  archivo   también  se  considera  una  ruta,  pero  es  una  ruta  relativa  porque  el  
simple,  como  si  se  relacionara  con  el  directorio  actual.  Si  el  directorio  actual  es , nombre  del  archivo
se  referiría  a .

Una  ruta  que  comienza  con  no  depende  del  directorio  actual;  se  llama  un  camino  absoluto.  Para  encontrar  
la  ruta  absoluta  a  un  archivo,  puede  usar :

proporciona  otras  funciones  para  trabajar  con  nombres  de  archivos  y  rutas.  Por  ejemplo,
comprueba  si  existe  un  archivo  o  directorio:

Si  existiera, comprueba  si  es  un  directorio:
Machine Translated by Google

140 Capítulo  14.  Archivos

Similarmente, comprueba  si  es  un  archivo.

devuelve  una  lista  de  los  archivos  (y  otros  directorios)  en  el  directorio  dado:

Para  demostrar  estas  funciones,  el  siguiente  ejemplo  "camina"  a  través  de  un  directorio,  imprime  los  
nombres  de  todos  los  archivos  y  se  llama  a  sí  mismo  recursivamente  en  todos  los  directorios.

toma  un  directorio  y  un  nombre  de  archivo  y  los  une  en  una  ruta  completa.

El  módulo  proporciona  una  función  llamada   que  es  similar  a  este  pero  más  ver
satile.  Como  ejercicio,  lea  la  documentación  y  utilícela  para  imprimir  los  nombres  de  los  archivos  en  un  
directorio  dado  y  sus  subdirectorios.  Puedes  descargar  mi  solución  desde
.

14.5  Captura  de  excepciones
Muchas  cosas  pueden  salir  mal  cuando  intentas  leer  y  escribir  archivos.  Si  intenta  abrir  un  archivo  que  
no  existe,  obtiene  un :

Si  no  tiene  permiso  para  acceder  a  un  archivo:

Y  si  intenta  abrir  un  directorio  para  leer,  obtiene

Para  evitar  estos  errores,  puede  usar  funciones  como   y ,

pero  se  necesitaría  mucho  tiempo  y  código  para  verificar  todas  las  posibilidades  (si   es  cualquier

"  indica,  hay  al  menos  21  cosas  que  pueden  salir  mal).

Es  mejor  seguir  adelante  e  intentar,  y  lidiar  con  los  problemas  si  ocurren,  que  es  exactamente  lo  que  
hace  la  declaración.  La  sintaxis  es  similar  a  una declaración:
Machine Translated by Google

14.6.  bases  de  datos 141

Python  comienza  ejecutando  los   cláusula.  Si  todo  va  bien,  se  salta  la   cláusula  y  


ingresos.  Si  ocurre  una  excepción,  salta  fuera  del cláusula  y  ejecuta  el cláusula.

Manejar  una  excepción  con  una  declaración  se  llama  capturar  una  excepción.  En  este  ejemplo,  la  cláusula  
muestra  un  mensaje  de  error  que  no  es  muy  útil.  En  general,  detectar  una  excepción  le  brinda  la  
oportunidad  de  solucionar  el  problema,  o  intentarlo  de  nuevo,  o  al  menos  finalizar  el  programa  correctamente.

14.6  Bases  de  datos

Una  base  de  datos  es  un  archivo  que  está  organizado  para  almacenar  datos.  Muchas  bases  de  datos  están  
organizadas  como  un  diccionario  en  el  sentido  de  que  asignan  claves  a  valores.  La  mayor  diferencia  entre  una  
base  de  datos  y  un  diccionario  es  que  la  base  de  datos  está  en  el  disco  (u  otro  almacenamiento  permanente),  por  
lo  que  persiste  después  de  que  finaliza  el  programa.

El  módulo  proporciona  una  interfaz  para  crear  y  actualizar  archivos  de  base  de  datos.  Como  ejemplo,  
crearé  una  base  de  datos  que  contenga  subtítulos  para  archivos  de  imágenes.

Abrir  una  base  de  datos  es  similar  a  abrir  otros  archivos:

El  modo  significa  que  la  base  de  datos  debe  crearse  si  aún  no  existe.  El  resultado  es  un  objeto  de  base  de  
datos  que  se  puede  usar  (para  la  mayoría  de  las  operaciones)  como  un  diccionario.

Cuando  creas  un  nuevo  elemento, actualiza  el  archivo  de  la  base  de  datos.

Cuando  acceda  a  uno  de  los  elementos, lee  el  archivo:

El  resultado  es  un  objeto  de  bytes,  por  lo  que  comienza  con . Un  objeto  de  bytes  es  similar  a  
una  cadena  en  muchos  aspectos.  Cuando  profundizas  en  Python,  la  diferencia  se  vuelve  importante,  pero  
por  ahora  podemos  ignorarla.

Si  realiza  otra  asignación  a  una  clave  existente, reemplaza  el  valor  anterior:

Algunos  métodos  de  diccionario,  como   y , no  trabaje  con  objetos  de  base  de  datos.  Pero
la  iteración  con  un  bucle,  funcionan:

Al  igual  que  con  otros  archivos,  debe  cerrar  la  base  de  datos  cuando  haya  terminado:
Machine Translated by Google

142 Capítulo  14.  Archivos

14.7  Decapado
Una  limitación  de   es  que  las  claves  y  valores  tienen  que  ser  cadenas  o  bytes.  Si  intentas  usar
cualquier  otro  tipo,  te  da  un  error.

El  módulo  puede  ayudar.  Traduce  casi  cualquier  tipo  de  objeto  en  una  cadena  adecuada  para  el  almacenamiento  en  
una  base  de  datos  y  luego  convierte  las  cadenas  nuevamente  en  objetos.

toma  un  objeto  como  parámetro  y  devuelve  una  representación  de  cadena  ( es

abreviatura  de  "cadena  de  volcado"):

El  formato  no  es  obvio  para  los  lectores  humanos;  está  destinado  a  ser  fácil  para  ("cadena   interpretar.
de  carga")  reconstituye  el  objeto:

Aunque  el  nuevo  objeto  tiene  el  mismo  valor  que  el  anterior,  no  es  (en  general)  el  mismo  objeto:

En  otras  palabras,  decapar  y  luego  decapar  tiene  el  mismo  efecto  que  copiar  el  objeto.

Puede  usar   para  almacenar  no  cadenas  en  una  base  de  datos.  De  hecho,  esta  combinación  es  tan  com
mon  que  ha  sido  encapsulado  en  un  módulo  llamado .

14.8  Tuberías
La  mayoría  de  los  sistemas  operativos  proporcionan  una  interfaz  de  línea  de  comandos,  también  conocida  como  shell.  
Los  shells  suelen  proporcionar  comandos  para  navegar  por  el  sistema  de  archivos  y  ejecutar  aplicaciones.  Por  
ejemplo,  en  Unix  puede  cambiar  directorios  con ,  mostrar  el  contenido  de  un  directorio  e  iniciar  un  navegador  web   ,
escribiendo  (por  ejemplo) .

Cualquier  programa  que  pueda  iniciar  desde  el  shell  también  puede  iniciarse  desde  Python  utilizando  un  objeto  de  
canalización,  que  representa  un  programa  en  ejecución.

Por  ejemplo,  la  rectoría  de  comandos  de   normalmente  muestra  el  contenido  del  di  actual
Unix  en  formato  largo.  Puedes  lanzar  con 1 :

1
está  en  desuso  ahora,  lo  que  significa  que  se  supone  que  debemos  dejar  de  usarlo  y  comenzar  a  usar  el
módulo.  Pero  para  casos  sencillos,   más  complicado  de  lo  necesario.  Así  que  voy  a  seguir  usando
encuentro  hasta  que  me  lo  quitan.
Machine Translated by Google

14.9.  Módulos  de  escritura 143

El  argumento  es  una  cadena  que  contiene  un  comando  de  shell.  El  valor  de  retorno  es  un  objeto  que  se  
comporta  como  un  archivo  abierto.  Puede  leer  la  salida  del  proceso  una  línea  a  la  vez  u  obtener  todo  de  una  
vez  con :

Cuando  haya  terminado,  cierre  la  tubería  como  un  archivo:

El  valor  devuelto  es  el  estado  final  del  proceso;  (sin  errores). significa  que  termino  normalmente

Por  ejemplo,  la  mayoría  de  los  sistemas  Unix  proporcionan  un  comando   que  lee  el  contenido
llamado  de  un  archivo  y  calcula  una  "suma  de  verificación".  Puede  leer  sobre  
MD5  en .  Este  comando  proporciona  una  forma  eficaz  de  comprobar  si  dos  archivos  tienen  el  
mismo  contenido.  La  probabilidad  de  que  diferentes  contenidos  produzcan  la  misma  suma  de  verificación  es  
muy  pequeña  (es  decir,  es  poco  probable  que  suceda  antes  de  que  el  universo  colapse).

Puedes  usar  una  tubería  para  correr de  Python  y  obtener  el  resultado:

14.9  Módulos  de  escritura
Cualquier  archivo  que  contenga  código  de  Python  se  puede  importar  como  un  módulo.  Por  ejemplo,  suponga  
que  tiene  un  archivo  llamado con  el  siguiente  código:

Si  ejecuta  este  programa,  se  lee  solo  e  imprime  el  número  de  líneas  en  el  archivo,  que  es  7.
También  puedes  importarlo  así:

Ahora  tienes  un  objeto  de  módulo:
Machine Translated by Google

144 Capítulo  14.  Archivos

El  objeto  del  módulo  proporciona :

Así  es  como  escribes  módulos  en  Python.

El  único  problema  con  este  ejemplo  es  que  cuando  importa  el  módulo,  ejecuta  el  código  de  prueba  en  la  
parte  inferior.  Normalmente,  cuando  importa  un  módulo,  define  nuevas  funciones  pero  no  las  ejecuta.

Los  programas  que  se  importarán  como  módulos  a  menudo  usan  la  siguiente  expresión:

es  una  variable  integrada  que  se  establece  cuando  se  inicia  el  programa.  Si  el  programa  se  está  ejecutando  
de  comandos,   tiene  el  valor ;  en  ese  caso,  se  ejecuta  el  código  de  prueba.  De  lo  contrario,  como  secuencia  

si  se  está  importando  el  módulo,  se  omite  el  código  de  prueba.

Como  ejercicio,  escriba  este  ejemplo  en  un  archivo  llamado   y  ejecutarlo  como  un  script.  Entonces  
intérprete  de  Python  y  ¿se  está   corre .  ¿Cuál  es  el  valor  de  cuando  el  módulo  es
importando?

Advertencia:  si  importa  un  módulo  que  ya  se  ha  importado,  Python  no  hace  nada.  No  vuelve  a  leer  el  archivo,  
incluso  si  ha  cambiado.

,
Si  desea  volver  a  cargar  un  módulo,  puede  usar  la  función  incorporada,  pero  puede  ser  complicado,  
por  lo  
que  lo  más  seguro  es  reiniciar  el  intérprete  y  luego  importar  el  módulo  nuevamente.

14.10  Depuración
Cuando  lee  y  escribe  archivos,  es  posible  que  tenga  problemas  con  los  espacios  en  blanco.
Estos  errores  pueden  ser  difíciles  de  depurar  porque  los  espacios,  tabulaciones  y  saltos  de  línea  normalmente  son  invisibles:

La  función  integrada  puede  ayudar.  Toma  cualquier  objeto  como  argumento  y  devuelve  una  representación  
de  cadena  del  objeto.  Para  cadenas,  representa  caracteres  de  espacio  en  blanco  con  secuencias  de  barra  
invertida:

Esto  puede  ser  útil  para  la  depuración.

Otro  problema  con  el  que  te  puedes  encontrar  es  que  diferentes  sistemas  usan  diferentes  caracteres  para  
indicar  el  final  de  una  línea.  Algunos  sistemas  usan  una  nueva  línea,  representada .  Otros  usan  un  carácter  
de  retorno,  representado .  Algunos  usan  ambos.  Si  mueve  archivos  entre  diferentes  sistemas,  estas  
inconsistencias  pueden  causar  problemas.

Para  la  mayoría  de  los  sistemas,  existen  aplicaciones  para  convertir  de  un  formato  a  otro.  Puede  encontrarlos  
(y  leer  más  sobre  este  tema)  en  O,  por  supuesto,  puede   .
escribir  uno  usted  mismo.
Machine Translated by Google

14.11.  Glosario 145

14.11  Glosario
persistente:  Perteneciente  a  un  programa  que  se  ejecuta  indefinidamente  y  mantiene  al  menos  parte  de  su
datos  en  almacenamiento  permanente.

operador  de  formato:  un  operador, ,  que  toma  una  cadena  de  formato  y  una  tupla  y  genera  una  cadena  que  incluye  los  
elementos  de  la  tupla  con  el  formato  especificado  por  la  cadena  de  formato.

cadena  de  formato:  Una  cadena,  utilizada  con  el  operador  de  formato,  que  contiene  secuencias  de  formato.

secuencia  de  formato:  Se  debe  formatear  una  secuencia  de  caracteres  en  una  cadena  de   , que  especifica  cómo  un
formato,  como  el  valor.

archivo  de  texto:  Una  secuencia  de  caracteres  almacenados  en  almacenamiento  permanente  como  un  disco  duro.

directorio:  una  colección  de  archivos  con  nombre,  también  llamada  carpeta.

ruta:  una  cadena  que  identifica  un  archivo.

ruta  relativa:  Una  ruta  que  comienza  desde  el  directorio  actual.

ruta  absoluta:  una  ruta  que  comienza  desde  el  directorio  superior  en  el  sistema  de  archivos.

catch:  para  evitar  que  una  excepción  finalice  un  programa  utilizando  las  teclas  y estado
mentos.

base  de  datos:  Un  archivo  cuyo  contenido  está  organizado  como  un  diccionario  con  claves  que  corresponden
a  los  valores

bytes  object:  Un  objeto  similar  a  una  cadena.

shell:  Un  programa  que  permite  a  los  usuarios  escribir  comandos  y  luego  los  ejecuta  iniciando  otros  programas.

objeto  de  tubería:  un  objeto  que  representa  un  programa  en  ejecución,  lo  que  permite  que  un  programa  de  Python  ejecute  
comandos  y  lea  los  resultados.

14.12  Ejercicios

Ejercicio  14.1.  Escriba  una  función  llamada  que  tome  como  argumentos  una  cadena  patrón,  una  cadena  de  reemplazo  y  dos  
nombres  de  archivo;  debe  leer  el  primer  archivo  y  escribir  el  contenido  en  el  segundo  archivo  (creándolo  si  es  necesario).  Si  la  
cadena  de  patrón  aparece  en  cualquier  parte  del  archivo,  debe  reemplazarse  con  la  cadena  de  reemplazo.

Si  ocurre  un  error  al  abrir,  leer,  escribir  o  cerrar  archivos,  su  programa  debe  detectar  la  excepción,  imprimir  un  mensaje  de  error  
y  salir.  Solución:
.

Ejercicio  14.2.  Si  descarga  mi  solución  al  Ejercicio  12.2  desde ,  verá  que  crea  un  
diccionario  que  mapea  desde  una  cadena  ordenada  de  mapas  al
letras  a  la  lista  de  palabras  que  se  pueden  escribir  con  esas  letras.  Por  ejemplo,  lista
.

Escriba  un  módulo  que  importe  y  proporcione  dos  nuevas  funciones:  debe  almacenar  el  diccionario  de  
anagramas  en  un  "estante";  una  lista  de  sus  anagramas.   debe  buscar  una  palabra  y  regresar
Solución: .
Machine Translated by Google

146 Capítulo  14.  Archivos

Ejercicio  14.3.  En  una  gran  colección  de  archivos  MP3,  puede  haber  más  de  una  copia  de  la  misma  canción,  almacenada  en  
diferentes  directorios  o  con  diferentes  nombres  de  archivo.  El  objetivo  de  este  ejercicio  es  buscar  duplicados.

1.  Escriba  un  programa  que  busque  un  directorio  y  todos  sus  subdirectorios,  recursivamente,  y  devuelva  una  lista  de  rutas  
completas  para  todos  los  archivos  con  un  sufijo  dado  (como ).  Sugerencia:  proporciona  varias  funciones  útiles  para  
manipular  archivos  y  nombres  de  rutas.

2.  Para  reconocer  duplicados,  puede  usar  archivos   para  calcular  una  "suma  de  comprobación"  para  cada  archivo.  si  dos
que  tengan  la  misma  suma  de  verificación,  probablemente  tengan  el  mismo  contenido.

3.  Para  verificar,  puede  usar  el  comando  Unix .

Solución: .
Machine Translated by Google

Capítulo  15

clases  y  objetos

En  este  punto,  sabe  cómo  usar  funciones  para  organizar  código  y  tipos  integrados  para  organizar  datos.  El  
siguiente  paso  es  aprender  "programación  orientada  a  objetos",  que  utiliza  tipos  definidos  por  el  programador  
para  organizar  tanto  el  código  como  los  datos.  La  programación  orientada  a  objetos  es  un  gran  tema;  tomará  
algunos  capítulos  para  llegar  allí.

Los  ejemplos  de  código  de  este  capítulo  están  disponibles  en ;  Las  
soluciones  de  los  ejercicios  están  disponibles  en
.

15.1  Tipos  definidos  por  el  programador

Hemos  usado  muchos  de  los  tipos  integrados  de  Python;  ahora  vamos  a  definir  un  nuevo  tipo.  Como  ejemplo,  
crearemos  un  tipo  llamado  que  representa  un  punto  en  un  espacio  bidimensional.

En  notación  matemática,  los  puntos  a  menudo  se  escriben  entre  paréntesis  con  una  coma  que  separa  las  
coordenadas.  Por  ejemplo,  (0,  0)  representa  el  origen  y  (x,  y)  representa  el  punto  x  unidades  a  la  derecha  e  y  
unidades  hacia  arriba  desde  el  origen.

Hay  varias  formas  de  representar  puntos  en  Python:

•  Podríamos  almacenar  las  coordenadas  por  separado  en  dos  variables,  y .

•  Podríamos  almacenar  las  coordenadas  como  elementos  en  una  lista  o  tupla.

•  Podríamos  crear  un  nuevo  tipo  para  representar  puntos  como  objetos.

Crear  un  nuevo  tipo  es  más  complicado  que  las  otras  opciones,  pero  tiene  ventajas  que  se  harán  evidentes  
pronto.

Un  tipo  definido  por  el  programador  también  se  denomina  clase.  Una  definición  de  clase  se  ve  así:
Machine Translated by Google

148 Capítulo  15.  Clases  y  objetos

Punto
blanco X 3.0

y 4.0

Figura  15.1:  Diagrama  de  objetos.

El  encabezado  indica  que  la  nueva  clase  se  llama .  El  cuerpo  es  una  cadena  de  documentación  que  explica  para  
qué  sirve  la  clase.  Puede  definir  variables  y  métodos  dentro  de  una  definición  de  clase,  pero  volveremos  a  eso  más  
adelante.

Definición  de  una  clase  llamada crea  un  objeto  de  clase.

Porque se  define  en  el  nivel  superior,  su  "nombre  completo"  es .

El  objeto  de  clase  es  como  una  fábrica  para  crear  objetos.  Para  crear  un  Punto,  llame  a  una   como  si
función.

El  valor  devuelto  es  una  referencia  a  un  objeto  Punto,  que  asignamos  a .

La  creación  de  un  nuevo  objeto  se  denomina  creación  de  instancias  y  el  objeto  es  una  instancia  de  la  clase.

Cuando  imprime  una  instancia,  Python  le  dice  a  qué  clase  pertenece  y  dónde  está  almacenada  en  la  memoria  (el  
prefijo  significa  que  el  siguiente  número  está  en  hexadecimal).

Cada  objeto  es  una  instancia  de  alguna  clase,  por  lo  que  "objeto"  e  "instancia"  son  intercambiables.
Pero  en  este  capítulo  uso  "instancia"  para  indicar  que  estoy  hablando  de  un  tipo  definido  por  el  programador.

15.2  Atributos
Puede  asignar  valores  a  una  instancia  utilizando  la  notación  de  puntos:

Esta  sintaxis  es  similar  a  la  sintaxis  para  seleccionar  una  variable  de  un  módulo,  como  en  este  caso,  
o . sin  embargo,  estamos  asignando  valores  a  elementos  con  nombre  de  un  objeto.  
Estos  elementos  se  denominan  atributos.

Como  sustantivo,  “AT­trib­ute”  se  pronuncia  con  énfasis  en  la  primera  sílaba,  a  diferencia  de  “a­TRIB­ute”,  que  es  
un  verbo.

La  figura  15.1  es  un  diagrama  de  estado  que  muestra  el  resultado  de  estas  asignaciones.  Un  diagrama  de  estado  
que  muestra  un  objeto  y  sus  atributos  se  llama  diagrama  de  objeto.

La  variable  se   se  refiere  a  un  objeto  Point,  que  contiene  dos  atributos.  cada  atributo
refiere  a  un  número  de  punto  flotante.

Puede  leer  el  valor  de  un  atributo  usando  la  misma  sintaxis:
Machine Translated by Google

15.3.  Rectángulos 149

La  expresión  se  refiere  a  y  obtiene  
significa,  
el  v"alor  
Ir  al  d
oe .”  
bjetoEn  el  ejemplo,  asignamos  ese  valor  a  una  variable  
llamada .  No  hay  conflicto  entre  la  variable  y  el  atributo.

Puede  utilizar  la  notación  de  puntos  como  parte  de  cualquier  expresión.  Por  ejemplo:

Puede  pasar  una  instancia  como  argumento  de  la  forma  habitual.  Por  ejemplo:

toma  un  punto  como  argumento  y  lo  muestra  en  notación  matemática.  A  como  argumento:
invocalo,  puedes  pasar

Dentro  de  la  función,  hay  un  alias  para , entonces  si  la  función  modifica , cambios.

Como  ejercicio,  escribe  una  función  llamada   que  toma  dos  Puntos  como
argumentos  y  devuelve  la  distancia  entre  ellos.

15.3  Rectángulos
A  veces  es  obvio  cuáles  deberían  ser  los  atributos  de  un  objeto,  pero  otras  veces  hay  que  tomar  
decisiones.  Por  ejemplo,  imagine  que  está  diseñando  una  clase  para  representar  rectángulos.
¿Qué  atributos  usaría  para  especificar  la  ubicación  y  el  tamaño  de  un  rectángulo?  Puede  ignorar  el  
ángulo;  para  simplificar  las  cosas,  suponga  que  el  rectángulo  es  vertical  u  horizontal.

Hay  al  menos  dos  posibilidades:

•  Puede  especificar  una  esquina  del  rectángulo  (o  el  centro),  el  ancho  y  el
altura.

•  Podría  especificar  dos  esquinas  opuestas.

En  este  punto  es  difícil  decir  si  alguno  es  mejor  que  el  otro,  así  que  implementaremos  el  primero,  solo  
como  ejemplo.

Aquí  está  la  definición  de  clase:
Machine Translated by Google

150 Capítulo  15.  Clases  y  objetos

Rectángulo
caja ancho 100.0
Punto
altura 200.0 X 0.0
esquina
y 0.0

Figura  15.2:  Diagrama  de  objetos.

La  cadena  de  documentación  enumera  los   y son  números; es  un  objeto  Point


atributos:  eso  especifica  la  esquina  inferior  izquierda.

Para  representar  un  rectángulo,  debe  instanciar  un  objeto  Rectangle  y  asignar  valores  a  los  atributos:

La  expresión  significa,  “Ir  al  objeto  nombrado;  luego  vaya  a  ese   hace  referencia  y  seleccione  el  atributo
objeto  y  seleccione  el  atributo  llamado  ”.

La  figura  15.2  muestra  el  estado  de  este  objeto.  Se  incrusta  un  objeto  que  es  un  atributo  de  otro  objeto .

15.4  Instancias  como  valores  de  retorno

Las  funciones  pueden  devolver  instancias.  Por   toma  a   como  argumento


ejemplo,  ment  y  devuelve  un que  contiene  las  coordenadas  del  centro  de  la :

Aquí  hay  un  ejemplo  que  pasa como  argumento  y  asigna  el  Punto  resultante  a
:
Machine Translated by Google

15.5.  Los  objetos  son  mutables 151

15.5  Los  objetos  son  mutables
Puede  cambiar  el  estado  de  un  objeto  haciendo  una  asignación  a  uno  de  sus  atributos.  Por  ejemplo,  
para  cambiar  el  tamaño  de  un  rectángulo  sin  cambiar  su  posición,  puede  modificar  los  valores  de  y
:

También  puede  escribir  funciones  que  modifiquen  objetos.  Por  ejemplo,   toma  a  
objeto  Rectángulo  y  dos  números,  y  ancho  y  alto  del   , y  suma  los  números  al
rectángulo:

Aquí  hay  un  ejemplo  que  demuestra  el  efecto:

Dentro  de  la  función,   es  un  alias  para , entonces  cuando  la  función  modifica ,


cambios.

Como  ejercicio,  escriba  una  función  llamada  que  tome  un  Rectángulo  y  dos  números  llamados  y .  
Debería  cambiar  la  ubicación  del  rectángulo  sumando  a  la  coordenada  de  y  sumando  a  la  coordenada  
de .

15.6  Copia
El  alias  puede  dificultar  la  lectura  de  un  programa  porque  los  cambios  en  un  lugar  pueden  tener  efectos  
inesperados  en  otro  lugar.  Es  difícil  hacer  un  seguimiento  de  todas  las  variables  que  podrían  referirse  
a  un  objeto  determinado.

Copiar  un  objeto  suele  ser  una  alternativa  a  la  creación  de  alias.  El   módulo  contiene  una  función
llamado  que  puede  duplicar  cualquier  objeto:

y  contienen  los  mismos  datos,  pero  no  son  el  mismo  Punto.
Machine Translated by Google

152 Capítulo  15.  Clases  y  objetos

caja ancho 100.0 100.0 ancho caja2

altura 200.0 200.0 altura


X 0.0
esquina esquina
y 0.0

Figura  15.3:  Diagrama  de  objetos.

El  operador  indica  que  y  no  son  el  mismo  objeto,  que  es  lo  que  esperábamos.  Pero  es  posible  que  haya  
esperado  ceder  porque  estos  puntos  contienen  los  mismos  datos.  En  ese  caso,  se  sentirá  decepcionado  al  
saber  que,  por  ejemplo,  el  comportamiento  predeterminado  del  operador  es  el  mismo  que  el  del  operador;  
comprueba  la  identidad  del  objeto,  no  la  equivalencia  del  objeto.  Esto  se  debe  a  que,  para  los  tipos  definidos  
por  el  programador,  Python  no  sabe  qué  se  debería  considerar  equivalente.  Al  menos  no  todavía.

Si  usa  el   para  duplicar  un  Rectángulo,  encontrará  que  copia  el  Rectángulo
objeto  pero  no  el  punto  incrustado.

La  figura  15.3  muestra  cómo  se  ve  el  diagrama  de  objetos.  Esta  operación  se  denomina  copia  superficial  
porque  copia  el  objeto  y  las  referencias  que  contiene,  pero  no  los  objetos  incrustados.

Para  la  mayoría  de  las  aplicaciones,  esto  no  es  lo  que  desea.  En  este  ejemplo,  invocar  a  uno  de  los  
Rectángulos  no  afectaría  al  otro,  ¡pero  invocar  a  cualquiera  afectaría  a  ambos!  Este  
comportamiento  es  confuso  y  propenso  a  errores.

Afortunadamente,  el  módulo  proporciona  un  método  llamado  que  copia  no  solo  el  objeto  sino  también  los  
objetos  a  los  que  se  refiere,  y  los  objetos  a  los  que  se  refieren,  y  así  sucesivamente.  No  te  sorprenderá  
saber  que  esta  operación  se  denomina  copia  profunda.

y  son  objetos  completamente  separados.

Como  ejercicio,  escriba  una  versión  de   que  crea  y  devuelve  un  nuevo  Rectángulo
en  lugar  de  modificar  la  anterior.

15.7  Depuración
Cuando  comience  a  trabajar  con  objetos,  es  probable  que  encuentre  algunas  excepciones  nuevas.  Si  intenta  
acceder  a  un  atributo  que  no  existe,  obtiene  un :
Machine Translated by Google

15.8.  Glosario 153

Si  no  está  seguro  de  qué  tipo  es  un  objeto,  puede  preguntar:

También  puedes  usar para  comprobar  si  un  objeto  es  una  instancia  de  una  clase:

Si  no  está  seguro  de  si  un  objeto  tiene  un  atributo  en  particular,  puede  usar  la  función  integrada
:

El  primer  argumento  puede  ser  cualquier  objeto;  el  segundo  argumento  es  una  cadena  que  contiene  el  
nombre  del  atributo.

También  puedes  usar  un instrucción  para  ver  si  el  objeto  tiene  los  atributos  que  necesita:

Este  enfoque  puede  facilitar  la  escritura  de  funciones  que  funcionan  con  diferentes  tipos;  más  sobre  ese  
tema  se  presenta  en  la  Sección  17.9.

15.8  Clase  del  glosario:  

Un  tipo  definido  por  el  programador.  Una  definición  de  clase  crea  un  nuevo  objeto  de  clase.

objeto  de  clase:  un  objeto  que  contiene  información  sobre  un  tipo  definido  por  el  programador.  El  objeto  
de  clase  se  puede  utilizar  para  crear  instancias  del  tipo.

instancia:  Un  objeto  que  pertenece  a  una  clase.

instanciar:  Para  crear  un  nuevo  objeto.  

atributo:  Uno  de  los  valores  con  nombre  asociados  con  un  objeto.

objeto  incrustado:  Un  objeto  que  se  almacena  como  un  atributo  de  otro  objeto.

copia  superficial:  para  copiar  el  contenido  de  un  objeto,  incluidas  las  referencias  al  módulo  incrustado.
objetos;  implementado  por  el función  en  el

copia  profunda:  para  copiar  el  contenido  de  un  objeto,  así  como  cualquier  objeto  incrustado,  y  cualquier  
objetos  incrustados  en  ellos,  etc.;  implementado  por  el  módulo. función  en  el

diagrama  de  objetos:  un  diagrama  que  muestra  objetos,  sus  atributos  y  los  valores  de  los  at
tributos.
Machine Translated by Google

154 Capítulo  15.  Clases  y  objetos

15.9  Ejercicios

Ejercicio  15.1.  Escribe  una  definición  para  una  clase  llamada   con  atributos y ,
donde  es  un  objeto  Punto  y  es  un  número.

Cree  una  instancia  de  un  objeto  Circle  que  represente  un  círculo  con  su  centro  en  (150,  100)  y  un  radio  de  75.

Escriba  una  función  llamada  que  tome  un  círculo  y  un  punto  y  devuelva  verdadero  si  el  punto  se  encuentra  en  
o  sobre  el  límite  del  círculo.

Escriba  una  función  llamada  que  tome  un  Círculo  y  un  Rectángulo  y  devuelva  Verdadero  si  el  Rectángulo  se  encuentra  
completamente  dentro  o  sobre  el  límite  del  círculo.

Escriba  una  función  llamada  que  tome  un  Círculo  y  un  Rectángulo  y  devuelva  Verdadero  si  alguna  de  las  
esquinas  del  Rectángulo  cae  dentro  del  Círculo.  O  como  una  versión  más  desafiante,  devuelva  True  si  alguna  
parte  del  Rectángulo  cae  dentro  del  Círculo.

Solución:   .
Ejercicio  15.2.  Escriba  una  función  llamada  que  tome  un  objeto  Tortuga  y  un  Rectángulo  y  use  la  Tortuga  para  
dibujar  el  Rectángulo.  Vea  el  Capítulo  4  para  ver  ejemplos  usando  objetos  Turtle.

Escribe  una  función  llamada que  toma  una  Tortuga  y  un  Círculo  y  dibuja  el  Círculo.

Solución: .
Machine Translated by Google

capitulo  16

clases  y  funciones

Ahora  que  sabemos  cómo  crear  nuevos  tipos,  el  siguiente  paso  es  escribir  funciones  que  tomen  objetos  
definidos  por  el  programador  como  parámetros  y  los  devuelvan  como  resultados.  En  este  capítulo  
también  presento  el  “estilo  de  programación  funcional”  y  dos  nuevos  planes  de  desarrollo  de  programas.

Los  ejemplos  de  código  de  este  capítulo  están  disponibles  en .  
Las  soluciones  a  los  ejercicios  están  en
.

16.1  Tiempo

Como  otro  ejemplo  de  un  tipo  definido  por  el  programador,  definiremos  una  clase  llamada   eso
registra  la  hora  del  día.  La  definición  de  clase  se  ve  así:

Podemos  crear  un  nuevo objeto  y  asigne  atributos  para  horas,  minutos  y  segundos:

El  diagrama  de  estado  de  la El  objeto  se  parece  a  la  figura  16.1.

Como  ejercicio,  escriba  una  función  llamada  que  tome  un  objeto  Hora  y  lo  imprima  en  la  forma .  
Sugerencia:  la  secuencia  de  formato  imprime  un  número  entero  con  al  menos  dos  dígitos,  incluido  un  
cero  inicial  si  es  necesario.

Escribe  una  función  booleana  llamada que  toma  dos  objetos  Time,  y , y  re


si  sigue  cronológicamente  y  gira   de  lo  contrario.  Desafío:  no  uses  un
declaración.
Machine Translated by Google

156 Capítulo  16.  Clases  y  funciones

Tiempo

tiempo hora 11

minuto 59

segundo 30

Figura  16.1:  Diagrama  de  objetos.

16.2  Funciones  puras

En  las  próximas  secciones,  escribiremos  dos  funciones  que  suman  valores  de  tiempo.  Demuestran  dos  tipos  de  
funciones:  funciones  puras  y  modificadores.  También  demuestran  un  plan  de  desarrollo  que  llamaré  prototipo  y  
parche,  que  es  una  forma  de  abordar  un  problema  complejo  comenzando  con  un  prototipo  simple  y  lidiando  
gradualmente  con  las  complicaciones.

Aquí  hay  un  prototipo  simple  de :

La  función  crea  un  nuevo  objeto,  inicializa  sus  atributos  y  devuelve  una  referencia  al  nuevo  objeto.  Esto  se  
denomina  función  pura  porque  no  modifica  ninguno  de  los  objetos  que  se  le  pasan  como  argumentos  y  no  tiene  
ningún  efecto,  como  mostrar  un  valor  u  obtener  la  entrada  del  usuario,  aparte  de  devolver  un  valor.

Para  probar  esta  función,  crearé  dos  objetos  de  tiempo:   contiene  la  hora  de  inicio  de  una  película,  
como  Monty  Python  y  el  Santo  Grial,  que  dura  una   contiene  el  tiempo  de  ejecución  de  la  película,
hora  y  35  minutos.

determina  cuándo  se  terminará  la  película.

El  resultado,  puede  que  no  sea  lo  que  esperabas.  El  problema  es  que  esta  función  no  se  ocupa  de  los  casos  en  
los  que  la  cantidad  de  segundos  o  minutos  suman  más  de  sesenta.  Cuando  eso  sucede,  tenemos  que  "llevar"  
los  segundos  adicionales  a  la  columna  de  minutos  o  los  minutos  adicionales  a  la  columna  de  horas.

Aquí  hay  una  versión  mejorada:
Machine Translated by Google

16.3.  modificadores 157

Aunque  esta  función  es  correcta,  se  está  empezando  a  hacer  grande.  Veremos  una  alternativa  más  corta  más  
adelante.

16.3  Modificadores
A  veces  es  útil  que  una  función  modifique  los  objetos  que  obtiene  como  parámetros.  En  ese  caso,  los  cambios  
son  visibles  para  la  persona  que  llama.  Las  funciones  que  funcionan  de  esta  manera  se  llaman  modificadores.

, que  suma  un  número  dado  de  segundos  a  un objeto,  se  puede  escribir  naturalmente
como  modificador.  Aquí  hay  un  borrador:

La  primera  línea  realiza  la  operación  básica;  el  resto  trata  de  los  casos  especiales  que  vimos  antes.

¿Es  correcta  esta  función?  Qué  pasa  si es  mucho  mayor  que  sesenta?

En  ese  caso,  no  basta  con  llevar  una  vez;  tenemos  que  seguir  haciéndolo  hasta  que  sea  menos  de  sesenta.  Una  
solución  es  reemplazar  las  sentencias  por  sentencias.  Eso  haría  que  la  función  fuera  correcta,  pero  no  muy  
eficiente.  Como  ejercicio,  escriba  una  versión  correcta  de  que  no  contenga  bucles.

Cualquier  cosa  que  se  pueda  hacer  con  modificadores  también  se  puede  hacer  con  funciones  puras.  De  hecho,  
algunos  lenguajes  de  programación  solo  permiten  funciones  puras.  Existe  alguna  evidencia  de  que  los  programas  
que  usan  funciones  puras  son  más  rápidos  de  desarrollar  y  menos  propensos  a  errores  que  los  programas  que  
usan  modificadores.  Pero  los  modificadores  son  convenientes  a  veces  y  los  programas  funcionales  tienden  a  ser  
menos  eficientes.
Machine Translated by Google

158 Capítulo  16.  Clases  y  funciones

En  general,  recomiendo  que  escriba  funciones  puras  siempre  que  sea  razonable  y  recurra  a  modificadores  
solo  si  hay  una  ventaja  convincente.  Este  enfoque  podría  llamarse  un  estilo  de  programación  funcional.

Como  ejercicio,  escriba  una  versión  "pura"  del   que  crea  y  devuelve  un  nuevo  Time
objeto  en  lugar  de  modificar  el  parámetro.

16.4  Creación  de  prototipos  frente  a  planificación

El  plan  de  desarrollo  que  estoy  demostrando  se  llama  "prototipo  y  parche".  Para  cada  función,  escribí  un  
prototipo  que  realizaba  el  cálculo  básico  y  luego  lo  probaba,  corrigiendo  errores  en  el  camino.

Este  enfoque  puede  ser  efectivo,  especialmente  si  aún  no  tiene  una  comprensión  profunda  del  problema.  Pero  
las  correcciones  incrementales  pueden  generar  código  que  es  innecesariamente  complicado,  ya  que  trata  con  
muchos  casos  especiales,  y  poco  confiable,  ya  que  es  difícil  saber  si  ha  encontrado  todos  los  errores.

Una  alternativa  es  el  desarrollo  diseñado,  en  el  que  una  visión  de  alto  nivel  del  problema  puede  facilitar  mucho  
la  programación.  En  este  caso,  la  idea  es  que  un  objeto  Tiempo  es  realmente  un  número  de  tres  dígitos  en  
base  60  (ver ).  El  atributo  es  la  "columna  de  unidades",  el  atributo  es  la  "columna  de  sesenta"  y  el  atributo  es  
la  "columna  de  treinta  y  seis  centenas".

Cuando  escribimos  y  efectivamente  estábamos  sumando  
, en  base  60,  por  lo  que  tuvimos  que  llevar  de  una  
columna  a  la  siguiente.

Esta  observación  sugiere  otro  enfoque  para  todo  el  problema:  podemos  convertir  objetos  de  tiempo  en  
números  enteros  y  aprovechar  el  hecho  de  que  la  computadora  sabe  cómo  hacer  aritmética  de  números  
enteros.

Aquí  hay  una  función  que  convierte  tiempos  a  números  enteros:

Y  aquí  hay  una  función  que  convierte  un  número  entero  en  una  Hora  (recupere   divide  la  primera
ese  argumento  por  segundo  y  devuelva  el  cociente  y  el  resto  como  una  tupla).

Es  posible  que  deba  pensar  un  poco  y  realizar  algunas  pruebas  para  convencerse  de  que  estas  funciones  son  
correctas.  Una  forma  de  probarlos  es  comprobar  que  para  muchos  valores  de .  Este  es  un  ejemplo  de  una  
verificación  de  consistencia.

Una  vez  que  esté  convencido  de  que  son  correctos,  puede  usarlos  para  reescribir :
Machine Translated by Google

16.5.  depuración 159

Esta  versión  es  más  corta  que  la  original  y  más  fácil  de  verificar.  Como  ejercicio,  reescribe
usando y .

De  alguna  manera,  convertir  de  base  60  a  base  10  y  viceversa  es  más  difícil  que  simplemente  lidiar  con  los  
tiempos.  La  conversión  base  es  más  abstracta;  nuestra  intuición  para  tratar  con  valores  de  tiempo  es  mejor.

Pero  si  tenemos  la  perspicacia  de  tratar  los  tiempos  como  números  de  base  60  y  hacemos  la  inversión  
de  escribir  las  funciones  de  conversión  ( ),  obtenemos  uyn  programa  que  es  más  corto,  más  fácil  de  leer  
y  depurar,  y  más  confiable.

También  es  más  fácil  agregar  funciones  más  adelante.  Por  ejemplo,  imagina  restar  dos  
Tiempos  para  encontrar  la  duración  entre  ellos.  El  enfoque  ingenuo  sería  implementar  la  resta  
con  préstamo.  Usar  las  funciones  de  conversión  sería  más  fácil  y  más  probable  que  sea  correcto.

Irónicamente,  a  veces  hacer  un  problema  más  difícil  (o  más  general)  lo  hace  más  fácil  
(porque  hay  menos  casos  especiales  y  menos  oportunidades  de  error).

16.5  Depuración
Un  objeto  de  tiempo  está  bien  formado  si  los  valores   y  y están  entre  0  y  60  
de  (incluido  0  pero  no  60)  y  si  es  positivo.  pero   deben  ser  valores  enteros,
podríamos  permitir  tener  una  parte  fraccionaria.

Requisitos  como  estos  se  llaman  invariantes  porque  siempre  deben  ser  verdaderos.  Para  
decirlo  de  otra  manera,  si  no  son  ciertas,  algo  ha  ido  mal.
Escribir  código  para  verificar  invariantes  puede  ayudar  a  detectar  errores  y  encontrar  sus  causas.  Por  
ejemplo,  podría  tener  una  función  como  la  que  toma  un  objeto  de  tiempo  y  lo  devuelve  si  viola  un  
invariante:

Al  comienzo  de  cada  función,  puede  verificar  los  argumentos  para  asegurarse  de  que  sean  
válidos:

O  podría  usar  una  declaración  de  afirmación,  que  verifica  un  invariante  dado  y  genera  una  
excepción  si  falla:

Las  sentencias  son  útiles  porque  distinguen  el  código  que  se  ocupa  de  las  condiciones  
normales  del  código  que  comprueba  si  hay  errores.
Machine Translated by Google

160 Capítulo  16.  Clases  y  funciones

16.6  Glosario
prototipo  y  parche:  Un  plan  de  desarrollo  que  implica  escribir  un  borrador  de  un  programa,  probar  y  corregir  
errores  a  medida  que  se  encuentran.

Desarrollo  diseñado:  un  plan  de  desarrollo  que  implica  una  visión  de  alto  nivel  del  problema  y  más  planificación  
que  el  desarrollo  incremental  o  el  desarrollo  de  prototipos.
mento

función  pura:  Una  función  que  no  modifica  ninguno  de  los  objetos  que  recibe  como  argumentos.
La  mayoría  de  las  funciones  puras  son  fructíferas.

modificador:  una  función  que  cambia  uno  o  más  de  los  objetos  que  recibe  como  argumentos.  La  mayoría  de  
los  modificadores  son  nulos;  es  decir,  vuelven .

estilo  de  programación  funcional:  un  estilo  de  diseño  de  programa  en  el  que  la  mayoría  de  func
ciones  son  puras.

invariante:  Una  condición  que  siempre  debe  ser  cierta  durante  la  ejecución  de  un  programa.

declaración  de  aserción:  una  declaración  que  verifica  una  condición  y  genera  una  excepción  si  falla.

16.7  Ejercicios

Los  ejemplos  de  código  de  este  capítulo  están  disponibles  en ;  Las  
soluciones  de  los  ejercicios  están  disponibles  en
.
Ejercicio  16.1.  Escriba  una  función  llamada  que  tome  un  objeto  Tiempo  y  un  número  y  devuelva  un  nuevo  
objeto  Tiempo  que  contenga  el  producto  del  Tiempo  original  y  el  número.

Luego  use  para  escribir  una  función  que  tome  un  objeto  de  tiempo  que  represente  el  tiempo  final  en  una  
carrera  y  un  número  que  represente  la  distancia,  y  devuelva  un  objeto  de  tiempo  que  represente  el  ritmo  
promedio  (tiempo  por  milla).
Ejercicio  16.2.  El  módulo  proporciona  objetos  que  son  similares  a  los  objetos  de  tiempo  de  este  capítulo,  pero  
proporcionan  un  amplio  conjunto  de  métodos  y  operadores.  Lea  la  documentación  en
.

1.  Usa  la   módulo  para  escribir  un  programa  que  obtenga  la  fecha  actual  e  imprima  el  día  de
semana.

2.  Escriba  un  programa  que  tome  un  cumpleaños  como  entrada  e  imprima  la  edad  del  usuario  y  el  número  
de  días,  horas,  minutos  y  segundos  hasta  su  próximo  cumpleaños.

3.  Para  dos  personas  nacidas  en  días  diferentes,  hay  un  día  en  que  una  tiene  el  doble  de  edad  que  la  otra.
Ese  es  su  Día  Doble.  Escriba  un  programa  que  tome  dos  fechas  de  nacimiento  y  calcule  su  Día  Doble.

4.  Para  un  poco  más  de  desafío,  escriba  la  versión  más  general  que  calcula  el  día  en  que  uno
persona  es  n  veces  mayor  que  la  otra.

Solución:
Machine Translated by Google

capitulo  17

Clases  y  métodos

Aunque  estamos  usando  algunas  de  las  funciones  orientadas  a  objetos  de  Python,  los  programas  de  los  
últimos  dos  capítulos  no  están  realmente  orientados  a  objetos  porque  no  representan  las  relaciones  entre  
los  tipos  definidos  por  el  programador  y  las  funciones  que  operan  en  ellos.  El  siguiente  paso  es  transformar  
esas  funciones  en  métodos  que  hagan  explícitas  las  relaciones.

Los  ejemplos  de  código  de  este  capítulo  están  disponibles  en  y  
, las  soluciones  a  los  ejercicios  están  en
.

17.1  Funciones  orientadas  a  objetos
Python  es  un  lenguaje  de  programación  orientado  a  objetos,  lo  que  significa  que  proporciona  funciones  
que  admiten  la  programación  orientada  a  objetos,  que  tiene  estas  características  definitorias:

•  Los  programas  incluyen  definiciones  de  clases  y  métodos.

•  La  mayor  parte  del  cálculo  se  expresa  en  términos  de  operaciones  sobre  objetos.

•  Los  objetos  a  menudo  representan  cosas  en  el  mundo  real,  y  los  métodos  a  menudo  corresponden  a  las  
formas  en  que  interactúan  las  cosas  en  el  mundo  real.

Por  ejemplo,  la  clase  definida  en  el  Capítulo  16  corresponde  a  la  forma  en  que  las  personas  registran  la  
hora  del  día,  y  las  funciones  que  definimos  corresponden  al  tipo  de  cosas  que  las  personas  hacen  con  las  
horas.  De  manera  similar,  las  clases  y  del  Capítulo  15  corresponden  a  los  conceptos  matemáticos  de  un  
punto  y  un  rectángulo.

Hasta  ahora,  no  hemos  aprovechado  las  características  que  proporciona  Python  para  admitir  la  
programación  orientada  a  objetos.  Estas  características  no  son  estrictamente  necesarias;  la  mayoría  de  
ellos  proporcionan  una  sintaxis  alternativa  para  las  cosas  que  ya  hemos  hecho.  Pero  en  muchos  casos,  la  
alternativa  es  más  concisa  y  transmite  con  mayor  precisión  la  estructura  del  programa.

Por  ejemplo,  en   no  hay  una  conexión  obvia  entre  la  definición  de  clase  y
las  definiciones  de  funciones  que  siguen.  Con  un  poco  de  examen,  es  evidente  que  cada  función  toma  al  
menos  un  objeto  como  argumento.
Machine Translated by Google

162 Capítulo  17.  Clases  y  métodos

Esta  observación  es  la  motivación  de  los  métodos;  un  método  es  una  función  que  está  asociada  con  una  clase  
particular.  Hemos  visto  métodos  para  cadenas,  listas,  diccionarios  y  tuplas.  En  este  capítulo,  definiremos  métodos  
para  tipos  definidos  por  el  programador.

Los  métodos  son  semánticamente  lo  mismo  que  las  funciones,  pero  hay  dos  diferencias  sintácticas:

•  Los  métodos  se  definen  dentro  de  una  definición  de  clase  para  hacer  explícita  la  relación  entre  la  clase  y  el  
método.

•  La  sintaxis  para  llamar  a  un  método  es  diferente  de  la  sintaxis  para  llamar  a  una  función.

En  las  próximas  secciones,  tomaremos  las  funciones  de  los  dos  capítulos  anteriores  y  las  transformaremos  en  
métodos.  Esta  transformación  es  puramente  mecánica;  puedes  hacerlo  siguiendo  una  secuencia  de  pasos.  Si  se  
siente  cómodo  convirtiendo  de  un  formulario  a  otro,  podrá  elegir  el  mejor  formulario  para  lo  que  esté  haciendo.

17.2  Objetos  de  impresión
En  el  Capítulo  16,  definimos  una  clase  llamada  named y  en  la  Sección  16.1,  escribiste  una  función
:

Para  llamar  a  esta  función,  debe  pasar  un objeto  como  argumento:

Para  hacer   un  método,  todo  lo  que  tenemos  que  hacer  es  mover  la  definición  de  la  función  dentro  del
definición  de  clase.  Observe  el  cambio  en  la  sangría.

Ahora  hay  dos  formas  de  llamar  a  la   .  La  primera  (y  menos  común)  forma  es  usar
sintaxis  de  la  función:

En  este  uso  de  la  notación  de   es  el  nombre  de  la  clase,  y es  el  nombre  del


puntos,  método. se  pasa  como  parámetro.

La  segunda  forma  (y  más  concisa)  es  usar  la  sintaxis  del  método:
Machine Translated by Google

17.3.  Otro  ejemplo 163

En  este  uso  de  la  notación  de  puntos,  es  el  objeto  
es  esl  obre  
el  qdue  
nombre   el  sme  
invoca  
étodo   el  método,  que  
(nuevamente),   y se  denomina  
sujeto .  Así  como  el  sujeto  de  una  oración  es  de  lo  que  trata  la  oración,  el  sujeto  de  la  invocación  de  
un  método  es  de  lo  que  trata  el  método.

Dentro  del  método,  el  sujeto  se  asigna  al  primer  parámetro,  por  lo  que  en  este  caso  se   es

asigna  a .

Por  convención,  el  primer  parámetro  de  un  método  se  llama   , asi  seria  mas  comun
para  escribir  así:

La  razón  de  esta  convención  es  una  metáfora  implícita:

•  La  sintaxis  para  una  llamada  de   ,  sugiere  que  la  función  es  la !  Aquí  
función,  agente  activo.  Dice  algo  como,  "Oye,   hay  un  objeto  para  que  usted
imprime".

•  En  la  programación  orientada  a  objetos,  los  objetos  son  los  agentes  activos.  Un  método  invoca  
ción  como dice  "Oye !  Por  favor,  imprímete”.

Este  cambio  de  perspectiva  puede  ser  más  cortés,  pero  no  es  obvio  que  sea  útil.  En  los  ejemplos  que  
hemos  visto  hasta  ahora,  puede  que  no  lo  sea.  Pero  a  veces  cambiar  la  responsabilidad  de  las  
funciones  a  los  objetos  hace  posible  escribir  funciones  (o  métodos)  más  versátiles  y  facilita  el  
mantenimiento  y  la  reutilización  del  código.

como  ejercicio,  reescribir   (de  la  Sección  16.4)  como  método.  Puede  sentirse  tentado  
para  reescribir  también  como  un  método,  pero  eso  realmente  no  tiene  sentido  porque  no  habría  ningún  
objeto  para  invocarlo.

17.3  Otro  ejemplo
Aquí  hay  una  versión  de (de  la  Sección  16.3)  reescrito  como  un  método:

Esta  versión  asume  esa   se  escribe  como  un  método.  Además,  tenga  en  cuenta  que  es  un  puro
función,  no  un  modificador.

Así  es  como  invocarías :
Machine Translated by Google

164 Capítulo  17.  Clases  y  métodos

El  sujeto,   ,  se  asigna  al  primer  parámetro, .  El  argumento, ,  obtiene


asignado  al  segundo  parámetro, .

Este  mecanismo  puede  resultar  confuso,  especialmente  si  comete  un  error.  Por  ejemplo,  si  invocas
con  dos  argumentos,  se  obtiene:

El  mensaje  de  error  es  inicialmente  confuso,  porque  solo  hay  dos  argumentos  entre  paréntesis.  Pero  
el  tema  también  se  considera  un  argumento,  así  que  en  total  son  tres.

Por  cierto,  un  argumento  posicional  es  un  argumento  que  no  tiene  un  nombre  de  parámetro;  es  decir,  
no  es  un  argumento  de  palabra  clave.  En  esta  función  llama:

y son  posicionales  y es  un  argumento  de  palabra  clave.

17.4  Un  ejemplo  más  complicado
Reescribir  (de  la  Sección  16.1)  es  un  poco  más  complicado  porque  toma  dos  objetos  de  tiempo  como  
parámetros.  En  este  caso  es  convencional  nombrar  el  primer  parámetro  y  el  segundo  parámetro
:

Para  usar  este  método,  debe  invocarlo  en  un  objeto  y  pasar  el  otro  como  argumento:

Una  cosa  buena  de  esta  sintaxis  es  que  casi  se  lee  como  en  inglés:  "end  is  after  start?"

17.5  El  método  de  inicio
El  método  init  (abreviatura  de  "inicialización")  es  un  método  especial  que  se  invoca  cuando  se  crea  
una  instancia  de  un  objeto.  Su  nombre  completo  es  (dos  guiones  bajos,  seguidos  de  y  luego  dos  
, guiones  bajos  más).  Un  método  init  para  la  clase  podría  verse  como
este:

Es  común  que  los  parámetros  de tener  los  mismos  nombres  que  los  atributos.  El
declaración
Machine Translated by Google

17.6.  El método 165

almacena  el  valor  del  parámetro como  atributo  de .

Los  parámetros  son  opcionales,  así  que  si  llamas   sin  argumentos,  obtienes  el  valor  predeterminado
a  values.

Si  proporciona  un  argumento,  anula :

Si  proporciona  dos  argumentos,  estos  anulan y .

Y  si  proporciona  tres  argumentos,  anulan  los  tres  valores  predeterminados.

Como  ejercicio,  escriba  un  método  init  para  la  clase  que  tome  y  como  parámetros  opcionales  y  los  
asigne  a  los  atributos  correspondientes.

17.6  El método
es  un  método  especial,   , que  se  supone  que  devuelve  una  cadena  representa
como  ción  de  un  objeto.

Por  ejemplo,  aquí  hay  un  método  para  objetos  de  tiempo:

Cuando  usted un  objeto,  Python  invoca  el método:

Cuando  escribo  una  nueva  clase,  casi  siempre  empiezo   , lo  que  hace  que  sea  más  fácil
depuración.  para  instanciar  objetos,  y , escribiendo  lo  que  es  útil  para  la  

Como  ejercicio,  escriba  un  método  para  la clase.  Cree  un  objeto  Punto  e  imprímalo.

17.7  Sobrecarga  del  operador
Al  definir  otros  métodos  especiales,  puede  especificar  el  comportamiento  de  los  operadores  en  los  
tipos  definidos  por  el  programador.  Por  ejemplo,  si  define  un  método  con  el  nombre  de  la  clase,  
puede  usar  el  operador  en  los  objetos  de  tiempo.

Así  es  como  se  vería  la  definición:
Machine Translated by Google

166 Capítulo  17.  Clases  y  métodos

Y  así  es  como  podrías  usarlo:

Cuando  aplica  el  operador  a  los  objetos  de  tiempo,  Python  invoca .  Cuando  imprime  el  resultado,  Python  
invoca .  ¡Así  que  están  sucediendo  muchas  cosas  detrás  de  escena!

Cambiar  el  comportamiento  de  un  operador  para  que  funcione  con  tipos  definidos  por  el  programador  se  
denomina  sobrecarga  de  operadores.  Para  cada  operador  en  Python  hay  un  método  especial  
correspondiente,  como .  Para  más  detalles,  consulte
.

Como  ejercicio,  escriba  un  método  para  la  clase  Point.

17.8  Despacho  basado  en  tipos
En  la  sección  anterior,  agregamos  dos  objetos  de  tiempo,  pero  es  posible  que  también  desee  agregar  un  
número  entero  a  un  objeto  de  tiempo.  La  siguiente  es  una  versión  de  que  comprueba  el  tipo  de
e  invoca  ya  sea o :

El  valor  de  la  función   toma  un  valor  y  un  objeto  de  clase,  y  devuelve Si  el


incorporada  es  una  instancia  de  la  clase.

Si  invoca.  es  
De   lo  
un   contrario,  
objeto   asume  que  el  parámetro  es  un  número  e  invoca .  Esta  operación  se  denomina  
de  tiempo,
envío  basado  en  tipos  porque  envía  el  cálculo  a  diferentes  métodos  según  el  tipo  de  argumentos.

Aquí  hay  ejemplos  que  usan  el  operador  con  diferentes  tipos:
Machine Translated by Google

17.9.  Polimorfismo 167

Desafortunadamente,  esta  implementación  de  la  suma  no  es  conmutativa.  Si  el  entero  es  el  primer  
operando,  obtienes

El  problema  es  que,  en  lugar  de  pedirle  al  objeto  Hora  que  agregue  un  número  entero,  Python  le  está  
pidiendo  a  un  número  entero  que  agregue  un  objeto  Hora  y  no  sabe  cómo  hacerlo.  Pero  hay  una  
,
solución  inteligente  para  este  problema:  el  método   especial  que  significa  "suma  del  lado  derecho".  Este  
método  se  invoca  cuando  aparece  un  objeto  de  tiempo  en  el  lado  derecho  del  operador.  Aquí  está  la  
definición:

Y  así  es  como  se  usa:

Como  ejercicio,  escriba  un  método  para  Puntos  que  funcione  con  un  objeto  Punto  o  una  tupla:

•  Si  el  segundo  operando  es  un  Punto,  el  método  debe  devolver  un  nuevo  Punto  cuya  coordenada  
x  sea  la  suma  de  las  coordenadas  x  de  los  operandos,  y  lo  mismo  para  las  coordenadas  y.

•  Si  el  segundo  operando  es  una  tupla,  el  método  debe  agregar  el  primer  elemento  de  la  tupla  a  la  
coordenada  x  y  el  segundo  elemento  a  la  coordenada  y,  y  devolver  un  nuevo  Punto  con  el  
resultado.

17.9  Polimorfismo
El  despacho  basado  en  tipos  es  útil  cuando  es  necesario,  pero  (afortunadamente)  no  siempre  es  
necesario.  A  menudo,  puede  evitarlo  escribiendo  funciones  que  funcionen  correctamente  para  
argumentos  con  diferentes  tipos.

Muchas  de  las  funciones  que  escribimos  para  cadenas  también  funcionan  para  otros  tipos  de  secuencias.  Por  
ejemplo,  en  la  Sección  11.2  solíamos  contar  el  número  de  veces  que  aparece  cada  letra  en  una  palabra.
Machine Translated by Google

168 Capítulo  17.  Clases  y  métodos

Esta  función  también  funciona  para  listas,  tuplas  e  incluso  diccionarios,  siempre  que  los  elementos  de  sean  
hashable,  para  que  puedan  usarse  como  claves  en .

Las  funciones  que  trabajan  con  varios  tipos  se  llaman  polimórficas.  El  polimorfismo  puede  facilitar  la  
, los  elementos  de  una  secuencia,  
reutilización  del  código.  Por  ejemplo,  la  función  incorporada  que  agrega  
funciona  siempre  que  los  elementos  de  la  secuencia  admitan  la  adición.

Dado  que  los  objetos  de  tiempo  proporcionan  una método,  trabajan  con:

En  general,  si  todas  las  operaciones  dentro  de  una  función  funcionan  con  un  tipo  dado,  la  función  funciona  
con  ese  tipo.

El  mejor  tipo  de  polimorfismo  es  el  tipo  no  intencional,  donde  descubres  que  una  función  que  ya  escribiste  
se  puede  aplicar  a  un  tipo  que  nunca  planeaste.

17.10  Depuración
Es  legal  agregar  atributos  a  los  objetos  en  cualquier  punto  de  la  ejecución  de  un  programa,  pero  si  tiene  
objetos  del  mismo  tipo  que  no  tienen  los  mismos  atributos,  es  fácil  cometer  errores.  Se  considera  una  
buena  idea  inicializar  todos  los  atributos  de  un  objeto  en  el  método  init.

Si  no  está  seguro  de  si  un  objeto  tiene  un  atributo  en  particular,  puede  usar  la  función  incorporada  
(consulte  la  Sección  15.7).

Otra  forma  de  acceder  a  los  atributos  es  que  la  función  integrada   , que  toma  un  objeto  y
devuelve  un  diccionario  que  asigna  los  nombres  de  los  atributos  (como  cadenas)  a  sus  valores:

Para  fines  de  depuración,  puede  que  le  resulte  útil  tener  esta  función  a  mano:

atraviesa  el  diccionario  e  imprime  cada  nombre  de  atributo  y  su  correlato
valor  correspondiente.

La  función  incorporada  el   toma  un  objeto  y  un  nombre  de  atributo  (como  una  cadena)  y  devuelve
valor  del  atributo.
Machine Translated by Google

17.11.  Interfaz  e  implementación 169

17.11  Interfaz  e  implementación
Uno  de  los  objetivos  del  diseño  orientado  a  objetos  es  hacer  que  el  software  sea  más  fácil  de  mantener,  lo  
que  significa  que  puede  mantener  el  programa  funcionando  cuando  otras  partes  del  sistema  cambian  y  
modificar  el  programa  para  cumplir  con  los  nuevos  requisitos.

Un  principio  de  diseño  que  ayuda  a  lograr  ese  objetivo  es  mantener  las  interfaces  separadas  de  las  
implementaciones.  Para  los  objetos,  eso  significa  que  los  métodos  que  proporciona  una  clase  no  deberían  
depender  de  cómo  se  representen  los  atributos.

Por  ejemplo,  en  este  capítulo  desarrollamos  una  clase  que  representa  una  hora  del  día.  Los  métodos  
proporcionados  por  esta  clase  incluyen , ,y .

Podríamos  implementar  esos  métodos  de  varias  maneras.  Los  detalles  de  la  implementación  
dependen  de  cómo  representemos  el  tiempo.  En  este  capítulo,  los  atributos  de  un objeto  son ,
,y .

Como  alternativa,  podríamos  reemplazar  estos  atributos  con  un  solo  número  entero  que  represente  la  
cantidad  de  segundos  desde  la  medianoche.  Esta  implementación  haría  que  algunos  métodos  fueran  más  
, fáciles  de  escribir,  pero  hace  que  otros  métodos  sean  más  difíciles.
Después  de  implementar  una  nueva  clase,  es  posible  que  descubra  una  mejor  implementación.  Si  
otras  partes  del  programa  están  usando  su  clase,  puede  llevar  mucho  tiempo  y  ser  propenso  a  errores  
cambiar  la  interfaz.

Pero  si  diseñó  la  interfaz  con  cuidado,  puede  cambiar  la  implementación  sin  cambiar  la  
interfaz,  lo  que  significa  que  otras  partes  del  programa  no  tienen  que  cambiar.

17.12  Glosario
lenguaje  orientado  a  objetos:  un  lenguaje  que  proporciona  funciones,  como  tipos  y  métodos  
definidos  por  el  programador,  que  facilitan  la  programación  orientada  a  objetos.

Programación  orientada  a  objetos:  un  estilo  de  programación  en  el  que  los  datos  y  las  operaciones
que  lo  manipulan  están  organizados  en  clases  y  métodos.

método:  una  función  que  se  define  dentro  de  una  definición  de  clase  y  se  invoca  en  instancias  de
esa  clase.

sujeto:  El  objeto  sobre  el  que  se  invoca  un  método.

argumento  posicional:  un  argumento  que  no  incluye  un  nombre  de  parámetro,  por  lo  que  no  es  un
argumento  de  palabra  clave.

sobrecarga  del  operador:  cambiar  el  comportamiento  de  un  operador  para  que  funcione  con  un
tipo  definido  por  el  programador.

despacho  basado  en  tipo:  Un  patrón  de  programación  que  verifica  el  tipo  de  un  operando  y  en
invoca  diferentes  funciones  para  diferentes  tipos.

polimórfico:  Perteneciente  a  una  función  que  puede  trabajar  con  más  de  un  tipo.
Machine Translated by Google

170 Capítulo  17.  Clases  y  métodos

17.13  Ejercicios

Ejercicio  17.1.  Descargue  el  código  de  este  capítulo  para  que  sea  un  
.  Cambia  los  atributos  de  la   solo  número  entero  que  represente  los  segundos  desde  
noche.  Luego  modifique  los  métodos  (y  la  función   mediados  de)  para  trabajar  con  el  nuevo  
tation.  No  debería  tener  que  modificar  el  código  de  prueba   implemento.  Cuando  haya  terminado,  la  salida  debería
para  que  sea  el  mismo  que  antes.   .
Solución:  Ejercicio  17.2.  Este  ejercicio  es  una  advertencia  sobre  uno  de  los  errores  más  comunes  y  difíciles  
de  encontrar.  en  Python  Escriba  una  definición  para  una  clase  nombrada  con  los  siguientes  métodos:

1.  Un método  que  inicializa  un  atributo  llamado a  una  lista  vacía.

2.  Un  método  llamado que  toma  un  objeto  de  cualquier  tipo  y  lo  agrega  a
.

método  que  devuelve  una  representación  de  cadena  del  objeto  Canguro  y  el  
contenido  de  la  bolsa.

Pruebe  su  código  creando  dos  objetos,  asignándolos  a  variables  nombradas  y  luego   y
, agregándolos  al  contenido  de  la  bolsa  de .

Descargue  el   .  Contiene  una  solución  a  la
problema  anterior  con  un  error  grande  y  desagradable.  Encuentra  y  corrige  el  error.

Si  se  atasca,  puede  descargarlo,   ,
que  explica  el  problema  y  demuestra  una  solución.
Machine Translated by Google

capitulo  18

Herencia

La  característica  del  lenguaje  más  frecuentemente  asociada  con  la  programación  orientada  a  objetos  
es  la  herencia.  La  herencia  es  la  capacidad  de  definir  una  nueva  clase  que  es  una  versión  modificada  
de  una  clase  existente.  En  este  capítulo,  demuestro  la  herencia  usando  clases  que  representan  
naipes,  barajas  de  cartas  y  manos  de  póquer.

Si  no  juegas  al  póquer,  puedes  leer  sobre  ello  en   ,
pero  no  tienes  que  hacerlo;  Te  diré  lo  que  necesitas  saber  para  los  ejercicios.

Los  ejemplos  de  código  de  este  capítulo  están  disponibles  en
.

18.1  Objetos  de  tarjeta
Hay  cincuenta  y  dos  cartas  en  una  baraja,  cada  una  de  las  cuales  pertenece  a  uno  de  cuatro  
palos  y  uno  de  trece  rangos.  Los  palos  son  Picas,  Corazones,  Diamantes  y  Tréboles  (en  
orden  descendente  en  el  bridge).  Los  rangos  son  As,  2,  3,  4,  5,  6,  7,  8,  9,  10,  Jota,  Reina  y  
Rey.  Según  el  juego  que  esté  jugando,  un  As  puede  ser  mayor  que  el  Rey  o  menor  que  2.

Si  queremos  definir  un  nuevo  objeto  para  representar  un  naipe,  es  obvio  cuáles  deben  ser  los  
atributos:  y .  No  es  tan  obvio  de  qué  tipo  deben  ser  los  atributos.
Una  posibilidad  es  usar  cadenas  que  contengan  palabras  como  trajes  y  rangos.  Un  problema  
con  esta  implementación  es  que  no  sería  fácil  comparar  cartas  para  ver  cuál  tenía  un  rango  o  
palo  más  alto.

Una  alternativa  es  usar  números  enteros  para  codificar  los  rangos  y  palos.  En  este  contexto,  
“codificar”  significa  que  vamos  a  definir  un  mapeo  entre  números  y  palos,  o  entre  números  y  
rangos.  Este  tipo  de  codificación  no  pretende  ser  un  secreto  (eso  sería  "cifrado").

Por  ejemplo,  esta  tabla  muestra  los  palos  y  los  códigos  enteros  correspondientes:

Picas  →  3
Corazones  →  2
Diamantes  →  1
Clubes  →  0
Machine Translated by Google

172 Capítulo  18.  Herencia

Este  código  facilita  la  comparación  de  tarjetas;  Debido  a  que  los  palos  más  altos  se  asignan  a  números  más  
altos,  podemos  comparar  palos  comparando  sus  códigos.

El  mapeo  de  rangos  es  bastante  obvio;  cada  uno  de  los  rangos  numéricos  se  asigna  al  entero  
correspondiente,  y  para  las  cartas  con  figuras:

jota  →  11
Reina  →  12
Rey  →  13
Estoy  usando  el  símbolo  →  para  dejar  en  claro  que  estas  asignaciones  no  son  parte  del  
programa  Python.  Son  parte  del  diseño  del  programa,  pero  no  aparecen  explícitamente  en  el  código.

La  definición  de  clase  para Se  ve  como  esto:

Como  de  costumbre,  el  método  init  toma  un  parámetro  opcional  para  cada  atributo.  La  carta  por  defecto  
es  el  2  de  Tréboles.

Para  crear  una  Tarjeta,  llamas con  el  palo  y  el  rango  de  la  carta  que  quieras.

18.2  Atributos  de  clase
Para  imprimir  objetos  de  cartas  de  una  manera  que  las  personas  puedan  leer  fácilmente,  necesitamos  
un  mapeo  de  los  códigos  enteros  a  los  rangos  y  palos  correspondientes.  Una  forma  natural  de  hacerlo  
es  con  listas  de  cadenas.  Asignamos  estas  listas  a  atributos  de  clase:

Las  variables  como  las  que  se  dyefinen  dentro  de  una  
, clase  pero  fuera  de  cualquier  método,  se  
denominan  atributos  de  clase  porque  están  asociadas  con  el  objeto  de  clase.
.

Este  término  las  distingue  de  variables  como   y , que  se  llaman  instancia
atributos  porque  están  asociadas  con  una  instancia  particular.
Se  accede  a  ambos  tipos  de  atributos  mediante  la  notación  de  puntos.  Por  ejemplo,   ,
in  es  un  objeto  Card  y  es  su  rango.  De  manera  similar,  es  un  objeto  de  clase  y  es  una  lista  de  cadenas  
asociadas  con  la  clase.
Machine Translated by Google

18.3.  Comparando  cartas 173

tipo lista

Tarjeta trajes_nombres

lista

rank_names

Tarjeta

tarjeta1 traje 1

rango 11

Figura  18.1:  Diagrama  de  objetos.

Cada  tarjeta  tiene  la  suya. y , pero  solo  hay  una  copia  de y
.

Poniendo  todo  junto,  la  expresión   significa  "usar  el  at  de  
tributo  del  objeto  como  un  índice  en  la  lista  y  seleccione   la  clase ,
la  cadena  apropiada”.
El  primer  elemento  de  porque  no  hay  ces
arta  con  rango  cero.  Al  incluirlo  como  guardián  de  lugar,  obtenemos  
una  asignación  con  la  buena  propiedad  de  que  el  índice  2  se  asigna  a  la  cadena  y  así  
, evitar  este  ajuste,  podríamos  haber  usado  un  diccionario  en  lugar  de  una  lista.
sucesivamente.  Para  

Con  los  métodos  que  tenemos  hasta  ahora,  podemos  crear  e  imprimir  tarjetas:

La  figura  18.1  es  un  diagrama  del  objeto  de  clase  y  una  instancia  de  Card.  es  un  objeto  de  clase;  su  tipo  es  
una  instancia  de  por  lo  que  .su  tipo  es .  Para  ahorrar  espacio,  yo  
,y
no  dibujó  el  contenido  de .

18.3  Comparación  de  cartas

Para  los  tipos  integrados,  existen  operadores  relacionales  (, , ,  etc.)  que  comparan  valores  y  
determinan  cuándo  uno  es  mayor,  menor  o  igual  que  otro.  Para  los  tipos  definidos  por  el  
programador,  podemos  anular  el  comportamiento  de  los  operadores  integrados  al  proporcionar  un  
, método  denominado  que  significa  "menor  que".

toma  dos  parámetros, y , y  regresa si es  estrictamente  menor  que


.

El  orden  correcto  de  las  tarjetas  no  es  obvio.  Por  ejemplo,  ¿cuál  es  mejor,  el  3  de  
Tréboles  o  el  2  de  Diamantes?  Uno  tiene  un  rango  más  alto,  pero  el  otro  tiene  un  palo  
más  alto.  Para  comparar  cartas,  debe  decidir  si  el  rango  o  el  palo  es  más  importante.
La  respuesta  puede  depender  del  juego  que  esté  jugando,  pero  para  simplificar  las  cosas,  tomaremos  la  
decisión  arbitraria  de  que  el  palo  es  más  importante,  de  modo  que  todas  las  espadas  superen  a  todas  las  
diamantes,  y  así  sucesivamente.
Machine Translated by Google

174 Capítulo  18.  Herencia

Con  eso  decidido,  podemos  escribir :

Puedes  escribir  esto  de  manera  más  concisa  usando  la  comparación  de  tuplas:

Como  ejercicio,  escriba  un  método  para  objetos  de  tiempo.  Puede  usar  la  comparación  de  tuplas,  pero  
también  podría  considerar  comparar  números  enteros.

18.4  Mazos
Ahora  que  tenemos  Cartas,  el  siguiente  paso  es  definir  Barajas.  Dado  que  un  mazo  se  compone  de  
cartas,  es  natural  que  cada  Deck  contenga  una  lista  de  cartas  como  atributo.

La  siguiente  es  una  definición  de  clase  para   .  El  método  init  crea  el  atributo. y
genera  el  conjunto  estándar  de  cincuenta  y  dos  cartas:

La  forma  más  fácil  de  llenar  el  mazo  es  con  un  bucle  anidado.  El  bucle  exterior  enumera  los  palos  del  
0  al  3.  El  bucle  interior  enumera  los  rangos  del  1  al  13.  Cada  iteración  crea  una  nueva  Carta  con  el  
palo  y  el  rango  actuales,  y  la  agrega  a .

18.5  Impresión  de  la  baraja
Aquí  hay  un método  para :
Machine Translated by Google

18.6.  Añadir,  eliminar,  barajar  y  ordenar 175

Este  método  demuestra  una  forma  eficiente  de  acumular  una  cadena  grande:  crear  una  lista  de  cadenas  y  luego  usar  
el  método  de  cadena.  La  función  integrada  invoca  el  método  en  cada  tarjeta  y  devuelve  la  representación  de  cadena.

Ya  que  invocamos   en  un  carácter  de  nueva  línea,  las  tarjetas  están  separadas  por  nuevas  líneas.  Aquí  está
cómo  se  ve  el  resultado:

Aunque  el  resultado  aparece  en  52  líneas,  es  una  cadena  larga  que  contiene  saltos  de  línea.

18.6  Añadir,  eliminar,  barajar  y  ordenar
Para  repartir  cartas,  nos  gustaría  un  método  que  retire  una  carta  de  la  baraja  y  la  devuelva.
El  método  de  lista  proporciona  una  manera  conveniente  de  hacerlo:

Dado  que  elimina  la  última  carta  de  la  lista,  estamos  repartiendo  desde  la  parte  inferior  de  la  baraja.

Para  agregar  una  tarjeta,  podemos  usar  el  método  de  lista :

Un  método  como  este  que  usa  otro  método  sin  hacer  mucho  trabajo  a  veces  se  llama  revestimiento.  La  metáfora  
proviene  de  la  carpintería,  donde  una  chapa  es  una  capa  delgada  de  madera  de  buena  calidad  pegada  a  la  superficie  
de  una  pieza  de  madera  más  barata  para  mejorar  la  apariencia.

En  este  caso  es  un  método  “delgado”  que  expresa  una  operación  de  lista  en  términos  apropiados  para  mazos.  Mejora  
la  apariencia,  o  interfaz,  de  la  implementación.

Como  otro  ejemplo,  podemos  escribir  un  método  Deck  nombrado  desde  el   usando  la  función
módulo:
Machine Translated by Google

176 Capítulo  18.  Herencia

No  olvides  importar .

Como  ejercicio,  escribe  un  método  de  Deck   que  utiliza  el  método  de  lista ordenar  el


llamado  cards  en  .un  usa  el método  que  definimos  para  determinar  el  orden.

18.7  Herencia
La  herencia  es  la  capacidad  de  definir  una  nueva  clase  que  es  una  versión  modificada  de  una  clase  existente.
Como  ejemplo,  digamos  que  queremos  que  una  clase  represente  una  “mano”,  es  decir,  las  cartas  que  
tiene  un  jugador.  Una  mano  es  similar  a  una  baraja:  ambas  se  componen  de  una  colección  de  cartas  y  
ambas  requieren  operaciones  como  agregar  y  quitar  cartas.

Una  mano  también  es  diferente  de  una  baraja;  hay  operaciones  que  queremos  para  manos  que  no  tienen  sentido  
para  una  baraja.  Por  ejemplo,  en  el  póquer  podemos  comparar  dos  manos  para  ver  cuál  gana.  En  el  bridge,  
podríamos  calcular  el  puntaje  de  una  mano  para  hacer  una  oferta.

Esta  relación  entre  clases  —similares,  pero  diferentes—  se  presta  a  la  herencia.  Para  definir  una  nueva  clase  que  
herede  de  una  clase  existente,  coloque  el  nombre  de  la  clase  existente  entre  paréntesis:

Esta  definición  indica  que  y hereda  de   ;  eso  significa  que  podemos  usar  métodos  como


Manos  y  Barajas.

Cuando  una  nueva  clase  hereda  de  una  existente,  la  existente  se  llama  padre  y  la  nueva  clase  se  llama  hijo.

,
En  este  ejemplo,  hereda  de  pero  en  realidad  no  hace  lo  que  queremos:  
en  lugar  de  llenar  la  mano  con  52  cartas  
nuevas,  el  método  init  para  Hands  debería  inicializarse  con  una  lista  vacía.

Si  proporcionamos  un  método  init  en  el clase,  anula  la  de  la  clase clase:

Cuando  crea  una  mano,  Python  invoca  este  método  init,  no  el  que  está  en .

Los  otros  métodos  se  heredan  de  una  tarjeta: , para  que  podamos  usar y tratar


Machine Translated by Google

18.8.  diagramas  de  clase 177

Un  próximo  paso  natural  es  encapsular  este  código  en  un  método  llamado :

toma  dos  argumentos,  un  objeto  Mano  y  el  número  de  cartas  a  repartir.  Se  modifica
cumple  con  ambos y , y  regresa .

En  algunos  juegos,  las  cartas  se  mueven  de  una  mano  a  otra,  o  de  una  mano  al  mazo.  Puedes  
usar  para  cualquiera  de  estas  operaciones:  puede  ser  un  Deck  o  una  Mano,  y ,  a  pesar  del  
nombre,  también  puede  ser  un .

La  herencia  es  una  característica  útil.  Algunos  programas  que  serían  repetitivos  sin  la  herencia  se  
pueden  escribir  de  manera  más  elegante  con  ella.  La  herencia  puede  facilitar  la  reutilización  del  
código,  ya  que  puede  personalizar  el  comportamiento  de  las  clases  principales  sin  tener  que  
modificarlas.  En  algunos  casos,  la  estructura  de  herencia  refleja  la  estructura  natural  del  problema,  
lo  que  facilita  la  comprensión  del  diseño.

Por  otro  lado,  la  herencia  puede  dificultar  la  lectura  de  los  programas.  Cuando  se  invoca  un  
método,  a  veces  no  está  claro  dónde  encontrar  su  definición.  El  código  relevante  puede  
distribuirse  en  varios  módulos.  Además,  muchas  de  las  cosas  que  se  pueden  hacer  usando  
la  herencia  se  pueden  hacer  igual  o  mejor  sin  ella.

18.8  Diagramas  de  clases

Hasta  ahora  hemos  visto  diagramas  de  pila,  que  muestran  el  estado  de  un  programa,  y  diagramas  de  
objetos,  que  muestran  los  atributos  de  un  objeto  y  sus  valores.  Estos  diagramas  representan  una  
instantánea  de  la  ejecución  de  un  programa,  por  lo  que  cambian  a  medida  que  se  ejecuta  el  programa.

También  son  muy  detallados;  para  algunos  propósitos,  demasiado  detallada.  Un  diagrama  de  
clases  es  una  representación  más  abstracta  de  la  estructura  de  un  programa.  En  lugar  de  
mostrar  objetos  individuales,  muestra  clases  y  las  relaciones  entre  ellos.

Hay  varios  tipos  de  relaciones  entre  clases:

•  Los  objetos  de  una  clase  pueden  contener  referencias  a  objetos  de  otra  clase.  Por  ejemplo,  
cada  Rectángulo  contiene  una  referencia  a  un  Punto  y  cada  Mazo  contiene  referencias  a  
muchas  Cartas.  Este  tipo  de  relación  se  llama  HAS­A,  como  en  "un  rectángulo  tiene  un  
punto".

•  Una  clase  puede  heredar  de  otra.  Esta  relación  se  llama  IS­A,  como  en  "una  mano  es  
una  especie  de  mazo".

•  Una  clase  puede  depender  de  otra  en  el  sentido  de  que  los  objetos  de  una  clase  toman  
objetos  de  la  segunda  clase  como  parámetros,  o  usan  objetos  de  la  segunda  clase  
como  parte  de  un  cálculo.  Este  tipo  de  relación  se  llama  dependencia.

Un  diagrama  de  clases  es  una  representación  gráfica  de  estas  relaciones.  Por  ejemplo,  
la  figura  18.2  muestra  las  relaciones  entre , y .
Machine Translated by Google

178 Capítulo  18.  Herencia

Cubierta
* Tarjeta

Mano

Figura  18.2:  Diagrama  de  clases.

La  flecha  con  cabeza  triangular  hueca  representa  una  relación  IS­A;  en  este  caso  indica  que  Hand  
hereda  de  Deck.

La  punta  de  flecha  estándar  representa  una  relación  HAS­A;  en  este  caso,  una  baraja  tiene  
referencias  a  objetos  de  cartas.

La  estrella  ()  cerca  de  la  punta  de  la  flecha  es  una  multiplicidad;  indica  cuántas  Cartas  tiene  un  Deck.
Una  multiplicidad  puede  ser  un  simple  número,  como  o  u,na  
erstrella,  
un   ango,  clomo
o  que  indica  que  un  Deck  puede  tener  
cualquier  número  de  Cartas.

No  hay  dependencias  en  este  diagrama.  Normalmente  se  mostrarían  con  una  flecha  discontinua.  O  
si  hay  muchas  dependencias,  a  veces  se  omiten.

Un  diagrama  más  detallado  podría  mostrar  que  un  Deck  en  realidad  contiene  una  lista  de  Cartas,  pero  los  
tipos  incorporados  como  list  y  dict  generalmente  no  se  incluyen  en  los  diagramas  de  clase.

18.9  Depuración
La  herencia  puede  dificultar  la  depuración  porque  cuando  invoca  un  método  en  un  objeto,  puede  ser  
difícil  determinar  qué  método  se  invocará.

Suponga  que  está  escribiendo  una  función  que  funciona  con  objetos  de  mano.  Le  gustaría  que  
funcionara  con  todo  tipo  de  manos,  como  PokerHands,  BridgeHands,  etc.  Si  invoca  un  método  
como ,  puede  obtener  el  definido  en  pero  si  alguna  de  las  s,ubclases  anula  este  método,  obtendrá  
esa  versión  en  su  lugar. .  Este  comportamiento  suele  ser  bueno,  pero  puede  ser  confuso.

Cada  vez  que  no  esté  seguro  del  flujo  de  ejecución  a  través  de  su  programa,  la  solución  más  simple  
es  agregar  sentencias  de  impresión  al  comienzo  de  los  métodos  relevantes.  Si  imprime  un  mensaje  
que  dice  algo  como  entonces,  mientras  se  ejecuta  el  programa,  rastrea  el  f,lujo  de  
ejecución.

Como  alternativa,  podría  usar  esta  función,  que  toma  un  objeto  y  un  nombre  de  método  (como  una  
cadena)  y  devuelve  la  clase  que  proporciona  la  definición  del  método:

Aquí  hay  un  ejemplo:
Machine Translated by Google

18.10.  Encapsulación  de  datos 179

Entonces  el método  para  esta  Mano  es  el  que  está  en .

utiliza  el  método  para  obtener  la  lista  de  objetos  de  clase  (tipos)  en  los  que  
se  buscarán  métodos.  "MRO"  significa  "orden  de  resolución  de  métodos",  que  es  la  secuencia  de  
clases  que  Python  busca  para  "resolver"  el  nombre  de  un  método.

Aquí  hay  una  sugerencia  de  diseño:  cuando  reemplaza  un  método,  la  interfaz  del  nuevo  método  debe  
ser  la  misma  que  la  anterior.  Debe  tomar  los  mismos  parámetros,  devolver  el  mismo  tipo  y  obedecer  
las  mismas  condiciones  previas  y  posteriores.  Si  sigue  esta  regla,  encontrará  que  cualquier  función  
diseñada  para  funcionar  con  una  instancia  de  una  clase  principal,  como  una  baraja,  también  funcionará  
con  instancias  de  clases  secundarias  como  una  mano  y  una  mano  de  póquer.

Si  viola  esta  regla,  que  se  llama  el  "principio  de  sustitución  de  Liskov",  su  código  colapsará  como  (lo  
siento)  un  castillo  de  naipes.

18.10  Encapsulación  de  datos
Los  capítulos  anteriores  demuestran  un  plan  de  desarrollo  que  podríamos  llamar  "diseño  orientado  a  
objetos".  Identificamos  los  objetos  que  necesitábamos,   , y  —y  definido
como  clases  para  representarlos.  En  cada  caso  hay  una  correspondencia  obvia  entre  el  objeto  y  
alguna  entidad  en  el  mundo  real  (o  al  menos  un  mundo  matemático).

Pero  a  veces  es  menos  obvio  qué  objetos  necesita  y  cómo  deben  interactuar.  En  ese  caso  se  necesita  
un  plan  de  desarrollo  diferente.  De  la  misma  manera  que  descubrimos  las  interfaces  de  función  por  
encapsulación  y  generalización,  podemos  descubrir  las  interfaces  de  clase  por  encapsulación  de  datos.

El  análisis  de  Markov,  de  la  Sección  13.8,  proporciona  un  buen  ejemplo.  Si  descarga  mi  código  de ,  
verá  que  utiliza  dos  variables  globales,  que  se  leen  y  escriben  desde  varias  funciones.
y

Debido  a  que  estas  variables  son  globales,  solo  podemos  ejecutar  un  análisis  a  la  vez.  Si  leemos  
dos  textos,  sus  prefijos  y  sufijos  se  agregarían  a  las  mismas  estructuras  de  datos  (lo  que  hace  
que  el  texto  generado  sea  interesante).

Para  ejecutar  varios  análisis  y  mantenerlos  separados,  podemos  encapsular  el  estado  de  cada  análisis  
en  un  objeto.  Esto  es  lo  que  parece:

A  continuación,  transformamos  las  funciones  en  métodos.  Por  ejemplo,  aquí  está :
Machine Translated by Google

180 Capítulo  18.  Herencia

Transformar  un  programa  como  este  (cambiar  el  diseño  sin  cambiar  el  comportamiento)  es  otro  ejemplo  de  
refactorización  (consulte  la  Sección  4.7).

Este  ejemplo  sugiere  un  plan  de  desarrollo  para  diseñar  objetos  y  métodos:

1.  Comience  escribiendo  funciones  que  lean  y  escriban  variables  globales  (cuando  sea  necesario).

2.  Una  vez  que  tenga  el  programa  funcionando,  busque  asociaciones  entre  variables  globales
y  las  funciones  que  los  utilizan.

3.  Encapsular  variables  relacionadas  como  atributos  de  un  objeto.

4.  Transformar  las  funciones  asociadas  en  métodos  de  la  nueva  clase.

Como  ejercicio,  descargue  mi  código  de  Markov  y  siga  los  pasos  
, descritos  anteriormente  para  encapsular  las  variables  globales.  Solución:
como  atributos  de  una  nueva  clase  llamada
.

18.11  Glosario
codificar:  para  representar  un  conjunto  de  valores  utilizando  otro  conjunto  de  valores  mediante  la  construcción  de  un  mapa
hacer  ping  entre  ellos.

atributo  de  clase:  Un  atributo  asociado  con  un  objeto  de  clase.  Los  atributos  de  clase  están  definidos
dentro  de  una  definición  de  clase  pero  fuera  de  cualquier  método.

atributo  de  instancia:  Un  atributo  asociado  con  una  instancia  de  una  clase.

barniz:  Un  método  o  función  que  proporciona  una  interfaz  diferente  a  otra  función  con
haciendo  muchos  cálculos.

herencia:  La  capacidad  de  definir  una  nueva  clase  que  es  una  versión  modificada  de  una  previamente
clase  definida.

clase  principal:  la  clase  de  la  que  hereda  una  clase  secundaria.

clase  secundaria:  una  nueva  clase  creada  al  heredar  de  una  clase  existente;  también  llamado  "sub
clase".

Relación  IS­A:  una  relación  entre  una  clase  secundaria  y  su  clase  principal.

Relación  HAS­A:  Una  relación  entre  dos  clases  donde  las  instancias  de  una  clase  contienen  referencias  a  
instancias  de  la  otra.

dependencia:  una  relación  entre  dos  clases  donde  las  instancias  de  una  clase  se  usan  en  instancias  de  la  otra  
clase,  pero  no  las  almacenan  como  atributos.
Machine Translated by Google

18.12.  Ejercicios 181

diagrama  de  clases:  un  diagrama  que  muestra  las  clases  en  un  programa  y  las  relaciones
entre  ellos.

multiplicidad:  una  notación  en  un  diagrama  de  clases  que  muestra,  para  una  relación  HAS­A,  cuántas  
referencias  hay  a  instancias  de  otra  clase.

encapsulación  de  datos:  un  plan  de  desarrollo  de  programa  que  implica  un  prototipo  que  utiliza  
variables  globales  y  una  versión  final  que  convierte  las  variables  globales  en  atributos  de  instancia.

18.12  Ejercicios

Ejercicio  18.1.  Para  el  siguiente  programa,  dibuje  un  diagrama  de  clases  UML  que  muestre  estas  
clases  y  las  relaciones  entre  ellas.

Ejercicio  18.2.  Escribe  un  método  Deck  llamado  que  tome  dos  parámetros,  el  número  de  manos  y  el  
número  de  cartas  por  mano.  Debe  crear  la  cantidad  adecuada  de  objetos  Mano,  repartir  la  cantidad  
adecuada  de  cartas  por  mano  y  devolver  una  lista  de  Manos.
Ejercicio  18.3.  Las  siguientes  son  las  manos  posibles  en  el  póquer,  en  orden  creciente  de  valor  y  
orden  decreciente  de  probabilidad:

pareja:  dos  cartas  del  mismo  valor  
dos  parejas:  dos  parejas  de  cartas  del  mismo  valor
trío:  tres  cartas  del  mismo  valor

escalera:  cinco  cartas  con  rangos  en  secuencia  (los  ases  pueden  ser  altos  o  bajos,  por  lo  que es  un  recto
y  tambien , pero no  es.)

color:  cinco  cartas  del  mismo  palo  
full  house:  tres  cartas  con  un  rango,  dos  cartas  con  otro
Machine Translated by Google

182 Capítulo  18.  Herencia

póquer:  cuatro  cartas  del  mismo  valor  escalera  
de  color:  cinco  cartas  en  secuencia  (como  se  definió  anteriormente)  y  del  mismo  palo

El  objetivo  de  estos  ejercicios  es  estimar  la  probabilidad  de  dibujar  estas  distintas  manos.

1.  Descargue  los  siguientes  archivos  de:   :

Una  versión  completa  de:   , y clases  de  este  capítulo.
Una  implementación  incompleta  de  una  clase  que  representa  una  mano  de  póquer  
y  algún  código  que  la  prueba.

, de  póquer  de  7  cartas  y  verifica  si  alguna  de  ellas  contiene  color.  Lea  
2.  Si  lo  ejecuta,  reparte  siete  manos  
este  código  detenidamente  antes  de  continuar.

3.  Agregar  métodos  a llamado , , etc.  que  devuelven  


Verdadero  o  Falso  según  si  la  mano  cumple  o  no  con  los  criterios  pertinentes.  Tu  código  debería  
funcionar  correctamente  para  "manos"  que  contengan  cualquier  cantidad  de  cartas  (aunque  5  y  7  son  
los  tamaños  más  comunes).

4.  Escriba  un  método  denominado  que  determine  la  clasificación  de  mayor  valor  para  una  mano  y  establezca  el  
atributo  en  consecuencia.  Por  ejemplo,  una  mano  de  7  cartas  puede  contener  un  color  y  un  par;  debe  estar  
etiquetado  como  "al  ras".

5.  Cuando  esté  convencido  de  que  sus  métodos  de  clasificación  funcionan,  el  siguiente  paso  es  
estimar  las  probabilidades  de  las  distintas  manos.  Escriba  una  función  en  la  que  baraje  una  baraja  
de  cartas,  la  divida  en  manos,  clasifique  las  manos  y  cuente  el  número  de  veces  que  aparecen  
varias  clasificaciones.

6.  Imprime  una  tabla  de  las  clasificaciones  y  sus  probabilidades.  Ejecute  su  programa  con  un  número  
cada  vez  mayor  de  manos  hasta  que  los  valores  de  salida  converjan  en  un  grado  razonable  de  
precisión.  Compare  sus  resultados  con  los  valores  de
.

Solución: .
Machine Translated by Google

capitulo  19

las  golosinas

Uno  de  mis  objetivos  para  este  libro  ha  sido  enseñarle  lo  menos  posible  sobre  Python.  Cuando  había  
dos  formas  de  hacer  algo,  elegía  una  y  evitaba  mencionar  la  otra.  O  a  veces  pongo  el  segundo  en  un  
ejercicio.

Ahora  quiero  regresar  por  algunas  de  las  partes  buenas  que  quedaron  atrás.  Python  proporciona  una  
serie  de  características  que  no  son  realmente  necesarias  (puedes  escribir  buen  código  sin  ellas),  pero  
con  ellas  a  veces  puedes  escribir  código  que  es  más  conciso,  legible  o  eficiente,  y
a  veces  los  tres.

19.1  Expresiones  condicionales
Vimos  sentencias  condicionales  en  la  Sección  5.4.  Las  declaraciones  condicionales  se  utilizan  a  menudo  
para  elegir  uno  de  dos  valores;  Por  ejemplo:

Esta  sentencia  comprueba  si  es  positiva.  Si  es  así,  calcula  generaría  un   . Si  no,
ValueError.  Para  evitar  detener  el  programa,  generamos  un  "NaN",  que  es  un  valor  especial  de  punto  
flotante  que  representa  "No  es  un  número".

Podemos  escribir  esta  declaración  de  manera  más  concisa  usando  una  expresión  condicional:

Casi  puedes  leer  esta  línea  como  en  inglés:  "gets   obtiene  log­  si  es  mayor  que  0;  de  lo  contrario
NaN".

Las  funciones  recursivas  a  veces  se  pueden  reescribir  usando  expresiones  condicionales.  Por  ejemplo,  
aquí  hay  una  versión  recursiva  de :
Machine Translated by Google

184 Capítulo  19.  Las  golosinas

Podemos  reescribirlo  así:

Otro  uso  de  las  expresiones  condicionales  es  el  manejo  de  argumentos  opcionales.  Por  ejemplo,  aquí  está  el  método  
init  de (ver  Ejercicio  17.2):

Podemos  reescribir  este  así:

En  general,  puede  reemplazar  una  declaración  condicional  con  una  expresión  condicional  si  ambas  ramas  contienen  
expresiones  simples  que  se  devuelven  o  se  asignan  a  la  misma  variable.

19.2  Lista  de  comprensiones
En  la  Sección  10.7  vimos  el  mapa  y  los  patrones  de  filtro.  Por  ejemplo,  esta  función  toma  una  lista  de  cadenas,  asigna  
el  método  de  cadena  a  los  elementos  y  devuelve  una  nueva  lista  de  cadenas:

Podemos  escribir  esto  de  manera  más  concisa  usando  una  lista  de  comprensión:

Los  operadores  de  paréntesis  indican  que  estamos  construyendo  una  nueva  lista.  La  expresión  dentro  de  los  corchetes  
especifica  los  elementos  de  la  lista,  y  la  cláusula  indica  qué  secuencia  estamos  atravesando.

La  sintaxis  de  una  lista  por  comprensión  es  un  poco  incómoda  porque  la  variable  de  ciclo,  en  este  ejemplo,  aparece  
en  la  expresión  antes  de  que  lleguemos  a  la  definición.

Las  listas  de  comprensión  también  se  pueden  usar  para  filtrar.  Por  ejemplo,  esta  función  selecciona  solo  los  elementos  
que  están  en  mayúsculas  y  devuelve  una  nueva  lista:
Machine Translated by Google

19.3.  Generador  de  expresiones 185

Podemos  reescribirlo  usando  una  lista  por  comprensión.

Las  listas  de  comprensión  son  concisas  y  fáciles  de  leer,  al  menos  para  expresiones  simples.  Y  
suelen  ser  más  rápidos  que  el  equivalente  de  bucles,  a  veces  mucho  más  rápidos.  Entonces,  si  
estás  enojado  conmigo  por  no  mencionarlos  antes,  lo  entiendo.

Pero,  en  mi  defensa,  las  listas  por  comprensión  son  más  difíciles  de  depurar  porque  no  se  puede  
poner  una  declaración  de  impresión  dentro  del  bucle.  Le  sugiero  que  los  use  solo  si  el  cálculo  es  lo  
suficientemente  simple  como  para  hacerlo  bien  la  primera  vez.  Y  para  los  principiantes  eso  significa  nunca.

19.3  Expresiones  generadoras
Las  expresiones  generadoras  son  similares  a  las  listas  de  comprensión,  pero  con  paréntesis  en  lugar  
de  corchetes:

El  resultado  es  un  objeto  generador  que  sabe  cómo  iterar  a  través  de  una  secuencia  de  valores.  Pero  
a  diferencia  de  una  lista  de  comprensión,  no  calcula  todos  los  valores  a  la  vez;  espera  a  ser  preguntado.
La  función  incorporada  obtiene  el  siguiente  valor  del  generador:

Cuando  llega  al  final  de  la  secuencia,  genera  una  excepción  StopIteration.  También  puede  usar  un  
bucle  para  iterar  a  través  de  los  valores:

El  objeto  generador  realiza  un  seguimiento  de  dónde  se  encuentra  en  la  secuencia,   bucle  recoge
así  que  dónde  se  quedó.  Una  vez  que  el  generador  se  agota,  continúa  subiendo :

Las  expresiones  generadoras  se  usan  a  menudo  con  funciones  como , , y :

19.4 y
Python  proporciona  una  función  integrada,   , que  toma  una  secuencia  de  valores  booleanos  y  re .  
son  turnos si  alguno  de  los  valores   Funciona  en  listas:
Machine Translated by Google

186 Capítulo  19.  Las  golosinas

Pero  a  menudo  se  usa  con  expresiones  generadoras:

Ese  ejemplo  no  es  muy  útil  porque  hace  lo  mismo  que  el  operador.  Pero  podríamos  reescribir  algunas  de  
las  funciones  de  búsqueda  que  escribimos  en  la  Sección  9.3.  Por  ejemplo,  podríamos  escribir  así:

La  función  casi  se  lee  como  en  inglés,  "den   evita si  no  hay  ninguna  prohibir


letras  en".

Usar   con  una  expresión  generadora  es  eficiente  porque  se  detiene  inmediatamente  si  encuentra  un
valor,  por  lo  que  no  tiene  que  evaluar  toda  la  secuencia.

,la  secuencia  
Python  proporciona  otra  función  integrada,  que  devuelve   si  cada  elemento  de  la  
es .  Como  ejercicio,  utilice  para  reescribir Sección  9.3.

19,5  conjuntos

En  la  Sección  13.6  utilizo  diccionarios  para  encontrar  las  palabras  que  aparecen  en  un  documento  pero  no  
en  una  lista  de  palabras.  La  función  que  escribí  ,toma  la  que  contiene  las  palabras  del  documento  como  
, contiene  la  lista  de  palabras.  Devuelve  un  diccionario  que  contiene  las  claves  que  no  están  
claves  y  la  que  
en .

En  todos  estos  diccionarios,  los  valores  desperdician   porque  nunca  los  usamos.  Como  resultado,  nosotros
algo  de  espacio  de  almacenamiento.

,
Python  proporciona  otro  tipo  integrado,  llamado  a,  que  se  comporta   como  una  colección  de  claves  de  
diccionario  sin  valores.  Agregar  elementos  a  un  conjunto  es  rápido;  también  lo  es  verificar  la  membresía.
Y  los  conjuntos  proporcionan  métodos  y  operadores  para  calcular  operaciones  de  conjuntos  comunes.

Por  ejemplo,  la  resta  de  conjuntos  está  disponible  como  un  método  llamado .   o  como  operador,
Entonces  podemos  reescribir como  esto:

El  resultado  es  un  conjunto  en  lugar  de  un  diccionario,  pero  para  operaciones  como  la  iteración,  el  comportamiento  
es  el  mismo.

Algunos  de  los  ejercicios  de  este  libro  se  pueden  hacer  de  manera  concisa  y  eficiente  con  series.  Por  
ejemplo,  aquí  hay  una  solución  del  Ejercicio  10.7,  que  u,sa  un  diccionario:
Machine Translated by Google

19.6.  Contadores 187

Cuando  un  elemento  aparece  por  primera  vez,  se  agrega  al  diccionario.  Si  vuelve  a  aparecer  el  mismo  elemento,  la  
función  devuelve .

Usando  conjuntos,  podemos  escribir  la  misma  función  así:

Un  elemento  solo  puede  aparecer  una  vez  en  un  conjunto,  por  lo  que  si  un  elemento  aparece  más  de  una  vez,  el  
conjunto  será  más  pequeño  que . Si  no  hay  duplicados,  el  conjunto  tendrá  el  mismo  tamaño  que .

También  podemos  usar  conjuntos  para  hacer  algunos  de  los  ejercicios  del  Capítulo  9.  Por  ejemplo,  aquí  hay  una  
versión  con  un  bucle:

comprueba  si  todas  las  letras  en están  en .  Podemos  reescribirlo  así:

El  operador  verifica  si  un  conjunto  es  un  subconjunto  de  otro,  incluida  la  posibilidad  de  que  sean  iguales,  lo  cual  es  
cierto  si  todas  las  letras  en aparecer  en .

Como  ejercicio,  reescribe utilizando  conjuntos.

19.6  Contadores
Un  Contador  es  como  un  conjunto,  excepto  que  si  un  elemento  aparece  más  de  una  vez,  el  Contador  realiza  un  
seguimiento  de  cuántas  veces  aparece.  Si  está  familiarizado  con  la  idea  matemática  de  un  conjunto  múltiple,  un  
Contador  es  una  forma  natural  de  representar  un  conjunto  múltiple.

El  contador  se  define  en  un  módulo  estándar  llamado  puede   , así  que  tienes  que  importarlo.  Tú
inicializar  un  contador  con  una  cadena,  una  lista  o  cualquier  otra  cosa  que  admita  la  iteración:

Los  contadores  se  comportan  como  diccionarios  en  muchos  aspectos;  se  asignan  desde  cada  tecla  al  número  de  
veces  que  aparece.  Como  en  los  diccionarios,  las  claves  tienen  que  ser  hashable.

A  diferencia  de  los  diccionarios,  los  contadores  no  generan  una  excepción  si  accede  a  un  elemento  que  no  aparece.  
En  su  lugar,  devuelven  0:
Machine Translated by Google

188 Capítulo  19.  Las  golosinas

Podemos  usar  contadores  para  reescribir del  ejercicio  10.6:

Si  dos  palabras  son  anagramas,  contienen  las  mismas  letras  con  los  mismos  números,  por  lo  que  sus  
Contadores  son  equivalentes.

Los  contadores  proporcionan  métodos  y  operadores  para  realizar  operaciones  similares  a  conjuntos,  
incluidas  la  suma,  la  resta,  la  unión  y  la  intersección.  Y  proporcionan  un  método  a  menudo  útil,  que  
, devuelve  una  lista  de  pares  de  valor­frecuencia,  ordenados  del  más  común  al  más  común.
el  menos:

19.7  dictamen  predeterminado

El  módulo  también  proporciona  si  accede  a   , que  es  como  un  diccionario  excepto  que
una  clave  que  no  existe,  puede  generar  un  nuevo  valor  sobre  la  marcha.

Cuando  crea  un  dictado  predeterminado,  proporciona  una  función  que  se  usa  para  crear  nuevos  
valores.  Una  función  utilizada  para  crear  objetos  a  veces  se  denomina  fábrica.  Las  funciones  integradas  
que  crean  listas,  conjuntos  y  otros  tipos  se  pueden  usar  como  fábricas:

, cuál  es  un  objeto  de  clase,  no  
Tenga  en  cuenta  que  el  argumento  es   , que  es  una  nueva  lista.
La  función  que  proporciona  no  se  llama  a  menos  que  acceda  a  una  clave  que  no  existe.

La  nueva  lista,  a  la  que  llamamos ,  también  se  agrega  al  diccionario.  Entonces  si  modificamos,  
el  
cambio  aparece  en:

Si  está  haciendo  un  diccionario  de  listas,  a  menudo  puede  escribir  un  código  más   .
simple  usando  En  mi  solución  al  Ejercicio  12.2,  que  puede  
, obtener  de  Hago  un  diccionario  que  asigna  una  cadena  ordenada  de  letras  a  la  
palabras  que  se  pueden  escribir  con  esas  letras.  Por  ejemplo, lista  de  mapas  a  la  lista
.

Aquí  está  el  código  original:
Machine Translated by Google

19.8.  tuplas  con  nombre 189

Esto  se  puede  simplificar  usando , que  podría  haber  usado  en  el  ejercicio  11.2:

Esta  solución  tiene  el  inconveniente  de  que  crea  una  nueva  lista  cada  vez,  independientemente  de  si  es  
necesario.  Para  las  listas,  eso  no  es  gran  cosa,  pero  si  la  función  de  fábrica  es  complicada,  podría  serlo.

Podemos  evitar  este  problema  y  simplificar  el  código  usando  un :

Mi  solución  al  Ejercicio  18.3,  que  puedes  descargar  desde
, usos en  la  función .  esta  solución

ción  tiene  el  inconveniente  de  crear  una   objeto  cada  vez  que  pasa  por  el  bucle,  ya  sea
necesaria  o  no.  Como  ejercicio,  reescríbalo  usando  un  dictado  predeterminado.

19.8  Tuplas  con  nombre
Muchos  objetos  simples  son  básicamente  colecciones  de  valores  relacionados.  Por  ejemplo,  el  objeto  
Punto  definido  en  el  Capítulo  15  contiene  dos  números  y .  Cuando  define  una  clase  como  esta,  
generalmente  comienza  con  un  método  init  y  un  método  str:
Machine Translated by Google

190 Capítulo  19.  Las  golosinas

Esto  es  mucho  código  para  transmitir  una  pequeña  cantidad  de  información.  Python  proporciona  una  
forma  más  concisa  de  decir  lo  mismo:

El  primer  argumento  es  el  nombre  de  la  clase  que  desea  crear.  El  segundo  es  una  lista  de  los  atributos  
que  deben  tener  los  objetos  Point,  como  cadenas.  El  valor  de  retorno  de  es  un  objeto  de  clase:

proporciona  automáticamente  métodos   y para  que  no  tengas  que  hacerlo
como  escribirlos.

Para  crear  un  objeto  Point,  usa  la  clase  Point  como  una  función:

El  método  init  asigna  los  argumentos  a  los  atributos  usando  los  nombres  que  proporcionó.  El  método  str  
imprime  una  representación  del  objeto  Point  y  sus  atributos.

Puede  acceder  a  los  elementos  de  la  tupla  nombrada  por  su  nombre:

Pero  también  puede  tratar  una  tupla  con  nombre  como  una  tupla:

Las  tuplas  con  nombre  proporcionan  una  forma  rápida  de  definir  clases  simples.  El  inconveniente  es  que  
las  clases  simples  no  siempre  se  mantienen  simples.  Puede  decidir  más  tarde  que  desea  agregar  métodos  
a  una  tupla  con  nombre.  En  ese  caso,  podría  definir  una  nueva  clase  que  herede  de  la  tupla  nombrada:

O  podría  cambiar  a  una  definición  de  clase  convencional.

19.9  Recopilación  de  argumentos  de  palabras  clave

En  la  Sección  12.4,  vimos  cómo  escribir  una  función  que  reúne  sus  argumentos  en  una  tupla:

Puede  llamar  a  esta  función  con  cualquier  cantidad  de  argumentos  posicionales  (es  decir,  argumentos  que  
no  tienen  palabras  clave):
Machine Translated by Google

19.10.  Glosario 191

Pero  el  operador  no  recopila  argumentos  de  palabras  clave:

Para  recopilar  argumentos  de  palabras  clave,  puede  usar  el  operador:

Puede  llamar  al  parámetro  de  recopilación  de  palabras  clave  como  desee,  pero   es  un  común
elija.  El  resultado  es  un  diccionario  que  mapea  de  palabras  clave  a  valores:

Si  tiene  un  diccionario  de  palabras  clave  y  valores,  puede  usar  el  operador  de  dispersión,  llamar  a   a
una  función:

Sin  el  operador  de  dispersión,  la  función  se  trataría  como  un  solo  argumento  posicional,  por  lo  que  se  
asignaría  y  se  quejaría  porque  no  hay  nada  que  asignar:

Cuando  trabaja  con  funciones  que  tienen  una  gran  cantidad  de  parámetros,  a  menudo  es  útil  crear  y  pasar  
diccionarios  que  especifiquen  las  opciones  de  uso  frecuente.

19.10  Glosario
expresión  condicional:  Una  expresión  que  tiene  uno  de  dos  valores,  dependiendo  de  una  condición
ción

comprensión  de  lista:  Una  expresión  con  un bucle  entre  corchetes  que  produce  un  nuevo
lista.

expresión  generador:  Una  expresión  con  un  objeto   bucle  entre  paréntesis  que  produce  un  género
tor.

multiconjunto:  Una  entidad  matemática  que  representa  un  mapeo  entre  los  elementos  de  un  conjunto
y  el  número  de  veces  que  aparecen.

fábrica:  una  función,  generalmente  pasada  como  parámetro,  utilizada  para  crear  objetos.
Machine Translated by Google

192 Capítulo  19.  Las  golosinas

19.11  Ejercicios

Ejercicio  19.1.  La  siguiente  es  una  función  que  calcula  recursivamente  el  coeficiente  binomial.

Vuelva  a  escribir  el  cuerpo  de  la  función  usando  expresiones  condicionales  anidadas.

Una  nota:  esta  función  no  es  muy  eficiente  porque  termina  calculando  los  mismos  valores  una  y  otra  vez.  Puede  hacerlo  
más  eficiente  memorizando  (consulte  la  Sección  11.6).  Pero  encontrará  que  es  más  difícil  de  memorizar  si  lo  escribe  
usando  expresiones  condicionales.
Machine Translated by Google

Apéndice  A

depuración

Cuando  esté  depurando,  debe  distinguir  entre  diferentes  tipos  de  errores  para  localizarlos  más  
rápidamente:

•  El  intérprete  descubre  los  errores  de  sintaxis  cuando  está  traduciendo  el  código  fuente  a  
código  de  bytes.  Indican  que  hay  algo  mal  con  la  estructura  del  programa.  Ejemplo:  Omitir  
los  dos  puntos  al  final  de  una  instrucción  genera  un  mensaje  algo  redundante
.

•  El  intérprete  produce  errores  de  tiempo  de  ejecución  si  algo  sale  mal  mientras  se  ejecuta  el  
programa.  La  mayoría  de  los  mensajes  de  error  de  tiempo  de  ejecución  incluyen  información  
sobre  dónde  ocurrió  el  error  y  qué  funciones  se  estaban  ejecutando.  Ejemplo:  una  recursión  
infinita  eventualmente  provoca  el  error  de  tiempo  de  ejecución  "profundidad  máxima  de  recursión  excedida".

•  Los  errores  semánticos  son  problemas  con  un  programa  que  se  ejecuta  sin  generar  
mensajes  de  error  pero  no  hace  lo  correcto.  Ejemplo:  es  posible  que  una  expresión  no  se  
evalúe  en  el  orden  esperado  y  produzca  un  resultado  incorrecto.

El  primer  paso  en  la  depuración  es  averiguar  con  qué  tipo  de  error  está  lidiando.  Aunque  las  
siguientes  secciones  están  organizadas  por  tipo  de  error,  algunas  técnicas  son  aplicables  en  más  
de  una  situación.

A.1  Errores  de  sintaxis

Los  errores  de  sintaxis  generalmente  son  fáciles  de  corregir  una  vez  que  descubre  cuáles  son.  
Desafortunadamente,  los  mensajes  de  error  a  menudo  no  son  útiles.  Los  mensajes  más  
, informativo.
comunes  son  y  ninguno  de  los  cuales  es  muy  
tivo

Por  otro  lado,  el  mensaje  le  dice  en  qué  parte  del  programa  ocurrió  el  problema.
En  realidad,  le  dice  dónde  Python  notó  un  problema,  que  no  es  necesariamente  donde  está  el  
error.  A  veces,  el  error  es  anterior  a  la  ubicación  del  mensaje  de  error,  a  menudo  en  la  línea  
anterior.
Machine Translated by Google

194 Apéndice  A.  Depuración

Si  está  construyendo  el  programa  de  forma  incremental,  debe  tener  una  buena  idea  de  dónde  está  
el  error.  Estará  en  la  última  línea  que  agregó.

Si  está  copiando  el  código  de  un  libro,  comience  por  comparar  su  código  con  el  código  del  libro  
con  mucho  cuidado.  Revisa  cada  personaje.  Al  mismo  tiempo,  recuerda  que  el  libro  puede  estar  
equivocado,  por  lo  que  si  ves  algo  que  parece  un  error  de  sintaxis,  podría  serlo.

Aquí  hay  algunas  formas  de  evitar  los  errores  de  sintaxis  más  comunes:

1.  Asegúrese  de  no  utilizar  una  palabra  clave  de  Python  para  un  nombre  de  variable.

2.  Verifique  que  tiene  dos  puntos  al  final  del  encabezado  de  cada  declaración  compuesta,
incluido , , ,y declaraciones.

3.  Asegúrese  de  que  todas  las  cadenas  del  código  tengan  comillas  coincidentes.  Cerciorarse
que  todas  las  comillas  son  "comillas  rectas",  no  "comillas  curvas".

4.  Si  tiene  cadenas  de  varias  líneas  con  comillas  triples  (simples  o  dobles),  asegúrese  de  haber  
terminado  la  cadena  correctamente.  Una  cadena  sin  terminar  puede  causar  una
error  al  final  de  su  programa,  o  puede  tratar  la  siguiente  parte  del  programa  como  
una  cadena  hasta  que  llegue  a  la  siguiente  cadena.  En  el  segundo  caso,  ¡es  posible  que  no  
produzca  ningún  mensaje  de  error!

5.  Un  operador  de  apertura  no  cerrado—,  o  —hace  que  Python  continúe  con  la  siguiente  línea  
como  parte  de  la  instrucción  actual.  Generalmente,  un  error  ocurre  casi  inmediatamente  en  el
Proxima  linea.

6.  Verifique  el  clásico  en  lugar  de  dentro  de  un  condicional.

7.  Verifique  la  sangría  para  asegurarse  de  que  se  alinee  de  la  forma  en  que  se  supone  que  debe  
hacerlo.  Python  puede  manejar  el  espacio  y  las  pestañas,  pero  si  los  mezcla  puede  causar  
problemas.  La  mejor  manera  de  evitar  este  problema  es  usar  un  editor  de  texto  que  conozca  
Python  y  genere  una  sangría  consistente.

8.  Si  tiene  caracteres  que  no  son  ASCII  en  el  código  (incluidas  cadenas  y  comentarios),  eso  
podría  causar  un  problema,  aunque  Python  3  generalmente  maneja  caracteres  que  no  son  
ASCII.  Tenga  cuidado  si  pega  texto  de  una  página  web  u  otra  fuente.

Si  nada  funciona,  pase  a  la  siguiente  sección...

A.1.1  Sigo  haciendo  cambios  y  no  hace  ninguna  diferencia.
Si  el  intérprete  dice  que  hay  un  error  y  usted  no  lo  ve,  puede  deberse  a  que  usted  y  el  intérprete  no  
están  mirando  el  mismo  código.  Verifique  su  entorno  de  programación  para  asegurarse  de  que  el  
programa  que  está  editando  es  el  que  Python  está  tratando  de  ejecutar.

Si  no  está  seguro,  intente  poner  un  error  de  sintaxis  obvio  y  deliberado  al  comienzo  del  programa.  
Ahora  ejecútalo  de  nuevo.  Si  el  intérprete  no  encuentra  el  nuevo  error,  no  está  ejecutando  el  nuevo  
código.

Hay  algunos  posibles  culpables:

•  Editó  el  archivo  y  olvidó  guardar  los  cambios  antes  de  volver  a  ejecutarlo.  Alguno
los  entornos  de  programación  hacen  esto  por  usted,  pero  algunos  no  lo  hacen.
Machine Translated by Google

A.2.  Errores  de  tiempo  de  ejecución 195

•  Cambió  el  nombre  del  archivo,  pero  todavía  está  ejecutando  el  nombre  antiguo.

•  Algo  en  su  entorno  de  desarrollo  está  configurado  incorrectamente.  •  Si  está  escribiendo  

, el  mismo  nombre  que  uno  de  los  módulos  
un  módulo  y  usándolo,  asegúrese  de  no  darle  a  su  módulo  
estándar  de  Python.

•  Si  está  utilizando  un   para  leer  un  módulo,  recuerda  que  tienes  que  reiniciar  el  para  leer  un  
intérprete  o  el  uso  no   archivo  modificado.  Si  vuelve  a  importar  el  módulo,
hace  nada.

Si  te  quedas  atascado  y  no  puedes  entender  lo  que  está  pasando,  un  enfoque  es  comenzar  de  nuevo  con  un  
nuevo  programa  como  “¡Hola,  mundo!”,  y  asegurarte  de  que  puedas  ejecutar  un  programa  conocido.  Luego  
agregue  gradualmente  las  piezas  del  programa  original  al  nuevo.

A.2  Errores  de  tiempo  de  ejecución

Una  vez  que  su  programa  es  sintácticamente  correcto,  Python  puede  leerlo  y  al  menos  comenzar  a  ejecutarlo.
¿Qué  podría  salir  mal?

A.2.1  Mi  programa  no  hace  absolutamente  nada.
Este  problema  es  más  común  cuando  su  archivo  consta  de  funciones  y  clases,  pero  en  realidad  no  invoca  
una  función  para  iniciar  la  ejecución.  Esto  puede  ser  intencional  si  solo  planea  importar  este  módulo  para  
proporcionar  clases  y  funciones.

Si  no  es  intencional,  asegúrese  de  que  haya  una  llamada  de  función  en  el  programa  y  asegúrese  de  que  el  
flujo  de  ejecución  lo  alcance  (consulte  "Flujo  de  ejecución"  a  continuación).

A.2.2  Mi  programa  se  cuelga.
Si  un  programa  se  detiene  y  parece  no  hacer  nada,  está  "colgado".  A  menudo,  eso  significa  que  está  atrapado  
en  un  bucle  infinito  o  recursión  infinita.

•  Si  hay  un  bucle  en  particular  que  sospecha  que  es  el  problema,  agregue  un declaración
inmediatamente  antes  del  bucle  que  dice  "entrar  en  el  bucle"  y  otro  inmediatamente  después  que  dice  
"salir  del  bucle".
Ejecuta  el  programa.  Si  recibe  el  primer  mensaje  y  no  el  segundo,  tiene  un  bucle  infinito.  Vaya  a  la  
sección  "Bucle  infinito"  a  continuación.

•  La  mayoría  de  las  veces,  una  recursión  infinita  hará  que  el  programa  se  ejecute  durante  un  tiempo  y  
luego  produzca  un  error  de  "RuntimeError:  se  excedió  la  profundidad  de  recursión  máxima".  Si  eso  
sucede,  vaya  a  la  sección  "Recursión  infinita"  a  continuación.
Si  no  recibe  este  error  pero  sospecha  que  hay  un  problema  con  un  método  o  una  función  recursiva,  
aún  puede  usar  las  técnicas  en  la  sección  "Recursión  infinita".

•  Si  ninguno  de  esos  pasos  funciona,  comience  a  probar  otros  bucles  y  otras  funciones  recursivas
y  métodos.

•  Si  eso  no  funciona,  es  posible  que  no  comprenda  el  flujo  de  ejecución.
ción  en  su  programa.  Vaya  a  la  sección  "Flujo  de  ejecución"  a  continuación.
Machine Translated by Google

196 Apéndice  A.  Depuración

Bucle  infinito

Si  cree  que  tiene  un  ciclo  infinito  y  sabe  qué  ciclo  está  causando  el  problema,  agregue  una  declaración  
al  final  del  ciclo  que  imprima  los  valores  de  las  variables  en  la  condición  y  el  valor  de  la  condición.

Por  ejemplo:

Ahora,  cuando  ejecute  el  programa,  verá  tres  líneas  de  salida  por  cada  tiempo  a  través  del  bucle.  La  
.ver  los  valores  de  y  
última  vez  que  pasó  por  el  ciclo,  la  condición  debería  ser  Si  el  ciclo  continúa,  podrá  
y  podría  descubrir  por  qué  no  se  actualizan  correctamente.,

recursividad  infinita

La  mayoría  de  las  veces,  la  recursividad  infinita  hace  que  el  programa  se  ejecute  durante  un  tiempo  y  luego  produzca
a error.

Si  sospecha  que  una  función  está  causando  una  recursividad  infinita,  asegúrese  de  que  haya  un  caso  
base.  Debe  haber  alguna  condición  que  haga  que  la  función  regrese  sin  hacer  una  invocación  recursiva.  
De  lo  contrario,  debe  repensar  el  algoritmo  e  identificar  un  caso  base.

Si  hay  un  caso  base  pero  el  programa  no  parece  alcanzarlo,  agregue  un  ment  al   estado

comienzo  de  la  función  que  imprime  los  parámetros.  Ahora,  cuando  ejecute  el  programa,  verá  algunas  
líneas  de  salida  cada  vez  que  se  invoque  la  función  y  verá  los  valores  de  los  parámetros.  Si  los  
parámetros  no  se  están  moviendo  hacia  el  caso  base,  obtendrá  algunas  ideas  sobre  por  qué  no.

Flujo  de  ejecución

Si  no  está  seguro  de  cómo  se  mueve  el  flujo  de  ejecución  a  través  de  su  programa,  agregue  
declaraciones  al  principio  de  cada  función  con  un  mensaje  como  “entrar  en  función  donde  está   ”,
el  nombre  de  la  función.

Ahora,  cuando  ejecute  el  programa,  imprimirá  un  rastro  de  cada  función  a  medida  que  se  invoque.

A.2.3  Cuando  ejecuto  el  programa  obtengo  una  excepción.

Si  algo  sale  mal  durante  el  tiempo  de  ejecución,  Python  imprime  un  mensaje  que  incluye  el  nombre  de  
la  excepción,  la  línea  del  programa  donde  ocurrió  el  problema  y  un  rastreo.

El  rastreo  identifica  la  función  que  se  está  ejecutando  actualmente,  y  luego  la  función  que  la  llamó,  y  
luego  la  función  que  la  llamó,  y  así  sucesivamente.  En  otras  palabras,  rastrea  la
Machine Translated by Google

A.2.  Errores  de  tiempo  de  ejecución 197

secuencia  de  llamadas  de  función  que  lo  llevaron  a  donde  está,  incluido  el  número  de  línea  en  su  
archivo  donde  ocurrió  cada  llamada.

El  primer  paso  es  examinar  el  lugar  del  programa  donde  ocurrió  el  error  y  ver  si  puede  averiguar  qué  
sucedió.  Estos  son  algunos  de  los  errores  de  tiempo  de  ejecución  más  comunes:

NameError:  está  intentando  utilizar  una  variable  que  no  existe  en  el  entorno  actual.
Compruebe  si  el  nombre  está  escrito  correctamente,  o  al  menos  de  forma  coherente.  Y  recuerda  que  las  
variables  locales  son  locales;  no  puede  hacer  referencia  a  ellos  desde  fuera  de  la  función  en  la  que  están  
definidos.

TypeError:  Hay  varias  causas  posibles:
•  Está  tratando  de  usar  un  valor  incorrectamente.  Ejemplo:  indexar  una  cadena,  lista  o
tupla  con  algo  que  no  sea  un  número  entero.
•  Hay  una  discrepancia  entre  los  elementos  de  una  cadena  de  formato  y  los  elementos  
pasados  para  la  conversión.  Esto  puede  suceder  si  la  cantidad  de  elementos  no  coincide  o  
si  se  solicita  una  conversión  no  válida.

•  Está  pasando  el  número  incorrecto  de  argumentos  a  una  función.  Para  los  métodos,  mire  la  
definición  del  método  y  verifique  que  el  primer  parámetro  sea .  Luego  mira  la  invocación  del  
método;  asegúrese  de  invocar  el  método  en  un  objeto  con  el  tipo  correcto  y  proporcionar  
los  otros  argumentos  correctamente.

KeyError:  Está  intentando  acceder  a  un  elemento  de  un  diccionario  utilizando  una  clave  que  no  contiene  
el  diccionario.  Si  las  claves  son  cadenas,  recuerde  que  las  mayúsculas  son  importantes.

AttributeError:  Está  intentando  acceder  a  un  atributo  o  método  que  no  existe.  Marque  para  enumerar  los  
¡la  ortografía!  Puede  usar  la  función  incorporada  Si   atributos  que  existen.

un  AttributeError  indica  que  un  objeto  tiene  Entonces,   , eso  quiere  decir  que  es .
el  problema  no  es  el  nombre  del  atributo,  sino  el  objeto.
La  razón  por  la  que  el  objeto  es  none  podría  ser  que  se  olvidó  de  devolver  un  valor  de  una  
función;  si  llega  al  final  de  una  función  sin  presionar  una  declaración,  devuelve .  Otra  causa  
común  es  usar  el  resultado  de  un  método  de  lista,  como  ese ,
devoluciones .

IndexError:  el  índice  que  está  utilizando  para  acceder  a  una  lista,  cadena  o  tupla  es  mayor  que  su  
longitud  menos  uno.  Inmediatamente  antes  del  sitio  del  error,  agregue  una   declaración  a
pantalla  con  el  valor  del  índice  y  la  longitud  de  la  matriz.  ¿La  matriz  es  del  tamaño  correcto?
¿Es  el  índice  el  valor  correcto?

El  depurador  de  Python  ()  es  útil  para  rastrear  excepciones  porque  le  permite  examinar  el  estado  del  
programa  inmediatamente  antes  del  error.  Puedes  leer  sobre en
.

A.2.4  Agregué  tantos declaraciones  me  inundan  con  la  salida.
Uno  de  los  problemas  con  el  uso  de  declaraciones  para  la  depuración  es  que  puede  terminar  enterrado  
en  la  salida.  Hay  dos  formas  de  proceder:  simplificar  la  salida  o  simplificar  el  programa.
Machine Translated by Google

198 Apéndice  A.  Depuración

Para  simplificar  la  salida,  puede  eliminar  o  comentar,  combinarlos  o   declaraciones  que  no  son  de  ayuda
formatear  la  salida  para  que  sea  más  fácil  de  entender.

Para  simplificar  el  programa,  hay  varias  cosas  que  puede  hacer.  Primero,  reduzca  el  problema  en  el  que  está  
trabajando  el  programa.  Por  ejemplo,  si  está  buscando  en  una  lista,  busque  en  una  lista  pequeña.  Si  el  programa  
toma  información  del  usuario,  déle  la  entrada  más  simple  que  cause  el  problema.

En  segundo  lugar,  limpie  el  programa.  Elimine  el  código  muerto  y  reorganice  el  programa  para  que  sea  lo  más  fácil  
de  leer  posible.  Por  ejemplo,  si  sospecha  que  el  problema  está  en  una  parte  profundamente  anidada  del  programa,  
intente  volver  a  escribir  esa  parte  con  una  estructura  más  simple.  Si  sospecha  de  una  función  grande,  intente  dividirla  
en  funciones  más  pequeñas  y  pruébelas  por  separado.

A  menudo,  el  proceso  de  encontrar  el  caso  de  prueba  mínimo  lo  lleva  al  error.  Si  encuentra  que  un  programa  
funciona  en  una  situación  pero  no  en  otra,  eso  le  da  una  pista  sobre  lo  que  está  pasando.

De  manera  similar,  reescribir  un  fragmento  de  código  puede  ayudarlo  a  encontrar  errores  sutiles.  Si  realiza  un  
cambio  que  cree  que  no  debería  afectar  el  programa,  y  lo  hace,  eso  puede  alertarlo.

A.3  Errores  semánticos
De  alguna  manera,  los  errores  semánticos  son  los  más  difíciles  de  depurar,  porque  el  intérprete  no  proporciona  
información  sobre  lo  que  está  mal.  Solo  usted  sabe  lo  que  se  supone  que  debe  hacer  el  programa.

El  primer  paso  es  hacer  una  conexión  entre  el  texto  del  programa  y  el  comportamiento  que  está  viendo.  Necesita  
una  hipótesis  sobre  lo  que  realmente  está  haciendo  el  programa.  Una  de  las  cosas  que  lo  hace  difícil  es  que  las  
computadoras  funcionan  muy  rápido.

A  menudo  deseará  poder  ralentizar  el  programa  a  la  velocidad  humana,  y  con  algunos  depuradores  puede  hacerlo.  
Pero  el  tiempo  que  lleva  insertar  algunos  bien  colocados  suele  ser  corto  en  comparación  con   declaraciones
configurar  el  depurador,  insertar  y  eliminar  puntos  de  interrupción  y  "llevar"  el  programa  al  lugar  donde  se  produce  el  
error.

A.3.1  Mi  programa  no  funciona.
Debes  hacerte  estas  preguntas:

•  ¿Hay  algo  que  se  suponía  que  debía  hacer  el  programa  pero  que  no  parece  estar  sucediendo?  Encuentre  la  
sección  del  código  que  realiza  esa  función  y  asegúrese  de  que  se  esté  ejecutando  cuando  crea  que  debería  
hacerlo.

•  ¿Está  sucediendo  algo  que  no  debería?  Encuentre  código  en  su  programa  que  realice  esa  función  y  vea  si  se  
está  ejecutando  cuando  no  debería.

•  ¿Hay  una  sección  de  código  que  produce  un  efecto  que  no  es  el  esperado?  Asegúrese  de  comprender  el  
código  en  cuestión,  especialmente  si  involucra  funciones  o  métodos  en  otros  módulos  de  Python.  Lea  la  
documentación  de  las  funciones  a  las  que  llama.  Pruébelos  escribiendo  casos  de  prueba  sencillos  y  
comprobando  los  resultados.
Machine Translated by Google

A.3.  Errores  semánticos 199

Para  programar,  necesitas  un  modelo  mental  de  cómo  funcionan  los  programas.  Si  escribe  un  
programa  que  no  hace  lo  que  espera,  a  menudo  el  problema  no  está  en  el  programa;  está  en  tu  
modelo  mental.

La  mejor  manera  de  corregir  su  modelo  mental  es  dividir  el  programa  en  sus  componentes  
(generalmente  las  funciones  y  métodos)  y  probar  cada  componente  de  forma  independiente.  Una  
vez  que  encuentre  la  discrepancia  entre  su  modelo  y  la  realidad,  puede  resolver  el  problema.

Por  supuesto,  debe  construir  y  probar  componentes  a  medida  que  desarrolla  el  programa.
Si  encuentra  un  problema,  debe  haber  solo  una  pequeña  cantidad  de  código  nuevo  que  no  se  sabe  
si  es  correcto.

A.3.2  Tengo  una  gran  expresión  peluda  y  no  es  lo  que  espero.
Escribir  expresiones  complejas  está  bien  siempre  que  sean  legibles,  pero  pueden  ser  difíciles  de  
depurar.  Suele  ser  una  buena  idea  dividir  una  expresión  compleja  en  una  serie  de  asignaciones  a  
variables  temporales.

Por  ejemplo:

Esto  se  puede  reescribir  como:

La  versión  explícita  es  más  fácil  de  leer  porque  los  nombres  de  las  variables  brindan  documentación  
adicional  y  es  más  fácil  de  depurar  porque  puede  verificar  los  tipos  de  las  variables  intermedias  y  
mostrar  sus  valores.

Otro  problema  que  puede  ocurrir  con  las  expresiones  grandes  es  que  el  orden  de  evaluación  puede  
no  ser  el  esperado.  Por  ejemplo,  si  está  traduciendo  la  expresión  a  Python,  podría  escribir:
x2π  _

Eso  no  es  correcto  porque  la  multiplicación  y  la  división  tienen  la  misma  precedencia  y  se  evalúan  de  
izquierda  a  derecha.  Entonces  esta  expresión  calcula  xπ/2.

Una  buena  manera  de  depurar  expresiones  es  agregar  paréntesis  para  hacer  explícito  el  orden  de  
evaluación:

Siempre  que  no  esté  seguro  del  orden  de  evaluación,  utilice  paréntesis.  El  programa  no  solo  será  
correcto  (en  el  sentido  de  hacer  lo  que  pretendía),  sino  que  también  será  más  legible  para  otras  
personas  que  no  hayan  memorizado  el  orden  de  las  operaciones.

A.3.3  Tengo  una  función  que  no  devuelve  lo  que  esperaba.
Si  tiene  una  declaración  con  una  expresión  compleja,  no  tiene  la  oportunidad  de  imprimir  el  resultado  
antes  de  regresar.  Nuevamente,  puede  usar  una  variable  temporal.  Por  ejemplo,  en  lugar  de:
Machine Translated by Google

200 Apéndice  A.  Depuración

podrías  escribir:

Ahora  tienes  la  oportunidad  de  mostrar  el  valor  de antes  de  volver.

A.3.4  Estoy  muy,  muy  atascado  y  necesito  ayuda.

Primero,  trate  de  alejarse  de  la  computadora  por  unos  minutos.  Las  computadoras  emiten  ondas  que  afectan  
el  cerebro  y  causan  estos  síntomas:

•  Frustración  y  rabia.

•  Creencias  supersticiosas  (“la  computadora  me  odia”)  y  pensamiento  mágico  (“el  programa
solo  funciona  cuando  me  pongo  el  sombrero  al  revés”).

•  Programación  de  caminata  aleatoria  (el  intento  de  programar  escribiendo  todos  los  programas  posibles  
y  eligiendo  el  que  hace  lo  correcto).

Si  te  encuentras  sufriendo  alguno  de  estos  síntomas,  levántate  y  sal  a  caminar.  Cuando  estés  tranquilo,  piensa  
en  el  programa.  ¿Qué  está  haciendo?  ¿Cuáles  son  algunas  posibles  causas  de  ese  comportamiento?  ¿Cuándo  
fue  la  última  vez  que  tuvo  un  programa  de  trabajo  y  qué  hizo  a  continuación?

A  veces  solo  lleva  tiempo  encontrar  un  error.  A  menudo  encuentro  errores  cuando  estoy  lejos  de  la  computadora  
y  dejo  que  mi  mente  divague.  Algunos  de  los  mejores  lugares  para  encontrar  insectos  son  los  trenes,  las  
duchas  y  la  cama,  justo  antes  de  dormirse.

A.3.5  No,  realmente  necesito  ayuda.

Sucede.  Incluso  los  mejores  programadores  se  atascan  de  vez  en  cuando.  A  veces  trabajas  en  un  programa  
durante  tanto  tiempo  que  no  puedes  ver  el  error.  Necesitas  un  nuevo  par  de  ojos.

Antes  de  traer  a  alguien  más,  asegúrese  de  estar  preparado.  Su  programa  debe  ser  lo  más  simple  posible  y  
debe  estar  trabajando  en  la  entrada  más  pequeña  que  cause  el  error.
Debe  tener  declaraciones  en  los  lugares  apropiados  (y  el  resultado  que  producen  debe  ser  comprensible).  
Debe  comprender  el  problema  lo  suficientemente  bien  como  para  describirlo  de  manera  concisa.

Cuando  traiga  a  alguien  para  que  le  ayude,  asegúrese  de  darle  la  información  que  necesita:

•  Si  hay  un  mensaje  de  error,  ¿cuál  es  y  qué  parte  del  programa  indica?

•  ¿Qué  fue  lo  último  que  hizo  antes  de  que  ocurriera  este  error?  ¿Cuáles  fueron  las  últimas  líneas  de  
código  que  escribiste  o  cuál  es  el  nuevo  caso  de  prueba  que  falla?

•  ¿Qué  ha  intentado  hasta  ahora  y  qué  ha  aprendido?

Cuando  encuentre  el  error,  tómese  un  segundo  para  pensar  qué  podría  haber  hecho  para  encontrarlo  más  
rápido.  La  próxima  vez  que  vea  algo  similar,  podrá  encontrar  el  error  más  rápidamente.

Recuerde,  el  objetivo  no  es  solo  hacer  que  el  programa  funcione.  El  objetivo  es  aprender  cómo  hacer  que  el  
programa  funcione.
Machine Translated by Google

apéndice  B

Análisis  de  Algoritmos

Este  apéndice  es  un  extracto  editado  de  Think  Complexity,  de  Allen  B.  Downey,  también  publicado  
por  O'Reilly  Media  (2012).  Cuando  haya  terminado  con  este  libro,  es  posible  que  desee  pasar  a  
ese.

El  análisis  de  algoritmos  es  una  rama  de  la  informática  que  estudia  el  rendimiento  de  los  algoritmos,  especialmente  
su  tiempo  de  ejecución  y  los  requisitos  de  espacio.  Ver
.

El  objetivo  práctico  del  análisis  de  algoritmos  es  predecir  el  rendimiento  de  diferentes  algoritmos  para  guiar  las  
decisiones  de  diseño.

Durante  la  campaña  presidencial  de  Estados  Unidos  de  2008,  se  le  pidió  al  candidato  Barack  Obama  que  
realizara  un  análisis  improvisado  cuando  visitó  Google.  El  presidente  ejecutivo,  Eric  Schmidt,  le  preguntó  en  
broma  "la  forma  más  eficiente  de  clasificar  un  millón  de  números  enteros  de  32  bits".  Aparentemente,  Obama  
había  recibido  un  aviso,  porque  respondió  rápidamente:  "Creo  que  el  tipo  de  burbuja  sería  el  camino  equivocado".  
Ver .

Esto  es  cierto:  la  ordenación  de  burbuja  es  conceptualmente  simple  pero  lenta  para  grandes  conjuntos  de  datos.  La  
respuesta  que  Schmidt  probablemente  estaba  buscando  es  "clasificación  radix" (
) 1.

El  objetivo  del  análisis  de  algoritmos  es  hacer  comparaciones  significativas  entre  algoritmos,  pero  existen  algunos  
problemas:

•  El  rendimiento  relativo  de  los  algoritmos  puede  depender  de  las  características  del  hardware,  por  lo  que  un  
algoritmo  puede  ser  más  rápido  en  la  Máquina  A  y  otro  en  la  Máquina  B.
La  solución  general  a  este  problema  es  especificar  un  modelo  de  máquina  y  analizar  el  número  de  pasos  
u  operaciones  que  requiere  un  algoritmo  bajo  un  modelo  dado.

•  El  rendimiento  relativo  puede  depender  de  los  detalles  del  conjunto  de  datos.  Por  ejemplo,  algunos  
algoritmos  de  clasificación  se  ejecutan  más  rápido  si  los  datos  ya  están  parcialmente  ordenados;  otros  algoritmos
1
Pero  si  recibe  una  pregunta  como  esta  en  una  entrevista,  creo  que  una  mejor  respuesta  es:  “La  forma  más  rápida  de  clasificar  un  
millón  de  números  enteros  es  usar  cualquier  función  de  clasificación  que  proporcione  el  lenguaje  que  estoy  usando.  Su  rendimiento  es  
lo  suficientemente  bueno  para  la  gran  mayoría  de  las  aplicaciones,  pero  si  resulta  que  mi  aplicación  es  demasiado  lenta,  usaría  un  
generador  de  perfiles  para  ver  dónde  se  gasta  el  tiempo.  Si  pareciera  que  un  algoritmo  de  clasificación  más  rápido  tendría  un  efecto  
significativo  en  el  rendimiento,  entonces  buscaría  una  buena  implementación  de  la  clasificación  radix”.
Machine Translated by Google

202 Apéndice  B.  Análisis  de  algoritmos

correr  más  lento  en  este  caso.  Una  forma  común  de  evitar  este  problema  es  analizar  el  peor  de  los  casos .  
A  veces  es  útil  analizar  el  rendimiento  promedio  de  los  casos,  pero  eso  suele  ser  más  difícil  y  puede  que  
no  sea  obvio  sobre  qué  conjunto  de  casos  promediar.

•  El  rendimiento  relativo  también  depende  del  tamaño  del  problema.  Un  algoritmo  de  clasificación  que  es  
rápido  para  listas  pequeñas  puede  ser  lento  para  listas  largas.  La  solución  habitual  a  este  problema  es  
expresar  el  tiempo  de  ejecución  (o  el  número  de  operaciones)  en  función  del  tamaño  del  problema  y  
agrupar  las  funciones  en  categorías  según  la  rapidez  con  la  que  crecen  a  medida  que  aumenta  el  tamaño  
del  problema.

Lo  bueno  de  este  tipo  de  comparación  es  que  se  presta  a  una  clasificación  simple  de  algoritmos.  Por  ejemplo,  si  
sé  que  el  tiempo  de  ejecución  del  algoritmo  A  tiende  a  ser  proporcional  al  tamaño  de  la  entrada,  n,  y  el  algoritmo  
2
,
B  tiende  a  ser  proporcional  a  n,  entonces  espero  que  A  sea  más  rápido  que  B,  al  menos  para  grandes  valores  
de  n

Este  tipo  de  análisis  viene  con  algunas  advertencias,  pero  hablaremos  de  eso  más  adelante.

B.1  Orden  de  crecimiento

Suponga  que  analizó  dos  algoritmos  y  expresó  sus  tiempos  de  ejecución  en  términos  del  tamaño  de  la  entrada:  el  
algoritmo  A  toma  100n  +  1  pasos  para  resolver  un  problema  con  tamaño  n;  Algo  2  ritmo  B  toma  n
+  n  +  1  pasos.

La  siguiente  tabla  muestra  el  tiempo  de  ejecución  de  estos  algoritmos  para  diferentes  tamaños  de  problemas:

Entrada  Tiempo  de  ejecución  de  Tiempo  de  
ejecución  de  tamaño  Algoritmo  A  Algoritmo  B
10 1  001 111
100   10  001   10  101  
1  000   100  001 1  001  001  
10  000 1  000  001  100  010  001

En  n  =  10,  el  Algoritmo  A  se  ve  bastante  mal;  tarda  casi  10  veces  más  que  el  algoritmo  B.  Pero  para  n  =  100  son  
casi  iguales,  y  para  valores  más  grandes,  A  es  mucho  mejor.

La  razón  fundamental  es  que  para  valores  grandes  de  n,  cualquier  función  que  contenga  una  n  crecerá   2  término

más  rápido  que  una  función  cuyo  término  principal  sea  n.  El  término  principal  es  el  término  con  el  exponente  más  
alto.

Para  el  algoritmo  A,  el  término  principal  tiene  un  coeficiente  grande,  100,  por  lo  que  B  funciona  mejor  que  A  para  
n  pequeño.  Pero  independientemente  de  los  coeficientes,  siempre  habrá  algún  valor  de  n  donde  an2  >  bn,  para  
cualquier  valor  de  a  y  b.

El  mismo  argumento  se  aplica  a  los  términos  no  principales.  Incluso  si  el  tiempo  de  ejecución  del  Algoritmo  A  fuera  
n  +  1000000,  aún  sería  mejor  que  el  Algoritmo  B  para  un  n  suficientemente  grande.

En  general,  esperamos  que  un  algoritmo  con  un  término  inicial  más  pequeño  sea  un  mejor  algoritmo  para  
problemas  grandes,  pero  para  problemas  más  pequeños,  puede  haber  un  punto  de  cruce  en  el  que  otro  algoritmo  
sea  mejor.  La  ubicación  del  punto  de  cruce  depende  de  los  detalles  de  los  algoritmos,  las  entradas  y  el  hardware,  
por  lo  que  generalmente  se  ignora  para  fines  de  análisis  algorítmico.  Pero  eso  no  significa  que  puedas  olvidarte  
de  él.
Machine Translated by Google

B.1.  orden  de  crecimiento 203

Si  dos  algoritmos  tienen  el  mismo  término  de  orden  principal,  es  difícil  decir  cuál  es  mejor;  de  nuevo,  la  respuesta  
depende  de  los  detalles.  Entonces,  para  el  análisis  algorítmico,  las  funciones  con  el  mismo  término  principal  se  
consideran  equivalentes,  incluso  si  tienen  diferentes  coeficientes.

Un  orden  de  crecimiento  es  un  conjunto  de  funciones  cuyo  comportamiento  de  crecimiento  se  considera  equivalente.
Por  ejemplo,  2n,  100n  y  n  +  1  pertenecen  al  mismo  orden  de  crecimiento,  que  se  escribe  O(n)  en  notación  Big­Oh  y,  a  
menudo,  se  denomina  lineal  porque  todas  las  funciones  del  conjunto  crecen  linealmente  con  n.

2 2
Todas  las  funciones  con  el  término  principal  n  La   pertenecen  a  O(n );  se  llaman  cuadráticos.

siguiente  tabla  muestra  algunos  de  los  órdenes  de  crecimiento  que  aparecen  más  comúnmente  en  el  análisis  algorítmico,  
en  orden  creciente  de  maldad.

orden  de   Nombre
crecimiento
O(1) constante

O(logb  n)  logarítmico  (para  cualquier  b)
En) lineal  
lineal  rítmico
O(n  logb  
2
En cúbico  
3 cuadrático
Enn) ) )
O(c  n )  exponencial  (para  cualquier  c)
Para  los  términos  logarítmicos,  la  base  del  logaritmo  no  importa;  cambiar  bases  es  el  equivalente  a  multiplicar  por  una  
constante,  lo  que  no  cambia  el  orden  de  crecimiento.  De  manera  similar,  todas  las  funciones  exponenciales  pertenecen  
al  mismo  orden  de  crecimiento  sin  importar  la  base  del  exponente.  Las  funciones  exponenciales  crecen  muy  
rápidamente,  por  lo  que  los  algoritmos  exponenciales  solo  son  útiles  para  problemas  pequeños.

Ejercicio  B.1.  Lea  la  página  de  Wikipedia  sobre  la  notación  Big­Oh  y  responda  
las  siguientes  preguntas:  1.  ¿Cuál  es  el  
3 +  n  2?  ¿Qué  hay  de  n3  +
orden  de  crecimiento  de  n3  +  n  2?  ¿Qué  pasa  con  1000000n  1000000n  2?

2
2.  ¿Cuál  es  el  orden  de  crecimiento  de  (n
+  n)  ∙  (n  +  1)?  Antes  de  empezar  a  multiplicar,  recuerda  
que  solo  necesitas  el  término  principal.
3.  Si  f  está  en  O(g),  para  alguna  función  g  no  especificada,  ¿qué  podemos  decir  acerca  de  af  +  b,  donde  a  y
b  son  constantes?

4.  Si  f1  y  f2  están  en  O(g),  ¿qué  podemos  decir  acerca  de  f1  +  f2?

5.  Si  f1  está  en  O(g)  y  f2  está  en  O(h),  ¿qué  podemos  decir  acerca  de  f1  +  f2?

6.  Si  f1  está  en  O(g)  y  f2  es  O(h),  ¿qué  podemos  decir  acerca  de  f1  ∙  f2?

Los  programadores  que  se  preocupan  por  el  rendimiento  a  menudo  encuentran  este  tipo  de  análisis  difícil  de  tragar.  
Tienen  un  punto:  a  veces  los  coeficientes  y  los  términos  no  principales  marcan  una  diferencia  real.  A  veces,  los  detalles  
del  hardware,  el  lenguaje  de  programación  y  las  características  de  la  entrada  marcan  una  gran  diferencia.  Y  para  
problemas  pequeños,  el  orden  de  crecimiento  es  irrelevante.

Pero  si  tiene  en  cuenta  estas  advertencias,  el  análisis  algorítmico  es  una  herramienta  útil.  Al  menos  para  problemas  
grandes,  el  algoritmo  "mejor"  suele  ser  mejor  y,  a  veces,  es  mucho  mejor.
La  diferencia  entre  dos  algoritmos  con  el  mismo  orden  de  crecimiento  suele  ser  un  factor  constante,  pero  la  diferencia  
entre  un  buen  algoritmo  y  un  mal  algoritmo  no  tiene  límites.
Machine Translated by Google

204 Apéndice  B.  Análisis  de  algoritmos

B.2  Análisis  de  las  operaciones  básicas  de  Python
En  Python,  la  mayoría  de  las  operaciones  aritméticas  son  de  tiempo  constante;  la  multiplicación  suele  
tardar  más  que  la  suma  y  la  resta,  y  la  división  tarda  incluso  más,  pero  estos  tiempos  de  ejecución  no  
dependen  de  la  magnitud  de  los  operandos.  Los  enteros  muy  grandes  son  una  excepción;  en  ese  caso,  
el  tiempo  de  ejecución  aumenta  con  el  número  de  dígitos.

Las  operaciones  de  indexación  (leer  o  escribir  elementos  en  una  secuencia  o  diccionario)  también  son  de  
tiempo  constante,  independientemente  del  tamaño  de  la  estructura  de  datos.

Un  bucle  que  atraviesa  una  secuencia  o  un  diccionario  suele  ser  lineal,  siempre  que  todas  las  operaciones  
en  el  cuerpo  del  bucle  sean  de  tiempo  constante.  Por  ejemplo,  sumar  los  elementos  de  una  lista  es  lineal:

La  función  incorporada  también  es  lineal  porque  hace  lo  mismo,  pero  tiende  a  ser  más  rápida  porque  es  
una  implementación  más  eficiente;  en  el  lenguaje  del  análisis  algorítmico,  tiene  un  coeficiente  principal  
más  pequeño.
un+1
Como  regla  general,  si  el  cuerpo  de  un  bucle  está  en  O(n  a ) ,  entonces  todo  el  bucle  está  en  O(n ,   ).  El
excepto  si  puede  mostrar  que  el  bucle  sale  después  de  un  número  constante  de  iteraciones.  Si  un  bucle  ejecuta  
k  veces  independientemente  de  n,  entonces  el  bucle  está  en  O(n  a ),  incluso  para  k  grande.

Multiplicar  por  k  no  cambia  el  orden  de  crecimiento,  pero  tampoco  lo  hace  dividir.  Entonces  si  el
el  cuerpo  de  un  bucle  está  en  O(n  a )  y  se  ejecuta  n/k  veces,  el  bucle  está  en  O(nun+1 ),  incluso  para  k  grande.

, y  que  son  de  tiempo  
La  mayoría  de  las  operaciones  de  cadenas  y  tuplas  son  lineales,  excepto  la  indexación  
constante.  Las  funciones  integradas  y  son  lineales.  El  tiempo  de  ejecución  de  una  operación  de  división  es  
proporcional  a  la  longitud  de  la  salida,  pero  independiente  del  tamaño  de  la  entrada.

La  concatenación  de  cadenas  es  lineal;  el  tiempo  de  ejecución  depende  de  la  suma  de  las  longitudes  de  los  
operandos.

Todos  los  métodos  de  cadena  son  lineales,  pero  si  las  longitudes  de  las  cadenas  están  limitadas  por  una  
constante,  por  ejemplo,  operaciones  en  caracteres  individuales,  se  consideran  tiempo  constante.  El  
método  de  la  cadena  es  lineal;  el  tiempo  de  ejecución  depende  de  la  longitud  total  de  las  cadenas.

La  mayoría  de  los  métodos  de  lista  son  lineales,  pero  hay  algunas  excepciones:

•  Agregar  un  elemento  al  final  de  una  lista  es  un  tiempo  constante  en  promedio;  cuando  se  queda  
sin  espacio,  ocasionalmente  se  copia  en  una  ubicación  más  grande,  pero  el  tiempo  total  para  n  
operaciones  es  O(n),  por  lo  que  el  tiempo  promedio  para  cada  operación  es  O(1).

•  Eliminar  un  elemento  del  final  de  una  lista  es  un  tiempo  constante.

•  La  clasificación  es  O(n  log  n).

La  mayoría  de  las  operaciones  y  métodos  del  diccionario  son  de  tiempo  constante,  pero  hay  algunas  excepciones:

•  El  tiempo  de  ejecución  de es  proporcional  al  tamaño  del  diccionario  pasado  como  pa
rameter,  no  el  diccionario  que  se  actualiza.
• , y son  de  tiempo  constante  porque  devuelven  iteradores.  Pero  si  
recorre  los  iteradores,  el  ciclo  será  lineal.
Machine Translated by Google

B.3.  Análisis  de  algoritmos  de  búsqueda 205

El  rendimiento  de  los  diccionarios  es  uno  de  los  pequeños  milagros  de  la  informática.  Veremos  cómo  funcionan  en  la  
Sección  B.4.
Ejercicio  B.2.  Lea  la  página  de  Wikipedia  sobre  algoritmos  de  clasificación  en  
y  responda  las  siguientes  preguntas:

1.  ¿Qué  es  una  "clasificación  de  comparación"?  ¿Cuál  es  el  mejor  orden  de  crecimiento  en  el  peor  de  los  casos  para  una  comparación
¿clasificar?  ¿Cuál  es  el  mejor  orden  de  crecimiento  en  el  peor  de  los  casos  para  cualquier  tipo  de  algoritmo?

2.  ¿Cuál  es  el  orden  de  crecimiento  del  tipo  de  burbuja  y  por  qué  Barack  Obama  piensa  que  es  “el  mal
¿camino  a  seguir?"

3.  ¿Cuál  es  el  orden  de  crecimiento  de  tipo  radix?  ¿Qué  condiciones  previas  necesitamos  para  usarlo?

4.  ¿Qué  es  un  tipo  estable  y  por  qué  podría  ser  importante  en  la  práctica?

5.  ¿Cuál  es  el  peor  algoritmo  de  clasificación  (que  tiene  nombre)?

6.  ¿Qué  algoritmo  de  clasificación  usa  la  biblioteca  C?  ¿Qué  algoritmo  de  clasificación  usa  Python?  Son  estos
algoritmos  estables?  Es  posible  que  tengas  que  buscar  en  Google  para  encontrar  estas  respuestas.

7.  Muchos  de  los  tipos  que  no  son  de  comparación  son  lineales,  entonces,  ¿por  qué  Python  usa  una  comparación  O  (n  log  n) ?
tipo  ison?

B.3  Análisis  de  algoritmos  de  búsqueda
Una  búsqueda  es  un  algoritmo  que  toma  una  colección  y  un  elemento  objetivo  y  determina  si  el  objetivo  está  en  la  
colección,  a  menudo  devolviendo  el  índice  del  objetivo.

El  algoritmo  de  búsqueda  más  simple  es  una  “búsqueda  lineal”,  que  recorre  los  elementos  de  la  colección  en  orden,  
deteniéndose  si  encuentra  el  objetivo.  En  el  peor  de  los  casos,  tiene  que  recorrer  toda  la  colección,  por  lo  que  el  tiempo  
de  ejecución  es  lineal.

El  operador  de  secuencias  utiliza  una  búsqueda  lineal;  también  lo  hacen  los  métodos  de  cadena  como y
.

Si  los  elementos  de  la  secuencia  están  en  orden,  puede  usar  una  búsqueda  de  bisección,  que  es  O  (log  n).  La  búsqueda  
de  bisección  es  similar  al  algoritmo  que  puede  usar  para  buscar  una  palabra  en  un  diccionario  (un  diccionario  en  papel,  
no  la  estructura  de  datos).  En  lugar  de  comenzar  desde  el  principio  y  verificar  cada  elemento  en  orden,  comience  con  
el  elemento  en  el  medio  y  verifique  si  la  palabra  que  está  buscando  viene  antes  o  después.  Si  viene  antes,  busca  en  la  
primera  mitad  de  la  secuencia.  De  lo  contrario,  busca  la  segunda  mitad.  De  cualquier  manera,  reduce  la  cantidad  de  
elementos  restantes  a  la  mitad.

Si  la  secuencia  tiene  1.000.000  de  elementos,  se  necesitarán  unos  20  pasos  para  encontrar  la  palabra  o  concluir  que  
no  está  allí.  Eso  es  unas  50.000  veces  más  rápido  que  una  búsqueda  lineal.

La  búsqueda  en  bisección  puede  ser  mucho  más  rápida  que  la  búsqueda  lineal,  pero  requiere  que  la  secuencia  esté  en  
orden,  lo  que  puede  requerir  trabajo  adicional.

Existe  otra  estructura  de  datos,  llamada  tabla  hash ,  que  es  aún  más  rápida  (puede  realizar  una  búsqueda  en  tiempo  
constante)  y  no  requiere  que  se  ordenen  los  elementos.  Los  diccionarios  de  Python  se  implementan  mediante  tablas  
hash,  por  lo  que  la  mayoría  de  las  operaciones  del  diccionario,  incluido  el  operador,  son  de  tiempo  constante.
Machine Translated by Google

206 Apéndice  B.  Análisis  de  algoritmos

B.4  Tablas  hash
Para  explicar  cómo  funcionan  las  tablas  hash  y  por  qué  su  rendimiento  es  tan  bueno,  empiezo  con  una  
implementación  simple  de  un  mapa  y  lo  mejoro  gradualmente  hasta  que  se  convierte  en  una  tabla  hash.

Uso  Python  para  demostrar  estas  implementaciones,  pero  en  la  vida  real  no  escribirías  código  como  este  en  
Python;  ¡simplemente  usarías  un  diccionario!  Entonces,  para  el  resto  de  este  capítulo,  debe  imaginar  que  los  
diccionarios  no  existen  y  desea  implementar  una  estructura  de  datos  que  se  asigne  de  claves  a  valores.  Las  
operaciones  que  tienes  que  implementar  son:

:  agregue  un  nuevo  elemento  que  se  asigne  de  clave  a  valor .  Con  un  diccionario  de  Python,  esta  
operación  se  escribe .

:  Busque  y  devuelva  el  valor  que  corresponde  a  key .  Con  un  diccionario  de  Python,  esta  operación  
, se  escribe o .

Por  ahora,  supongo  que  cada  tecla  solo  aparece  una  vez.  La  implementación  más  simple  de  esta  interfaz  
utiliza  una  lista  de  tuplas,  donde  cada  tupla  es  un  par  clave­valor.

agrega  una  tupla  clave­valor  a  la  lista  de  elementos,  lo  que  requiere  un  tiempo  constante.

usa  un bucle  para  buscar  en  la  lista:  si  encuentra  la  clave  de  destino,  devuelve  la  correspondiente  
valor;  de  lo  contrario,  plantea  un .  Entonces es  lineal.

Una  alternativa  es  mantener  la  lista  ordenada  por  clave.  Entonces  podría  usar  una  búsqueda  de  bisección,  
que  es  O  (log  n).  Pero  insertar  un  nuevo  elemento  en  medio  de  una  lista  es  lineal,  por  lo  que  esta  podría  no  
ser  la  mejor  opción.  Hay  otras  estructuras  de  datos  que  se  pueden  implementar  y  en  tiempo  de  registro,  pero  
aún  no  son  tan  buenas  como  el  tiempo  constante,  así  que  sigamos  adelante.

Una  forma  de  mejorar   es  dividir  la  lista  de  pares  clave­valor  en  listas  más  pequeñas.
Aquí  hay  una  implementación  llamada  que  es  una  lista  ,de  100  LinearMaps.  Como  veremos  en  un  segundo,  el  
orden  de  crecimiento  sigue  siendo  lineal,  pero  es  un  paso  en  el  camino  hacia  las  tablas  hash:
Machine Translated by Google

B.4.  tablas  hash 207

hace  una  lista  de s.

es  utilizado  por  y  para  averiguar  en  qué  mapa  colocar  el  nuevo  elemento  o  en  qué  mapa  
buscar.

utiliza  la  función  integrada  que  toma  
, casi  cualquier  objeto  de  Python  y  devuelve  un  número  
entero.  Una  limitación  de  esta  implementación  es  que  solo  funciona  con  claves  hashable.
Los  tipos  mutables  como  listas  y  diccionarios  no  se  pueden  modificar.

Los  objetos  hashable  que  se  consideran  equivalentes  devuelven  el  mismo  valor  hash,  pero  lo  contrario  
no  es  necesariamente  cierto:  dos  objetos  con  valores  diferentes  pueden  devolver  el  mismo  valor  hash.

usa  el  operador  de  módulo  para  envolver  los  valores  hash  en  el  rango  de  0  a,  por  lo  que  el  
, resultado  es  un  índice  legal  en  la  lista.  Por  supuesto,  esto  significa  que  muchos  
valores  hash  diferentes  se  ajustarán  al  mismo  índice.  Pero  si  la  función  hash  distribuye  las  cosas  de  
manera  bastante  uniforme  (que  es  para  lo  que  están  diseñadas  las  funciones  hash),  entonces  esperamos  
n/100  elementos  por  LinearMap.

Dado  que  el  tiempo  de  ejecución  de  es  proporcional  a  la  cantidad  de  elementos,  esperamos  que  BetterMap  sea  
unas  100  veces  más  rápido  que  LinearMap.  El  orden  de  crecimiento  sigue  siendo  lineal,  pero  el  coeficiente  
principal  es  más  pequeño.  Eso  es  bueno,  pero  aún  no  es  tan  bueno  como  una  tabla  hash.

Aquí  (finalmente)  está  la  idea  crucial  que  hace  que  las  tablas  hash  sean  rápidas:  si  puede  mantener  limitada  
la  longitud  máxima  de  LinearMaps,  es  un  tiempo  constante.  Todo  lo  que  tiene  que  hacer  es  realizar  un  
seguimiento  de  la  cantidad  de  elementos  y,  cuando  la  cantidad  de  elementos  por  LinearMap  supere  un  umbral,  
cambie  el  tamaño  de  la  tabla  hash  agregando  más  LinearMaps.

Aquí  hay  una  implementación  de  una  tabla  hash:
Machine Translated by Google

208 Apéndice  B.  Análisis  de  algoritmos

crea  un e  inicializa , que  realiza  un  seguimiento  del  número  de  elementos.

solo  se  envía  a  de   .  El  trabajo  real  ocurre  en:  si  son   , que  comprueba  el  número


artículos  y  el  tamaño  de  la iguales,  el  número  promedio  de  elementos  por
LinearMap  es  1,  por  lo  que  llama .

Hacer  una  nueva , dos  veces  más  grande  que  el  anterior,  y  luego  "rehace"  el
elementos  del  mapa  antiguo  al  nuevo.

El  refrito  es  necesario  porque  al  cambiar  el  número  de  LinearMaps  cambia  el  denominador  del  operador  de  
módulo  en .  Eso  significa  que  algunos  objetos  que  solían  generar  hash  en  el  mismo  LinearMap  se  dividirán  (que  
es  lo  que  queríamos,  ¿verdad?).

El  refrito  es  lineal,  por  lo  que   es  lineal,  lo  que  puede  parecer  malo,  ya  que  prometí  que
sería  un  tiempo  constante.  Pero  recuerde  que  no  tenemos  que  cambiar  el  tamaño  cada  vez,  por  lo  general,   es

el  tiempo  es  constante  y  solo  ocasionalmente  es  lineal.  La  cantidad  total  de  trabajo  para  los  tiempos  de   norte

ejecución  es  proporcional  a  n,  por  lo  que  el  tiempo  promedio  de  cada  uno  es  un  tiempo  constante.

Para  ver  cómo  funciona  esto,  piense  en  comenzar  con  un  HashTable  vacío  y  agregar  una  secuencia  de  elementos.  
Comenzamos  con  2  LinearMaps,  por  lo  que  las  primeras  2  adiciones  son  rápidas  (no  se  requiere  cambiar  el  tamaño).  
Digamos  que  toman  una  unidad  de  trabajo  cada  uno.  El  próximo  agregado  requiere  un  cambio  de  tamaño,  por  lo  que  
tenemos  que  repetir  los  dos  primeros  elementos  (llamémoslos  2  unidades  de  trabajo  más)  y  luego  agregar  el  tercer  
elemento  (una  unidad  más).  Agregar  el  siguiente  artículo  cuesta  1  unidad,  por  lo  que  el  total  hasta  ahora  es  de  6  
unidades  de  trabajo  para  4  artículos.

El  siguiente  cuesta  5  unidades,  pero  los  siguientes  tres  son  solo  una  unidad  cada  uno,  por  lo  que  el  total  es  de  14  unidades  para  los  
primeros  8  agregados.

El  siguiente  cuesta  9  unidades,  pero  luego  podemos  agregar  7  más  antes  del  próximo  cambio  de  tamaño,  por  lo  que  el  total  es  de  30  
unidades  para  los  primeros  16  agregados.

Después  de  32  agregados,  el  costo  total  es  de  62  unidades  y  espero  que  esté  comenzando  a  ver  un  patrón.  
Después  de  n  sumas,  donde  n  es  una  potencia  de  dos,  el  costo  total  es  2n  −  2  unidades,  por  lo  que  el  trabajo  
promedio  por  suma  es  un  poco  menos  de  2  unidades.  Cuando  n  es  una  potencia  de  dos,  ese  es  el  mejor  de  los  
casos;  para  otros  valores  de  n  el  trabajo  promedio  es  un  poco  más  alto,  pero  eso  no  es  importante.  Lo  importante  
es  que  es  O(1).

La  Figura  B.1  muestra  cómo  funciona  esto  gráficamente.  Cada  bloque  representa  una  unidad  de  trabajo.  Las  
columnas  muestran  el  trabajo  total  para  cada  adición  en  orden  de  izquierda  a  derecha:  las  dos  primeras  cuestan  1  
unidad  cada  una,  la  tercera  cuesta  3  unidades,  etc.
Machine Translated by Google

B.5.  Glosario 209

Figura  B.1:  El  costo  de  agregar  una  tabla  hash.

El  trabajo  adicional  de  refrito  aparece  como  una  secuencia  de  torres  cada  vez  más  altas  con  un  espacio  cada  vez  mayor  
entre  ellas.  Ahora,  si  derriba  las  torres  y  distribuye  el  costo  de  cambiar  el  tamaño  entre  todas  las  adiciones,  puede  ver  
gráficamente  que  el  costo  total  después  de  n  adiciones  es  2n  −  2.

Una  característica  importante  de  este  algoritmo  es  que  cuando  cambiamos  el  tamaño  de  HashTable,  crece  geométricamente;  
es  decir,  multiplicamos  el  tamaño  por  una  constante.  Si  aumenta  el  tamaño  aritméticamente,  agregando  un  número  fijo  
cada  vez,  el  tiempo  promedio  por es  lineal.

Puede  descargar  mi  implementación  de  HashMap  desde  pero  recuerde  que  no  
, hay  razón  para  usarla;  si  quieres  un  mapa,  solo  usa  un
Diccionario  de  Python.

B.5  Glosario
análisis  de  algoritmos:  Una  forma  de  comparar  algoritmos  en  términos  de  su  tiempo  de  ejecución  y/o
requerimientos  de  espacio.

modelo  de  máquina:  una  representación  simplificada  de  una  computadora  utilizada  para  describir  algoritmos.

Peor  caso:  La  entrada  que  hace  que  un  algoritmo  determinado  se  ejecute  más  lentamente  (o  requiera  la  mayor  cantidad  de
espacio).

término  principal:  En  un  polinomio,  el  término  con  el  exponente  más  alto.

punto  de  cruce:  El  tamaño  del  problema  donde  dos  algoritmos  requieren  el  mismo  tiempo  de  ejecución  o
espacio.

orden  de  crecimiento:  Un  conjunto  de  funciones  que  crecen  todas  de  una  manera  considerada  equivalente  para  propósitos  
de  análisis  de  algoritmos.  Por  ejemplo,  todas  las  funciones  que  crecen  linealmente  pertenecen  al  mismo  orden  de  
crecimiento.

Notación  Big­Oh:  Notación  para  representar  un  orden  de  crecimiento;  por  ejemplo,  O(n)  repre
envía  el  conjunto  de  funciones  que  crecen  linealmente.

lineal:  Un  algoritmo  cuyo  tiempo  de  ejecución  es  proporcional  al  tamaño  del  problema,  al  menos  para  grandes
tamaños  de  problemas.

2 , donde  n  es  una  medida  de
cuadrático:  un  algoritmo  cuyo  tiempo  de  ejecución  es  proporcional  al  tamaño  del  
problema  n.

búsqueda:  El  problema  de  localizar  un  elemento  de  una  colección  (como  una  lista  o  diccionario)  o  determinar  que  no  está  
presente.
Machine Translated by Google

210 Apéndice  B.  Análisis  de  algoritmos

hashtable:  una  estructura  de  datos  que  representa  una  colección  de  pares  clave­valor  y  realiza  
búsquedas  en  tiempo  constante.
Machine Translated by Google

Índice

abecedario,  73,  84   aumentado,  93,  100  
función  abs,  52   elemento,  74,  90,  
ruta  absoluta,  139,  145   116  tupla,  116,  117,  119,  122  
acceso,  90   declaración  de  asignación,  9  
acumulador,  100   atributo,  153,  169  
histograma,  127   __dict__,  168  
lista,  93   clase,  172,  180  
cadena,  175   inicializando,  168  
suma,  93 instancia,  148,  153,  172,  180
función  de  Ackermann,  61,  113   AttributeError,  152,  197  
método  de  suma,   asignación  aumentada,  93,  100
165  suma  con  acarreo,  68   Austen,  Jane,  127  
algoritmo,  67,  69,  130,  201 caso  promedio,  202  
MD5,  146   costo  promedio,  208
raíz  cuadrada,  69  
aliasing,  95,  96,  100,  149,  151,  170   maldad,  caso  
copiar  para  evitar,  99   base  203,  44,  47  
todo,   evaluación  comparativa,  133,  
186  alfabeto,   , 134  
37  ejecución  alternativa,  41   206  grande,  expresión  peluda,  199
ambigüedad,  5   Notación  Big­Oh,  209  
anagrama,  101   notación  big­oh,  203  
conjunto  de  anagramas,   búsqueda  binaria,  101  
123,  145  análisis  de  algoritmos ,  201,   bingo,  123  
209  análisis  de  primitivas,  204  y   cumpleaños,  
operador,  40   160  paradoja  de  
cualquiera,   cumpleaños,  101  
185  método  de  adición,  92,  97,  101,  174,  175   módulo  de  bisección,  101  
función  de  arco,  31 búsqueda  de  bisección,  101,  205  
Espiral  de  Arquímedes,  38   bisección,  depuración  
argumento,  17,  19,  21,  22,  26,  97   por,  68  operador  
recopilar,  118   bit  a  bit,  3  
palabra  clave,  33,  36,   cuerpo,  19,  26,  65  tipo  booleano,  
191   40  expresión  booleana,  
lista,  97  opcional,  76,  79,  95,  107,   40,  47  función  booleana,  
184  posicional,  164,  169,  190   54  operador  booleano,  76  préstamo,  resta  
variable­  tupla  de  longitud,  118   con,  68,  159  
dispersión  de  argumentos,   acotado,  
118  operador  aritmético,  3   207  corchete  
declaración  de  afirmación,  159,   ondulado,  103  operador  de  
160  asignación,  14,  63,  89 corchete,  71,  90,  116  rama,  41,  47
Machine Translated by Google

212 Índice

declaración  de  interrupción,   declaración  compuesta,  41,  47  
66  clasificación  de   concatenación,  12,  14,  22,  73,  74,  95  lista,  91,  
burbuja,  201   97,  101  condición,  
error,  6,  7,  13   41,  47,  65,  196  condicional,  194  
peor,  170  función   encadenado,  41,  47  
incorporada   anidado,  42,  47  
cualquiera,  185,  186  objeto  de  bytes,  141,  145 ejecución  
condicional ,  41  expresión  
calculadora,  8,  15   condicional,  183,  191  declaración  condicional,  
gráfico  de  llamadas,  109,  112 41,  47,  55,  184  verificación  de  consistencia,  111,  
Charla  de  coche,  88,  113,  124 158  tiempo  constante,  208  
clase  de  tarjeta,  172   contribuyentes,  tipo  de  
tarjeta,  jugar,  171  llevar,   conversión  vii,  17  copia  
suma  con,  68,  156,  158  atrapar,  145  condicional   profunda,  152  
encadenado,   superficial,  
41,  47  carácter,  71  suma  de   152  
verificación,  143,   rebanada,  74,  
146  clase  infantil,  176,  180   92  para  evitar  
función  de  elección,  126   aliasing ,  99  
función  de  círculo,  31   módulo  de  copia,  151  copia  
definición  circular,  clase   de  objetos,  151  método  
55,  4,  147,  153 de  conteo,  79

Tarjeta,  172   Contador,  187  
niño,  176,  180 contador,  75,  79,  104,  111  conteo  
Cubierta,  174 y  bucle,  75
Mano,  176 Creative  Commons,  punto  de  
Canguro,  170  padre,   cruce  vi,  202,  209  crucigramas,  83  
176 suma  acumulada,  
Punto,  148,  165 100
Rectángulo,  149
Tiempo,  155   encapsulación  de  datos,  179,  181  
atributo  de  clase,  172,  180   estructura  de  datos,  122,  123,  132  base  
definición  de  clase,  147   de  datos,  141,  145  objeto  
diagrama  de  clase,  177,  181   de  base  de  datos,  141  
objeto  de  clase,  148,  153,  190   módulo  de  fecha  y  hora,  160  
método  de  cierre,  138,  141,  143   módulo  dbm,  141  código  
método  __cmp__,  173 muerto,  52,  60,  198  depurador  
Conjetura  de  Collatz,  65   (pdb),  197  depuración,  6,  7 ,  
colecciones,  187,  188,  190  dos   13,  36,  46,  59,  77,  87,  98,  111,  122,  133,  144,  152,  159,  168,  
puntos,  19,  194   178,  185,  193  por  bisección,  68  respuesta  
comentario,  12,  14   emocional,  
conmutatividad,  12,  167  función   6,  200  experimental,  
de  comparación,  52  algoritmos   25  pato  de  goma,  134  superstición,  
de  comparación,  201  cadena  de   200  cubierta,  171
comparación,  77  
tupla,  116,  
174  clasificación  de  
comparación,  205  composición,   Clase  de  baraja,  174  
19 ,  22,  26,  54,  174 baraja,  naipes,  174
Machine Translated by Google

Índice 213

declaración,  110,  112   walk,  140  
decremento,  64,  69   trabajando,  139  
copia  profunda,  152,  153   despacho  
función  de  copia  profunda,  152   basado  en  tipos,  167  
palabra  clave  def,  19   despacho,  basado  en  tipos,  166  
valor  predeterminado,  129,  134,   divisibilidad,  39  
165  evitando  mutable,  170   división  de  
dictado   coma  flotante,  39  piso,  
39,  46,  47  divmod,  
predeterminado,   117,  158  docstring,  
188   35,  37,  148  notación  de  
definición   puntos,  18,  26,  76,  148,  162,  172
circular,  55  clase,   Doble  Día,  160  letras  
147  función,  19   dobles,  88
recursivo ,  124  del  operador,  94   Doyle,  Arthur  Conan,  25  
eliminación,  elemento   duplicados,  101,  113,  146,  187
de  lista,  94  delimitador,  95,  100  
desarrollo  diseñado,  160   elemento,  89,  100  
determinista,  126,  134  plan   eliminación  de  elementos,  
de  desarrollo,  36  encapsulación  de   94  palabra  clave  elif,  42
datos,  179,  181   Elkner,  Jeff,  v,  vi  
diseñado,  158  encapsulación  y  generalización,   puntos  
35  incremental,  52,  193   suspensivos,  19  otra  
prototipo  y  parche,  156,  158   palabra  clave,  41  
programación  de  recorrido  aleatorio,  134,  200   dirección  de  correo  electrónico,  117  
reducción,  85,  87   objeto  incrustado,  
gráfico  de   150,  153,  170  copia,  152  depuración  
llamada  de   emocional,  6,  200  
diagrama,  112   lista  vacía,  89  cadena  
clase,  177,  181  objeto,  148,  150,  152,  153,   vacía,  79,  95  encapsulación,  32,  36 ,  54,  69,  
155,  173  pila,   75,  177  codificar,  
23,  97  estado,  9 ,  63,  78,  90,  96,  108,  120,  148,  150,   171,  180  cifrar,  
152,  155,  173   171  carácter  de  fin  de  línea,  144  
atributo  __dict__,  168  función   enumerar  función,  119  enumerar  
dict,  103  diccionario,   objeto,  119  épsilon,  67  
103,  112,  120,  197  inicializar,  120   igualdad  y  
invertir,  107   asignación,  63  equivalencia,  96,  152  
buscar,  106   equivalente,  100
bucle  con ,  106  
búsqueda  inversa,  106   error

resta,  129  transversal,   tiempo  de  ejecución,  13,  44,  
120,  168  métodos   46,  193  semántica,  13,  193,  
de  diccionario,  204   198  forma,  
módulo  dbm,  141  resta  de   122  sintaxis,  13,  
diccionario,  186  diff,   193  comprobación  de  
146 errores,  58  mensaje  de  error,  7,  
13,  193  función  eval,  
Dijkstra,  Edsger,  87   69  evaluar,  10  
función  dir,  197   excepción,  13,  14,  193 ,  196
directorio,  139,  145 Error  de  atributo,  152,  197
Machine Translated by Google

214 Índice

Error  de  archivo  no  encontrado,  140 bucle  for,  30,  44,  72,  91,  119,  184  
Error  de  índice,  72,  78,  90,  197 lenguaje  formal,  4,  7  
Error  de  clave,  104,  197 operador  de  formato,  138,  145,  197  
Error  de  búsqueda,  107 secuencia  de  formato,  138,  145  
Error  de  nombre,  22,  197 cadena  de  formato,  138,  145  
Error  de  desbordamiento,  46 marco,  23,  26,  44,  56,  109
Error  de  tiempo  de  ejecución,  45 Licencia  de  documentación  libre,  GNU,  frecuencia  v,  
Detener  iteración,  185 vi,  105  letras,  123  
Error  de  sintaxis,  19 palabras,  
Error  de  tipo,  72,  74,  108,  116,  118,  139,  164, 125,  134  función  
197 fructífera,  24,  26  frustración,  
UnboundLocalError,  110 200  función,  3,  17,  
ValueError,  46,  117   19,  25,  161  abs,  52  ack,  61,  113  
excepción,  captura,  140   arc,  31  
ejecutar,  11,  14   elección,  126  
función  existente,  139   círculo,  
depuración  experimental,  25,  134  exponente,   31  comparar,  
202  crecimiento   52  copia  
exponencial,  203  expresión,  10,   profunda,  152  
14  grande  y  peludo,   dict,  103  dir,  197  
199  booleano,  40,  47   enumerar,  
condicional,  183 ,   119  
191  generador,  185,  186,   evaluar,  69  existe,  
191  método  extendido,  92 139  
factorial,  56,  
183  fibonacci,  57,  
factorial,  183   109  encontrar,  74  
función  factorial,  56,  58  fábrica,   flotar,  17  
191  función  de   fructífero,  
fábrica,  188,  189 24  getattr,  
Falso  valor  especial,  40 168  getcwd,  
Último  teorema  de  Fermat,  48   139  hasattr,  
función  de  fibonacci,  57,  109   153,  168  entrada,  45  
archivo,   int,  17  es  
137  permiso,  140   instancia,  
lectura  y  escritura,  137  objeto  de   58,  153,  166  len,  26,  72,  104  
archivo,  83,  87   lista,  94  log,  18  
nombre  de  archivo,  139
FileNotFoundError,  140  patrón  
de  filtro,  93,  100,  184  función  de   matemáticas,  
búsqueda,  74  bandera,   18  max,  117,  118  
110,  112  función   min,  117,  118  
flotante,  17  tipo   abierto,  83 ,  84,  137,  140,  141  
flotante,  4  punto   polígono,  31  
flotante,  4,  7,  67,  183  división  de   popen,  142  
punto  flotante,  39  división  de  piso,   definido  por  programador,  22,  129  
39,  46,  47  flujo  de  ejecucion,   randint,  101,  126  
21,  26,  58,  59,  65,  178,  196  flor,  37  carpeta,  139 aleatorio,  126  
razones  para,  24  
recursivo,  43
Machine Translated by Google

Índice 215

recargar,  144,  195   hashable,  108,  112,  120
repr,  144   HashMap,  tabla  
invertido,  121   hash  207,  112,  206,  
aleatorio,  175   encabezado  210,  19,  25,  194
ordenado,  99,  106,  121   Hola,  mundo,  3  
sqrt,  18,  53   hexadecimal,  148  
str,  18   lenguaje  de  alto  nivel,  6  
suma,  118,  185   histograma,  105  
trigonométrico,  18   selección  aleatoria,  126,  130  
tupla,  115   frecuencias  de  palabras,  127
tupla  como  valor  de  retorno,   Holmes,  Sherlock,  25  
117  tipo,   homófono,  113  
153   hipotenusa,  54
vacío ,  
24  zip,  118  argumento  de   idéntico,  100  
función,  21  llamada  de   identidad,  96,  152  
función,  17,  26  composición   declaración  if,  41  
de  función,  54  definición  de  función,   inmutabilidad,  74,  79,  97,  108,  115,  121  
19,  20,  25  marco  de  función,  23,  26,  44,   implementación,  105,  112,  132,  169  
56,  109  objeto  de   declaración  de  importación,  
función,  27  parámetro  de   26,  144  
función,  21  sintaxis  de   operador,  205  operador  in,  76,  
función,  162  tipo  de   85,  90,  104  incremento,  64,  69,  
función,  20   157,  163  desarrollo  incremental,  60,  193  
modificador,   sangría,  19,  162,  194  índice,  
157  puro,  156  estilo  de  programación  funcional,  158,  16071,  78,  79,  90,  103,  197  bucle  con,  
86,  91  negativo,  72  
función  gamma,  58   rebanada,  73 ,  
reunir,  118,  123,  190 91  a  partir  de  
GCD  (máximo  común  divisor),  61   cero,  71,  90
generalización,  32,  36,  85,  159   IndexError,  72,  78,  90,  197  
expresión  generadora,  185,  186,  191   indexación,  204  
objeto  generador,  185   bucle  infinito,  65,  69,  195,  196  
cambio  de  tamaño   recursividad  infinita,  44,  47,  58,  195,  196  
geométrico,  209   herencia,  176,  178,  180,  190  método  
método  get,  105  función   init,  164,  168,  172,  174,  176  variable  de  
getattr,  168  función   inicialización,  
getcwd,  139  declaración  global,   69  inicialización  
110,  112  variable  global,  110,   (antes  de  actualizar),  64  función  de  
112  actualizar,  110 entrada,  45  instancia,  
Licencia  de  documentación  libre  GNU,  v,  vi   148,  153  como  
máximo  común  divisor  (MCD),  61  cuadrícula,   argumento,  149  
27  patrón   como  valor  devuelto,  
guardián,  59,  60,  78 150  atributo  de  instancia,  148,  153,  172,  
180  instanciar,  
Clase  de  mano,   153  instanciación,  
176  colgando,  195 148  función  int,  17  
relación  HAS­A,  177,  180  función   tipo  int,  4  
hasattr,  153,  168  función  hash,   entero,  4,  7  
108,  112,  207 modo  interactivo,  11,  14,  24
Machine Translated by Google

216 Índice

interfaz,  33,  36,  169,  179   Principio  de  sustitución  de  Liskov,  179  
palabras  entrelazadas,  101   lista,  89,  94,  100,  121,  184  
interpretar,   como  argumento,  
6  intérprete,  2   97  concatenación,  91,  97,  
invariante,  159,  160   101  
invertir  diccionario,  107   copia,  92  
invocación,  76,  79   elemento,  
es  operador,  95,  152 90  vacío,  89  
relación  IS­A,  177,  180  función   función,  
de  instancia,  58,  153,  166  elemento,   94  índice,  90  
74,  79,  89,  103   pertenencia,  
diccionario,  112   90  método,  92  
asignación  de  elemento,  74,  90,   anidado,  89,  91  
116  actualización   de  objetos,  174  
de  elemento,  91   de  tuplas,  119  
método  de   operación,  91  
elementos,  120  iteración,  64,  69  iterador ,  119–121,  123,  204 repetición,  
91  corte,  91  
, 204
transversal,  91  lista  de  
método  de  unión,  95,  175 comprensión,  184,  
191  métodos  
Clase  canguro,  170  
de  lista,  204  literalidad,  
tecla,  103,  112  
5  variable  local,  
par  clave­valor,  103,  112,  120  
22,  26  función  
entrada  de  teclado,  45
de  registro,  18  logaritmo,  
Error  de  clave,  104,  197  
, 206 135  logarítmico  
crecimiento,  
palabra  clave,  10,  14,  194  
def,  19   203  operador  lógico,  40  búsqueda,  112  búsqueda,  diccionario,  106
elif,  42   LookupError,  107  
else,  41   loop,  31,  36,  65,  119  
condition,  196  
argumento  de  palabra  clave,  33,  36,  191
curva  de  Koch,  49 for,  30,  44,  72,  91  
infinite,  65,  196  
lenguaje   nested,  174  
formal,  4   transversal,  
natural,  4   72  while,  
seguro,  13 64  loop  variable,  184  
Turing  completo,  55   looping  
coeficiente  principal,  202   con  diccionarios,  106  
término  principal,  202,   con  índices,  86,  91  
209  acto  de  fe,  57   con  cadenas,  75  
función  len,  26,  72,  104   bucles  y  conteos,  75  lenguaje  
frecuencia  de  letras,   de  bajo  nivel,  6  ls  
123  rotación  de  letras,   (comando  Unix),  142
80,  113  
lineal,  209  crecimiento   modelo  de  máquina,  201,  
lineal,  203  búsqueda   209  principal,  23,  43,  
, lineal,  205  206 110,  144  mantenible,  
Linux,  25   169  patrón  de  mapa,  
lipograma,  84 93,  100  mapa  a,  171
Machine Translated by Google

Índice 217

cartografía,  112,  131 método,  lista,  92
análisis  de  Markov,  130   Meyers,  Chris,  función  
mash­up,  132   vi  min,  117,  118
función  matemática,   Moby  Project,  83  
18  matplotlib,  135   modelo,  mental,  199  
función  máxima,  117,  118 modificador,  157,  160  
McCloskey,  Robert,  73  md5,   módulo,  18,  26  
143 bisecar,  101  
algoritmo  MD5,  146   colecciones,  187,  188,  190  
md5sum,  146   copiar,  151  
búsqueda   fecha  y  hora,  160  
binaria  de  membresía,   dbm,  141  
101  búsqueda  de   os,  139  
bisección,  101   pickle,  137,  142  
pprint,  112  
perfil ,  133  
diccionario,  104   aleatorio,  101,  126,  175  
lista,  90  conjunto,  113   recargar,  144,  195  
memo,  109,  112  modelo  mental,  199   dejar  de  lado,  
metáfora,  invocación   142  cadena,  
de  método,  163  metátesis,  123   125  forma  de  
método,  36,  75,   estructura,  
161 ,  169  __cmp__,   122  tiempo,  101  objeto  de  
173   módulo,  18,  143  módulo,  
__str__,  165,  174  agregar,  165   escritura,  143  operador  de  módulo,  39,  47
agregar,  92,  97,  101,   Monty  Python  y  el  Santo  Grial,  156
174,  175   MP3,  146  
cerrar,  138,   mro  method,  179  
141,  143   multiline  string,  35,  194  
contar,  79  extender,  92   multiplicity  (in  class  diagram),  178,  181  multiset,  
obtener,  105   187  mutability,  
iniciar,  164,   74,  90,  92,  96,  111,  115,  121,  151  mutable  object,  as  
172,  174,   default  value,  170
176  elementos ,  
120  unirse,   nombre  variable  incorporada,  144  
95,  175   tupla  nombrada,  190
mro,  179  pop,  94,   Error  de  nombre,  22,  197
175  radd,  167   NaN,  183  
leer,  143  leer   lenguaje  natural,  4,  7  índice  
línea,  83,  143   negativo,  72  condicional  
eliminar,  94   anidado,  42,  47  lista  anidada,  
reemplazar,  125   89,  91,  100  nueva  línea,  45,  
establecer   175
por  defecto,  113   método  de  Newton,  66
ordenar,  92,  99,   Ninguno  valor  especial,  24,  26,  52,  92,  94
176  dividir,  95,   NingunoTipo  tipo,  24  no  
117  cadena,   operador,  40  
79   número,  aleatorio,  126
despojar,  84,  125  traducir,  125  
actualizar,  120  valores,  104  anular,  92  orden  de  resolución  dObama,   Barack,  
179  s2
el  método,   01 del  método,  162
intaxis  
Machine Translated by Google

218 Índice

objeto,  74,  79,  95,  96,  100   u  operador,  40  
bytes,  141,  145   orden  de  crecimiento,  202,  
clase,  147,  148,  153,  190   209  orden  de  operaciones,  11,  14,  
copiando,  151 199  módulo  os,  
Contador,  187   139  otro  (nombre  del  parámetro),  164
base  de  datos,   OverflowError,  46  
141  predeterminado,   sobrecarga,  169  
188  incrustado,  150,  153,  170   anular,  129,  134,  165,  173,  176,  179
enumerar,  119  
archivo,  83,   palíndromo,  61,  80,  86,  88  
87  función,  27   parámetro,  21,  23,  26,  97  
generador,  185   recopilar,  
módulo,  143   118  opcional,  129,  
mutable,  151   165  otro,  
tupla  con  nombre,   164  uno  
190   mismo,  163  clase  
tubería,  145   principal,  176,  
impresión,   180  paréntesis  
162   argumento  en,  
conjunto,  186  zip,  123  diagrama  de  objetos,  148,   17  vacío,  19,  76  
150,  152,  153,  155,  173  diseño   parámetros  en ,  21,  22  
orientado  a  objetos,  169  lenguaje   entrada  de  
orientado  a  objetos,  169  programación  orientada  a   clase  
principal,  176  tuplas,  
objetos,  147,  161,  169,  176  odómetro,  88 115  análisis,  5,  
Olin  College,   7  declaración  
función  abierta  v,  83,  84,  137,  140,  141   de  aprobación,  
operando,  14   41  ruta,  
operador,  7   139,  145  absoluta,  
y,  40   139  relativa,  139  filtro  
aritmética,  3   de  patrón,  93,  
bit  a  bit,  3   100,  184  guardián,  
booleano,  76   59,  60,  78  mapa,  93,  100  
corchete,  71,  90,  116   reducir,  93,  
del,  94   100  buscar,  75,  79,  85,  107,  186  intercambiar,  116  pdb  (depurador  de  Python),  197
formato,  138,  145,  197   PEMDAS,  11  
en,  76,  85,  90,  104   permiso,  archivo,  140  
es,  95,  152   persistencia,  137,  145  
lógico,  40   pi,  18,  70  
módulo,  39,  47  no,   módulo  de  decapado,  137,  
40  o,   142  decapado,  
40   142  pie,  
sobrecarga,  169   37  tubería,  
relacional,  40,  173   142  objeto  de  
rebanada,  73,  79,  91,  98,   tubería,  145  texto  sin  
116   formato,  83,  125  desarrollo  
cadena,  12   planificado,  158  poesía,  5
actualización,  93  sobrecarga  del   Clase  de  puntos,  148,  
operador,  166,  173  argumento  opcional,  76,   165  puntos,  matemática,  147  
79,  95,  107,  184  parámetro  opcional,  129,  165 póquer,  171,  181
Machine Translated by Google

Índice 219

función  poligonal,  31   programación  de  recorrido  aleatorio,  134,  200  
polimorfismo,  168,  169  método   rango,  171  
pop,  94,  175  función  popen,   método  de  lectura,  143  
142  portabilidad,  6   método  readline,  83,  143  
argumento   reasignación,  63,  68,  90,  110
posicional,  164,  169,  190  postcondición,  36,   Clase  de  rectángulo,  149  
59,  179  módulo  pprint,  112   recursión,  43,  47,  55,  57  caso  
precedencia,  199   base,  44  infinito,  
precondición,  36,  37,   44,  58,  196  definición  
59,  179  prefijo,  131  letra  bonita,  112   recursiva,  56,  124  árbol  rojo­negro,  
función  de   206  patrón  reducido,  93,  
impresión,  3   100  palabra  reducible,  113,  
declaración  de   124  reducción  a  un  problema  
impresión,  3,  7,  165,  197  resolución  de   previamente  resuelto,  85  reducción  a  un  problema  
problemas,  1,  6  módulo  de  
perfil,  133  programa,  1,  6   previamente  resuelto,  87  redundancia,  5  refactorización,  34–
prueba  de   36,  

programa,  87  función   180  referencia,  96,  
definida  por  el  programador,  22,  129  tipo  definido   97,  100  aliasing,  96  refrito,  208  
por  el  programador,  147,  153,  155,  162,  165,  173 operador  relacional,  40,  173  
ruta  relativa,  
Proyecto  Gutenberg,  125   139,  145  recargar  
indicador,  2,  6,  45   función,  144,  195  eliminar  método,  
prosa,  5   94  repetición,  30  lista,  91  
prototipo  y  parche,  156,  158,  160   reemplazar  método,  125  repr  
pseudoaleatorio,  126,  134  función   función,  144  representación,  
pura,  156,  160 147,  149,  171  
Rompecabezas,  88,  113,  124

teorema  de  Pitágoras,  52 declaración  de  retorno,  44,  
Pitón   51,  199  valor  de  retorno,  
corriendo,  2 17,  26,  51,  150  tupla,  117  búsqueda  
Pitón  2,  2,  3,  33,  40,  45 inversa,  112  búsqueda  inversa,  
Python  en  un  navegador,  2 diccionario,  106  par  de  palabras  
Python  en  cualquier  lugar,  2 inversas,  101  
función  inversa,  121  
cuadrático,  209   rotación
crecimiento  cuadrático,  203  
comillas,  3,  4,  35,  74,  194

método  radd,  167   letras,  113  
radianes,  18   rotación,  carta,  80  
radix  sort,  201   depuración  de  patitos  de  goma,  134  
rage,  200   ritmo  de  ejecución,  8,  15,  160  
declaración  de  aumento,  107,  112,  159 ejecutando  Python,  2  
Ramanujan,  Srinivasa,  70  función   errores  de  tiempo  de  ejecución,  13,  44,  46,  193,  196
aleatoria,  101,  126  función  aleatoria,   Error  de  tiempo  de  ejecución,  45,  58

126  módulo  aleatorio,  101,  
126,  175  número  aleatorio,  126  texto   lenguaje  seguro,  13  
aleatorio,  131 control  de  cordura,  111  
andamios,  53,  60,  112
Machine Translated by Google

220 Índice

dispersión,  118,  123,  191 soporte  ondulado,  
Schmidt,  Eric,  201 clasificación  
Scrabble,  123   estable  103,  diagrama  de  pila  205,  diagrama  de  
guión,  11,  14   estado  23,  26,  37,  44,  56,  60,  97,  9,  14,  63,  78,  90,  96,  108,  120,
modo  guión,  11,  14,  24   148,  150,  152,  155,  173  
búsqueda,  107,  205,  209   declaración,  10,  14  
patrón  de  búsqueda,  75,  79,  85,  186   afirmación,  159,  
búsqueda,  binario,  101   160  asignación,  9,  63  
búsqueda,  bisección,  101   descanso,  
auto  (nombre  del  parámetro),  163   66  compuesto,  
error  semántico,  13,  14,  193,  198   41  condicional,  41,  47,  55,  184  
semántica,  14,  162   para,  30,  72,  91  
secuencia,  4,  71,  79,  89,  94,  115,  121   global,  110,  112  si,  
conjunto,  130,   41  
186  anagrama,  123,   importar,  26,  144  
145  conjunto  de   pasar,  41  
pertenencia,  113   imprimir,  3,  7,  165,  197  
conjunto  resta,   subir,  107,  112,  159  
186  conjunto  predeterminado,   volver,  44,  51,  199  
189  método   intentar,  140,  
predeterminado,  113   153  
sexagesimal,   mientras,  64  tamaño  de  paso,  79
158  copia  superficial,   StopIteration,  185  
152,  153  forma,   función  str,  18  
123  error  de  forma,  122   método  __str__,  165,  174  
shell,  142,  145  módulo   cadena,  4,  7,  94,  121  
de  estantería,  142   acumulador,  175  
función  aleatoria,  175  función   comparación,  77  
sinusoidal,   vacío,  95  
18  singleton,   inmutable,  74  
108,   método,  75  
112,  115   multilínea,  35,  194  
rebanada,   operación,  12  
79  copia,  74,   rebanada,  
92  lista,  91  cadena,  73  tupla,  116   73  triple­  citado,  35  
actualización,  92  operador  de   concatenación  de  cadenas,  
204  método  de  
segmento,  73,  79,  91,  98,   cadena,  79  métodos  de  
116  método  de   cadena,  204  módulo  
ordenación,  92,  99,   de  cadena,  125  representación  de  
176  función  ordenada,   cadena,  144,  
165  
99,  106  función  ordenada,  121  clasificación,  204,  205  caso   tipo  de  
especial,   cadena,  
87,   4   especial
157  valor  
falso,  40 método  de  tira,  84,  125  módulo  
Ninguno,  24,  26,  52,  92,  94 structshape,  
Verdadero,   122  estructura,  5  
40  espiral,   sujeto,  163,  
38  método  dividido,  95,   169  
117  sqrt,   subconjunto,  187  
53  función  sqrt,  18   diccionario  de  restas,  
raíz  cuadrada,  66 129  con  préstamo,  68  resta  con  préstamo,  159
Machine Translated by Google

Índice 221

sufijo,  131   Tesis  de  Turing,  55
traje,  171   Turing,  Alan,  55  
suma,  185   módulo  tortuga,  48  
función  de  suma,  118   máquina  de  escribir  tortuga,  
depuración  supersticiosa,  200  patrón   37  tipo,  4,  7  
de  intercambio,  116   bool,  40  
sintaxis,  5,  7,  13,  162,  194  error   dict,  103  
de  sintaxis,  13,  14,  193 archivo,  
Error  de  sintaxis,  19 137  float,  
4  función,  20  
variable  temporal,  51,  60,  199  caso  de   int,  4  
prueba,  mínimo,  198  pruebas   lista,  89
y   NoneType,  24  
ausencia  de  errores,  87  desarrollo   definido  por  el  programador,  147,  153,  155,  162,  165,  
incremental,  52  es  difícil,  87  saber  la   173  set,  
respuesta,  53   130  str,  4  
salto  de  fe,  57  caso  de  prueba   tuple,  
mínimo,  198 115  
verificación  de  tipos,  58  
texto conversión  de  tipos,  17  
simple,  83,  125   función  de  tipos,  153  
aleatorio,  131   despacho  basado  en  tipos,  166,  167,  169
archivo  de  texto,  145 TypeError,  72,  74,  108,  116,  118,  139,  164,  197  máquina  de  
Clase  de  tiempo,   escribir,  tortuga,  37  error  
155  módulo  de  tiempo,   tipográfico,  134
101  token,  5,  
7  rastreo,  24,  26,  44,  46,  107,  196  método   UnboundLocalError,  110  carácter  
de  traducción,  125  transversal,   de  subrayado,  10  singularidad,  
72,  75,  77,  79,  85,  93,  100,  105,  106,  119,  127  diccionario,   101
168  lista,   comando  Unix  ls,  142  

91  travesía
actualizar,  64,  67,  69  
base  de  datos,  
diccionario,  120   141  variable  global,  110  
triángulo,  48   histograma,  127  
función  trigonométrica,  18  cadena   elemento,  
entre  comillas  triples,  35 91  
Valor  especial  verdadero,  40   segmento,  92  método  de  
declaración  de  prueba,  140,   actualización,  120  operador  
153  tupla,  115,  117,  121,  122   de  actualización,  93  usar  antes  de  definición,  20
como  clave  en  diccionario,  120,  132  
asignación,  116   valor,  4,  7,  95,  96,  112  
comparación,  116,  174  entre   predeterminado,  
paréntesis,  120   129  tupla,  117
singleton,  115   ValueError,  46,  117  
división,   método  de  valores,  104  
116  asignación  de  tupla,  117 ,  119,  122   variable,  9,  14  
función  de  tupla,  115   global,  110  
métodos  de  tupla,  204 local,  22  
Lenguaje  completo  de  Turing,  55 temporal,  51,  60,  199
Machine Translated by Google

222 Índice

actualización,  
64  tupla  de  argumento  de  longitud  variable,  
118  barniz,  175,  
180  función  de  vacío,  24,  
26  método  de  vacío,  
92  vorpal,  55

caminar,  directorio,  140  
while  loop,  64  
espacios  en  blanco,  46,  84,  144,  
194  recuento  de  
palabras,  143  frecuencia  de  
palabras,  125,  134  palabras,  
reducible,  113,  124  directorio  
de  trabajo,  139  
peor  error,  170  peor  de  los  casos,  202,  209

cero,  índice  que  comienza  en,  
71  cero,  índice  que  comienza  
en,  90  función  zip,  
118  usar  con  dict,  120  
objeto  zip,  123
ley  de  Zipf,  134

Common questions

Con tecnología de IA

El principio de sustitución de Liskov establece que las instancias de clases derivadas deben poder reemplazar las de la clase base sin alterar el correcto funcionamiento del programa. Es crucial para la herencia, permitiendo que las clases secundarias extiendan y modifiquen comportamientos de manera coherente y predecible .

El "salto de fe" es un concepto de lectura de programas que implica asumir que una función funciona correctamente y devuelve el resultado correcto sin seguir todo el flujo detallado de ejecución. Se aplica en funciones recursivas al confiar en que las llamadas recursivas funcionan correctamente, permitiendo así centrarse en el resultado final sin enredarse en la complejidad del flujo de ejecución .

Dividir programas en funciones más pequeñas crea puntos de control naturales que hacen el flujo de ejecución más visible y manejable. Esto permite realizar pruebas específicas de partes del código, mejorando la identificación y corrección de errores .

El patrón "map" aplica una función a cada elemento en una secuencia, transformando la lista. "Filter" recorre la lista y selecciona elementos que cumplen con un criterio definido. "Reduce" combina elementos de una lista en un único valor, siendo útil para acumulaciones como sumas o productos .

Una copia superficial copia el objeto y sus referencias, pero no los objetos embebidos, lo cual es suficiente cuando no se precisa modificar objetos internos. Por otro lado, una copia profunda copia el objeto y todos los objetos a los que éste hace referencia, siendo preferible cuando se requiere modificar tales objetos sin alterar el original .

Para resolver problemas de recursión infinita, se recomienda asegurarse de que la función tenga un caso base claro y añadir declaraciones de impresión para rastrear los parámetros y el flujo de ejecución. Esto ayuda a identificar por qué el caso base no se alcanza. Si los parámetros no cambian adecuadamente para alcanzar el caso base, es necesario repensar el algoritmo .

Las funciones guardián utilizan condicionales para proteger el código de valores que podrían causar errores. Actúan como una primera línea de defensa, descartando inputs incorrectos antes de procesarlos, lo cual facilita la identificación y corrección de errores en una etapa temprana del flujo de ejecución .

Las clases secundarias heredan atributos y métodos de las clases principales, permitiendo la reutilización de código mientras se especializan en comportamientos específicos. La encapsulación permite que los detalles de implementación se oculten en la clase principal, garantizando que las clases secundarias cumplan con las interfaces definidas, manteniendo así la integridad del modelo de objetos .

Las condiciones previas son requisitos que deben cumplirse antes de ejecutar una función, mientras que las condiciones posteriores aseguran que la función proporcione resultados válidos. Se verifica mediante declaraciones al inicio y fin de la función, por ejemplo, confirmando tipos de datos o rangos numéricos válidos .

La programación orientada a objetos organiza código y datos mediante la creación de tipos definidos por el programador, o clases, que representan entidades del mundo real. Esto permite modularidad, reutilización de código, y una representación más intuitiva de problemas complejos al encapsular estado y comportamiento en objetos .

Piensa  en  Python
2.ª  edición,  versión  2.4.0
Cómo  pensar  como  un  científico  informático
Machine Translated by Google
Machine Translated by Google
Piensa  en  Python
2.ª  edición,  versión  2.4.0
Cómo  pensar  como  un  científico  informático
allen  downey
Prensa  de  té
Prensa  de  té  verde
.
Derechos  de  autor  ©  2015  Allen  Downey.
Se  otorga  permiso  para  copiar,  distribuir  y/o  mod
Prefacio
Necesitaba  un  título,  así  que  por  capricho  elegí  Cómo  pensar  como  un  científico  informático.
•  Que  se
Expresiones  de  gratitud
El  resultado  es  este  libro,  ahora  con  el  título  menos  grandioso  Think  Python.  Algunos 
Lista  de  colaboradores
función  en  la  Sección  3.10.
•  Jonah  Cohen  escribió  los  scripts  de  Perl  para  convertir  
•  Chris  Wrobel  hizo  correcciones  al  código  en  el  capítulo  sobre  E/S  de  archivos  y  excepciones.
•  Tauhidul  Ho
•  C.  Corey  Capel  detectó  la  palabra  que  faltaba  en  el  Tercer  Teorema  de  Depuración  y  un  error  tipográfico  
X
•  Nick  King  encontró  una  palabra  que  faltaba.
.
demasiado  temprano.  Y
•  Jeff  Paine  conoce  la  diferencia  entr

También podría gustarte