python

Page 1

Pythonparatodos ExplorandolainformaciónconPython3 CharlesR.Severance

Créditos

SoporteEditorial:ElliottHauser,SueBlumenberg Diseñodeportada:TobyKoening,AimeeAndrion Contribuidores:JuanCarlosPerezCastellanos,JuanDougnac, DanielMerinoEcheverría,JaimeBermeoRamírezyFernandoTardío.

Historialdeimpresión

•02-Abr-2020TraducciónalEspañolcompletadePython3.0

•05-Jul-2016PrimeraversióncompletadePython3.0

•20-Dic-2015BorradorinicialdeconversiónaPython3.0

DetallesdeCopyright

Copyright~2009-CharlesSeverance.

EstetrabajoestáregistradobajounaLicenciaCreativeCommonsAttributionNonCommercial-ShareAlike3.0UnportedLicense.Estelicenciaestádisponible en http://creativecommons.org/licenses/by-nc-sa/3.0/

Puedesverloqueelautorconsiderausoscomercialesyno-comercialesdeeste material,asícomolasexencionesdelicenciaenelApéndicetitulado“Detallesde Copyright”.

Prólogo

RemezclandounLibroLibre

Sesueledecirdelosacadémicosdeben“publicaroperecer”continuamente,de modoqueesbastantenormalquesiemprequieranempezaralgodesdecero,para queseasupropiayflamantecreación.Estelibroesunexperimento,yaqueno partedesdecero,sinoqueenvezdeeso“remezcla”ellibrotitulado ThinkPython: HowtoThinkLikeaComputerScientist (PiensaenPython:Cómopensarcomo uncientíficodelacomputación),escritoporAllenB.Bowney,JeffElkner,yotros.

EnDiciembrede2009,yomeestabapreparandoparaenseñar SI502-ProgramaciónenRed enlaUniversidaddeMichiganporquintosemestreconsecutivo,y decidíqueyaerahoradeescribirunlibrodetextosobrePythonquesecentrase enlaexploracióndedatosenlugardeenexplicaralgoritmosyabstracciones.Mi objetivoenSI502esenseñaralagentehabilidadespermanentesparaelmanejo dedatosusandoPython.Pocosdemisestudiantespretendenllegaraserprogramadoresdecomputadorasprofesionales.Envezdeeso,quierenserbibliotecarios, gerentes,abogados,biólogos,economistas,etc.,quetalvezquieranaplicar eluso delatecnologíaensusrespectivoscampos.

Parecíaquenopodríaencontrarellibroperfectoparamicurso,queestuviera orientadoalmanejodedatosenPython,demodoquedecidíempezaraescribirlo pormimismo.Porsuerte,enunareunióndeprofesorestressemanasantesdelas vacaciones,queeralafechaenqueteníaplaneadoempezaraescribirmilibrodesde cero,elDr.AtulPrakashmemostróellibro ThinkPython (PiensaenPython), queélhabíautilizadoparaimpartirsucursodePythonesesemestre.Setrata deuntextodeCienciasdelaComputaciónbienescrito,conunenfoquebreve, explicacionesdirectasyfácildeaprender.

Laestructuraprincipaldellibrosehacambiado,paraempezararealizarproblemas deanálisisdedatosloantesposible,yparatenerunaseriedeejemplosfuncionales ydeejerciciossobreelanálisisdedatosdesdeelprincipio.

Loscapítulos2-10sonsimilaresalosdellibro ThinkPython,perohahabido cambiosimportantes.Losejemplosorientadosanúmerosylosejerciciossehan reemplazadoporotrosorientadosadatos.Lostemassepresentanenelorden necesarioparaircreandosolucionesdeanálisisdedatoscuyacomplejidadaumente progresivamente.Algunostemascomo try y except (manejodeexcepciones) sehanadelantado,ysepresentancomopartedelcapítulodeloscondicionales. Lasfuncionessetratanmuyporencimahastaquesonnecesariasparamanejar programascomplejos,enlugardeintroducirlascomoabstracciónenlasprimeras lecciones.Casitodaslasfuncionesdefinidasporelusuariosehaneliminadodel códigodelosejemplosydelosejerciciosexceptoenelcapítulo4.Lapalabra “recursión”1 noapareceentodoellibro.

Todoelcontenidodelcapítulo1ydel11al16esnuevo,centradoenaplicaciones paraelmundorealyenejemplossimplesdelusodePythonparaelanálisisde datos,incluyendoexpresionesregularesparabúsquedayanálisis,automatización detareasenlacomputadora,descargadedatosatravésdelared,escaneodepáginaswebpararecuperardatos,programaciónorientadaaobjetos,usodeservicios

1 Excepto,porsupuesto,enesalínea.

iii

web,análisisdedatosenformatoXMLyJSON,creaciónyusodebasesdedatos usandoelLenguajedeConsultasEstructurado(SQL),ylavisualizacióndedatos.

Elobjetivofinaldetodosestoscambiosesvariarlaorientación,desdeunadirigida alasCienciasdelaComputaciónhaciaotrapuramenteinformática,quetrate sólotemasadecuadosparaunaclasedetecnologíaparaprincipiantes,quepuedan resultarlesútilesinclusosieligennoserprogramadoresprofesionales.

Losestudiantesqueencuentrenestelibrointeresanteyquieranirmásallá,deberíanecharunvistazoallibro ThinkPython deAllenB.Downey’s.Comoambos libroscompartenunmontóndemateria,losestudiantesadquiriránrápidamente habilidadesenlasáreasadicionalesdelaprogramacióntécnicaypensamientoalgorítmicoquesetratanen ThinkPython.Ydadoqueamboslibroscompartenun estilodeescriturasimilar,deberíansercapacesdeavanzarrápidamenteatravés delcontenidode ThinkPython conunesfuerzomínimo.

Comopropietariodelcopyrightde ThinkPython,Allenmehadadopermisopara cambiarlalicenciadelcontenidodesulibroqueseutilizaenéste,yqueoriginalmenteposeíauna GNUFreeDocumentationLicense aotramásactual,Creative CommonsAttribution—ShareAlikelicense.Asísesigueunatendenciageneral enlaslicenciasdedocumentaciónabierta,queestánpasandodesdelaGFDLala CC-BY-SA(porejemplo,Wikipedia).ElusodelalicenciaCC-BY-SAmantiene laarraigadatradición copyleft dellibro,alavezquehacenmássencilloparalos autoresnuevoslareutilizacióndeesematerialasuconveniencia.

Personalmentecreoqueestelibrosirvecomoejemplodeporquéloscontenidos libressontanimportantesparaelfuturodelaeducación,yquieroagradecera AllenB.Downeyyala CambridgeUniversityPress porsuamplituddemiras alahoradedistribuirellibrobajouncopyrightabierto.Esperoquesesientan satisfechosconelresultadodemisesfuerzosydeseoquetúcomolectortambién tesientassatisfechode nuestros esfuerzoscolectivos.

QuieroagradeceraAllenB.DowneyyLaurenCowlessuayuda,pacienciayorientaciónalahoradetrataryresolverlosproblemasdecopyrightreferentesa este libro.

CharlesSeverance www.dr-chuck.com AnnArbor,MI,USA 9deSeptiembre,2013

CharlesSeveranceesProfesorClínicoAdjuntoenlaEscueladeInformación(School ofInformation)delaUniversidaddeMichigan.

iv
Contents 1¿Porquédeberíasaprenderaescribirprogramas? 1 1.1Creatividadymotivación....................... 2 1.2Arquitecturahardwaredelascomputadoras............. 3 1.3Comprendiendolaprogramación................... 4 1.4Palabrasyfrases............................ 5 1.5ConversandoconPython....................... 6 1.6Terminología:intérpreteycompilador................ 8 1.7Escribiendounprograma....................... 10 1.8¿Quéesunprograma?.......................... 11 1.9Losbloquesdeconstruccióndelosprogramas............ 12 1.10¿Quéesposiblequevayamal?.................... 13 1.11Depurandolosprogramas....................... 15 1.12Elcaminodelaprendizaje....................... 16 1.13Glosario................................. 17 1.14Ejercicios................................ 17 2Variables,expresionesysentencias 19 2.1Valoresytipos............................. 19 2.2Variables................................ 20 2.3Nombresdevariablesypalabrasclaves................ 21 2.4Sentencias................................ 22 2.5Operadoresyoperandos........................ 22 2.6Expresiones............................... 23 2.7Ordendelasoperaciones....................... 24 2.8Operadormódulo........................... 24 2.9Operacionesconcadenas....................... 25 v
vi CONTENTS
2.10Peticióndeinformaciónalusuario.................. 25 2.11Comentarios.............................. 26 2.12Eleccióndenombresdevariablesmnemónicos............ 27 2.13Depuración............................... 29 2.14Glosario................................. 29 2.15Ejercicios................................. 31 3Ejecucióncondicional 33 3.1Expresionesbooleanas......................... 33 3.2Operadoreslógicos........................... 34 3.3Ejecucióncondicional......................... 34 3.4Ejecuciónalternativa......................... 36 3.5Condicionalesencadenados...................... 36 3.6Condicionalesanidados........................ 37 3.7Capturadeexcepcionesusandotryyexcept............ 38 3.8Evaluaciónencortocircuitodeexpresioneslógicas......... 40 3.9Depuración................................ 41 3.10Glosario................................. 42 3.11Ejercicios................................ 43 4Funciones 45 4.1Llamadasafunciones......................... 45 4.2Funcionesinternas........................... 45 4.3Funcionesdeconversióndetipos................... 46 4.4Funcionesmatemáticas........................ 47 4.5Númerosaleatorios........................... 48 4.6Añadiendofuncionesnuevas...................... 49 4.7Definiciónyusos............................ 50 4.8Flujodeejecución............................ 51 4.9Parámetrosyargumentos....................... 52 4.10Funcionesproductivasyfuncionesestériles............. 53 4.11¿Porquéfunciones?.......................... 54 4.12Depuración............................... 55 4.13Glosario................................. 55 4.14Ejercicios................................ 57
CONTENTS vii 5Iteración 59 5.1Actualizacióndevariables....................... 59 5.2Lasentencia while ........................... 59 5.3Buclesinfinitos............................. 60 5.4“Buclesinfinitos”y break 61 5.5Finalizariteracionescon continue .................. 62 5.6Buclesdefinidosusando for 62 5.7Diseñosdebucles........................... 63 5.7.1Buclesderecuentoysuma.................. 64 5.7.2Buclesdemáximosymínimos................ 65 5.8Depuración............................... 66 5.9Glosario................................. 67 5.10Ejercicios................................ 67 6Cadenas 69 6.1Unacadenaesunasecuencia..................... 69 6.2Obtenereltamañodeunacadenausando len 70 6.3Recorriendounacadenamedianteunbucle............. 70 6.4Rebanadodeunacadena........................ 71 6.5Loscadenassoninmutables...................... 72 6.6Iterandoycontando.......................... 72 6.7Eloperador in 73 6.8Comparacióndecadenas....................... 73 6.9Métodosdecadenas.......................... 73 6.10Analizandocadenas.......................... 76 6.11Eloperadordeformato........................ 77 6.12Depuración............................... 78 6.13Glosario................................. 79 6.14Ejercicios................................ 79 7Archivos 81 7.1Persistencia................................ 81 7.2Abrirarchivos............................. 82 7.3Archivosdetextoylíneas....................... 83 7.4Lecturadearchivos.......................... 84
viii CONTENTS
7.5Búsquedaatravésdeunarchivo................... 85 7.6Permitiendoalusuarioelegirelnombredearchivo......... 88 7.7Utilizando try,except, y open 88 7.8Escrituradearchivos......................... 90 7.9Depuración................................ 91 7.10Glosario.................................. 91 7.11Ejercicios................................ 92 8Listas 95 8.1Unalistaesunasecuencia....................... 95 8.2Laslistassonmutables........................ 96 8.3Recorriendounalista......................... 96 8.4Operacionesdelistas.......................... 97 8.5Rebanadodelistas........................... 98 8.6Métodosdelistas............................ 98 8.7Eliminandoelementos......................... 99 8.8Listasyfunciones........................... 100 8.9Listasycadenas............................. 101 8.10Analizandolíneas........................... 102 8.11Objetosyvalores............................ 103 8.12Alias................................... 104 8.13Listascomoargumentos........................ 104 8.14Depuración............................... 106 8.15Glosario................................. 109 8.16Ejercicios................................ 110 9Diccionarios 113 9.1Diccionariocomounconjuntodecontadores............ 115 9.2Diccionariosyarchivos........................ 116 9.3Buclesydiccionarios.......................... 118 9.4Análisisavanzadodetexto...................... 119 9.5Depuración................................ 121 9.6Glosario.................................. 121 9.7Ejercicios................................ 122

10Tuplas 125 10.1LasTuplassoninmutables...................... 125 10.2Comparacióndetuplas........................ 126 10.3Asignacióndetuplas.......................... 128 10.4Diccionariosytuplas.......................... 129 10.5Asignaciónmúltiplecondiccionarios................. 130 10.6Laspalabrasmáscomunes....................... 131 10.7Usodetuplascomoclavesendiccionarios.............. 132 10.8Secuencias:cadenas,listas,ytuplas-¡Diosmío!.......... 133 10.9Depuración............................... 133 10.10Glosario................................. 134 10.11Ejercicios................................ 134 11Expresionesregulares 137 11.1Coincidenciadecaracteresenexpresionesregulares......... 138 11.2Extrayendodatosusandoexpresionesregulares........... 139 11.3Combinandobúsquedayextracción................. 142 11.4EscapadodeCaracteres........................ 146 11.5Resumen................................ 146 11.6SecciónadicionalparausuariosdeUnix/Linux.......... 147 11.7Depuración............................... 148 11.8Glosario................................. 149 11.9Ejercicios................................ 149

CONTENTS ix
12.3RecepcióndeunaimagenmedianteHTTP.............
12Programasenred 151 12.1ProtocolodeTransportedeHipertexto-HTTP........... 151 12.2Elnavegadorwebmássencillodelmundo.............. 152
154 12.4Recepcióndepáginaswebcon urllib 156 12.5Leyendoarchivosbinarioscon urllib ................ 157 12.6AnálisistheHTMLyrascadodelaweb............... 159 12.7AnálisisdeHTMLmedianteexpresionesregulares......... 159 12.8AnálisisdeHTMLmedianteBeautifulSoup.............. 161 12.9SecciónextraparausuariosdeUnix/Linux............ 164 12.10Glosario................................. 164 12.11Ejercicios................................ 165
x CONTENTS
14.11Resumen................................
14.12Glosario.................................
15BasesdedatosySQL 199 15.1¿Quéesunabasededatos?...................... 199 15.2Conceptossobrebasesdedatos....................
15.3NavegadordebasesdedatosparaSQLite..............
15.4Creacióndeunatablaenunabasededatos..............
15.5ResumendeLenguajedeConsultasEstructurado..........
15.6RastreoenTwitterusandounabasededatos............
13UsodeServiciosWeb 167 13.1eXtensibleMarkupLanguage-XML................. 167 13.2AnálisisdeXML............................ 168 13.3Desplazamientoatravésdelosnodos................ 169 13.4JavaScriptObjectNotation-JSON................. 170 13.5AnálisisdeJSON............................ 171 13.6Interfacesdeprogramacióndeaplicaciones............. 172 13.7SeguridadyusodeAPIs....................... 174 13.8Glossary................................. 174 13.9AplicaciónNº1:ServiciowebdegeocodificacióndeGoogle.... 175 13.10Aplicación2:Twitter......................... 178 14ProgramaciónOrientadaaObjetos 185 14.1Manejandoprogramasmásgrandes................. 185 14.2Cómoempezar............................. 186 14.3Usandoobjetos............................. 186 14.4Comenzandoconprogramas..................... 187 14.5Subdividiendounproblema...................... 189 14.6NuestroprimerobjetodePython................... 190 14.7Clasescomotipos........................... 192 14.8Ciclodevidadeunobjeto...................... 193 14.9Múltiplesinstancias.......................... 194 14.10Herencia................................ 195
196
197
200
200
201
204
205 15.7Modeladodedatosbásico........................ 211 15.8Programaciónconmúltiplestablas.................. 213

15.8.1Restriccionesentablasdebasesdedatos.......... 216

15.8.2Recuperary/oinsertarunregistro.............. 217

15.8.3Almacenarlasrelacionesentreamigos............ 218

15.9Trestiposdeclaves.......................... 219 15.10UsodeJOINpararecuperardatos.................. 219 15.11Resumen................................ 222 15.12Depuración............................... 223 15.13Glosario................................. 223

16Visualizacióndedatos 225

16.1MapadeGoogleapartirdedatosgeocodificados.......... 225 16.2Visualizaciónderedeseinterconexiones............... 228 16.3Visualizacióndedatosdecorreo................... 230

AColaboraciones 237

A.1ContributorListforPythonparatodos............... 237

A.2ContributorListforPythonforEverybody............. 237

A.3Listadecolaboradoresde“PythonparaInformáticos”....... 237

A.4Prefaciopara“ThinkPython”.................... 238

A.5Listadecolaboradoresde“ThinkPython”............. 239

BDetallesdelCopyright 241

CONTENTS xi
xii CONTENTS

¿Porquédeberíasaprender aescribirprogramas?

Escribirprogramas(oprogramar)esunaactividadmuycreativaygratificante. Puedesescribirprogramaspormuchasrazones,quepuedenirdesdemantenerte activoresolviendounproblemadeanálisisdedatoscomplejohastahacerlopor puradiversiónayudandoaotrosaresolverunenigma.Estelibroasumeque todo elmundo necesitasaberprogramar,yqueunavezqueaprendasaprogramarya encontrarásquéquiereshacerconesashabilidadesreciénadquiridas.

Ennuestravidadiariaestamosrodeadosdecomputadoras,desdeequiposportátiles (laptops)hastateléfonosmóviles(celulares).Podemospensarenesascomputadorascomonuestros“asistentespersonales”,quepuedenocuparsedemuchastareas pornosotros.Elhardwareenlosequiposqueusamoscadadíaestádiseñadoesencialmenteparahacernoslamismapreguntadeformaconstante,“¿Quéquieres quehagaahora?”

¿Qué hago a continuación?

¿Qué hago a continuación?

¿Qué hago a continuación?

¿Qué hago a continuación?

Figure1.1:PersonalDigitalAssistant

LosprogramadoressuelenañadirunsistemaoperativoyunconjuntodeaplicacionesalhardwareyasínosproporcionanunAsistenteDigitalPersonalquees bastanteútilycapazdeayudarnosarealizarunagranvariedaddetareas.

Nuestrosequipossonrápidosytienengrandescantidadesdememoria.Podrían resultarnosmuyútilessitansolosupiéramosquéidiomautilizarparaexplicarle alacomputadoraquéesloquequeremosque“hagaahora”.Siconociéramosese idioma,podríamospedirlealaparatoquerealizaseennuestrolugar,porejemplo, tareasrepetitivas.Precisamenteeltipodecosasquelascomputadorassaben hacer mejorsuelensereltipodecosasquelaspersonasencontramospesadasyaburridas.

Chapter1
1

Porejemplo,miralosprimerostrespárrafosdeestecapítulosydimecuáleslapalabraquemásserepite,ycuántasvecessehautilizado.Aunqueseascapazdeleer ycomprenderlaspalabrasenpocossegundos,contarlasteresultarácasidoloroso, porquelamentehumananofuediseñadapararesolveresetipodeproblemas.Para unacomputadoraesjustoalrevés,leerycomprendertextodeuntrozodepapel leseríadifícil,perocontarlaspalabrasydecirtecuántasvecesseharepetidola másutilizadaleresultamuysencillo:

pythonwords.py

Enterfile:words.txt to 16

Nuestro“asistentedeanálisisdeinformaciónpersonal”nosdiráenseguidaquela palabra“que”seusónuevevecesenlosprimerostrespárrafosdeestecapítulo. Elhechodequeloscomputadoresseanbuenosenaquellascosasenlasquelos humanosnolosoneselmotivoporelquenecesitasaprenderahablarel“idioma delascomputadoras”.Unavezqueaprendasestenuevolenguaje,podrásdelegar tareasmundanasatucompañero(lacomputadora),loquetedejarámástiempo paraocupartedelascosasparalasquesólotúestáscapacitado.Túpondrásla creatividad,intuiciónyelingenioenesaalianza.

1.1Creatividadymotivación

Apesardequeestelibronovadirigidoalosprogramadoresprofesionales,la programaciónanivelprofesionalpuedeseruntrabajomuygratificante,tantoa nivelfinancierocomopersonal.Crearprogramasútiles,eleganteseinteligentes paraquelosusenotros,esunaactividadmuycreativa.TucomputadoraoAsistenteDigitalPersonal(PDA1 ),normalmentecontienemuchosprogramasdiferentes pertenecientesadistintosgruposdeprogramadores,cadaunodeelloscompitiendo portuatencióneinterés.Todoselloshacensumejoresfuerzoporadaptarsea tusnecesidadesyproporcionarteunaexperienciadeusuariosatisfactoria.Enocasiones,cuandoelijesunsoftwaredeterminado,susprogramadoressondirectamente recompensadosgraciasatuelección.

Sipensamosenlosprogramascomoelproductodelacreatividaddelosprogramadores,talvezlafigurasiguienteseaunaversiónmásacertadadenuestraPDA:

Figure1.2:ProgramadoresDirigiéndoseaTi

Porahora,nuestraprincipalmotivaciónnoesconseguirdineronicomplaceralos usuariosfinales,sinosimplementeconseguirsermásproductivosanivelpersonal 1 PersonalDigitalAssistanteninglés(N.delT.).

2CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?
¡Elíge me! ¡Elíge me! ¡Elíge me! ¡Elíge me!

enelmanejodedatoseinformaciónqueencontremosennuestrasvidas.Cuandose empiezaporprimeravez,unoesalavezprogramadoryusuariofinaldesuspropios programas.Amedidaqueseganahabilidadcomoprogramador,ylaprogramación sehacemáscreativaparaunomismo,sepuedeempezarapensarendesarrollar programasparalosdemás.

1.2Arquitecturahardwaredelascomputadoras

Antesdequeempecemosaaprenderellenguajequedeberemoshablarparadarle instruccionesalascomputadorasparadesarrollarsoftware,tendremosqueaprenderunpocoacercadecómoestánconstruidosesasmáquinas.Sidesmontarastu computadorao smartphone ymirasesdentroconatención,encontraríaslossiguientescomponentes:

¿Qué hago a continuación?

Dispositivos Entrada Salida

Software Memoria Principal

Unidad Central Procesamiento

Red Memoria Secundaria

Figure1.3:ArquitecturaHardware

Lasdefinicionesdealtoniveldeesoscomponentessonlassiguientes:

•La UnidadCentraldeProcesamiento (oCPU2 )eselcomponentedelacomputadoradiseñadoparaestarobsesionadoconel“¿quéhagoahora?”.Situ equipoestádentrodelaclasificaciónde3.0Gigahercios,significaquelaCPU preguntará“¿Quéhagoahora?”tresmilmillonesdevecesporsegundo.Vas atenerqueaprenderahablarmuyrápidoparamantenerelritmodelaCPU.

•La MemoriaPrincipal seusaparaalmacenarlainformaciónquelaCPU necesitadeformainmediata.Lamemoriaprincipalescasitanrápidacomo laCPU.Perolainformaciónalmacenadaenlamemoriaprincipaldesaparece cuandoseapagaelequipo.

•La MemoriaSecundaria tambiénseutilizaparaalmacenarinformación,pero esmuchomáslentaquelamemoriaprincipal.Laventajadelamemoria secundariaesquepuedealmacenarlainformacióninclusocuandoelequipo estáapagado.Algunosejemplosdememoriasecundariaseríanlasunidades dediscoolasmemoriasflash(quesuelenencontrarseenlos pendrives USB yenlosreproductoresdemúsicaportátiles).

2 CentralProcessingUniteninglés(N.delT.).

1.2.ARQUITECTURAHARDWAREDELASCOMPUTADORAS 3

•Los DispositivosdeEntradaySalida sonsimplementelapantalla,teclado, ratón,micrófono,altavoz, touchpad,etc.Incluyencualquiermododeinteractuarconunacomputadora.

•Actualmente,casitodoslosequipostienenuna ConexióndeRed pararecibir informacióndentrodeunared.Podemospensarenunaredcomoenunlugar dondealmacenaryrecuperardatosdeformamuylenta,quepuedenoestar siempre“activo”.Asíque,enciertosentido,larednoesmásqueuntipode MemoriaSecundaria máslentayavecespocofiable.

Aunquelamayoríadelosdetallesacercadecómofuncionanestoscomponentes esmejordejárselaalosconstructoresdeequipos,resultaútildisponerdecierta terminologíaparapoderreferirnosaellosalahoradeescribirnuestrosprogramas.

Comoprogramador,tutrabajoesusaryorquestarcadaunodeesosrecursospara resolverelproblemadelquetengasqueocuparteyanalizarlosdatosdelosque dispongasparaencontrarlasolución.Comoprogramadorestaráscasisiempre “hablando”conlaCPUydiciéndolequéeslosiguientequedebehacer.Avecesle tendrásquepediralaCPUqueuselamemoriaprincipal,lasecundaria,lared,o losdispositivosdeentrada/salida.

¿Qué hago a continuación?

Dispositivos Entrada Salida

Software Memoria Principal

Unidad Central Procesamiento

Red Memoria Secundaria

Figure1.4:¿Dóndeestás?

Túdeberásserlapersonaquerespondaalapregunta“¿Quéhagoahora?”dela CPU.Peroseríamuyincómodoencogerseunomismohastalos5mm.dealtura eintroducirsedentrodelacomputadorasóloparapoderdarunaordentresmil millonesdevecesporsegundo.Asíqueenvezdeeso,tendrásqueescribirlas instruccionesporadelantado.Esasinstruccionesalmacenadasrecibenelnombrede programa yelactodeescribirlasyencontrarcuálessonlasinstruccionesadecuadas, programar

1.3Comprendiendolaprogramación

Enelrestodeestelibro,intentaremosconvertirteenunapersonaexpertaenel artedeprogramar.Alterminar,tehabrásconvertidoenun programador -talvez nounoprofesional,peroalmenostendráslacapacidaddeencararunproblemade análisisdedatos/informaciónydesarrollarunprogramapararesolverlo.

Enciertomodo,necesitasdoscapacidadesparaserprogramador:

4CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?

•Primero,necesitassaberunlenguajedeprogramación(Python)-debesconocersuvocabularioysugramática.Debessercapazdedeletrearcorrectamentelaspalabrasenesenuevolenguajeysaberconstruir“frases”bien formadas.

•Segundo,debes“contarunahistoria”.Alescribirunrelato,combinaspalabrasyfrasesparacomunicarunaideaallector.Hayunaciertatécnica yarteenlaconstruccióndeunrelato,ylahabilidadparaescribirrelatos mejoraescribiendoyrecibiendociertarespuesta.Enprogramación,nuestro programaesel“relato”yelproblemaqueestástratandoderesolveresla “idea”.

UnavezqueaprendasunlenguajedeprogramacióncomoPython,encontrarás muchomásfácilaprenderunsegundolenguajecomoJavaScriptoC++.Cada nuevolenguajetieneunvocabularioygramáticamuydiferentes,perolatécnica deresolucióndeproblemasserálamismaentodosellos.

Aprenderásel“vocabulario”y“frases”dePythonbastanterápido.Tellevarámás tiempoelsercapazdeescribirunprogramacoherentepararesolverunproblema totalmentenuevo.Seenseñaprogramacióndeformamuysimilaracomoseenseña aescribir.Seempiezaleyendoyexplicandoprogramas,luegoseescribenprogramassencillos,yacontinuaciónsevanescribiendoprogramasprogresivamente más complejosconeltiempo.Enalgúnmomento“encuentrastumusa”,empiezasa descubrirlospatronesportimismoyempiezasavercasideformainstintivacómo abordarunproblemayescribirunprogramapararesolverlo.Yunavezalcanzado esepunto,laprogramaciónseconvierteenunprocesomuyplacenteroycreativo. ComenzaremosconelvocabularioylaestructuradelosprogramasenPython.Ten pacienciasilasimplicidaddelosejemplosterecuerdaacuandoaprendistealeer.

1.4Palabrasyfrases

Adiferenciadeloslenguajeshumanos,elvocabulariodePythonesenrealidad bastantereducido.Llamamosaeste“vocabulario”las“palabrasreservadas”.Se tratadepalabrasquetienenunsignificadomuyespecialparaPython.Cuando Pythonseencuentraestaspalabrasenunprograma,sabequesólotienenunúnico significadoparaél.Másadelante,cuandoescribasprogramas,podrásusartus propiaspalabrasconsignificado,querecibenelnombrede variables.Tendrásgran libertadalahoradeelegirlosnombresparatusvariables,peronopodrásutilizar ningunadelaspalabrasreservadasdePythoncomonombredeunavariable.

Cuandoseentrenaaunperro,seutilizanpalabrasespecialescomo“siéntate”, “quieto”y“tráelo”.Cuandotedirigesaunperroynousasningunadelaspalabras reservadas,loúnicoqueconsiguesesquesetequedemirandoconcaraextrañada, hastaqueledicesunadelaspalabrasquereconoce.Porejemplo,sidices,“Me gustaríaquemásgentesalieraacaminarparamejorarsusaludgeneral”,lo quela mayoríadelosperrosoiríanes:“blablabla caminar blablablabla.”.Esosedebe aque“caminar”esunapalabrareservadaenellenguajedelperro.Seguramente habráquienapuntequeellenguajeentrehumanosygatosnodisponedepalabras reservadas3 . 3 http://xkcd.com/231/

1.4.PALABRASYFRASES 5

Laspalabrasreservadasenellenguajequeutilizanloshumanosparahablarcon Pythonson,entreotras,lassiguientes:

anddelglobalnotwith aselififoryield assertelseimportpass breakexceptinraise classfinallyisreturn continueforlambdatry deffromnonlocalwhile

Esdecir,adiferenciadeunperro,Pythonyaestácompletamenteentrenado.Cada vezledigas“inténtalo”,Pythonlointentaráunaveztrasotrasindesfallecer4 Aprenderemoscuálessonlaspalabrasreservadasycómoutilizarlasensumomento, peroporahoranoscentraremosenelequivalenteenPythonde“habla”(enel lenguajehumano-perro).LobuenodepedirleaPythonquehableesquepodemos inclusoindicarleloquedebedecir,pasándoleunmensajeentrecomillas: print('¡Hola,mundo!')

Yyaacabamosdeescribirnuestraprimeraoraciónsintácticamentecorrectaen Python.Lafrasecomienzaconlafunción print seguidadelacadenadetextoque hayamoselegidodentrodecomillassimples.Lascomillassimplesydoblescumplen lamismafunción;lamayoríadelaspersonasusanlascomillassimples,excepto cuandolacadenadetextocontienetambiénunacomillasimple(quepuedeserun apóstrofo).

1.5ConversandoconPython

Ahoraqueyaconocemosunapalabraysabemoscómocrearunafrasesencillaen Python,necesitamosaprenderainiciarunaconversaciónconélparacomprobar nuestrasnuevascapacidadesconellenguaje.

AntesdequepuedasconversarconPython,deberásinstalarelsoftwarenecesarioen tucomputadorayaprenderainiciarPythonenella.Enestecapítulonoentraremos endetallessobrecómohacerlo,perotesugieroqueconsultes https://es.py4e.com/ ,dondeencontrarásinstruccionesdetalladasycapturassobrecómoconfigurare iniciarPythonensistemasMacintoshyWindows.Sisigueslospasos,llegará unmomentoenqueteencuentresanteunaventanadecomandosoterminal.Si escribesentonces python,elintérpretedePythonempezaráaejecutarseenmodo interactivo,yapareceráalgocomoesto:

Python 3.5.1 (v3.5.1:37a07cee5969,Dec 62015, 01:54:25) [MSCv.190064 bit(AMD64)]onwin32

Type "help", "copyright", "credits" or "license" for moreinformation. >>>

4

Eninglés"inténtalo"es"try",queestambiénunapalabrareservadadentrodellenguaje Python(N.delT.).

6CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?

Elindicador >>> eselmodoquetieneelintérpretedePythondepreguntarte, “¿Quéquieresquehagaahora?”.Pythonestáyapreparadoparamanteneruna conversacióncontigo.Todoloquetienesquesaberescómohablarensuidioma.

Supongamosporejemploqueaúnnoconocesnilaspalabrasnifrasesmássencillas dePython.Puedequequierasutilizarelmétodoclásicodelosastronautascuando aterrizanenunplanetalejanoeintentanhablarconloshabitantesdeesemundo:

>>> Vengoensondepaz,porfavorllévameantetulíder File "<stdin>",line 1

Vengoensondepaz,porfavorllévameantetulíder

^

SyntaxError:invalidsyntax

>>>

Estonosevebien.Amenosquepiensesenalgorápidamente,loshabitantesdel planetasacaránsuslanzas,teensartarán,teasaránsobreelfuegoyalfinalles servirásdecena.

Porsuertecomprasteunacopiadeestelibrodurantetusviajes,asíqueloabres precisamenteporestapáginaypruebasdenuevo:

>>> print('¡Hola,mundo!') ¡Hola,mundo!

Estotienemejoraspecto,demodoqueintentascomunicarteunpocomás:

>>> print('Usteddebesereldioslegendarioquevienedelcielo') Usteddebesereldioslegendarioqueviene del cielo

>>> print('Hemosestadoesperándoledurantemuchotiempo') Hemosestadoesperándoledurantemuchotiempo

>>> print('Laleyendadicequedebeestarustedmuyricoconmostaza') Laleyendadicequedebeestarustedmuyricoconmostaza

>>> print 'Tendremosunfestínestanocheamenosquediga File"<stdin>",line1 print'Tendremosunfestínestanocheamenosquediga ^

SyntaxError:Missingparentheses in callto 'print' >>>

Laconversaciónfuebienduranteunrato,peroencuantocometisteelmásmínimo falloalutilizarellenguajePython,Pythonvolvióasacarlaslanzas.

Enestemomento,tehabrásdadocuentaqueapesardequePythonestremendamentecomplejoypoderoso,ymuyestrictoencuantoalasintaxisquedebes usarparacomunicarteconél,Python no esinteligente.Enrealidadestássolamentemanteniendounaconversacióncontigomismo;esosí,usandounasintaxis adecuada.

Enciertomodo,cuandoutilizasunprogramaescritoporotrapersona,laconversaciónsemantieneentretúyelprogramador,conPythonactuandomeramentede

1.5.CONVERSANDOCONPYTHON 7

intermediario.Pythonesunaherramientaquepermitealoscreadoresdeprogramasexpresarelmodoenquelaconversaciónsupuestamentedebefluir.Ydentro deunospocoscapítulosmás,serásunodeesosprogramadoresqueutilizanPython parahablarconlosusuariosdetuprograma.

Antesdequeabandonemosnuestraprimeraconversaciónconelintérpretede Python,deberíasaprendercualeselmodocorrectodedecir“adiós”alinteractuarconloshabitantesdelPlanetaPython:

>>> adiós

Traceback(mostrecentcalllast): File "<stdin>",line 1, in<module>

NameError:name 'adiós' isnot defined >>> if youdon'tmind,Ineedtoleave File"<stdin>",line1 ifyoudon'tmind,Ineedtoleave ^

SyntaxError:invalidsyntax >>> quit()

Tehabrásfijadoenqueelerroresdiferenteencadaunodelosdosprimerosintentos. Elsegundoerroresdiferenteporque if esunapalabrareservada,ycuandoPython lave,creequeestamosintentandodecirlealgo,peroencuentralasintaxisdela fraseincorrecta.

Laformacorrectadedecirle“adiós”aPythonesintroducir quit() enelsímbolo indicadordelsistema >>>.Seguramentetehubierallevadounbuenratoadivinarlo, asíquetenerestelibroamanoprobablementetehayaresultadoútil.

1.6Terminología:intérpreteycompilador

Pythonesunlenguaje dealtonivel,pensadoparaserrelativamentesencillodeleer yescribirparalaspersonas,yfácildeleeryprocesarparalasmáquinas.Otros lenguajesdealtonivelsonJava,C++,PHP,Ruby,Basic,Perl,JavaScript,ymuchosmás.ElhardwarerealqueestádentrodelaUnidadCentraldeProcesamiento (CPU),noentiendeningunodeesoslenguajesdealtonivel.

LaCPUentiendeúnicamenteunlenguajellamado lenguajedemáquina o código máquina.Elcódigomáquinaesmuysimpleyfrancamentemuypesadodeescribir, yaqueestárepresentadoensutotalidadporsolamentecerosyunos:

Elcódigomáquinaparecebastantesencilloasimplevista,dadoquesólocontiene cerosyunos,perosusintaxisesinclusomáscomplejaymuchomásenrevesada queladePython,razónporlacualmuypocosprogramadoresescribenencódigo máquina.Envezdeeso,sehancreadovariosprogramastraductoresparapermitir alosprogramadoresescribirenlenguajesdealtonivelcomoPythonoJavascript,

8CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?
001010001110100100101010000001111 11100110000011101010010101101101 ...

ysonesostraductoresquienesconviertenlosprogramasacódigomáquina,quees loqueejecutaenrealidadlaCPU.

Dadoqueelcódigomáquinaestáligadoalhardwaredelamáquinaqueloejecuta, esecódigonoes portable (trasladable)entreequiposdediferentetipo.Losprogramasescritosenlenguajesdealtonivelpuedensertrasladadosentredistintas máquinasusandounintérpretediferenteencadaunadeellas,orecompilandoel códigoparacrearunaversióndiferentedelcódigomáquinadelprogramaparacada unodelostiposdeequipo.

Esostraductoresdelenguajesdeprogramaciónformandoscategoríasgenerales: (1)intérpretesy(2)compiladores.

Un intérprete leeelcódigofuentedelosprogramastalycomohasidoescritopor elprogramador,loanaliza,einterpretasusinstruccionessobrelamarcha.Python esunintérpreteycuandoloestamosejecutandodeformainteractiva,podemos escribirunalíneadePython(unafrase),yestelaprocesadeformainmediata, quedandolistoparaquepodamosescribirotralínea.

AlgunasdeesaslíneasleindicanaPythonquetúquieresquerecuerdecierto valorparautilizarlomástarde.Tenemosqueescogerunnombreparaqueese valorsearecordadoyusaremosesenombresimbólicopararecuperarelvalormás tarde.Utilizamoseltérmino variable paradenominarlasetiquetasqueusamos parareferirnosaesosdatosalmacenados. >>> x = 6 >>> print(x) 6 >>> y = x * 7 >>> print(y) 42 >>>

Enesteejemplo,lepedimosaPythonquerecuerdeelvalorseisyuselaetiqueta x paraquepodamosrecuperarelvalormástarde.ComprobamosquePythonha guardadodeverdadelvalorusando print.LuegolepedimosaPythonquerecupere x,lomultipliqueporsieteyguardeelvalorcalculadoen y.Finalmente,lepedimos aPythonqueescribaelvaloractualde y.

ApesardequeestamosescribiendoestoscomandosenPythonlíneaalínea,Python losestátratandocomounasecuenciaordenadadesentencias,enlacuallasúltimas frasessoncapacesdeobtenerdatoscreadosenlasanteriores.Estamos,portanto, escribiendonuestroprimerpárrafosencilloconcuatrofrasesenunordenlógicoy útil.

Laesenciadeun intérprete consisteensercapazdemantenerunaconversación interactivacomolamostradamásarriba.Un compilador necesitaqueleentreguen elprogramacompletoenunfichero,yluegoejecutaunprocesoparatraducirel códigofuentedealtonivelacódigomáquina,traslocualcolocaesecódigomáquina resultantedentrodeotroficheroparasuejecuciónposterior.

EnsistemasWindows,amenudoesosejecutablesencódigomáquinatienenun sufijooextensióncomo“.exe”o“.dll”,quesignifican“ejecutable”y“libreríade

1.6.TERMINOLOGÍA:INTÉRPRETEYCOMPILADOR 9

enlacedinámico”(dynamiclinklibrary)respectivamente.EnLinuxyMacintosh, noexisteunsufijoqueidentifiquedemaneraexclusivaaunficherocomoejecutable.

Siabrierasunficheroejecutableconuneditordetexto,veríasalgocomplemente disparatadoeilegible:

^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@\xa0\x82 ^D^H4^@^@^@\x90^]^@^@^@^@^@^@4^@^@^G^@(^@$^@!^@^F^@ ^@^@4^@^@^@4\x80^D^H4\x80^D^H\xe0^@^@^@\xe0^@^@^@^E ^@^@^@^D^@^@^@^C^@^@^@^T^A^@^@^T\x81^D^H^T\x81^D^H^S ^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@^A\^D^HQVhT\x83^D^H\xe8

Noresultafácilleeroescribircódigomáquina,peroafortunadamentedisponemos de intérpretes y compiladores quenospermitenescribirenlenguajesdealtonivel, comoPythonoC.

Llegadosaestepuntoenlaexplicaciónacercadeloscompiladoreseintérpretes, seguramenteteestaráspreguntandoalgunascosasacercadelpropiointérpretede Python.¿Enquélenguajeestáescrito?¿Estáescritoenunlenguajecompilado? Cuandoescribimos“python”,¿quéocurreexactamente?

ElintérpretedePythonestáescritoenunlenguajedealtonivelllamado“C”. Enrealidad,puedesverelcódigofuentedelintérpretedePythonacudiendoa www.python.org einclusomodificarloatugusto.Quedamos,pues,enquePython esensímismounprogramayqueestácompiladoencódigomáquina.Cuando instalastePythonentucomputadora(oelvendedorloinstaló),colocasteunacopia delcódigomáquinadelprogramaPythontraducidoparatusistema.EnWindows, elcódigomáquinaejecutableparaelintérpretedePythonesprobablementeun ficheroconunnombrecomo:

Enrealidad,esoyaesmásdeloquenecesitassaberparaserunprogramadoren Python,peroalgunasvecesvalelapenacontestarestaspequeñasdudasrecurrentes justoalprincipio.

1.7Escribiendounprograma

EscribircomandosenelintérpretedePythonesunbuenmododeexperimentar conlascapacidadesdePython,peronoeslomásrecomendadoalahoraderesolver problemasmáscomplejos.

Cuandoqueremosescribirunprograma,usamosuneditordetextoparaescribir lasinstruccionesdePythonenunfichero,querecibeelnombrede script.Por convención,losscriptsdePythontienennombresqueterminanen .py.

Paraejecutarelscript,hayqueindicarlealintérpretedePythonelnombredel fichero.EnunaventanadecomandosdeUnixoWindows,escribirías python hola.py,deestemodo:

10CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?
C:\Python35\python.exe

csev$cathola.py print('¡Hola,mundo!') csev$pythonhola.py ¡Hola,mundo! csev$

“csev$”eselindicador(prompt)delsistemaoperativo,yelcomando“cathola.py” nosmuestraqueelarchivo“hola.py”contieneunprogramaconunaúnicalíneade códigoqueimprimeenpantallaunacadenadetexto.

LlamamosalintérpretedePythonylepedimosqueleaelcódigofuentedesdeel archivo“hola.py”,envezdeesperaraquevayamosintroduciendolíneasdecódigo Pythondeformainteractiva.

Habrásnotadoquecuandotrabajamosconunficherononecesitamosincluirel comando quit() alfinaldelprogramaPython.CuandoPythonvaleyendotucódigo fuentedesdeunarchivo,sabequedebepararcuandollegaalfinaldelfichero.

1.8¿Quéesunprograma?

Podemosdefinirun programa,ensuformamásbásica,comounasecuenciade declaracionesosentenciasquehansidodiseñadasparahaceralgo.Inclusonuestro sencilloscript“hola.py”esunprograma.Esunprogramadeunasolalíneayno resultaparticularmenteútil,perosinosajustamosestrictamentealadefinición,se tratadeunprogramaenPython.

Talvezresultemásfácilcomprenderquéesunprogramapensandoenunproblema quepudieraserresueltoatravésdeunprograma,yluegoestudiandocómosería elprogramaquesolucionaríaeseproblema.

SupongamosqueestáshaciendounainvestigacióndecomputaciónoinformáticasocialenmensajesdeFacebook,yteinteresaconocercualeslapalabramásutilizada enunconjuntodemensajes.PodríasimprimirelflujodemensajesdeFacebooky revisarconatencióneltexto,buscandolapalabramáscomún,peroseríaunprocesolargoymuypropensoaerrores.Seríamásinteligenteescribirunprograma enPythonparaencargarsedelatareaconrapidezyprecisión,yasípoderemplear elfindesemanaenhacerotrascosasmásdivertidas.

Porejemplo,fíjateenelsiguientetexto,quetratadeunpayasoyuncoche.Estúdialoytratadeaveriguarcualeslapalabramáscomúnycuántasvecesserepite.

elpayasocorriótraselcocheyelcochesemetiódentrodelatienda ylatiendacayósobreelpayasoyelcoche

Ahoraimaginaquehaceslomismoperobuscandoatravésdemillonesdelíneas detexto.Francamente,tardaríasmenosaprendiendoPythonyescribiendoun programaeneselenguajeparacontarlaspalabrasquesituvierasqueirrevisando todasellasunaauna.

Perohayunanoticiaaúnmejor,yesquesemehaocurridounprogramasencillo paraencontrarcuáleslapalabramáscomúndentrodeunficherodetexto.Ya loescribí,loprobé,yahorateloregaloparaquelopuedasutilizaryahorrarte muchotiempo.

1.8.¿QUÉESUNPROGRAMA? 11

name = input('Enterfile:') handle = open(name, 'r') counts = dict()

for line in handle: words = line.split() for word in words: counts[word] = counts.get(word, 0) + 1 bigcount = None bigword = None for word,count in list(counts.items()): if bigcount is None or count > bigcount: bigword = word bigcount = count print(bigword,bigcount)

#Código:https://es.py4e.com/code3/words.py

NonecesitasnisiquierasaberPythonparausaresteprograma.Tendrásquellegar hastaelcapítulo10deestelibroparaentenderporcompletolasimpresionantes técnicasdePythonquesehanutilizadoparacrearlo.Ahoraereselusuariofinal, sólotienesqueusarelprogramaysorprendertedesushabilidadesydecómote permiteahorrarunmontóndeesfuerzo.Tansólotienesqueescribirelcódigo dentrodeunficherollamado words.py yejecutarlo,opuedesdescargarelcódigo fuentedirectamentedesde https://es.py4e.com/code3/ yejecutarlo.

EsteesunbuenejemplodecómoPythonyellenguajePythonactúancomoun intermediarioentretú(elusuariofinal)yyo(elprogramador).Pythonesunmedio paraqueintercambiemossecuenciasdeinstruccionesútiles(esdecir,programas) enunlenguajecomúnquepuedeserusadoporcualquieraqueinstalePythonen sucomputadora.Asíqueningunodenosotrosestáhablando conPython,sinoque estamoscomunicándonosunoconelotro atravésde Python.

1.9Losbloquesdeconstruccióndelosprogramas

Enlospróximoscapítulos,aprenderemosmássobreelvocabulario,laestructurade lasfrasesydelospárrafosylaestructuradelosrelatosenPython.Aprenderemos cuálessonlaspoderosascapacidadesdePythonycómocombinaresascapacidades entresíparacrearprogramasútiles.

Hayciertospatronesconceptualesdebajonivelqueseusanparaestructurarlos programas.EsasestructurasnosonexclusivasdePython,sinoqueformanpartede cualquierlenguajedeprogramación,desdeelcódigomáquinahastaloslenguajes dealtonivel.

entrada Obtenerdatosdel“mundoexterior”.Puedeconsistirenleerdatosdesde unfichero,oinclusodesdealgúntipodesensor,comounmicrófonoounGPS.

12CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?

Ennuestrosprimerosprogramas,lasentradasvanaprovenirdelusuario,que introducirálosdatosatravésdelteclado.

salida Mostrarlosresultadosdelprogramaenunapantalla,almacenarlosenun ficherooinclusoesposibleenviarlosaundispositivocomounaltavozpara reproducirmúsicaoleeruntexto.

ejecuciónsecuencial Ejecutarunasentenciatrasotraenelmismoordenenque sevanencontrandoenel script. ejecucióncondicional Comprobarciertascondicionesyluegoejecutaruomitir unasecuenciadesentencias.

ejecuciónrepetida Ejecutarunconjuntodesentenciasvariasveces,normalmenteconalgúntipodevariación.

reutilización Escribirunconjuntodeinstruccionesunavez,darlesunnombre yasípoderreutilizarlasluegocuandosenecesitenencualquierpuntodetu programa.

Parecedemasiadosimpleparasercierto,yporsupuestonuncaestansencillo. Escomosidijéramosqueandaressimplemente“ponerunpiedelantedelotro”. El“arte”deescribirunprogramaescomponeryentrelazarjuntosesoselementos básicosmuchasveceshastaconseguiralfinalalgoqueresulteútilparasususuarios.

Elprogramaparacontarpalabrasquevimosantesutilizaalmismotiempo todos esospatronesexceptouno.

1.10¿Quéesposiblequevayamal?

ComovimosennuestraanteriorconversaciónconPython,debemoscomunicarnos conmuchaprecisióncuandoescribimoscódigoPython.Elmenorerrorprovocará quePythonseniegueahacerfuncionartuprograma.

LosprogramadoresnovatosamenudosetomanelhechodequePythonnopermita cometererrorescomolapruebadefinitivadequeesperverso,odiosoycruel.A pesardequeaPythonparecegustarletodoslosdemás,escapazdeidentificara losnovatosenconcreto,ylesguardaungranrencor.Debidoaello,tomasusprogramasperfectamenteescritos,ylosrechaza,considerándoloscomo“inservibles”, sóloparaatormentarlos.

>>> primt '¡Hola,mundo!'

File "<stdin>",line 1 primt '¡Hola,mundo!' ^

SyntaxError:invalidsyntax

>>> primt('Hola,mundo')

Traceback(mostrecentcalllast):

File "<stdin>",line 1, in<module>

NameError:name 'primt' isnot defined

>>> ¡Teodio,Python!

File "<stdin>",line 1 ¡Teodio,Python! ^

1.10.¿QUÉESPOSIBLEQUEVAYAMAL? 13

SyntaxError:invalidsyntax

>>> sisalesfuera,tedaréunalección File "<stdin>",line 1 sisalesfuera,tedaréunalección

^

SyntaxError:invalidsyntax

>>>

NoesmucholoqueseganadiscutiendoconPython.Soloesunaherramienta. Notieneemociones,esfelizyestápreparadoparaservirteenelmomentoquelo necesites.Susmensajesdeerrorparecencrueles,perosimplementesetratade unapeticióndeayudadelpropioPython.Haexaminadoloquehastecleado,y sencillamentenoescapazdeentenderloquehasescrito.

Pythonseparecemuchoaunperro,tequiereincondicionalmente,entiendealgunas pocaspalabrasclave,temiraconunamiradadulceensucara(>>>),yesperaque ledigasalgoqueélpuedacomprender.CuandoPythondice“SyntaxError:invalid syntax”(Errordesintaxis:sintaxisinválida),tansoloestáagitandosucolay diciendo:“Creoquehasdichoalgo,peronoteentiendo;detodosmodos,por favor,siguehablandoconmigo(>>>).”

Amedidaquetusprogramasvayanaumentandosucomplejidad,teencontrarás contrestiposdeerroresgenerales:

Erroresdesintaxis(Syntaxerrors) Estossonlosprimeroserroresquecometerásytambiénlosmásfácilesdesolucionar.Unerrordesintaxissignifica quehasvioladolasreglas“gramaticales”dePython.Pythonhacetodolo quepuedeparaseñalarelpuntoexacto,lalíneayelcarácterdondehadetectadoelfallo.Loúnicocomplicadodeloserroresdesintaxisesqueaveces elerrorquedebecorregirseestáenrealidadenunalíneaanterioralacual Python detectó esefallo.DemodoquelalíneayelcarácterquePython indicaenunerrordesintaxispuedensertansólounpuntodepartidapara tuinvestigación.

Erroreslógicos Seproduceunerrorlógicocuandounprogramatieneunasintaxiscorrecta,peroexisteunerrorenelordendelassentenciasoenlaforma enqueestánrelacionadasunasconotras.Unbuenejemplodeunerrorlógico sería:“tomauntragodetubotelladeagua,ponlaentumochila,camina hastalabibliotecayluegovuelveaenroscarlatapaenlabotella.”

Erroressemánticos Unerrorsemánticoocurrecuandoladescripciónquehas brindadodelospasosaseguiressintácticamenteperfectayestáenelorden correcto,perosencillamentehayunerrorenelprograma.Elprogramaes correcto,peronohaceloquetú pretendías quehiciera.Unejemplopodría sercuandoledasindicacionesaalguiensobrecómollegaraunrestaurante, yledices“...cuandolleguesalaintersecciónconlagasolinera,giraala izquierda,continúaduranteotrokilómetroyelrestauranteeseledificiorojo queencontrarásatuizquierda.”.Tuamigoseretrasaytellamaparadecirte queestáenunagranjadandovueltasalrededordeungranero,sinrastro algunodeunrestaurante.Entonceslepreguntas“¿girastealaizquierda oladerecha?”,yteresponde“Seguítusindicacionesalpiedelaletra,dijistequegiraraalaizquierdaycontinuarunkilómetrodesdelagasolinera.”, entonceslerespondes“Losientomucho,porqueapesardequemisindica-

14CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?

cionesfueronsintácticamentecorrectas,tristementeconteníanunpequeño peroindetectadoerrorsemántico.”.

Insistoenque,antecualquieradeestostrestiposdeerrores,Pythonúnicamente haceloqueestáasualcanceporseguiralpiedelaletraloquetúlehaspedido quehaga.

1.11Depurandolosprogramas

CuandoPythonmuestraunerror,uobtieneunresultadodiferentealqueesperabas, empiezaunaintensabúsquedadelacausadelerror.Depurareselprocesode encontrarlacausaoelorigendeeseerrorentucódigo.Cuandodepurasun programa,yespecialmentecuandotratasconun bug algodifícildesolucionar, existencuatrocosasporhacer:

leer Revisartucódigo,leerlodenuevo,yasegurartedequeahíestáexpresadode formacorrectaloquequieresdecir. ejecutar Pruebahaciendocambiosyejecutandodiferentesversiones.Confrecuencia,simuestrasentuprogramalocorrectoenellugarindicado,elproblema sevuelveobvio,peroenocasionesdebesinvertiralgodetiempohastaconseguirlo.

pensardetenidamente ¡Tomatutiempoparapensar!,¿Aquétipodeerror corresponde:sintaxis,entiempodeejecución,semántico?,¿Quéinformación puedesobtenerdelosmensajesdeerror,odelasalidadelprograma?,¿Qué tipodeerrorespodríagenerarelproblemaqueestásabordando?,¿Cuálfue elúltimocambioquehiciste,antesdequesepresentaraelproblema?

retroceder Enalgúnmomento,lomejorquepodráshaceresdarmarchaatrás, deshacerloscambiosrecienteshastaobtenerdenuevounprogramaquefuncioneypuedasentender.Llegadoaesepunto,podráscontinuarcontu trabajo.

Algunasveces,losprogramadoresnovatossequedanestancadosenunadeestas actividadesyolvidanlasotras.Encontrarun bug requiereleer,ejecutar,pensardetenidamenteyalgunasvecesretroceder.Sitebloqueasenalgunadeestas actividades,pruebalasotras.Cadaactividadtienesuprocedimientodeanálisis.

Porejemplo,leertucódigopodríaayudarsielproblemaesunerrortipográfico, peronosiesunoconceptual.Sinocomprendesloquehacetuprograma,puedes leerlo100vecesynoencontraráselerror,puestoquedichoerrorestáentumente.

Experimentarpuedeayudar,especialmentesiejecutaspequeñaspruebas.Perosi experimentassinpensaroleertucódigo,podríascaerenunpatrónquellamo “programacióndepaseoaleatorio”,queeselprocesoderealizarcambiosalazar hastaqueelprogramalogrehacerloquedebería.Nohacefaltamencionarque estetipodeprogramaciónpuedetomarmuchotiempo.

Debestomareltiemposuficienteparapensar.Depurarescomounacienciaexperimental.Debesplantearalmenosunahipótesissobrequépodríaserelproblema. Sihaydosomásposibilidades,piensaenalgunapruebaquepuedaayudartea descartarunadeellas.

1.11.DEPURANDOLOSPROGRAMAS 15

Descansaryconversarayudaaestimularelpensamiento.Sileexplicaselproblema aalguienmás(oinclusoatímismo),avecesencontraráslarespuestaantesde terminarlapregunta.

Peroinclusolasmejorestécnicasdedepuraciónfallaránsihaydemasiadoserrores, osielcódigoqueintentasmejoraresdemasiadoextensoycomplicado.Algunas veceslamejoropciónesretroceder,ysimplificarelprogramahastaqueobtengas algoquefuncioneypuedasentender.

Porlogeneral,losprogramadoresnovatossonreaciosaretrocederporquenosoportantenerqueborrarunalíneadecódigo(inclusosiestámal).Sitehacesentir mejor,pruebaacopiartuprogramaenotroarchivoantesdeempezaramodificarlo.Deesamanera,puedesrecuperarpocoapocopequeñaspiezasdecódigo quenecesites.

1.12Elcaminodelaprendizaje

Segúnvayasavanzandoporelrestodellibro,noteasustessilosconceptosno parecenencajarbienunosconotrosalprincipio.Cuandoestabasaprendiendoa hablar,nosupusounproblemaquedurantelosprimerosañossolopudierasemitir lindosbalbuceos.Ytambiénfuenormalquetellevaraseismesespasardeun vocabulariosimpleafrasessimples,yquetellevara5-6añosmáspasardefrasesa párrafos,yquetodavíatuvieranquetranscurrirunoscuantosañosmáshastaque fuistecapazdeescribirtupropiahistoriacortainteresante.

PretendemosqueaprendasPythonrápidamente,porloqueteenseñaremostodo almismotiempodurantelospróximoscapítulos.Aúnasí,tenencuentaqueel procesoessimilaraaprenderunidiomanuevo,quellevauntiempoabsorbery comprenderantesdequeteresultefamiliar.Esoproduceciertaconfusión,puesto querevisaremosendistintasocasionesdeterminadostemas,ytrataremosquede esamanerapuedasvisualizarlospequeñosfragmentosquecomponenestaobra completa.Apesardequeellibroestáescritodeformalineal,nodudesenser nolinealenlaformaenqueabordeslasmaterias.Avanzayretrocede,yleea vecesporencima.Alojearmaterialmásavanzadosincomprenderdeltodolos detalles,tendrásunamejorcomprensióndel“¿porqué?”delaprogramación.Al revisarelmaterialanterioreinclusoalrealizarnuevamentelosejerciciosprevios, tedaráscuentaqueyahasaprendidounmontóndecosas,inclusosieltemaque estásexaminandoenesemomentopareceunpocodifícildeabordar.

Normalmente,cuandounoaprendesuprimerlenguajedeprogramación,hayunos pocosmomentos“¡A-já!”estupendos,enloscualespuedeslevantarlavistadela rocaqueestásmachacandoconmartilloycincel,separarteunospasosycomprobar queloqueestásintentandoconstruiresunamaravillosaescultura.

Sialgopareceparticularmentedifícil,generalmentenovalelapenaquedarsemirándolotodalanoche.Respira,tomaunasiesta,comealgo,explícaleaalguien(quizás atuperro)conquéestásteniendoproblemas,ydespuésvuelveaobservarlocon unperspectivadiferente.Teaseguroqueunavezqueaprendaslosconceptosde laprogramaciónenellibro,volverásatrásyverásqueenrealidadtodoerafácil, eleganteyquesimplementetehallevadounpocodetiempollegaraabsorberlo.

16CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?

1.13Glosario

bug Unerrorenunprograma. códigofuente Unprogramaenunlenguajedealtonivel. códigomáquina Ellenguajedemásbajonivelparaelsoftware,esdecir, ellenguajequeesdirectamenteejecutadoporlaunidadcentralde procesamiento(CPU). compilar Traducirunprogramacompletoescritoenunlenguajedealtonivela unlenguajedebajonivel,paradejarlolistoparaunaejecuciónposterior. errorsemántico Unerrordentrodeunprogramaqueprovocaquehagaalgo diferentedeloquepretendíaelprogramador.

funciónprint UnainstrucciónquehacequeelintérpretedePythonmuestreun valorenlapantalla. indicadordelíneadecomandos(prompt) Cuandounprogramamuestraun mensajeysedetieneparaqueelusuariotecleealgúntipodedato. interpretar Ejecutarunprogramaescritoenunlenguajedealtoniveltraduciéndololíneaalínea.

lenguajedealtonivel UnlenguajedeprogramacióncomoPython,quehasido diseñadoparaqueseafácildeleeryescribirporlaspersonas.

lenguajedebajonivel Unlenguajedeprogramaciónqueestádiseñadoparaser fácildeejecutarparaunacomputadora;tambiénrecibeelnombrede“código máquina”,“lenguajemáquina”o“lenguajeensamblador”.

memoriaprincipal Almacenalosprogramasydatos.Lamemoriaprincipal pierdesuinformacióncuandosedesconectalaalimentación.

memoriasecundaria Almacenalosprogramasydatosymantienesuinformacióninclusocuandoseinterrumpelaalimentación.Esgeneralmentemás lentaquelamemoriaprincipal.Algunosejemplosdememoriasecundaria sonlasunidadesdediscoymemoriasflashqueseencuentrandentrodelos dispositivosUSB.

modointeractivo UnmododeusarelintérpretedePython,escribiendocomandosyexpresionesdirectamenteenelindicadordelalíneadecomandos.

parsear Examinarunprogramayanalizarlaestructurasintáctica. portabilidad Eslapropiedadqueposeenlosprogramasquepuedenfuncionaren másdeuntipodecomputadora.

programa Unconjuntodeinstruccionesqueindicancómorealizaralgúntipode cálculo. resolucióndeunproblema Elprocesodeformularunproblema,encontraruna solución,ymostraresasolución. semántica Elsignificadodeunprograma. unidadcentraldeprocesamiento Elcorazóndecualquiercomputadora.Es loqueejecutaelsoftwarequeescribimos.Tambiénrecibeelnombrede “CPU”porsussiglaseninglés(CentralProcesssingUnit),osimplemente, “elprocesador”.

1.14Ejercicios

1.13.GLOSARIO 17
Ejercicio1:¿Cuáleslafuncióndelamemoriasecundariaenunacomputadora? a)Ejecutartodosloscálculosylalógicadelprograma

b)DescargarpáginaswebdeInternet

c)Almacenarinformacióndurantemuchotiempo,inclusodespuésdeciclosde apagadoyencendido

d)Recolectarlaentradadelusuario

Ejercicio2:¿Quéesunprograma?

Ejercicio3:¿Cuálesladiferenciaentreuncompiladoryunintérprete?

Ejercicio4:¿Cuáldelossiguientescontiene“códigomáquina”?

a)ElintérpretedePython b)Elteclado c)ElcódigofuentedePython d)Undocumentodeunprocesadordetexto

Ejercicio5:¿Quéestámalenelsiguientecódigo?:

>>> primt '¡Hola,mundo!' File "<stdin>",line 1 primt '¡Hola,mundo!' ^ SyntaxError:invalidsyntax >>>

Ejercicio6:¿Enquélugardelcomputadorquedaalmacenadaunavariable,como enestecaso“X”,despuésdeejecutarlasiguientelíneadePython?: x = 123

a)Unidadcentraldeprocesamiento b)MemoriaPrincipal c)MemoriaSecundaria d)DispositivosdeEntrada e)DispositivosdeSalida

Ejercicio7:¿Quémostraráenpantallaelsiguienteprograma?: x = 43 x = x + 1 print(x)

a)43 b)44 c)x+1

d)Error,porquex=x+1noesposiblematemáticamente.

Ejercicio8:Explicacadaunodelossiguientesconceptosusandounejemplode unacapacidadhumana:(1)Unidadcentraldeprocesamiento,(2)Memoriaprincipal,(3)Memoriasecundaria,(4)Dispositivosdeentrada,y(5)Dispositivosde salida.Porejemplo,“¿CuálseríaelequivalentehumanodelaUnidadcentralde procesamiento?”.

Ejercicio9:¿Cómopuedescorregirun“Errordesintaxis”?.

18CHAPTER1.¿PORQUÉDEBERÍASAPRENDERAESCRIBIRPROGRAMAS?

Variables,expresionesy sentencias

2.1Valoresytipos

Un valor esunadelascosasbásicasqueutilizaunprograma,comounaletraoun número.Losvaloresquehemosvistohastaahorahansido 1, 2,y“¡Hola,mundo!”

Esosvalorespertenecena tipos diferentes: 2 esunentero(int),y“¡Hola,mundo!” esuna cadena (string),querecibeesenombreporquecontieneuna“cadena”de letras.Tú(yelintérprete)podéisidentificarlascadenasporquevanencerradas entrecomillas.

Lasentencia print tambiénfuncionaconenteros.Vamosausarelcomando python parainiciarelintérprete.

python >>> print(4) 4

Sinoestássegurodequétipodevalorestásmanejando,elintérpretetelopuede decir.

>>> type(''¡Hola,mundo!)

<class 'str'>

>>> type(17)

<class 'int'>

Notsurprisingly,stringsbelongtothetype str andintegersbelongtothetype int.Lessobviously,numberswithadecimalpointbelongtoatypecalled float, becausethesenumbersarerepresentedinaformatcalled floatingpoint

>>> type(3.2)

<class 'float'>

Chapter2
19

¿Quéocurreconvalorescomo“17”y“3.2”?Parecennúmeros,perovanentre comillascomolascadenas.

>>> type('17') <class 'str'> >>> type('3.2') <class 'str'>

Soncadenas.

Cuandoescribesunenterogrande,puedequetesientastentadoausarcomaso puntosparasepararloengruposdetresdígitos,comoen 1,000,000 1 .Esonoes unenteroválidoenPython,peroencambiosíqueresultaválidoalgocomo:

>>> print(1,000,000) 100

Bien,hafuncionado.¡Peroesonoeraloqueesperábamos!.Pythoninterpreta 1,000,000 comounasecuenciadeenterosseparadosporcomas,asíqueloimprime conespaciosenmedio.

Ésteeselprimerejemploquehemosvistodeunerrorsemántico:elcódigofunciona sinproducirningúnmensajedeerror,peronohacesutrabajo“correctamente”.

2.2Variables

Unadelascaracterísticasmáspotentesdeunlenguajedeprogramaciónesla capacidaddemanipular variables.Unavariableesunnombrequeserefiereaun valor.

Una sentenciadeasignación creavariablesnuevasylasdavalores:

>>> mensaje = 'Yahoraalgocompletamentediferente' >>> n = 17 >>> pi = 3.1415926535897931

Esteejemplohacetresasignaciones.Laprimeraasignaunacadenaaunavariable nuevallamada mensaje;lasegundaasignaelentero 17 a n;laterceraasignael valor(aproximado)de π a pi.

Paramostrarelvalordeunavariable,sepuedeusarlasentenciaprint:

>>> print(n) 17 >>> print(pi) 3.141592653589793

Eltipodeunavariableeseltipodelvaloralqueserefiere.

1 Enelmundoanglosajónel“separadordemillares”eslacoma, ynoelpunto(Notadeltrad.)

20 CHAPTER2.VARIABLES,EXPRESIONESYSENTENCIAS

>>> type(mensaje)

<class 'str'>

>>> type(n)

<class 'int'>

>>> type(pi)

<class 'float'>

2.3Nombresdevariablesypalabrasclaves

Losprogramadoresgeneralmenteeligennombresparasusvariablesquetengan sentidoydocumentenparaquéseusaesavariable.

Losnombresdelasvariablespuedenserarbitrariamentelargos.Puedencontener tantoletrascomonúmeros,peronopuedencomenzarconunnúmero.Sepueden usarletrasmayúsculas,peroesbuenaideacomenzarlosnombresdelasvariables conunaletrasminúscula(veremosporquémásadelante).

Elcarácterguión-bajo( )puedeutilizarseenunnombre.Amenudoseutilizaen nombresconmúltiplespalabras,comoen mi_nombre o velocidad_de_golondrina_sin_carga.Losnombresdelasvariablespueden comenzarconuncarácterguión-bajo,perogeneralmenteseevitausarloasía menosqueseestéescribiendocódigoparalibreríasqueluegoutilizaránotros. Siseledaaunavariableunnombrenopermitido,seobtieneunerrordesintaxis:

>>> 76trombones = 'grandesfile' SyntaxError:invalidsyntax

>>> more@ = 1000000 SyntaxError:invalidsyntax

>>> class = 'TeoremaavanzadodeZymurgy' SyntaxError:invalidsyntax

76trombones esincorrectoporquecomienzaporunnúmero. more@ esincorrecto porquecontieneuncarácternopremitido, @.Pero,¿quéesloqueestámalen class?

Puesresultaque class esunadelas palabrasclave dePython.Elintérprete usapalabrasclaveparareconocerlaestructuradelprograma,yesaspalabrasno puedenserutilizadascomonombresdevariables.

Pythonreserva33palabrasclavesparasupropiouso: anddelfromNoneTrue aselifglobalnonlocaltry assertelseifnotwhile breakexceptimportorwith classFalseinpassyield continuefinallyisraise defforlambdareturn

Puedequequierastenerestalistaamano.Sielintérpretesequejaporelnombre deunadetusvariablesynosabesporqué,compruebasiesenombreestáenesta lista.

2.3.NOMBRESDEVARIABLESYPALABRASCLAVES 21

2.4Sentencias

Una sentencia esunaunidaddecódigoqueelintérpretedePythonpuedeejecutar. Hemosvistohastaahoradostiposdesentencia:printylasasignaciones.

Cuandoescribesunasentenciaenmodointeractivo,elintérpretelaejecutaymuestraelresultado,siesquelohay.

Unscriptnormalmentecontieneunasecuenciadesentencias.Sihaymásdeuna sentencia,losresultadosaparecendeunoenunosegúnsevanejecutandolassentencias. Porejemplo,elscript print(1) x = 2 print(x) producelasalida 1 2

Lasentenciadeasignaciónnoproduceningunasalida.

2.5Operadoresyoperandos

Losoperadores sonsímbolosespecialesquerepresentancálculos,comolasumao lamultiplicación.Losvaloresaloscualesseaplicanesosoperadoresrecibenel nombrede operandos

Losoperadores + ,,, /,y \* realizansumas,restas,multiplicaciones,divisionesy exponenciación(elevarunnúmeroaunapotencia),comosemuestraenlosejemplos siguientes: 20+32 hour-1 hour*60+minute minute/60 5**2 (5+9)*(15-7)

HahabidouncambioeneloperadordedivisiónentrePython2.xyPython3.x. EnPython3.x,elresultadodeestadivisiónesunresultadodepuntoflotante: >>> minute = 59 >>> minute/60 0.9833333333333333

22 CHAPTER2.VARIABLES,EXPRESIONESYSENTENCIAS

EloperadordedivisiónenPython2.0dividiríadosenterosytruncarelresultado aunentero:

>>> minute = 59 >>> minute/60 0

ParaobtenerlamismarespuestaenPython3.0usedivisióndividida(// integer).

>>> minute = 59 >>> minute//60 0

EnPython3,ladivisióndeenterosfuncionamuchomáscomocabríaesperar.Si ingresastelaexpresiónenunacalculadora.

2.6Expresiones

Una expresión esunacombinacióndevalores,variablesyoperadores.Unvalor porsimismoseconsideraunaexpresión,ytambiénloesunavariable,asíque lassiguientesexpresionessontodasválidas(asumiendoquelavariable x tengaun valorasignado): 17 x x + 17

Siescribesunaexpresiónenmodointeractivo,elintérpretela evalúa ymuestrael resultado: >>> 1 + 1 2

Sinembargo,enunscript,¡unaexpresiónporsimismanohacenada!Estoa menudopuedeproducirconfusiónentrelosprincipiantes.

Ejercicio1:EscribelassiguientessentenciasenelintérpretedePython paracomprobarquéhacen: 5 x = 5 x + 1

2.6.EXPRESIONES 23

2.7Ordendelasoperaciones

Cuandoenunaexpresiónaparecemásdeunoperador,elordendeevaluacióndependedelas reglasdeprecedencia.Paralosoperadoresmatemáticos,Pythonsigue lasconvencionesmatemáticas.Elacrónimo PEMDSR resultaútilpararecordar esasreglas:

•Los Paréntesistienenelnivelsuperiordeprecedencia,ypuedenusarsepara forzaraqueunaexpresiónseaevaluadaenelordenquesequiera.Dado quelasexpresionesentreparéntesissonevaluadasprimero, 2*(3-1) es4, y (1+1)**(5-2) es8.Sepuedenusartambiénparéntesisparahaceruna expresiónmássencilladeleer,inclusosielresultadodelamismanovaría porello,comoen (minuto*100)/60

•La Exponenciación(elevarunnúmeroaunapotencia)tieneelsiguientenivel másaltodeprecedencia,demodoque 2**1+1 es3,no4,y 3*1**3 es3,no 27.

•La M ultiplicaciónyla Divisióntienenlamismaprecedencia,queessuperior aladela Sumayla Resta,quetambiéntienenentresielmismonivelde precedencia.Asíque 2*3-1 es5,no4,y 6+4/2 es8,no5.

•Losoperadoresconigualprecedenciasonevaluadosdeizquierdaaderecha. Asíquelaexpresión 5-3-1 es1yno3,yaque 5-3 seevalúaantes,ydespués seresta 1 de 2

Encasodeduda,añadesiempreparéntesisatusexpresionesparaasegurartede quelasoperacionesserealizanenelordenquetúquieres.

2.8Operadormódulo

El operadormódulo trabajaconenterosyobtieneelrestodelaoperaciónconsistenteendividirelprimeroperandoporelsegundo.EnPython,eloperadormódulo esunsignodeporcentaje(%).Lasintaxiseslamismaqueseusaparalosdemás operadores: >>> quotient = 7 // 3

Asíque7divididopor3es2ynossobra1.

Eloperadormóduloresultasersorprendentementeútil.Porejemplo,puedescomprobarsiunnúmeroesdivisibleporotro—si x%y escero,entonces x esdivisible por y.

Tambiénsepuedeextraereldígitomásaladerechadelosquecomponenun número.Porejemplo, x%10 obtieneeldígitoqueestámásaladerechade x (en base10).Deformasimilar, x%100 obtienelosdosúltimosdígitos.

24 CHAPTER2.VARIABLES,EXPRESIONESYSENTENCIAS
>>> print(quotient) 2 >>> remainder = 7 % 3 >>> print(remainder) 1

2.9Operacionesconcadenas

Eloperador + funcionaconlascadenas,peronorealizaunasumaenelsentido matemático.Envezdeeso,realizauna concatenación,quequieredecirqueune ambascadenas,enlazandoelfinaldelaprimeraconelprincipiodelasegunda.Por ejemplo:

>>> primero = 10 >>> segundo = 15 >>> print(primero+segundo) 25

>>> primero = '100' >>> segundo = '150' >>> print(primero + segundo) 100150

Lasalidadeesteprogramaes 100150

Eloperador * tambiéntrabajaconcadenasmultiplicandoelcontenidodeuna cadenaporunentero.Porejemplo:

>>> primero = 'Test' >>> second = 3 >>> print(primero * second) TestTestTest

2.10Peticióndeinformaciónalusuario

Avecesnecesitaremosqueseaelusuarioquiennosproporcioneelvalorparauna variable,atravésdelteclado.Pythonproporcionaunafuncióninternallamada input querecibelaentradadesdeelteclado.Cuandosellamaaesafunción,el programasedetieneyesperaaqueelusuarioescribaalgo.Cuandoelusuario pulsa Retorno o Intro,elprogramacontinúay input devuelvecomounacadena aquelloqueelusuarioescribió.

>>> entrada = input()

Cualquiercosaridícula

>>> print(entrada)

Cualquiercosaridícula

Antesderecibircualquierdatodesdeelusuario,esbuenaideaescribirunmensaje explicándolequédebeintroducir.Sepuedepasarunacadenaa input,queserá mostradaalusuarioantesdequeelprogramasedetengapararecibirsuentrada:

>>> nombre = input('¿Cómotellamas?\n')

¿Cómotellamas? Chuck

>>> print(nombre) Chuck

2.9.OPERACIONESCONCADENAS 25

Lasecuencia \n alfinaldelmensajerepresentaun newline,queesuncarácter especialqueprovocaunsaltodelínea.Poresolaentradadelusuarioaparece debajodenuestromensaje.

Siesperasqueelusuarioescribaunentero,puedesintentarconvertirelvalorde retornoa int usandolafunción int():

>>> prompt = '¿Cualeslavelocidaddevuelodeunagolondrinasincarga?\n'

>>> velocidad = input(prompt)

¿Cualeslavelocidaddevuelodeunagolondrinasincarga? 17

>>> int(velocidad) 17

>>> int(velocidad) + 5 22

Perosielusuarioescribealgoquenoseaunacadenadedígitos,obtendrásunerror:

>>> velocidad = input(prompt)

¿Cual....eslavelocidaddevuelodeunagolondrinasincarga?

¿Terefieresaunagolondrinaafricanaoaunaeuropea?

>>> int(velocidad)

ValueError:invalidliteral for int()

Veremoscómocontrolarestetipodeerroresmásadelante.

2.11Comentarios

Amedidaquelosprogramassevanvolviendomásgrandesycomplicados,sevuelvenmásdifícilesdeleer.Loslenguajesformalessondensos,yamenudoescomplicadomiraruntrozodecódigoeimaginarsequéesloquehace,oporqué.

Poresoesbuenaideaañadirnotasatusprogramas,paraexplicarenunlenguaje normalquéesloqueelprogramaestáhaciendo.Estasnotasrecibenelnombrede comentarios,yenPythoncomienzanconelsímbolo #:

#calculaelporcentajedehoratranscurrido

porcentaje = (minuto * 100) / 60

Enestecaso,elcomentarioaparececomounalíneacompleta.Perotambiénpuedes ponercomentariosalfinaldeunalínea

porcentaje = (minuto * 100) / 60 #porcentajedeunahora

Todoloquevadesde # hastaelfinaldelalíneaesignorado—noafectaparanada alprograma.

Lascomentariossonmásútilescuandodocumentancaracterísticasdelcódigoque noresultanobvias.Esrazonableasumirqueellectorpuededescifrar qué esloque elcódigohace;esmuchomásútilexplicarle porqué

Estecomentarioesredundanteconelcódigoeinútil:

26 CHAPTER2.VARIABLES,EXPRESIONESYSENTENCIAS

v = 5 #asigna5av

Estecomentariocontieneinformaciónútilquenoestáenelcódigo:

v = 5 #velocidadenmetros/segundo.

Elegirnombresadecuadosparalasvariablespuedereducirlanecesidaddecomentarios,perolosnombreslargostambiénpuedenocasionarquelasexpresiones complejasseandifícilesdeleer,asíquehayqueconseguirunasolucióndecompromiso.

2.12Eleccióndenombresdevariablesmnemónicos

Mientrassigaslassencillasreglasdenombradodevariablesyeviteslaspalabras reservadas,dispondrásdeunagranvariedaddeopcionesparaponernombresatus variables.Alprincipio,esadiversidadpuedellegararesultarteconfusa,tantoal leerunprogramacomoalescribireltuyopropio.Porejemplo,lostresprogramas siguientessonidénticosencuantoalafunciónquerealizan,peromuydiferentes cuandolosleeseintentasentenderlos.

a = 35.0 b = 12.50 c = a * b print(c) horas = 35.0 tarifa = 12.50 salario = horas * tarifa print(salario)

x1q3z9ahd = 35.0 x1q3z9afd = 12.50 x1q3p9afd = x1q3z9ahd * x1q3z9afd print(x1q3p9afd)

ElintérpretedePythonvelostresprogramascomo exactamenteidénticos,pero loshumanosvenyasimilanestosprogramasdeformabastantediferente.Los humanosentenderánmásrápidamenteel objetivo delsegundoprograma,yaque elprogramadorhaelegidonombresdevariablesquereflejanloquepretendíade acuerdoalcontenidoqueibaalmacenarencadavariable.

Esasabiaeleccióndenombresdevariablessedenominautilizar“nombresdevariablesmnemónicos”.Lapalabra mnemónico2 significa“queayudaamemorizar”.

2 Consulta https://es.wikipedia.org/wiki/Mnemonico paraobtenerunadescripcióndetallada delapalabra“mnemónico”.

2.12.ELECCIÓNDENOMBRESDEVARIABLESMNEMÓNICOS 27

Elegimosnombresdevariablesmnemónicosparaayudarnosarecordarporqué creamoslasvariablesalprincipio.

Apesardequetodoestoparezcaestupendo,ydequeseaunaideamuybuenausar nombresdevariablesmnemónicos,esetipodenombrespuedeninterponerseenel caminodelosprogramadoresnovatosalahoradeanalizarycomprenderelcódigo. Estosedebeaquelosprogramadoresprincipiantesnohanmemorizadoaúnlas palabrasreservadas(sólohay33),yavecesvariablesconnombresquesondemasiadodescriptivospuedenllegaraparecerlespartedellenguajeynosimplemente nombresdevariablebienelegidos3

EchaunvistazorápidoalsiguientecódigodeejemploenPython,quesemueve enbucleatravésdeunconjuntodedatos.Trataremoslosbuclespronto,peropor ahoratansólotratadeentendersusignificado:

for word in words: print(word)

¿Quéocurreaquí?¿Cuálesdelaspiezas(for,word,in,etc.)sonpalabrasreservadasycuálessonsimplementenombresdevariables?¿AcasoPythoncomprende deunmodobásicolanocióndepalabras(words)?Losprogramadoresnovatos tienenproblemasseparandoquépartedelcódigo debe mantenersetalcomoestá enesteejemployquépartessonsimplementeeleccióndelprogramador. Elcódigosiguienteesequivalentealdearriba:

for slice in pizza: print(slice)

Paralosprincipiantesesmásfácilestudiarestecódigoysaberquépartesson palabrasreservadasdefinidasporPythonyquépartessonsimplementenombres devariableselegidasporelprogramador.EstábastanteclaroquePythonno entiendenadadepizzanideporciones,nidelhechodequeunapizzaconsisteen unconjuntodeunaomásporciones.

Perosinuestroprogramaloquerealmentevaahaceresleerdatosybuscarpalabras enellos, pizza y porción sonnombresmuypocomnemónicos.Elegirloscomo nombresdevariablesdistraedelpropósitorealdelprograma.

Dentrodemuypocotiempo,conoceráslaspalabrasreservadasmáscomunes,y empezarásavercómoesaspalabrasreservadasresaltansobrelasdemás:

LaspartesdelcódigoqueestándefinidasporPython(for, in, print,y :)están ennegrita,mientrasquelasvariableselegidasporelprogramador(word y words) noloestán.MuchoseditoresdetextosonconscientesdelasintaxisdePython ycolorearánlaspalabrasreservadasdeformadiferenteparadartepistasque te permitanmantenertusvariablesylaspalabrasreservadasseparados.Dentrode pocoempezarásaleerPythonypodrásdeterminarrápidamentequéesunavariable yquéesunapalabrareservada.

3 Elpárrafoanteriorserefieremásbienaquieneseligennombresdevariableseninglés,yaque todaslaspalabrasreservadasdePythoncoincidenconpalabraspropiasdeeseidioma(Notadel trad.)

28 CHAPTER2.VARIABLES,EXPRESIONESYSENTENCIAS

2.13Depuración

Enestepunto,elerrordesintaxisqueesmásprobablequecometasseráintentar utilizarnombresdevariablesnoválidos,como class y yield,quesonpalabras clave,o odd~job y US$,quecontienencaracteresnoválidos.

Siponesunespacioenunnombredevariable,Pythoncreequesetratadedos operandossinningúnoperador:

>>> badname = 5

SyntaxError:invalidsyntax

>>> month = 09 File "<stdin>",line 1 month = 09 ^

SyntaxError:invalidtoken

Paralamayoríadeerroresdesintaxis,losmensajesdeerrornoayudanmucho. Losmensajesmáscomunesson SyntaxError:invalidsyntax y SyntaxError: invalidtoken,ningunodeloscualesresultamuyinformativo.

Elruntimeerror(errorentiempodeejecución)queesmásprobablequeobtengas esun“usebeforedef”(usoantesdedefinir);quesignificaqueestásintentando usarunavariableantesdequelehayasasignadounvalor.Esopuedeocurrirsi escribesmalelnombredelavariable:

>>> principal = 327.68

>>> interest = principle * rate

NameError:name 'principle' isnot defined

Losnombresdelasvariablessonsensiblesamayúsculas,asíque LaTeX noeslo mismoque latex.

Enestepunto,lacausamásprobabledeunerrorsemánticoeselordendelas operaciones.Porejemplo,paraevaluar 1 2π ,puedessentirtetentadoaescribir

>>> 1.0 / 2.0 * pi

Peroladivisiónseevalúaantes,¡asíqueobtendrás π/2,quenoeslomismo!No hayformadequePythonsepaquéesloquequeríasescribirexactamente,asíque enestecasonoobtienesunmensajedeerror;simplementeobtienesunarespuesta incorrecta.

2.14Glosario

asignación Unasentenciaqueasignaunvaloraunavariable.

2.13.DEPURACIÓN 29

cadena Untipoquerepresentasecuenciasdecaracteres.

concatenar Unirdosoperandos,unoacontinuacióndelotro.

comentario Informaciónenunprogramaqueseponeparaotrosprogramadores (oparacualquieraqueleaelcódigofuente),ynotieneefectoalgunoenla ejecucióndelprograma.

divisiónentera Laoperaciónquedividedosnúmerosytruncalapartefraccionaria.

entero Untipoquerepresentanúmerosenteros.

evaluar Simplificarunaexpresiónrealizandolasoperacionesenordenpara obtenerunúnicovalor.

expresión Unacombinacióndevariables,operadoresyvaloresquerepresentan unúnicovalorresultante.

mnemónico Unaayudaparamemorizar.Amenudodamosnombresmnemónicos alasvariablesparaayudarnosarecordarquéestáalmacenadoenellas.

palabraclave Unapalabrareservadaqueesusadaporelcompiladorpara analizarunprograma;nosepuedenusarpalabresclavecomo if, def,y while comonombresdevariables.

puntoflotante Untipoquerepresentanúmerosconpartedecimal.

operador Unsímboloespecialquerepresentauncálculosimple,comosuma,multiplicaciónoconcatenacióndecadenas.

operadormódulo Unoperador,representadoporunsignodeporcentaje(%), quefuncionaconenterosyobtieneelrestocuandounnúmeroesdividido porotro.

operando Unodelosvaloresconloscualesunoperadoropera.

30 CHAPTER2.VARIABLES,EXPRESIONESYSENTENCIAS

reglasdeprecedencia Elconjuntodereglasquegobiernaelordenenelcual sonevaluadaslasexpresionesqueinvolucranamúltiplesoperadores.

sentencia Unaseccióndelcódigoquerepresentauncomandooacción.Hasta ahora,lasúnicassentenciasquehemosvistosonasignacionesysentencias print.

tipo Unacategoríadevalores.Lostiposquehemosvistohastaahorasonenteros (tipo int),númerosenpuntoflotante(tipo float),ycadenas(tipo str).

valor Unadelasunidadesbásicasdedatos,comounnúmeroounacadena,que unprogramamanipula.

variable Unnombrequehacereferenciaaunvalor.

2.15Ejercicios

Ejercicio2:Escribeunprogramaqueuse input parapedirlealusuario sunombreyluegodarlelabienvenida.

Introduzcatunombre:Chuck Hola,Chuck

Ejercicio3:Escribeunprogramaparapedirlealusuarioelnúmerode horasylatarifaporhoraparacalcularelsalariobruto.

IntroduzcaHoras:35 IntroduzcaTarifa:2.75 Salario:96.25

Porahoranoesnecesariopreocuparsedequenuestrosalariotengaexactamente dosdígitosdespuésdelpuntodecimal.Siquieres,puedesprobarlafuncióninterna dePython round pararedondeardeformaadecuadaelsalarioresultanteados dígitosdecimales.

Ejercicio4:Asumequeejecutamoslassiguientessentenciasdeasignación: ancho=17 alto=12.0

Paracadaunadelasexpresionessiguientes,escribeelvalordelaexpresiónyel tipo(delvalordelaexpresión).

2.15.EJERCICIOS 31

1. ancho/2

2. ancho/2.0

3. alto/3

4. 1+2*5

UsaelintérpretedePythonparacomprobartusrespuestas.

Ejercicio5:EscribeunprogramaquelepidaalusuariounatemperaturaengradosCelsius,laconviertaagradosFahrenheiteimprima porpantallalatemperaturaconvertida.

32 CHAPTER2.VARIABLES,EXPRESIONESYSENTENCIAS

Ejecucióncondicional

3.1Expresionesbooleanas

Una expresiónbooleana esaquellaquepuedeserverdadera(True)ofalsa(False). Losejemplossiguientesusaneloperador ==,quecomparadosoperandosydevuelve True sisonigualesy False encasocontrario:

5 == 5 True >>> 5 == 6 False True y False sonvaloresespecialesquepertenecenaltipo bool(booleano);no soncadenas:

type(True) <class 'bool'>

type(False) <class 'bool'> Eloperador == esunodelos operadoresdecomparación;losdemásson:

Apesardequeestasoperacionesprobablementeteresultenfamiliares,lossímbolos enPythonsondiferentesdelossímbolosmatemáticosqueseusanpararealizarlas mismasoperaciones.Unerrormuycomúnesusarsólounsímboloigual(=)envez delsímbolodedobleigualdad(==).Recuerdaque = esunoperadordeasignación, y == esunoperadordecomparación.Noexistealgocomo =< o =>.

Chapter3
x
#xesdistintodey x
#xesmayorquey x
#xesmenorquey x
x
#xesmenoroigualquey x
>>>
>>>
>>>
!= y
> y
< y
>= y #xesmayoroigualquey
<= y
is y #xeslomismoquey x isnot y #xnoeslomismoquey
33

3.2Operadoreslógicos

Existentres operadoreslógicos: and(y), or(o),y not(no).Elsignificado semánticodeestasoperacionesessimilarasusignificadoeninglés.Porejemplo, x>0andx<10 esverdaderosólocuando x esmayorque0 y menorque10.

n%2==0orn%3==0 esverdaderosi cualquiera delascondicionesesverdadera, esdecir,sielnúmeroesdivisiblepor2 o por3.

Finalmente,eloperador not niegaunaexpresiónbooleana,demodoque not(x >y) esverdaderosi x>y esfalso;esdecir,si x esmenoroigualque y. Estrictamentehablando,losoperandosdelosoperadoreslógicosdeberíanserexpresionesbooleanas,peroPythonnoesmuyestricto.Cualquiernúmerodistinto deceroseinterpretacomo“verdadero.”

>>> 17 and True True

Estaflexibilidadpuedeserútil,peroexistenciertassutilezasenesetipodeuso quepuedenresultarconfusas.Esposiblequeprefierasevitarusarlodeestemodo hastaqueestésbiensegurodeloqueestáshaciendo.

3.3Ejecucióncondicional

Parapoderescribirprogramasútiles,casisiemprevamosanecesitarlacapacidad decomprobarcondicionesycambiarelcomportamientodelprogramadeacuerdoa ellas.Las sentenciascondicionales nosproporcionanesacapacidad.Laforma mássencillaeslasentencia if: if x > 0 : print('xespositivo')

Laexpresiónbooleanadespuésdelasentencia if recibeelnombrede condición. Lasentencia if sefinalizaconuncarácterdedos-puntos(:)yla(s)línea(s)que vandetrásdelasentenciaifvanindentadas1 (esdecir,llevanunatabulacióno variosespaciosenblancoalprincipio).

Silacondiciónlógicaesverdadera,lasentenciaindentadaseráejecutada.Sila condiciónesfalsa,lasentenciaindentadaseráomitida.

Lasentencia if tienelamismaestructuraqueladefinicióndefuncionesolos bucles for2 .Lasentenciaconsisteenunalíneadeencabezadoqueterminaconel carácterdos-puntos(:)seguidoporunbloqueindentado.Lassentenciasdeeste tiporecibenelnombrede sentenciascompuestas,porqueseextiendenalolargo devariaslíneas.

1 eltérminocorrectoenespañolsería“sangradas”,peroenel mundillodelaprogramaciónse sueledecirquelaslíneasvan“indentadas”(Notadeltrad.)

2 Estudiaremoslasfuncionesenelcapítulo4ylosbuclesenel capítulo5.

34 CHAPTER3.EJECUCIÓNCONDICIONAL

x > 0 print(‘x es positivo’)

sí Figure3.1:IfLogic

Nohaylímiteenelnúmerodesentenciasquepuedenaparecerenelcuerpo,pero debehaberalmenosuna.Ocasionalmente,puederesultarútilteneruncuerposin sentencias(normalmentecomoemplazamientoreservadoparacódigoquenoseha escritoaún).Enesecaso,sepuedeusarlasentencia pass,quenohacenada. if x < 0 : pass #¡necesitogestionarlosvaloresnegativos!

Siintroducesunasentencia if enelintérpretedePython,elpromptcambiarásu aspectohabitualporpuntossuspensivos,paraindicarqueestásenmediodeun bloquedesentencias,comosemuestraacontinuación:

bloque,delocontrarioPythondevolveráunerror:

Noesnecesariaunalíneaenblancoalfinaldeunbloquedeinstruccionesalescribir yejecutarunscript,peropuedemejorarlalegibilidaddesucódigo.

3.3.EJECUCIÓNCONDICIONAL 35
>>> x = 3 >>> if x < 10: ...print('Pequeño') Pequeño >>> AlusarelintérpretedePython,debedejarunalíneaenblancoalfinaldeun
>>> x = 3 >>> if x < 10: ...print('Pequeño') ...print('Hecho') File "<stdin>",line 3 print('Hecho') ^ SyntaxError:invalidsyntax

3.4Ejecuciónalternativa

Lasegundaformadelasentencia if esla ejecuciónalternativa,enlacualexisten dosposibilidadesylacondicióndeterminacualdeellasseráejecutada.Lasintaxis essimilaraésta:

if x%2 == 0 : print('xespar') else : print('xesimpar')

Sialdividir x por2obtenemoscomoresto0,entoncessabemosque x espar,yel programamuestraunmensajeatalefecto.Siesacondiciónesfalsa,seejecutael segundoconjuntodesentencias. x%2 == 0 print(‘x es par’)

sí print(‘x es impar’)

no Figure3.2:If-Then-ElseLogic

Dadoquelacondicióndebeserobligatoriamenteverdaderaofalsa,solamenteuna delasalternativasseráejecutada.Lasalternativasrecibenelnombrede ramas, dadoquesetrataderamificacionesenelflujodelaejecución.

3.5Condicionalesencadenados

Algunasveceshaymásdedosposibilidades,demodoquenecesitamosmásdedos ramas.Unaformadeexpresarunaoperacióncomoésaesusarun condicional encadenado: if x < y: print('xesmenorquey') elif x > y: print('xesmayorquey') else: print('xeysoniguales')

elif esunaabreviaturapara“elseif”.Enestecasotambiénseráejecutadaúnicamenteunadelasramas.

Nohayunlímiteparaelnúmerodesentencias elif.Sihayunaclausula else, debeiralfinal,perotampocoesobligatorioqueéstaexista.

36 CHAPTER3.EJECUCIÓNCONDICIONAL

x < y print(‘menor’)

sí print(‘igual’)

sí x > y print (‘mayor’)

Figure3.3:If-Then-ElseIfLogic

if choice == 'a': print('Respuestaincorrecta') elif choice == 'b': print('Respuestacorrecta') elif choice == 'c': print('Casi,peronoescorrecto')

Cadacondiciónescomprobadaenorden.Silaprimeraesfalsa,secompruebala siguienteyasíconlasdemás.Siunadeellasesverdadera,seejecutalarama correspondiente,ylasentenciatermina.Inclusosihaymásdeunacondiciónque seaverdadera,sóloseejecutalaprimeraqueseencuentra.

3.6Condicionalesanidados

Uncondicionalpuedetambiénestaranidadodentrodeotro.Podríamoshaber escritoelejemploanteriordelastresramasdeestemodo:

if x == y: print('xeysoniguales') else: if x < y: print('xesmenorquey') else: print('xesmayorquey')

Elcondicionalexteriorcontienedosramas.Laprimeraramaejecutaunasentencia simple.Lasegundacontieneotrasentencia if,quetieneasuvezsuspropiasdos ramas.Esasdosramassonambassentenciassimples,peropodríanhabersido sentenciascondicionalestambién.

Apesardequeelindentadodelassentenciashacequelaestructuraestéclara,los condicionalesanidados puedenvolversedifícilesdeleerrápidamente.Engeneral, esbuenaideaevitarlossisepuede.

3.6.CONDICIONALESANIDADOS 37

x == y No print(‘igual’)

sí x < y print(‘mayor’)

No print(‘menor’)

Figure3.4:NestedIfStatements

Losoperadoreslógicosamenudoproporcionanunmododesimplificarlassentenciascondicionalesanidadas.Porejemplo,elcódigosiguientepuedeserreescrito usandounúnicocondicional:

if 0 < x: if x < 10: print('xesunnúmeropositivoconunsólodígito.')

Lasentencia print seejecutasolamentesisecumplenlasdoscondicionesanteriores,asíqueenrealidadpodemosconseguirelmismoefectoconeloperador and:

if 0 < x and x < 10: print('xesunnúmeropositivoconunsólodígito.')

3.7Capturadeexcepcionesusandotryyexcept

Anteriormentevimosunfragmentodecódigodondeusábamoslasfunciones input e int paraleeryanalizarunnúmeroenterointroducidoporelusuario.También vimoslopocoseguroquepodíallegararesultarhaceralgoasí:

>>> velocidad = input(prompt)

¿Cual....eslavelocidaddevuelodeunagolondrinasincarga?

¿Terefieresaunagolondrinaafricanaoaunaeuropea?

>>> int(velocidad)

ValueError:invalidliteral for int() with base 10:

>>>

CuandoestamostrabajandoconelintérpretedePython,traselerrorsimplemente nosaparecedenuevoelprompt,asíquepensamos“¡epa,meheequivocado!”,y continuamosconlasiguientesentencia.

Sinembargo,siseescribeesecódigoenunscriptdePythonyseproduceelerror, elscriptsedetendráinmediatamente,ymostraráun“traceback”.Noejecutarála siguientesentencia.

38 CHAPTER3.EJECUCIÓNCONDICIONAL

Heaquíunprogramadeejemploparaconvertirunatemperaturadesdegrados FahrenheitagradosCelsius:

ent = input('IntroduzcalaTemperaturaFahrenheit:') fahr = float(ent) cel = (fahr - 32.0) * 5.0 / 9.0 print(cel)

#Código:https://es.py4e.com/code3/fahren.py

Siejecutamosestecódigoyledamosunaentradanoválida,simplementefallará conunmensajedeerrorbastanteantipático:

pythonfahren.py

IntroduzcalaTemperaturaFahrenheit:72 22.2222222222

pythonfahren.py

IntroduzcalaTemperaturaFahrenheit:fred Traceback(mostrecentcalllast):

File"fahren.py",line2,in<module> fahr=float(ent)

ValueError:invalidliteralforfloat():fred

ExistenestructurasdeejecucióncondicionaldentrodePythonparamanejareste tipodeerroresesperadoseinesperados,llamadas“try/except”.Laideade try y except esquesisesabequeciertasecuenciadeinstruccionespuedegenerarun problema,seaposibleañadirciertassentenciasparaqueseanejecutadasencasode error.Estassentenciasextras(elbloqueexcept)seránignoradassinoseproduce ningúnerror.

Puedespensarenlacaracterística try y except dePythoncomouna“pólizade seguros”enunasecuenciadesentencias.

Sepuedereescribirnuestroconversordetemperaturasdeestaforma: ent = input('IntroduzcalaTemperaturaFahrenheit:') try: fahr = float(ent) cel = (fahr - 32.0) * 5.0 / 9.0 print(cel) except: print('Porfavor,introduzcaunnúmero') #Código:https://es.py4e.com/code3/fahren2.py

Pythoncomienzaejecutandolasecuenciadesentenciasdelbloque try.Sitodo vabien,sesaltarátodoelbloque except yterminará.Siocurreunaexcepción dentrodelbloque try,Pythonsaltaráfueradeesebloqueyejecutarálasecuencia desentenciasdelbloque except.

3.7.CAPTURADEEXCEPCIONESUSANDOTRYYEXCEPT 39

pythonfahren2.py

IntroduzcalaTemperaturaFahrenheit:72 22.2222222222

pythonfahren2.py

IntroduzcalaTemperaturaFahrenheit:fred Porfavor,introduzcaunnúmero

Gestionarunaexcepciónconunasentencia try recibeelnombrede capturar una excepción.Enesteejemplo,laclausula except muestraunmensajedeerror.En general,capturarunaexcepcióntedalaoportunidaddecorregirelproblema, volverloaintentaro,almenos,terminarelprogramaconelegancia.

3.8Evaluaciónencortocircuitodeexpresiones lógicas

CuandoPythonestáprocesandounaexpresiónlógica,como x>=2and(x/y)> 2,evalúalaexpresióndeizquierdaaderecha.Debidoaladefiniciónde and,si x esmenorde2,laexpresión x>=2 resultaser falsa,demodoquelaexpresión completayavaaresultar falsa,independientementedesi (x/y)>2 seevalúa como verdadera o falsa.

CuandoPythondetectaquenosegananadaevaluandoelrestodeunaexpresiónlógica,detienesuevaluaciónynorealizaelcálculodelrestodelaexpresión. Cuandolaevaluacióndeunaexpresiónlógicasedetienedebidoaqueyaseconoce elvalorfinal,esoesconocidocomo cortocircuitar laevaluación.

Apesardequeestopuedaparecerhilardemasiadofino,elfuncionamientoen cortocircuitonosdescubreunaingeniosatécnicaconocidacomo patrónguardián. ExaminalasiguientesecuenciadecódigoenelintérpretedePython:

LaterceraoperaciónhafalladoporquePythonintentóevaluar (x/y) e y eracero, locualprovocaunruntimeerror(errorentiempodeejecución).Peroelsegundo

40 CHAPTER3.EJECUCIÓNCONDICIONAL
>>> x = 6 >>> y = 2 >>> x >= 2 and (x/y) > 2 True >>> x = 1 >>> y = 0 >>> x >= 2 and (x/y) > 2 False >>> x = 6 >>> y = 0 >>> x >= 2 and (x/y) > 2 Traceback(mostrecentcalllast): File "<stdin>",line 1, in<module> ZeroDivisionError:divisionbyzero >>>

ejemplo no falló,porquelaprimerapartedelaexpresión x>=2 fueevaluada como falsa,asíque (x/y) nollegóaejecutarsedebidoalaregladel cortocircuito, ynoseprodujoningúnerror.

Esposibleconstruirlasexpresioneslógicascolocandoestratégicamenteunaevaluacióncomo guardián justoantesdelaevaluaciónquepodríacausarunerror,como semuestraacontinuación:

>>> x = 1

>>> y = 0

>>> x >= 2 and y != 0 and (x/y) > 2 False

>>> x = 6

>>> y = 0

>>> x >= 2 and y != 0 and (x/y) > 2 False

>>> x >= 2 and (x/y) > 2 and y != 0

Traceback(mostrecentcalllast):

File "<stdin>",line 1, in<module>

ZeroDivisionError:divisionbyzero

>>>

Enlaprimeraexpresiónlógica, x>=2 es falsa,asíquelaevaluaciónsedetiene enel and.Enlasegundaexpresiónlógica, x>=2 es verdadera,pero y!=0 es falsa,demodoquenuncasealcanza (x/y).

Enlaterceraexpresiónlógica,el y!=0 va después delcálculode (x/y),demodo quelaexpresiónfallaconunerror.

Enlasegundaexpresión,sediceque y!=0 actúacomo guardián paragarantizar quesóloseejecute (x/y) enelcasodeque y noseacero.

3.9Depuración

Los“traceback”quePythonmuestracuandoseproduceunerrorcontienenun montóndeinformación,peropuedenresultarabrumadores.Laspartesmásútiles normalmenteson:

•Quétipodeerrorsehaproducido,y

•Dóndehaocurrido.

Loserroresdesintaxis(syntaxerrors),normalmentesonfácilesdelocalizar,pero avecestienentrampa.Loserroresdebidoaespaciosenblancopuedensercomplicados,yaquelosespaciosylastabulacionessoninvisibles,ysolemosignorarlos.

>>> x = 5

>>> y = 6

File "<stdin>",line 1 y = 6 ^

IndentationError:unexpectedindent

3.9.DEPURACIÓN 41

Enesteejemplo,elproblemaesquelasegundalíneaestáindentadaporunespacio. Peroelmensajedeerrorapuntaa y,locualresultaengañoso.Engeneral,los mensajesdeerrorindicandóndesehadescubiertoelproblema,peroelerrorreal podríaestarenelcódigoprevio,avecesenalgunalíneaanterior.

Ocurrelomismoconloserroresentiempodeejecución(runtimeerrors).Supón queestástratandodecalcularunarelaciónseñal-ruidoendecibelios.Lafórmula es SNRdb =10log10 (Psenal /Pruido ).EnPython,podríasescribiralgocomoesto:

importmath int_senal = 9 int_ruido = 10 relacion = int_senal / int_ruido decibelios = 10 * math.log10(relacion) print(decibelios)

#Código:https://es.py4e.com/code3/snr.py

Perocuandolohacesfuncionar,obtienesunmensajedeerror3 :

Traceback(mostrecentcalllast):

File "snr.py",line 5, in ? decibelios = 10 * math.log10(relacion)

OverflowError:mathrangeerror

Elmensajedeerrorapuntaalalínea5,peronohaynadaincorrectoeneselínea. Paraencontrarelerrorreal,puederesultarútilmostrarenpantallaelvalorde relacion,queresultaser0.Elproblemaestáenlalínea4,yaquealdividirdos enterosserealizaunadivisiónentera.Lasoluciónesrepresentarlaintensidadde laseñalylaintensidaddelruidoconvaloresenpuntoflotante.

Engeneral,losmensajesdeerrortedicendóndesehadescubiertoelproblema, peroamenudonoesahíexactamentedondesehaproducido.

3.10Glosario

condición Laexpresiónbooleanaenunasentenciacondicionalquedeterminaqué ramaseráejecutada.

condicionalanidado Unasentenciacondicionalqueapareceenunadelasramas deotrasentenciacondicional.

condicionalencadenado Unasentenciacondicionalconunaseriederamasalternativas.

3 EnPython3.0,yanoseproduceelmensajedeerror;eloperadordedivisiónrealizadivisión enpuntoflotanteinclusoconoperandosenteros.

42 CHAPTER3.EJECUCIÓNCONDICIONAL

cortocircuito CuandoPythonvaevaluandounaexpresiónlógicaportramosy detieneelprocesodeevaluacióndebidoaqueyaconoceelvalorfinalqueva atenerelresultadosinnecesidaddeevaluarelrestodelaexpresión.

cuerpo Lasecuenciadesentenciasenelinteriordeunasentenciacompuesta.

expresiónbooleana Unexpresióncuyovalorpuedeserobien Verdadero obien Falso operadoresdecomparación Unodelosoperadoresqueseutilizaparacomparardosoperandos: == , !=, >, <, >=,y <=. operadorlógico Unodelosoperadoresquesecombinanenlasexpresiones booleanas: and, or,y not. patrónguardián Cuandoconstruimosunaexpresiónlógicaconcomparaciones adicionalesparaaprovecharnosdelfuncionamientoencortocircuito.

rama Unadelassecuenciasalternativasdesentenciasenunasentenciacondicional. sentenciacompuesta Unasentenciaqueconsisteenunencabezadoyuncuerpo. Elencabezadoterminacondos-puntos(:).Elcuerpoestáindentadocon relaciónalencabezado. sentenciacondicional Unasentenciaquecontrolaelflujodeejecución,dependiendodeciertacondición.

traceback Unalistadelasfuncionesqueseestánejecutando,quesemuestraen pantallacuandoseproduceunaexcepción.

3.11Ejercicios

Ejercicio1:Reescribeelprogramadelcálculodelsalarioparadarlealempleado 1.5veceslatarifahorariaparatodaslashorastrabajadasqueexcedande40.

IntroduzcalasHoras:45

IntroduzcalaTarifaporhora:10 Salario:475.0

3.11.EJERCICIOS 43

Ejercicio2:Reescribeelprogramadelsalariousando try y except,demodoqueel programaseacapazdegestionarentradasnonuméricasconelegancia,mostrando unmensajeysaliendodelprograma.Acontinuaciónsemuestrandosejecuciones delprograma:

IntroduzcalasHoras:20 IntroduzcalaTarifaporhora:nueve Error,porfavorintroduzcaunnúmero

IntroduzcalasHoras:cuarenta Error,porfavorintroduzcaunnúmero

Ejercicio3:Escribeunprogramaquesoliciteunapuntuaciónentre0.0y1.0.Si la puntuaciónestáfueradeeserango,muestraunmensajedeerror.Silapuntuación estáentre0.0y1.0,muestralacalificaciónusandolatablasiguiente:

PuntuaciónCalificación

>=0.9Sobresaliente

>=0.8Notable

>=0.7Bien >=0.6Suficiente <0.6Insuficiente

Introduzcapuntuación:0.95 Sobresaliente

Introduzcapuntuación:perfecto Puntuaciónincorrecta

Introduzcapuntuación:10.0 Puntuaciónincorrecta

Introduzcapuntuación:0.75 Bien

Introduzcapuntuación:0.5 Insuficiente

Ejecutaelprogramarepetidamente,comosemuestraarriba,paraprobarconvarios valoresdeentradadiferentes.

44 CHAPTER3.EJECUCIÓNCONDICIONAL

Chapter4 Funciones

4.1Llamadasafunciones

Enelcontextodelaprogramación,una función esunasecuenciadesentenciasque realizanunaoperaciónyquerecibenunnombre.Cuandosedefineunafunción,se especificaelnombreylasecuenciadesentencias.Másadelante,sepuede“llamar” alafunciónporesenombre.Yahemosvistounejemplodeuna llamadaauna función:

>>> type(32) <class 'int'>

Elnombredelafunciónes type.Laexpresiónentreparéntesisrecibeelnombre de argumento delafunción.Elargumentoesunvalorovariablequesepasaala funcióncomoparámetrodeentrada.Elresultadodelafunción type eseltipodel argumento.

Eshabitualdecirqueunafunción“toma”(orecibe)unargumentoy“retorna”(o devuelve)unresultado.Elresultadosellama valorderetorno.

4.2Funcionesinternas

Pythonproporcionaunnúmeroimportantedefuncionesinternas,quepuedenser usadassinnecesidaddetenerquedefinirlaspreviamente.LoscreadoresdePython hanescritounconjuntodefuncionespararesolverproblemascomunesylashan incluidoenPythonparaquelaspodamosutilizar.

Lasfunciones max y min nosdaránrespectivamenteelvalormayorymenordeuna lista: >>> max('¡Hola,mundo!') 'u' >>> min('¡Hola,mundo!') '' >>>

45

Lafunción max nosdicecuálesel“caráctermásgrande”delacadena(queresulta serlaletra“u”),mientrasquelafunción min nosmuestraelcaráctermáspequeño (queenesecasoesunespacio).

Otrafuncióninternamuycomúnes len,quenosdicecuántoselementoshayen suargumento.Sielargumentode len esunacadena,nosdevuelveelnúmerode caracteresquehayenlacadena.

>>> len('Hola,mundo') 11 >>>

Estasfuncionesnoselimitanabuscarencadenas.Puedenoperarconcualquier conjuntodevalores,comoveremosenlossiguientescapítulos. Sedebentratarlosnombresdelasfuncionesinternascomosifueranpalabras reservadas(esdecir,evitausar“max”comonombreparaunavariable).

4.3Funcionesdeconversióndetipos

Pythontambiénproporcionafuncionesinternasqueconviertenvaloresdeuntipo aotro.Lafunción int tomacualquiervaloryloconvierteenunentero,sipuede, osequejasinopuede:

>>> int('32') 32 >>> int('Hola') ValueError:invalidliteral for int() with base 10: 'Hola' int puedeconvertirvaloresenpuntoflotanteaenteros,peronolosredondea; simplementecortaydescartalapartedecimal:

>>> int(3.99999) 3 >>> int(-2.3) -2 float convierteenterosycadenasennúmerosdepuntoflotante:

>>> float(32) 32.0 >>> float('3.14159') 3.14159

Finalmente, str conviertesuargumentoenunacadena: >>> str(32) '32' >>> str(3.14159) '3.14159'

46 CHAPTER4.FUNCIONES

4.4Funcionesmatemáticas

Pythontieneunmódulomatemático (math),queproporcionalamayoríadelas funcionesmatemáticashabituales.Antesdequepodamosutilizarelmódulo,deberemosimportarlo:

>>> importmath

Estasentenciacreaun objetomódulo llamadomath.Siseimprimeelobjeto módulo,seobtieneciertainformaciónsobreél:

>>> print(math)

<module 'math' (built-in)>

Elobjetomódulocontienelasfuncionesyvariablesdefinidasenelmódulo.Para accederaunadeesasfunciones,esnecesarioespecificarelnombredelmóduloyel nombredelafunción,separadosporunpunto(tambiénconocidoeningléscomo períod).Esteformatorecibeelnombrede notaciónpunto

>>> relacion = int_senal / int_ruido

>>> decibelios = 10 * math.log10(relacion)

>>> radianes = 0.7

>>> altura = math.sin(radianes)

Elprimerejemplocalculaellogaritmoenbase10delarelaciónseñal-ruido.El módulomathtambiénproporcionaunafunciónllamada log quecalculalogaritmos enbase e

Elsegundoejemplocalculaelsenodelavariable radianes.Elnombredela variableesunapistadeque sin ylasotrasfuncionestrigonométricas(cos, tan, etc.)tomanargumentosenradianes.Paraconvertirdegradosaradianes,hayque dividirpor360ymultiplicarpor2π:

>>> grados = 45

>>> radianes = grados / 360.0 * 2 * math.pi

>>> math.sin(radianes)

0.7071067811865476

Laexpresión math.pi tomalavariable pi delmódulomath.Elvalordeesavariable esunaaproximaciónde π,conunaprecisióndeunos15dígitos.

Sisabesdetrigonometría,puedescomprobarelresultadoanterior,comparándolo conlaraízcuadradadedosdivididapordos:

>>> math.sqrt(2) / 2.0

0.7071067811865476

4.4.FUNCIONESMATEMÁTICAS 47

4.5Númerosaleatorios

Apartirdelasmismasentradas,lamayoríadelosprogramasgeneraránlasmismas salidascadavez,queesloquellamamoscomportamiento determinista.Eldeterminismonormalmenteesalgobueno,yaqueesperamosquelamismaoperaciónnos proporcionesiempreelmismoresultado.Paraciertasaplicaciones,sinembargo, querremosqueelresultadoseaimpredecible.Losjuegossonelejemploobvio,pero haymás.

Conseguirqueunprogramasearealmenteno-deterministanoresultatanfácil, perohaymodosdehacerquealmenosloparezca.Unadeellosesusar algoritmos quegenerennúmeros pseudoaleatorios.Losnúmerospseudoaleatoriosnoson verdaderamentealeatorios,yaquesongeneradosporunaoperacióndeterminista, perosisólonosfijamosenlosnúmerosresultacasiimposibledistinguirlos delos aleatoriosdeverdad.

Elmódulo random proporcionafuncionesquegenerannúmerospseudoaleatorios(a losquesimplementellamaremos“aleatorios”deahoraenadelante).

Lafunción random devuelveunnúmeroflotantealeatorioentre0.0y1.0(incluyendo 0.0,perono1.0).Cadavezquesellamaa random,seobtieneelnúmerosiguiente deunalargaserie.Paraverunejemplo,ejecutaestebucle:

importrandom

for i in range(10): x = random.random() print(x)

Esteprogramaproducelasiguientelistade10númerosaleatoriosentre0.0yhasta (peronoincluyendo)1.0.

0.11132867921152356 0.5950949227890241 0.04820265884996877 0.841003109276478 0.997914947094958 0.04842330803368111 0.7416295948208405 0.510535245390327 0.27447040171978143 0.028511805472785867

Ejercicio1:Ejecutaelprogramaentusistemayobservaquénúmeros obtienes.

Lafunción random essolamenteunadelasmuchasquetrabajanconnúmeros aleatorios.Lafunción randint tomalosparámetros inferior y superior,y devuelveunenteroentre inferior y superior (incluyendoambosextremos).

>>> random.randint(5, 10) 5

>>> random.randint(5, 10) 9

48 CHAPTER4.FUNCIONES

Paraelegirunelementodeunasecuenciaaleatoriamente,sepuedeusar choice:

>>> t = [1, 2, 3]

>>> random.choice(t)

2

>>> random.choice(t)

3

Elmódulo random tambiénproporcionafuncionesparagenerarvaloresaleatorios devariasdistribucionescontinuas,incluyendogaussiana,exponencial,gamma,y unascuantasmás.

4.6Añadiendofuncionesnuevas

Hastaahora,sólohemosestadousandolasfuncionesquevienenincorporadasen Python,peroesposibleañadirtambiénfuncionesnuevas.Una definicióndefunción especificaelnombredeunafunciónnuevaylasecuenciadesentenciasquese ejecutancuandoesafunciónesllamada.Unavezdefinidaunafunción,sepuede reutilizarunayotravezalolargodetodoelprograma.

Heaquíunejemplo:

def muestra_estribillo(): print('Soyunleñador,quéalegría.') print('Duermotodalanocheytrabajotodoeldía.')

def esunapalabraclavequeindicaquesetratadeunadefinicióndefunción.El nombredelafunciónes muestra_estribillo.Lasreglasparalosnombresdelas funcionessonlosmismosqueparalasvariables:sepuedenusarletras,númerosy algunossignosdepuntuación,peroelprimercarácternopuedeserunnúmero.No sepuedeusarunapalabraclavecomonombredeunafunción,ysedeberíaevitar tambiéntenerunavariableyunafunciónconelmismonombre.

Losparéntesisvacíosdespuésdelnombreindicanqueestafunciónnotomaningún argumento.Mástardeconstruiremosfuncionesquerecibanargumentosdeentrada.

Laprimeralíneadeladefinicióndelafunciónesllamadala cabecera;elrestose llamael cuerpo.Lacabeceradebeterminarcondos-puntos(:),yelcuerpodebeir indentado.Porconvención,elindentadoessiempredecuatroespacios.Elcuerpo puedecontenercualquiernúmerodesentencias.

Lascadenasenlasentenciaprintestánencerradasentrecomillas.Daigualutilizarcomillassimplesquedobles;lamayoríadelagenteprefierecomillassimples, exceptoenaquelloscasosenlosqueunacomillasimple(quetambiénseusacomo apostrofe)apareceenmediodelacadena.

Siescribesunadefinicióndefunciónenmodointeractivo,elintérpretemostrará puntossuspensivos(... )parainformartedequeladefiniciónnoestácompleta:

4.6.AÑADIENDOFUNCIONESNUEVAS 49

>>> def muestra_estribillo():

...print 'Soyunleñador,quéalegría.' ...print 'Duermotodalanocheytrabajotodoeldía.'

...

Parafinalizarlafunción,debesintroducirunalíneavacía(estonoesnecesarioen unscript).

Aldefinirunafunciónsecreaunavariableconelmismonombre.

>>> print(muestra_estribillo)

<functionmuestra_estribilloat 0xb7e99e9c>

>>> print(type(muestra_estribillo)) <type 'function'>

Elvalorde muestra_estribillo es functionobject (objetofunción),quetiene comotipo“function”.

Lasintaxisparallamaranuestranuevafuncióneslamismaqueusamosparalas funcionesinternas:

>>> muestra_estribillo()

Soyunleñador,quéalegría.

Duermotodalanocheytrabajotodoeldía.

Unavezquesehadefinidounafunción,puedeusarsedentrodeotra.Porejemplo,pararepetirelestribilloanterior,podríamosescribirunafunciónllamada repite_estribillo:

def repite_estribillo(): muestra_estribillo() muestra_estribillo()

Ydespuésllamara repite_estribillo:

>>> repite_estribillo()

Soyunleñador,quéalegría.

Duermotodalanocheytrabajotodoeldía.

Soyunleñador,quéalegría.

Duermotodalanocheytrabajotodoeldía.

Peroenrealidadlacanciónnoesasí.

4.7Definiciónyusos

Reuniendolosfragmentosdecódigodelasseccionesanteriores,elprogramacompletoseríaalgocomoesto:

50 CHAPTER4.FUNCIONES

def muestra_estribillo(): print('Soyunleñador,quealegría.') print('Duermotodalanocheytrabajotodoeldía.')

def repite_estribillo(): muestra_estribillo() muestra_estribillo() repite_estribillo()

#Código:https://es.py4e.com/code3/lyrics.py

Esteprogramacontienedosdefinicionesdefunciones: muestra_estribillo y repite_estribillo.Lasdefinicionesdefuncionessonejecutadasexactamente igualquecualquierotrasentencia,perosuresultadoconsisteencrearobjetosdel tipofunción.Lassentenciasdentrodecadafunciónsonejecutadassolamente cuandosellamaaesafunción,yladefinicióndeunafunciónnogeneraninguna salida.

Comoyateimaginarás,esnecesariocrearunafunciónantesdequesepueda ejecutar.Enotraspalabras,ladefinicióndelafuncióndebeserejecutadaantesde quelafunciónsellameporprimeravez.

Ejercicio2:Desplazalaúltimalíneadelprogramaanteriorhaciaarriba, demodoquelallamadaalafunciónaparezcaantesquelasdefiniciones. Ejecutaelprogramayobservaquémensajedeerrorobtienes.

Ejercicio3:Desplazalallamadadelafuncióndenuevohaciael final, ycolocaladefiniciónde muestra_estribillo despuésdeladefiniciónde repite_estribillo.¿Quéocurrecuandohacesfuncionareseprograma?

4.8Flujodeejecución

Paraasegurarnosdequeunafunciónestádefinidaantesdeusarlaporprimera vez,esnecesariosaberelordenenquelassentenciassonejecutadas,queesloque llamamosel flujodeejecución

Laejecuciónsiemprecomienzaenlaprimerasentenciadelprograma.Lassentenciassonejecutadasunaporuna,enordendearribahaciaabajo.

Las definiciones defuncionesnoalteranelflujodelaejecucióndelprograma,pero recuerdaquelassentenciasdentrodeunafunciónnosonejecutadashastaquese llamaaesafunción.

Unallamadaaunafunciónescomoundesvíoenelflujodelaejecución.Envezde pasaralasiguientesentencia,elflujosaltaalcuerpodelafunción,ejecutatodas lassentenciasquehayallí,ydespuésvuelvealpuntodondelodejó.

Todoestoparecebastantesencillo,hastaqueunorecuerdaqueunafunciónpuede llamaraotra.Cuandoestáenmitaddeunafunción,elprogramapuedetenerque ejecutarlassentenciasdeotrafunción.Perocuandoestáejecutandoesanueva función,¡talvezhayaqueejecutartodavíamásfunciones!

4.8.FLUJODEEJECUCIÓN 51

Afortunadamente,Pythonescapazdellevarelseguimientodedóndeseencuentra encadamomento,demodoquecadavezquecompletalaejecucióndeunafunción, elprogramavuelvealpuntodondelodejóenlafunciónquehabíallamadoaesa. Cuandoestolellevahastaelfinaldelprograma,simplementetermina.

¿Cuáleslamoralejadeestaextrañahistoria?Cuandoleasunprograma,no siempreteconvendráhacerlodearribaaabajo.Avecestienemássentidoseguir elflujodelaejecución.

4.9Parámetrosyargumentos

Algunasdelasfuncionesinternasquehemosvistonecesitanargumentos.Por ejemplo,cuandosellamaa math.sin,selepasaunnúmerocomoargumento. Algunasfuncionesnecesitanmásdeunargumento: math.pow tomados,labasey elexponente.

Dentrodelasfunciones,losargumentossonasignadosavariablesllamadas parámetros.Acontinuaciónmostramosunejemplodeunafuncióndefinidaporelusuario querecibeunargumento:

def muestra_dos_veces(bruce): print(bruce) print(bruce)

Estafunciónasignaelargumentoaunparámetrollamado bruce.Cuandola funciónesllamada,imprimeelvalordelparámetro(seaésteloquesea)dosveces. Estafunciónfuncionaconcualquiervalorquepuedasermostradoenpantalla. >>> muestra_dos_veces('Spam') Spam Spam >>> muestra_dos_veces(17) 17 17 >>> muestra_dos_veces(math.pi) 3.14159265359 3.14159265359

Lasmismasreglasdecomposiciónqueseaplicanalasfuncionesinternas,también seaplicanalasfuncionesdefinidasporelusuario,demodoquepodemosusar cualquiertipodeexpresióncomoargumentopara muestra_dos_veces:

>>> muestra_dos_veces('Spam'*4)

SpamSpamSpamSpam SpamSpamSpamSpam

>>> muestra_dos_veces(math.cos(math.pi)) -1.0 -1.0

52 CHAPTER4.FUNCIONES

Elargumentoesevaluadoantesdequelafunciónseallamada,asíqueenlos ejemplos,laexpresión Spam*4 y math.cos(math.pi) sonevaluadassólounavez.

Tambiénsepuedeusarunavariablecomoargumento:

>>> michael = 'Eric,lamedio-abeja.'

>>> muestra_dos_veces(michael) Eric,lamedio-abeja. Eric,lamedio-abeja.

Elnombredelavariablequepasamoscomoargumento,(michael)notienenada queverconelnombredelparámetro(bruce).Noimportacómosehayallamadoal valorenorigen(enlallamada);dentrode muestra_dos_veces,siempresellamará bruce

4.10Funcionesproductivasyfuncionesestériles

Algunasdelasfuncionesqueestamosusando,comolasmatemáticas,producenresultados;afaltadeunnombremejor,lasllamaremos funcionesproductivas (fruitful functions).Otrasfunciones,como muestra_dos_veces,realizanunaacción,pero nodevuelvenunvalor.Aesaslasllamaremos funcionesestériles (voidfunctions).

Cuandollamasaunafunciónproductiva,casisiemprequerráshacerluegoalgo conelresultado;porejemplo,puedequequierasasignarloaunavariableousarlo comopartedeunaexpresión:

x = math.cos(radians) aurea = (math.sqrt(5) + 1) / 2

Cuandollamasaunafunciónenmodointeractivo,Pythonmuestraelresultado:

>>> math.sqrt(5) 2.23606797749979

Peroenunscript,sillamasaunafunciónproductivaynoalmacenaselresultado delamismaenunavariable,¡elvalorderetornosedesvaneceenlaniebla!

math.sqrt(5)

Estescriptcalculalaraízcuadradade5,perodadoquenoalmacenaelresultado enunavariablenilomuestra,noresultaenrealidadmuyútil.

Lasfuncionesestérilespuedenmostraralgoenlapantallaotenercualquierotro efecto,peronodevuelvenunvalor.Siintentasasignarelresultadoaunavariable, obtendrásunvalorespecialllamado None (nada).

>>> resultado = muestra_dos_veces('Bing') Bing Bing

>>> print(resultado) None

4.10.FUNCIONESPRODUCTIVASYFUNCIONESESTÉRILES 53

Elvalor None noeselmismoquelacadena“None”.Esunvalorespecialquetiene supropiotipo:

>>> print(type(None)) <class 'NoneType'>

Paradevolverunresultadodesdeunafunción,usamoslasentencia return dentro deella.Porejemplo,podemoscrearunafunciónmuysimplellamada sumados, quesumadosnúmerosydevuelveelresultado.

def sumados(a,b): suma = a + b return suma

x = sumados(3, 5) print(x)

#Código:https://es.py4e.com/code3/addtwo.py

Cuandoseejecutaestescript,lasentencia print mostrará“8”,yaquelafunción sumados hasidollamadacon3y5comoargumentos.Dentrodelafunción,los parámetros a y b equivaldrána3ya5respectivamente.Lafuncióncalculóla sumadeambosnúmeroylaguardóenunavariablelocalalafunciónllamada suma.Despuésusólasentencia return paraenviarelvalorcalculadodevueltaal códigodellamadacomoresultadodelafunción,quefueasignadoalavariable x ymostradoenpantalla.

4.11¿Porquéfunciones?

Puedenoestarmuyclaroporquémerecelapenamolestarseendividirunprograma enfunciones.Existenvariasrazones:

•Elcrearunafunciónnuevatedalaoportunidaddedarnombreaungrupo desentencias,locualhacetuprogramamásfácildeleer,entenderydepurar.

•Lasfuncionespuedenhacerunprogramamáspequeño,aleliminarcódigo repetido.Además,siquieresrealizarcualquiercambioenelfuturo,sólo tendrásquehacerloenunúnicolugar.

•Dividirunprogramalargoenfuncionestepermitedepurarlaspartesdeuna enunayluegoensamblarlasjuntasenunasolapieza.

•Lasfuncionesbiendiseñadasamenudoresultanútilesparaotrosmuchos programas.Unavezquehasescritoydepuradouna,puedesreutilizarla.

Alolargodelrestodellibro,amenudousaremosunadefinicióndefunciónpara explicarunconcepto.Partedelahabilidaddecrearyusarfuncionesconsisteen llegaratenerunafunciónquerepresentecorrectamenteunaidea,como“encontrar elvalormáspequeñoenunalistadevalores”.Másadelantetemostraremosel códigoparaencontrarelvalormáspequeñodeunalistadevaloresytelopresentaremoscomounafunciónllamada min,quetomaunalistadevalorescomo argumentoydevuelveelmenorvalordeesalista.

54 CHAPTER4.FUNCIONES

4.12Depuración

Siestásusandouneditordetextoparaescribirtuspropiosscripts,puedequetengas problemasconlosespaciosytabulaciones.Elmejormododeevitaresosproblemas esusarespaciosexclusivamente(notabulaciones).Lamayoríadeloseditoresde textoquereconocenPythonlohacenasípordefecto,aunquehayalgunosqueno.

Lastabulacionesylosespaciosnormalmentesoninvisibles,locualhacequesea difícildepurarloserroresquesepuedenproducir,asíquemejorbuscauneditor quegestioneelindentadoporti.

Tampocoteolvidesdeguardartuprogramaantesdehacerlofuncionar.Algunos entornosdedesarrollolohacenautomáticamente,perootrosno.Enesecaso,el programaqueestásviendoeneleditordetextopuedenoserelmismoqueestás ejecutandoenrealidad.

¡Ladepuraciónpuedellevarmuchotiemposiestáshaciendofuncionarelmismo programaconerroresunayotravez!

Asegúratedequeelcódigoqueestásexaminandoeselmismoqueestásejecutando. Sinoestásseguro,ponalgocomo print("hola") alprincipiodelprogramayhazlo funcionardenuevo.Sinoves hola enlapantalla,¡esquenoestásejecutandoel programacorrecto!

4.13Glosario

algoritmo Unprocesogeneralpararesolverunacategoríadeproblemas.

argumento Unvalorproporcionadoaunafuncióncuandoéstaesllamada.Ese valorseasignaalparámetrocorrespondienteenlafunción.

cabecera Laprimeralíneadeunadefinicióndefunción.

cuerpo Lasecuenciadesentenciasdentrodeladefinicióndeunafunción.

composición Usodeunaexpresiónosentenciacomopartedeotramáslarga, definicióndefunción Unasentenciaquecreaunafunciónnueva,especificando sunombre,parámetros,ylassentenciasqueejecuta.

determinístico Pertenecienteaunprogramaquehacelomismocadavezquese ejecuta,apartirdelasmismasentradas.

4.12.DEPURACIÓN 55

función Unasecuenciadesentenciasconunnombrequerealizanalgunaoperación útil.Lasfuncionespuedentomarargumentosono,ypuedenproducirun resultadoono. funciónproductiva(fruitfulfunction) Unafunciónquedevuelveunvalor.

funciónestéril(voidfunction) Unafunciónquenodevuelveningúnvalor.

flujodeejecución Elordenenelcualseejecutanlassentenciasduranteelfuncionamientodeunprograma.

llamadaafunción Unasentenciaqueejecutaunafunción.Consisteenelnombredelafunciónseguidoporunalistadeargumentos.

notaciónpunto Lasintaxisparallamaraunafuncióndeotromódulo,especificandoelnombredelmóduloseguidoporunpuntoyelnombredelafunción.

objetofunción Unvalorcreadoporunadefinicióndefunción.Elnombredela funciónesunavariablequeserefierealobjetofunción.

objetomódulo Unvalorcreadoporunasentencia import,queproporcionaaccesoalosdatosycódigodefinidosenunmódulo.

parámetro Unnombreusadodentrodeunafunciónparareferirsealvalorpasado comoargumento. pseudoaleatorio Pertenecienteaunasecuenciadenúmerosqueparecenser aleatorios,perosongeneradosporunprogramadeterminista.

sentenciaimport Unasentenciaqueleeunarchivomóduloycreaunobjeto módulo.

valorderetorno Elresultadodeunafunción.Siunallamadaaunafunciónes usadacomounaexpresión,elvalorderetornoeselvalordelaexpresión.

56 CHAPTER4.FUNCIONES

4.14Ejercicios

Ejercicio4:¿Cuáleslautilidaddelapalabraclave“def”enPython?

a)Esunajergaquesignifica“estecódigoesrealmenteestupendo”

b)Indicaelcomienzodeunafunción

c)Indicaquelasiguienteseccióndecódigoindentadodebeseralmacenadapara usarlamástarde d)bycsoncorrectasambas e)Ningunadelasanteriores

Ejercicio5:¿QuémostraráenpantallaelsiguienteprogramaPython?

def fred(): print("Zap")

def jane(): print("ABC") jane() fred() jane() a)ZapABCjanefredjane b)ZapABCZap c)ABCZapjane d)ABCZapABC e)ZapZapZap

Ejercicio6:Reescribeelprogramadecálculodelsalario,contarifa-ymediaparalashorasextras,ycreaunafunciónllamada calculo_salario querecibadosparámetros(horas y tarifa).

IntroduzcaHoras:45

IntroduzcaTarifa:10 Salario:475.0

Ejercicio7:Reescribeelprogramadecalificacionesdelcapítuloanteriorusandounafunciónllamada calcula_calificacion,querecibauna puntuacióncomoparámetroydevuelvaunacalificacióncomocadena.

PuntuaciónCalificación >0.9Sobresaliente >0.8Notable >0.7Bien >0.6Suficiente <=0.6Insuficiente

Introduzcapuntuación:0.95 Sobresaliente

4.14.EJERCICIOS 57

Introduzcapuntuación:perfecto Puntuaciónincorrecta

Introduzcapuntuación:10.0 Puntuaciónincorrecta

Introduzcapuntuación:0.75 Bien

Introduzcapuntuación:0.5 Insuficiente

Ejecutaelprogramarepetidamenteparaprobarconvariosvaloresdeentradadiferentes.

58 CHAPTER4.FUNCIONES

Chapter5 Iteración

5.1Actualizacióndevariables

Unodelosusoshabitualesdelassentenciasdeasignaciónconsisteenrealizaruna actualizaciónsobreunavariable–enlacualelvalornuevodeesavariabledepende delantiguo.

x = x + 1

Estoquieredecir“‘tomaelvaloractualde x,añádele1,yluegoactualiza x conel nuevovalor”.

Siintentasactualizarunavariablequenoexiste,obtendrásunerror,yaquePython evalúaelladoderechoantesdeasignarelvalora x:

>>> x = x + 1

NameError:name 'x' isnot defined

Antesdequepuedasactualizarunavariable,debes inicializarla,normalmentemedianteunasimpleasignación:

>>> x = 0 >>> x = x + 1

Actualizarunavariableañadiéndole1sedenomina incrementar;restarle1recibe elnombrede decrementar (odisminuir).

5.2Lasentencia while

LosPCssesuelenutilizaramenudoparaautomatizartareasrepetitivas.Repetir tareasidénticasomuysimilaressincometererroresesalgoquealasmáquinas selesdabienyencambioalaspersonasno.Comolasiteracionesresultantan

59

habituales,Pythonproporcionavariascaracterísticasensulenguajeparahacerlas mássencillas.

UnaformadeiteraciónenPythoneslasentencia while.Heaquíunprograma sencilloquecuentahaciaatrásdesdecincoyluegodice“¡Despegue!”.

n = 5 while n > 0: print(n) n = n - 1 print('¡Despegue!')

Casisepuedeleerlasentencia while comosiestuvieraescritaeninglés.Significa, “Mientras n seamayorque0,muestraelvalorde n yluegoreduceelvalorde n en1unidad.Cuandolleguesa0,saldelasentencia while ymuestralapalabra ¡Despegue!”

Ésteeselflujodeejecucióndelasentencia while,explicadodeunmodomás formal:

1.Seevalúalacondición,obteniendo Verdadero or Falso

2.Silacondiciónesfalsa,sesaledelasentencia while ysecontinúalaejecución enlasiguientesentencia.

3.Silacondiciónesverdadera,seejecutaelcuerpodel while yluegosevuelve alpaso1.

Estetipodeflujorecibeelnombrede bucle,yaqueeltercerpasoenlazadenuevo conelprimero.Cadavezqueseejecutaelcuerpodelbuclesedicequerealizamos una iteración.Paraelbucleanterior,podríamosdecirque“hatenidocincoiteraciones”,loquesignificaqueelcuerpodelbuclesehaejecutadocincoveces.

Elcuerpodelbucledebecambiarelvalordeunaomásvariables,demodoque lacondiciónpuedaenalgúnmomentoevaluarsecomofalsayelbucletermine.La variablequecambiacadavezqueelbucleseejecutaycontrolacuándotermina éste,recibeelnombrede variabledeiteración.Sinohayvariabledeiteración,el bucleserepetiráparasiempre,resultandoasíun bucleinfinito

5.3Buclesinfinitos

Unafuentedediversiónsinfinparalosprogramadoreseslaconstatacióndeque lasinstruccionesdelchampú:“Enjabone,aclare,repita”,sonunbucleinfinito,ya quenohayuna variabledeiteración quedigacuántasvecesdebeejecutarseel proceso.

Enelcasodeuna cuentaatrás,podemosverificarqueelbucletermina,yaque sabemosqueelvalorde n esfinito,ypodemosverqueesevalorsevahaciendomás pequeñocadavezqueserepiteelbucle,demodoqueenalgúnmomentollegaráa 0.Otrasvecesunbucleesobviamenteinfinito,porquenotieneningunavariable deiteración.

60 CHAPTER5.ITERACIÓN

5.4“Buclesinfinitos”y break

Avecesnosesabesihayqueterminarunbuclehastaqueseharecorridolamitad delcuerpodelmismo.Enesecasosepuedecrearunbucleinfinitoapropósitoy usarlasentencia break parasalirfueradeélcuandosedesee.

Elbuclesiguientees,obviamente,un bucleinfinito,porquelaexpresiónlógicade lasentencia while essimplementelaconstantelógica True(verdadero);

n = 10 while True: print(n,end='') n = n - 1 print('¡Terminado!')

Sicometeselerrordeejecutarestecódigo,aprenderásrápidamentecómodetener unprocesodePythonbloqueadoenelsistema,otendrásquelocalizardónde seencuentraelbotóndeapagadodetuequipo.Esteprogramafuncionarápara siempre,ohastaquelabateríadelequiposetermine,yaquelaexpresiónlógicaal principiodelbucleessiemprecierta,envirtuddelhechodequeesaexpresiónes precisamenteelvalorconstante True.

Apesardequeenestecasosetratadeunbucleinfinitoinútil,sepuedeusarese diseñoparaconstruirbuclesútiles,siemprequesetengalaprecaucióndeañadir códigoenelcuerpodelbucleparasalirexplícitamente,usando break cuandose hayaalcanzadolacondicióndesalida.

Porejemplo,supónquequieresrecogerentradasdetextodelusuariohastaque ésteescriba fin.Podríasescribir:

while True: linea = input('>') if linea == 'fin': break print(linea) print('¡Terminado!')

#Código:https://es.py4e.com/code3/copytildone1.py

Lacondicióndelbuclees True,locualesverdaderosiempre,asíqueelbuclese repetiráhastaqueseejecutelasentenciabreak.

Cadavezqueseentreenelbucle,sepediráunaentradaalusuario.Sielusuario escribe fin,lasentencia break haráquesesalgadelbucle.Encualquierotrocaso, elprogramarepetirácualquiercosaqueelusuarioescribayvolveráalprincipio delbucle.Ésteesunejemplodesufuncionamiento:

>holaatodos holaatodos >heterminado heterminado >fin ¡Terminado!

5.4.“BUCLESINFINITOS”Y BREAK 61

Estemododeescribirbucles while eshabitual,yaqueasísepuedecomprobarla condiciónencualquierpuntodelbucle(nosóloalprincipio),ysepuedeexpresar lacondicióndeparadaafirmativamente(“detentecuandoocurra...”),envezde tenerquehacerloconlógicanegativa(“siguehaciéndolohastaqueocurra...”).

5.5Finalizariteracionescon continue

Algunasveces,estandodentrodeunbuclesenecesitaterminarconlaiteración actualysaltaralasiguientedeformainmediata.Enesecasosepuedeutilizar lasentencia continue parapasaralasiguienteiteraciónsinterminarlaejecución delcuerpodelbucleparalaactual.

Acontinuaciónsemuestraunejemplodeunbuclequerepiteloquerecibecomo entradahastaqueelusuarioescribe“fin”,perotratalaslíneasqueempiezanporel carácteralmohadillacomolíneasquenodebenmostrarseenpantalla(algoparecido aloquehacePythonconloscomentarios).

while True: linea = input('>') if linea[0] == '#' : continue if linea == 'fin': break print(linea) print('¡Terminado!')

#Código:https://es.py4e.com/code3/copytildone2.py

Heaquíunaejecucióndeejemplodeesenuevoprogramaconlasentencia continue añadida.

>holaatodos holaatodos >#noimprimasesto >¡imprimeesto! ¡imprimeesto! >fin ¡Terminado!

Todaslaslíneasseimprimenenpantalla,exceptolaquecomienzaconelsímbolo dealmohadilla,yaqueenesecasoseejecuta continue,finalizalaiteraciónactual ysaltadevueltaalasentencia while paracomenzarlasiguienteiteración,de modoquequeseomitelasentencia print

5.6Buclesdefinidosusando for

Avecessedesearepetirunbucleatravésdeun conjunto decosas,comouna listadepalabras,laslíneasdeunarchivo,ounalistadenúmeros.Cuandose

62 CHAPTER5.ITERACIÓN

tieneunalistadecosaspararecorrer,sepuedeconstruirunbucle definido usando unasentencia for.Alasentencia while selallamaunbucle indefinido,porque simplementeserepitehastaqueciertacondiciónsehace Falsa,mientrasqueel bucle for serepiteatravésdeunconjuntoconocidodeelementos,demodoque ejecutatantasiteracionescomoelementoshayenelconjunto.

Lasintaxisdeunbucle for essimilaraladelbucle while,enellahayunasentencia for yuncuerpoqueserepite:

amigos = ['Joseph', 'Glenn', 'Sally'] for amigo in amigos: print('Felizañonuevo:',amigo) print('¡Terminado!')

EntérminosdePython,lavariable amigos esunalista1 detrescadenasyelbucle for semueverecorriendolalistayejecutasucuerpounavezparacadaunadelas trescadenasenlalista,produciendoestasalida:

Felizañonuevo:Joseph Felizañonuevo:Glenn Felizañonuevo:Sally ¡Terminado!

Latraduccióndeestebucle for alespañolnoestandirectacomoenelcaso del while,perosipiensasenlosamigoscomoun conjunto,seríaalgoasícomo: “Ejecutalassentenciasenelcuerpodelbucleunavez para(for) cadaamigoque esté en(in) elconjuntollamadoamigos.”

Revisandoelbucle for, for e in sonpalabrasreservadasdePython,mientrasque amigo y amigos sonvariables.

for amigo in amigos: print('Felizañonuevo::',amigo)

Enconcreto, amigo esla variabledeiteración paraelbuclefor.Lavariable amigo cambiaparacadaiteracióndelbucleycontrolacuándoseterminaelbucle for. La variabledeiteracion sedesplazasucesivamenteatravésdelastrescadenas almacenadasenlavariable amigos

5.7Diseñosdebucles

Amenudoseusaunbucle for o while paramovernosatravésdeunalistade elementosoelcontenidodeunarchivoysebuscaalgo,comoelvalormásgrande oelmáspequeñodelosdatosqueestamosrevisando.

Losbuclesgeneralmenteseconstruyenasí:

•Seinicializanunaomásvariablesantesdequeelbuclecomience

1 Examinaremoslaslistasconmásdetalleenuncapítuloposterior.

5.7.DISEÑOSDEBUCLES 63

•Serealizaalgunaoperaciónconcadaelementoenelcuerpodelbucle,posiblementecambiandolasvariablesdentrodeesecuerpo.

•Serevisanlasvariablesresultantescuandoelbuclesecompleta

Usaremosahoraunalistadenúmerosparademostrarlosconceptosyconstrucción deestosdiseñosdebucles.

5.7.1Buclesderecuentoysuma

Porejemplo,paracontarelnúmerodeelementosenunalista,podemosescribirel siguientebucle for: contador = 0 for valor in [3, 41, 12, 9, 74, 15]: contador = contador + 1 print('Num.elementos:',contador)

Ajustamoslavariable contador aceroantesdequeelbuclecomience,después escribimosunbucle for paramovernosatravésdelalistadenúmeros.Nuestra variablede iteración sellama valor,ydadoquenousamos valor dentrodel bucle,loúnicoquehaceescontrolarelbucleyhacerqueelcuerpodelmismosea ejecutadounavezparacadaunodelosvaloresdelalista.

Enelcuerpodelbucle,añadimos1alvaloractualde contador paracadaunode losvaloresdelalista.Mientraselbucleseestáejecutando,elvalorde contador eslacantidaddevaloresquesehayanvisto“hastaesemomento”.

Unavezelbuclesecompleta,elvalorde contador eselnúmerototaldeelementos. Elnúmerototal“caeennuestropoder”alfinaldelbucle.Seconstruyeelbuclede modoqueobtengamosloquequeremoscuandoéstetermina.

Otrobuclesimilar,quecalculaeltotaldeunconjuntodenúmeros,semuestraa continuación: total = 0 for valor in [3, 41, 12, 9, 74, 15]: total = total + valor print('Total:',total)

Enestebucle, sí utilizamosla variabledeiteración.Envezdeañadirsimplemente unoa contador comoenelbucleprevio,ahoradurantecadaiteracióndelbucle añadimoselnúmeroactual(3,41,12,etc.)altotalenesemomento.Sipiensasenla variable total,éstacontienela“sumaparcialdevaloreshastaesemomento”.Así queantesdequeelbuclecomience, total escero,porqueaúnnosehaexaminado ningúnvalor.Duranteelbucle, total eslasumaparcial,yalfinaldelbucle, total eslasumatotaldefinitivadetodoslosvaloresdelalista.

Cuandoelbucleseejecuta, total acumulalasumadeloselementos;unavariable queseusadeestemodorecibeaveceselnombrede acumulador.

64 CHAPTER5.ITERACIÓN

Nielbuclequecuentaloselementosnielquelossumaresultanparticularmente útilesenlapráctica,dadoqueexistenlasfuncionesinternas len() y sum() que cuentanelnúmerodeelementosdeunalistayeltotaldeelementosenlamisma respectivamente.

5.7.2Buclesdemáximosymínimos

Paraencontrarelvalormayordeunalistaosecuencia,construimoselbuclesiguiente: mayor = None print('Antes:',mayor) for valor in [3, 41, 12, 9, 74, 15]: if mayor is None or valor > mayor: mayor = valor print('Bucle:',valor,mayor) print('Mayor:',mayor)

Cuandoseejecutaelprograma,seobtienelasiguientesalida:

Antes:None Bucle:33 Bucle:4141 Bucle:1241 Bucle:941 Bucle:7474 Bucle:1574 Mayor:74

Debemospensarenlavariable mayor comoel“mayorvalorvistohastaesemomento”.Antesdelbucle,asignamosa mayor elvalor None. None esunvalor constanteespecialquesepuedealmacenarenunavariableparaindicarquela variableestá“vacía”.

Antesdequeelbuclecomience,elmayorvalorvistohastaentonceses None,dado quenosehavistoaúnningúnvalor.Durantelaejecucióndelbucle,si mayor es None,entoncestomamoselprimervalorquetenemoscomoelmayorhastaentonces.

Sepuedeverenlaprimeraiteración,cuandoelvalorde valor es3,mientrasque mayor es None,inmediatamentehacemosque mayor paseaser3.

Traslaprimeraiteración, mayor yanoes None,asíquelasegundapartedelaexpresiónlógicacompuestaquecompruebasi valor>mayor seactivarásólocuando encontremosunvalorqueseamayorqueel“mayorhastaesemomento”.Cuando encontramosunnuevovalor“mayoraún”,tomamosesenuevovalorpara mayor. Sepuedeverenlasalidadelprogramaque mayor pasadesde3a41yluegoa74.

Alfinaldelbucle,sehabránrevisadotodoslosvaloresylavariable mayor contendrá entonceselmayorvalordelalista.

Paracalcularelnúmeromáspequeño,elcódigoesmuysimilarconunpequeño cambio:

5.7.DISEÑOSDEBUCLES 65

print('Antes:',menor) for valor in [3, 41, 12, 9, 74, 15]: if menor is None or valor < menor: menor = valor print('Bucle:',valor,menor) print('Menor:',menor)

Denuevo, menor esel“menorhastaesemomento”antes,duranteydespuésdeque elbucleseejecute.Cuandoelbuclesehacompletado, menor contendráelvalor mínimodelalista

Tambiéncomoenelcasodelnúmerodeelementosydelasuma,lasfunciones internas max() y min() conviertenlaescrituradeestetipodebucleseninnecesaria. LosiguienteesunaversiónsimpledelafuncióninternadePython min():

def min(valores): menor = None for valor in valores: if menor is None or valor < menor: menor = valor return menor

Enestaversióndelafunciónparacalcularelmínimo,hemoseliminadolassentencias print,demodoqueseaequivalentealafunción min,queyaestáincorporada dentrodePython.

5.8Depuración

Amedidaquevayasescribiendoprogramasmásgrandes,puedequenotesquevas necesitandoemplearcadavezmástiempoendepurarlos.Máscódigosignificamás oportunidadesdecometerunerrorymáslugaresdondelosbugspuedenesconderse. Unmétodoparaacortareltiempodedepuraciónes“depurarporbisección”.Por ejemplo,sihay100líneasentuprogramaylascompruebasdeunaenuna,te llevará100pasos.

Enlugardeeso,intentapartirelproblemaporlamitad.Buscaenmediodel programa,ocercadeahí,unvalorintermedioquepuedascomprobar.Añade unasentencia print (oalgunaotracosaquetengaunefectoverificable),yhaz funcionarelprograma.

Sienelpuntomediolaverificaciónesincorrecta,elproblemadeberíaestarenla primeramitaddelprograma.Siéstaescorrecta,elproblemaestaráenlasegunda mitad.

Cadavezquerealicesunacomprobacióncomoesta,reducesalamitadelnúmero delíneasenlasquebuscar.Despuésdeseispasos(quesonmuchosmenosde100), lohabrásreducidoaunaodoslíneasdecódigo,almenosenteoría.

Enlaprácticanosiempreestáclaroquées“enmediodelprograma”,ynosiempre esposiblecolocarahíunaverificación.Notienesentidocontarlaslíneasyencontrar

66 CHAPTER5.ITERACIÓN

elpuntomedioexacto.Enlugardeeso,piensaenlugaresdelprogramaenloscuales puedahabererroresyenlugaresdonderesultefácilcolocarunacomprobación. Luegoeligeunsitiodondeestimesquelasoportunidadesdequeelbugestépor delanteylasdequeestépordetrásdeesacomprobaciónsonmásomenoslas mismas.

5.9Glosario

acumulador Unavariableusadaenunbucleparasumaroacumularunresultado. bucleinfinito Unbucleenelcuallacondicióndeterminaciónnosesatisface nuncaoparaelcualnoexistedichacondicióndeterminación. contador Unavariableusadaenunbucleparacontarelnúmerodevecesquealgo sucede.Inicializamoselcontadoraceroyluegolovamosincrementandocada vezquequeramosque“cuente”algo. decremento Unaactualizaciónquedisminuyeelvalordeunavariable. inicializar Unaasignaciónquedaunvalorinicialaunavariablequevaaser despuésactualizada. incremento Unaactualizaciónqueaumentaelvalordeunavariable(amenudo enunaunidad).

iteración Ejecuciónrepetidadeunaseriedesentenciasusandobienunafunción quesellamaasimismaobienunbucle.

5.10Ejercicios

Ejercicio1:Escribeunprogramaquelearepetidamentenúmeros hasta queelusuariointroduzca“fin”.Unavezsehayaintroducido“fin”, muestraporpantallaeltotal,lacantidaddenúmerosylamediade esosnúmeros.Sielusuariointroducecualquierotracosaquenoseaun número,detectasufallousando try y except,muestraunmensajede errorypasaalnúmerosiguiente.

Introduzcaunnúmero:4 Introduzcaunnúmero:5 Introduzcaunnúmero:datoerróneo Entradainválida

Introduzcaunnúmero:7 Introduzcaunnúmero:fin 1635.33333333333

5.9.GLOSARIO 67

Ejercicio2:Escribeotroprogramaquepidaunalistadenúmeros como laanterioryalfinalmuestreporpantallaelmáximoymínimodelos números,envezdelamedia.

68 CHAPTER5.ITERACIÓN

Chapter6 Cadenas

6.1Unacadenaesunasecuencia

Unacadenaesuna secuencia decaracteres.Puedesaccederaloscaracteresdeuno enunoconeloperadorcorchete:

>>> fruta = 'banana'

>>> letra = fruta[1]

Lasegundasentenciaextraeelcarácterenlaposicióndelindice1delavariable fruta ylaasignaalavariable letra

Laexpresiónenloscorchetesesllamada índice.Elíndiceindicaquécarácterde lasecuenciaquieres(deahíelnombre).

Peropodríasnoobtenerloqueesperas:

>>> print(letra)

a

Paralamayoríadelaspersonas,laprimerletrade“banana”es“b”,no“a”.Pero enPython,elíndiceesundesfasedesdeeliniciodelacadena,yeldesfasedela primeraletraescero.

>>> letra = fruta[0]

>>> print(letra)

b

Asíque“b”eslaletra0(“cero”)de“banana”,“a”eslaletraconíndice1,y“n” eslaquetieneíndice2,etc.

Puedesusarcualquierexpresión,incluyendovariablesyoperadores,comouníndice, peroelvalordelíndicetienequeserunentero.Deotromodoobtendrás:

>>> letra = fruta[1.5]

TypeError:stringindicesmustbeintegers

69

b [0] a [1] n [2] a [3] n [4] a [5]

Figure6.1:IndicesdeCadenas

6.2Obtenereltamañodeunacadenausando len

len esunafunciónnativaquedevuelveelnúmerodecaracteresenunacadena:

>>> fruta = 'banana'

>>> len(fruta) 6

Paraobtenerlaúltimaletradeunacadena,podríasestartentadoaprobaralgo comoesto:

>>> tamaño = len(fruta)

>>> ultima = fruta[tamaño]

IndexError:stringindexoutofrange

Larazóndequehayaun IndexError esqueahínohayningunaletraen“banana” conelíndice6.Puestoqueempezamosacontardesdecero,lasseisletrasestán enumeradasdesde0hasta5.Paraobtenerelúltimocarácter,tienesquerestar1 a length:

>>> ultima = fruta[tamaño-1] >>> print(ultima) a

Alternativamente,puedesusaríndicesnegativos,loscualescuentanhaciaatrás desdeelfinaldelacadena.Laexpresión fruta[-1] devuelvelaúltimaletra, fruta[-2] lapenúltimaletra,yasísucesivamente.

6.3Recorriendounacadenamedianteunbucle

Muchosdeloscálculosrequierenprocesarunacadenacarácterporcarácter.Frecuentementeempiezandesdeelinicio,seleccionandocadacarácterpresente,haciendoalgoconél,ycontinuandohastaelfinal.Estepatróndeprocesamientoes llamadoun recorrido.Unamaneradeescribirunrecorridoesconunbucle while:

indice = 0 while indice < len(fruta): letra = fruta[indice] print(letra) indice = indice + 1

70 CHAPTER6.CADENAS

Estebuclerecorrelacadenaeimprimecadaletraenunalíneacadauna.La condicióndelbuclees indice<len(fruta),asíquecuando indice esigualal tamañodelacadena,lacondiciónesfalsa,yelcódigodelbuclenoseejecuta.El últimocarácteraccedidoeselquetieneelíndice len(fruta)-1,elcualeselúltimo carácterenlacadena.

Ejercicio1:Escribeunbucle while quecomienceconelúltimocarácter enlacadenayhagaunrecorridohaciaatráshastaelprimercarácter enlacadena,imprimiendocadaletraenunalíneaindependiente.

Otraformadeescribirunrecorridoesconunbucle for:

for caracter in fruta: print(caracter)

Cadavezqueiteramoselbucle,elsiguientecarácterenlacadenaesasignadoala variable caracter.Elciclocontinúahastaquenoquedancaracteres.

6.4Rebanadodeunacadena

Unsegmentodeunacadenaesllamado rebanado.Seleccionarunrebanadoes similaraseleccionaruncarácter:

>>> s = 'MontyPython'

>>> print(s[0:5]) Monty >>> print(s[6:12]) Python

Eloperador[n:m]retornalapartedelacadenadesdeel“n-ésimo”carácterhasta el“m-ésimo”carácter,incluyendoelprimeroperoexcluyendoelúltimo.

Siomiteselprimeríndice(antesdelosdospuntos),elrebanadocomienzadesde eliniciodelacadena.Siomiteselsegundoíndice,elrebanadovahastaelfinalde lacadena:

>>> fruta = 'banana'

>>> fruta[:3]

'ban'

>>> fruta[3:] 'ana'

Sielprimeríndiceesmayorqueoigualqueelsegundo,elresultadoesuna cadena vacía,representadopordoscomillas:

>>> fruta = 'banana'

>>> fruta[3:3]

''

Unacadenavacíanocontienecaracteresytieneuntamañode0,perofuerade estoeslomismoquecualquierotracadena.

Ejercicio2:Dadoque fruta esunacadena,¿quesignifica fruta[:]?

6.4.REBANADODEUNACADENA 71

6.5Loscadenassoninmutables

Puedesertentadorutilizareloperador[]enelladoizquierdodeunaasignación, conlaintencióndecambiaruncarácterenunacadena.Porejemplo:

>>> saludo = 'Hola,mundo!'

>>> saludo[0] = 'J'

TypeError: 'str' objectdoes not supportitemassignment

El“objeto”enestecasoeslacadenayel“ítem”eselcarácterquetratamosde asignar.Porahora,un objeto eslamismacosaqueunvalor,perovamosaredefinir esadefinicióndespués.Un ítem esunodelosvaloresenunasecuencia.

Larazónporlacualocurreelerroresquelascadenasson inmutables,locual significaquenopuedesmodificarunacadenaexistente.Lomejorquepuedes hacerescrearunanuevacadenaqueseaunavariacióndelaoriginal:

>>> saludo = 'Hola,mundo!'

>>> nuevo_saludo = 'J' + saludo[1:]

>>> print(nuevo_saludo) Jola,mundo!

Esteejemploconcatenaunanuevaletraaunapartede saludo.Estonotiene efectosobrelacadenaoriginal.

6.6Iterandoycontando

Elsiguienteprogramacuentaelnúmerodevecesquelaletra“a”apareceenuna cadena: palabra = 'banana' contador = 0 for letra in palabra: if letra == 'a': contador = contador + 1 print(contador)

Esteprogramademuestraotropatróndecomputaciónllamado contador.Lavariable contador esinicializadaa0ydespuésseincrementacadavezqueuna“a”es encontrada.Cuandoelbucletermina, contador contieneelresultado:elnúmero totaldea’s.

Ejercicio3:Encapsulaestecódigoenunafunciónllamada cuenta,y hazlagenéricadetalmodoquepuedaaceptarunacadenayunaletra comoargumentos.

72 CHAPTER6.CADENAS

6.7Eloperador in

Lapalabra in esunoperadorbooleanoquetomadoscadenasyregresa True sila primeracadenaaparececomounasubcadenadelasegunda:

>>> 'a' in 'banana' True

>>> 'semilla' in 'banana' False

6.8Comparacióndecadenas

Losoperadoresdecomparaciónfuncionanencadenas.Paraversidoscadenasson iguales:

if palabra == 'banana': print('Muybien,bananas.')

Otrasoperacionesdecomparaciónsonútilesparaponerpalabrasenordenalfabético:

if palabra < 'banana': print('Tupalabra,' + palabra + ',estáantesdebanana.') elif palabra > 'banana': print('Tupalabra,' + palabra + ',estádespuésdebanana.') else: print('Muybien,bananas.')

Pythonnomanejaletrasmayúsculasyminúsculasdelamismaformaquelagente lohace.Todaslasletrasmayúsculasvanantesquetodaslasletrasminúsculas,por ejemplo:

Tupalabra,Piña,estáantesquebanana.

Unaformacomúndemanejaresteproblemaesconvertircadenasaunformato estándar,comotodasaminúsculas,antesdellevaracabolacomparación.Ten encuentaesoencasodequetengasquedefendertecontraunhombrearmadocon unaPiña.

6.9Métodosdecadenas

Loscadenassonunejemplode objetos enPython.Unobjetocontienetantodatos (elvalordelacadenamisma)como métodos,loscualessonefectivamentefunciones queestánimplementadasdentrodelobjetoyqueestándisponiblesparacualquier instancia delobjeto.

Pythontieneunafunciónllamada dir lacuallistalosmétodosdisponiblespara unobjeto.Lafunción type muestraeltipodeunobjetoylafunción dir muestra losmétodosdisponibles.

6.7.ELOPERADOR IN 73

>>> cosa = 'Holamundo'

>>> type(cosa)

<class 'str'>

>>> dir(cosa)

['capitalize', 'casefold', 'center', 'count', 'encode', 'endswith' , 'expandtabs', 'find', 'format', 'format_map', 'index' , 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier' , 'islower', 'isnumeric', 'isprintable', 'isspace' , 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip' , 'maketrans', 'partition', 'replace', 'rfind', 'rindex' , 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split' , 'splitlines', 'startswith', 'strip', 'swapcase', 'title' , 'translate', 'upper', 'zfill']

>>> help(str.capitalize)

Helponmethod_descriptor:

capitalize(...) S.capitalize() -> str

ReturnacapitalizedversionofS,i.e.makethefirstcharacter haveuppercase and therestlowercase.

>>>

Aunquelafunción dir listalosmétodosypuedesusarlafunción help paraobtenerunabrevedocumentacióndeunmétodo,unamejorfuente dedocumentaciónparalosmétodosdecadenassepuedeencontraren https://docs.python.org/library/stdtypes.html#string-methods.

Llamaraun método essimilarallamarunafunción(estatomaargumentosy devuelveunvalor)perolasintaxisesdiferente.Llamamosaunmétodouniendo elnombredelmétodoaldelavariable,usandounpuntocomodelimitador.

Porejemplo,elmétodo upper tomaunacadenaydevuelveunanuevacadenacon todaslasletrasenmayúscula:

Envezdelasintaxisdefunción upper(word),ésteutilizalasintaxisdemétodo word.upper().

>>> palabra = 'banana' >>> nueva_palabra = palabra.upper()

>>> print(nueva_palabra)

BANANA

Estaformadenotaciónconpuntoespecificaelnombredelmétodo, upper,yel nombredelacadenaalqueseleaplicaráelmétodo, palabra.Losparéntesisvacíos indicanqueelmétodonotomaargumentos.

Unallamadaaunmétodoesconocidacomouna invocación;enestecaso,diríamos queestamosinvocando upper en palabra.

Porejemplo,existeunmétododecadenallamado find quebuscalaposiciónde unacadenadentrodeotra:

74 CHAPTER6.CADENAS

>>> palabra = 'banana'

>>> indice = palabra.find('a')

>>> print(indice) 1

Enesteejemplo,invocamos find en palabra ypasamoslaletraqueestamos buscandocomounparámetro.

Elmétodo find puedeencontrarsubcadenasasícomocaracteres:

>>> palabra.find('na') 2

Tambiénpuedetomarcomounsegundoargumentoelíndicedesdedondedebe empezar:

>>> palabra.find('na', 3) 4

Unatareacomúneseliminarlosespaciosenblanco(espacios,tabs,onuevaslíneas) enelinicioyelfinaldeunacadenausandoelmétodo strip:

>>> linea = 'Aquívamos' >>> linea.strip() 'Aquívamos'

Algunosmétodoscomo startswith devuelvenvaloresbooleanos.

>>> linea = 'Quetengasunbuendía' >>> linea.startswith('Que') True >>> linea.startswith('q') False

Puedesnotarque startswith requierequeelformato(mayúsculasyminúsculas) coincida,demodoqueavecestendremosquetomarlalíneaycambiarlacompletamenteaminúsculasantesdehacerlaverificación,utilizandoelmétodo lower

>>> linea = 'Quetengasunbuendía'

>>> linea.startswith('q') False

>>> linea.lower() 'quetengasunbuendía'

>>> linea.lower().startswith('q') True

6.9.MÉTODOSDECADENAS 75

Enelúltimoejemplo,elmétodo lower esllamadoydespuésusamos startswith paraversilacadenaresultanteenminúsculascomienzaconlaletra“q”.Siempre ycuandoseamoscuidadososconelorden,podemoshacermúltiplesllamadasa métodosenunasolaexpresión.

Ejercicio4:Hayunmétododecadenasllamado count queessimilara lafuncióndelejercicioprevio.Leeladocumentacióndeestemétodo en:

https://docs.python.org/library/stdtypes.html#string-methods

Escribeunainvocaciónquecuentaelnúmerodevecesqueunaletra apareceen“banana”.

6.10Analizandocadenas

Frecuentemente,queremosexaminarunacadenaparaencontrarunasubcadena. Porejemplo,sisenospresentaranunaseriadelíneasconelsiguienteformato:

Fromstephen.marquard@uct.ac.za SatJan509:14:162008

yquisiéramosobtenerúnicamentelasegundapartedeladireccióndecorreo(esto es, uct.ac.za)decadalínea,podemoshacerestoutilizandoelmétodo find yuna partedelacadena.

Primerotenemosqueencontrarlaposicióndelaarrobaenlacadena.Después, tenemosqueencontrarlaposicióndelprimerespacio después delaarroba.Y despuéspartiremoslacadenaparaextraerlaporcióndelacadenaqueestamos buscando.

>>> dato = 'Fromstephen.marquard@uct.ac.zaSatJan509:14:162008' >>> arrobapos = dato.find('@') >>> print(arrobapos) 21 >>> espos = dato.find('',arrobapos) >>> print(espos) 31 >>> direccion = dato[arrobapos+1:espos] >>> print(direccion) uct.ac.za >>>

Utilizamosunaversióndelmétodo find quenospermiteespecificarlaposiciónen lacadenadesdedondequeremosque find comienceabuscar.Cuandorecortamos unapartedeunacadena,extraemosloscaracteresdesde“unodespuésdelaarroba hasta, peronoincluyendo,elcarácterdeespacio”.

Ladocumentacióndelmétodo find estádisponibleen https://docs.python.org/library/stdtypes.html#string-methods.

76 CHAPTER6.CADENAS

6.11Eloperadordeformato

El operadordeformato % nospermiteconstruircadenas,reemplazandopartesde lascadenascondatosalmacenadosenvariables.Cuandoloaplicamosaenteros, % eseloperadormódulo.Perocuandoesaplicadoaunacadena, % eseloperadorde formato.

Elprimeroperandoesla cadenaaformatear,lacualcontieneunaomás secuencias deformato queespecificancómoelsegundooperandoesformateado.Elresultado esunacadena.

Porejemplo,lasecuenciadeformato %d significaqueelsegundooperandodebería serformateadocomounentero(“d”significa“decimal”):

>>> camellos = 42

>>> '%d' % camellos '42'

Elresultadoeslacadena‘42’,elcualnodebeserconfundidoconelvalorentero 42.

Unasecuenciadeformatopuedeaparecerencualquierlugarenlacadena,asíque puedesmeterunvalorenunafrase:

>>> camellos = 42

>>> 'Yohevisto%dcamellos.' % camellos 'Yohevisto42camellos.'

Sihaymásdeunasecuenciadeformatoenlacadena,elsegundoargumentotiene queserunatupla1 .Cadasecuenciadeformatoesrelacionadaconunelementode latupla,enorden.

Elsiguienteejemplousa %d paraformatearunentero, %g paraformatearunnúmero depuntoflotante(nopreguntesporqué),y %s paraformatearunacadena:

>>> 'En%dañosyohevisto%g%s.' % (3, 0.1, 'camellos') 'En3añosyohevisto0.1camellos.'

Elnúmerodeelementosenlatupladebecoincidirconelnúmerodesecuencias deformatoenlacadena.Eltipodeloselementostambiéndebecoincidirconla secuenciadeformato:

>>> '%d%d%d' % (1, 2)

TypeError: not enougharguments for formatstring

>>> '%d' % 'dolares'

TypeError: %dformat:anumber is required, not str

1 Unatuplaesunasecuenciadevaloresseparadosporcomasdentrodeunpardeparéntesis. VeremostuplasenelCapítulo10

6.11.ELOPERADORDEFORMATO 77

Enelprimerejemplo,nohaysuficienteselementos;enelsegundo,elelementoes deuntipoincorrecto.

Eloperadordeformatoespoderoso,peropuedeserdifícildeusar.Puedesleer másalrespectoen https://docs.python.org/library/stdtypes.html#printf-style-string-formatting.

6.12Depuración

Unahabilidadquedebesdesarrollarcuandoprogramasessiemprepreguntarteati mismo,“¿Quépodríafallaraquí?”oalternativamente,“¿Quécosailógica podría hacerunusuarioparahacerfallarnuestro(aparentemente)perfectoprograma?”

Porejemplo,observaelprogramaqueutilizamosparademostrarelbucle while enelcapítulodeiteraciones:

while True: linea = input('>') if linea[0] == '#' : continue if linea == 'fin': break print(linea) print('¡Terminado!')

#Código:https://es.py4e.com/code3/copytildone2.py

Miraloquepasacuandoelusuariointroduceunalíneavacíacomoentrada: > holaatodos holaatodos > #noimprimasesto > ¡imprimeesto! ¡imprimeesto! > Traceback(mostrecentcalllast): File "copytildone.py",line 3, in<module> if linea[0] == '#': IndexError:stringindexoutofrange

Elcódigofuncionabienhastaquesepresentaunalíneavacía.Enesemomentono hayuncaráctercero,porloqueobtenemosunatrazadeerror(traceback).Existen dossolucionesaestoparaconvertirlalíneatresen“segura”,inclusosilalíneaestá vacía.

Unaposibilidadessimplementeusarelmétodo startswith quedevuelve False si lacadenaestávacía. if linea.startswith('#'):

78 CHAPTER6.CADENAS

Otraformaseguraesescribirunasentencia if utilizandoelpatrón guardián y asegurarsequelasegundaexpresiónlógicaesevaluadasólocuandohayalmenos uncarácterenlacadena:

if len(linea) > 0 and linea[0] == '#':

6.13Glosario

bandera Unavariablebooleanautilizadaparaindicarsiunacondiciónesverdaderaofalsa.

búsqueda Unpatrónderecorridoquesedetienecuandoencuentraloqueestá buscando. cadenaaformatear Unacadena,usadoconeloperadordeformato,quecontienesecuenciasdeformato.

cadenavacía unacadenasincaracteresydetamaño0,representadapordos comillassencillas. contador Unavariableutilizadaparacontaralgo,usualmenteinicializadaacero yluegoincrementada.

índice Unvalorenteroutilizadoparaseleccionarunítemenunasecuencia,tal comouncarácterenunacadena.

inmutable Lapropiedaddeunasecuenciacuyoselementosnopuedenserasignados. invocación Unasentenciaquellamaunmétodo. ítem Unodelosvaloresenunasecuencia. método Unafunciónqueestáasociadaaunobjetoyesllamadautilizandola notacióndepunto. objeto Algoaloqueunavariablepuedereferirse.Porahora,puedesusar“objeto” y“valor”indistintamente. operadordeformato Unoperador, %,quetomaunacadenadeformatoyuna tuplaygeneraunacadenaqueincluyeloselementosdelatuplaformateados comoseespecificaenlacadenadeformato.

rebanado Unapartedeunacadenaespecificadoporunrangodeíndices. recorrido Iteraratravésdelosítemsdeunasecuencia,ejecutandounaoperación similarencadauno. secuencia Unconjuntoordenado;estoes,unconjuntodevaloresdondecadavalor esidentificadoporuníndiceentero. secuenciadeformato Unasecuenciadecaracteresenunacadenaaformatear, como %d,queespecificacómounvalordebeserformateado.

6.14Ejercicios

Ejercicio5:TomaelsiguientecódigoenPythonquealmacenauna cadena:

str='X-DSPAM-Confidence:0.8475'

Utiliza find yunapartedelacadenaparaextraerlaporcióndelacadena despuésdelcarácterdospuntosydespuésutilizalafunción float para convertirlacadenaextraídaenunnúmerodepuntoflotante.

6.13.GLOSARIO 79

Ejercicio6:Leeladocumentacióndelosmétodosdecadenasen https://docs.python.org/library/stdtypes.html#string-methods Quizá quierasexperimentarconalgunosdeellosparaasegurartedeentender comofuncionan. strip y replace sonparticularmenteútiles.

Ladocumentaciónusaunasintaxisquepuedeserconfusa.Porejemplo,en find(sub[,start[,end]]),loscorchetesindicanargumentosopcionales.Demodoque sub esrequerido,pero start esopcional,ysise incluye start,entonces end esopcional.

80 CHAPTER6.CADENAS

Archivos

7.1Persistencia

Hastaahora,hemosaprendidocómoescribirprogramasycomunicarnuestrasintencionesala UnidadCentraldeProcesamiento utilizandoejecucionescondicionales, funciones,eiteraciones.Hemosaprendidocomocrearyusarestructurasdedatos enla MemoriaPrincipal.LaCPUylamemoriasonloslugaresdondenuestro softwarefuncionayseejecuta.Esdondetodala inteligencia ocurre.

Perosirecuerdasnuestrasdiscusionesdearquitecturadehardware,unavezque lacorrienteseinterrumpe,cualquiercosaalmacenadayaseaenlaCPUoenla memoriaeseliminada.Asíquehastaahoranuestrosprogramashansidosólouna diversiónpasajeraparaaprenderPython.

Enestecapítulo,vamosacomenzaratrabajarcon MemoriaSecundaria (o archivos).Lamemoriasecundarianoeseliminadacuandoapagamosunacomputadora.Incluso,enelcasodeunamemoriaUSB,losdatosqueescribimos

Chapter7
Dispositivos Entrada Salida Software Memoria Principal Unidad Central Procesamiento ¿Qué hago a continuación? Red Memoria Secundaria Figure7.1:MemoriaSecundaria
81

desdenuestrosprogramaspuedenserretiradosdelsistemaytransportadosaotro sistema.

Nosvamosaenfocarprincipalmenteenleeryescribirarchivoscomolosquecreamos enuneditordetexto.Másadelanteveremoscómotrabajarconarchivosdebases dedatos,quesonarchivosbinariosdiseñadosespecíficamenteparaserleídosy escritosatravésdesoftwareparamanejodebasesdedatos.

7.2Abrirarchivos

Cuandoqueremosabriroescribirunarchivo(digamos,eneldiscoduro),primero debemos abrir elarchivo.Alabrirelarchivonoscomunicamosconelsistema operativo,elcualsabedóndeestánalmacenadoslosdatosdecadaarchivo. Cuandoabresunarchivo,leestáspidiendoalsistemaoperativoqueencuentre elarchivoporsunombreyseaseguredequeexiste.Enesteejemplo,abrimos elarchivo mbox.txt,elcualdeberíaestaralmacenadoenelmismodirectorioen queestáslocalizadocuandoiniciasPython.Puedesdescargarestearchivodesde www.py4e.com/code3/mbox.txt

>>> manejador_archivo = open('mbox.txt')

>>> print(manejador_archivo) <_io.TextIOWrappername='mbox.txt' mode='r' encoding='cp1252'>

Siel open esexitoso,elsistemaoperativonosdevuelveun manejadordearchivo Elmanejadordearchivonosonlosdatoscontenidosenelarchivo,sinoun“manejador” (handler) quepodemosusarparaleerlosdatos.Obtendrásunmanejador dearchivosielarchivosolicitadoexisteysitieneslospermisosapropiadospara leerlo.

From stephen.m.. Return-Path: <p.. Date: Sat, 5 Jan .. To: source@coll..

From: stephen... Subject: [sakai]... Details: http:/...

Figure7.2:UnManejadordeArchivo

Sielarchivonoexiste, open fallaráconunmensajedeerrorynoobtendrásun manejadorparaaccederalcontenidodelarchivo:

>>> manejador_archivo = open('stuff.txt')

Traceback(mostrecentcalllast):

82 CHAPTER7.ARCHIVOS
Tu Programa H A N D L E open close read write

File "<stdin>",line 1, in<module>

FileNotFoundError:[Errno 2]Nosuchfile or directory: 'stuff.txt'

Másadelantevamosautilizar try y except paracontrolardemejormanerala situacióndondetratamosdeabrirunarchivoquenoexiste.

7.3Archivosdetextoylíneas

Unarchivodetextopuedeserconsideradocomounasecuenciadelíneas,asícomo unacadenadePythonpuedeserconsideradacomounasecuenciadecaracteres. Porejemplo,esteesunejemplodeunarchivodetextoqueregistralaactividad decorreosdevariaspersonasenunequipodedesarrollodeunproyectodecódigo abierto(opensource):

Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

Return-Path:<postmaster@collab.sakaiproject.org> Date:Sat,5Jan200809:12:18-0500

To:source@collab.sakaiproject.org

From:stephen.marquard@uct.ac.za Subject:[sakai]svncommit:r39772-content/branches/ Details:http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772 ...

Elarchivocompletodeinteraccionesporcorreoestádisponibleen www.py4e.com/code3/mbox.txt yunaversiónreducidadelarchivoestádisponibleen www.py4e.com/code3/mbox-short.txt

Esosarchivosestánenunformatoestándarparaunarchivoquecontienemúltiples mensajesdecorreo.Laslíneasquecomienzancon“From”separanlosmensajes ylaslíneasquecomienzancon“From:”sonpartedeesosmensajes.Paramás informaciónacercadelformatombox,consulta https://es.wikipedia.org/wiki/Mbox

Parasepararelarchivoenlíneas,hayuncarácterespecialquerepresentael“final deunalínea”llamado saltodelínea.

EnPython,representamosel saltodelínea comounabarrainvertida-nenlas cadenas.Inclusoaunqueestoparezcadoscaracteres,realmenteesunsolocarácter. Cuandovemoslavariableinteractuandoconelintérprete,estenosmuestrael \n enlacadena,perocuandousamos print paramostrarlacadena,vemoslacadena separadaendoslíneasdebidoalsaltodelínea.

>>> cosa = 'Hola\nMundo!'

>>> cosa 'Hola\nMundo!'

>>> print(cosa)

Hola

7.3.ARCHIVOSDETEXTOYLÍNEAS 83

Mundo!

>>> cosa = 'X\nY' >>> print(cosa) X Y >>> len(cosa) 3

Tambiénpuedesverqueeltamañodelacadena X\nY es tres caracteresdebidoa queelseparadordelíneaesunsolocarácter.

Portanto,cuandovemoslaslíneasenunarchivo,necesitamos imaginar queahí hayuncarácterinvisiblellamadoseparadordelíneaalfinaldecadalínea,elcual marcaelfinaldelamisma.

Demodoqueelseparadordelíneaseparaloscaracteresdelarchivoenlíneas.

7.4Lecturadearchivos

Aunqueel manejadordearchivo nocontienelosdatosdeunarchivo,esbastante fácilutilizarloenunbucle for paraleeratravésdelarchivoycontarcadaunade suslíneas: man_archivo = open('mbox-short.txt') contador = 0 for linea in man_archivo: contador = contador + 1 print('Contadordelíneas:',contador)

#Código:https://es.py4e.com/code3/open.py

Podemosusarelmanejadordearchivoscomounasecuenciaennuestrobucle for Nuestrobucle for simplementecuentaelnúmerodelíneasenelarchivoylas imprime.Latraducciónaproximadadeesebuclealespañoles,“paracadalínea enelarchivorepresentadoporelmanejadordearchivo,sumaunoalavariable count.”

Larazónporlacuallafunción open noleeelarchivocompletoesporqueelarchivo puedesermuygrande,inclusoconmuchosgigabytesdedatos.Lasentencia open emplealamismacantidaddetiemposinimportareltamañodelarchivo.Dehecho, eselbucle for elquehacequelosdatosseanleídosdesdeelarchivo.

Cuandoelarchivoesleídousandounbucle for deestamanera,Pythonseencarga dedividirlosdatosdelarchivoenlíneasseparadasutilizandoelseparadordelínea. Pythonleecadalíneahastaelseparadoreincluyeelseparadorcomoelúltimo carácterenlavariable line paracadaiteracióndelbucle for.

Debidoaqueelbucle for leelosdatoslíneaalínea,éstepuedeleereficientemente ycontarlaslíneasenarchivosmuygrandessinquedarsesinmemoriaprincipal paraalmacenarlosdatos.Elprogramapreviopuedecontarlaslíneasdecualquier

84 CHAPTER7.ARCHIVOS

tamañodearchivoutilizandopocamemoria,puestoquecadalíneaesleída,contada,ydespuésdescartada.

Sisabesqueelarchivoesrelativamentepequeñocomparadoaltamañodetumemoriaprincipal,puedesleerelarchivocompletoenunasolacadenautilizandoel método read enelmanejadordearchivos.

>>> manejador_archivo = open('mbox-short.txt')

>>> inp = manejador_archivo.read()

>>> print(len(inp)) 94626

>>> print(inp[:20])

Fromstephen.marquar

Enesteejemplo,elcontenidocompleto(todoslos94626caracteres)delarchivo mbox-short.txt sonleídosdirectamenteenlavariable inp.Utilizamoseltroceadode cadenasparaimprimirlosprimeros20caracteresdelacadenadedatosalmacenada en inp

Cuandoelarchivoesleídodeestaforma,todosloscaracteresincluyendolossaltos delíneasonunacadenagiganteenlavariable inp.Esunabuenaideaalmacenar lasalidade read comounavariableporquecadallamadaa read vacíaelcontenido porcompleto:

>>> manejador = open('mbox-short.txt')

>>> print(len(manejador.read())) 94626

>>> print(len(manejador.read())) 0

Recuerdaqueestaformadelafunción open solodebeserutilizadasilosdatosdel archivosonapropiadosparalamemoriaprincipaldelsistema.Sielarchivoesmuy grandeparacaberenlamemoriaprincipal,deberíasescribirtuprogramaparaleer elarchivoenbloquesutilizandounbucle for o while.

7.5Búsquedaatravésdeunarchivo

Cuandobuscasatravésdelosdatosdeunarchivo,unpatrónmuycomúnesleerel archivo,ignorarlamayoríadelaslíneasysolamenteprocesarlíneasquecumplan conunacondiciónparticular.Podemoscombinarelpatróndeleerunarchivocon métodosdecadenasparaconstruirmecanismosdebúsquedasencillos.

Porejemplo,siqueremosleerunarchivoysolamenteimprimirlaslíneasque comienzanconelprefijo“From:”,podríamosusarelmétododecadenas startswith paraseleccionarsoloaquellaslíneasconelprefijodeseado:

man_a = open('mbox-short.txt') contador = 0 for linea in man_a:

7.5.BÚSQUEDAATRAVÉSDEUNARCHIVO 85

if linea.startswith('From:'): print(linea)

#Código:https://es.py4e.com/code3/search1.py

Cuandoesteprogramaseejecuta,obtenemoslasiguientesalida:

From:stephen.marquard@uct.ac.za

From:louis@media.berkeley.edu

From:zqian@umich.edu

From:rjlowe@iupui.edu ...

Lasalidaparececorrectapuestoquelaslíneasqueestamosbuscandosonaquellas quecomienzancon“From:”,pero¿porquéestamosviendolaslíneasvacíasextras? Estoesdebidoalcarácterinvisible saltodelínea.Cadaunadelaslíneasleídas terminaconunsaltodelínea,asíquelasentencia print imprimelacadenaalmacenadaenlavariable line,lacualincluyeesesaltodelínea,ydespués print agrega otro saltodelínea,resultandoenelefectodedoblesaltodelíneaqueobservamos. Podemosusartroceadodelíneasparaimprimirtodosloscaracteresexceptoel último,perounaformamássencillaesusarelmétodo rstrip,elcualeliminalos espaciosenblancodelladoderechodeunacadena,talcomo:

man_a = open('mbox-short.txt') for linea in man_a: linea = linea.rstrip() if linea.startswith('From:'): print(linea)

#Código:https://es.py4e.com/code3/search2.py

Cuandoesteprogramaseejecuta,obtenemoslosiguiente:

From:stephen.marquard@uct.ac.za

From:louis@media.berkeley.edu

From:zqian@umich.edu

From:rjlowe@iupui.edu

From:zqian@umich.edu

From:rjlowe@iupui.edu

From:cwen@iupui.edu

Amedidaquetusprogramasdeprocesamientodearchivossevuelvenmáscomplicados,quizáquierasestructurartusbuclesdebúsquedautilizando continue.La ideabásicadeunbucledebúsquedaesqueestásbuscandolíneas“interesantes”e ignorandolíneas“nointeresantes”.Ycuandoencontramosunalíneainteresante, hacemosalgoconella.

86 CHAPTER7.ARCHIVOS

Podemosestructurarelbucleparaseguirelpatróndeignorarlaslíneasnointeresantesasí:

man_a = open('mbox-short.txt') for linea in man_a: linea = linea.rstrip()

#Ignorar'líneasquenonosinteresan' if not linea.startswith('From:'): continue

#Procesarlalíneaquenos'interesa' print(linea)

#Código:https://es.py4e.com/code3/search3.py

Lasalidadelprogramaeslamisma.EnEspañol,laslíneasnointeresantesson aquellasquenocomienzancon“From:”,asíquelassaltamosutilizando continue. Encambiolaslíneas“interesantes”(aquellasquecomienzancon“From:”)las procesamos.

Podemosusarelmétododecadenas find parasimularlafuncióndebúsquedade uneditordetexto,queencuentralaslíneasdondeaparecelacadenadebúsqueda enalgunaparte.Puestoque find buscacualquierocurrenciadeunacadenadentro deotraydevuelvelaposicióndeesacadenao-1silacadenanofueencontrada, podemosescribirelsiguientebucleparamostrarlaslíneasquecontienenlacadena“@uct.ac.za”(esdecir,losquevienendelaUniversidaddeCapeTownen Sudáfrica):

man_a = open('mbox-short.txt') for linea in man_a: linea = linea.rstrip() if linea.find('@uct.ac.za') ==-1: continue print(linea)

#Código:https://es.py4e.com/code3/search4.py

Locualproducelasiguientesalida:

Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

X-Authentication-Warning:setsendertostephen.marquard@uct.ac.zausing-f

From:stephen.marquard@uct.ac.za

Author:stephen.marquard@uct.ac.za

Fromdavid.horwitz@uct.ac.zaFriJan407:02:322008

X-Authentication-Warning:setsendertodavid.horwitz@uct.ac.zausing-f

From:david.horwitz@uct.ac.za

Author:david.horwitz@uct.ac.za ...

Aquíutilizamoslaformacontraídadelasentencia if dondeponemosel continue enlamismalíneaqueel if.Estaformacontraídadel if funcionadelamisma maneraquesiel continue estuvieraenlasiguientelíneaeindentado.

7.5.BÚSQUEDAATRAVÉSDEUNARCHIVO 87

7.6Permitiendoalusuarioelegirelnombrede archivo

DefinitivamentenoqueremostenerqueeditarnuestrocódigoPythoncadavez quequeremosprocesarunarchivodiferente.Seríamásútilpediralusuarioque introduzcaelnombredelarchivocadavezqueelprogramaseejecuta,demodo quepuedausarnuestroprogramaendiferentesarchivossintenerquecambiarel código.

Estoessencillodehacerleyendoelnombredearchivodelusuarioutilizando input comosemuestraacontinuación:

narchivo = input('Ingresaunnombredearchivo:') man_a = open(narchivo) contador = 0 for linea in man_a: if linea.startswith('Subject:'): contador = contador + 1 print('Hay',contador, 'líneasdeasunto(subject)en',narchivo)

#Código:https://es.py4e.com/code3/search6.py

Leemoselnombredearchivodelusuarioyloguardamosenunavariablellamada fname yabrimoselarchivo.Ahorapodemosejecutarelprogramarepetidamente endiferentesarchivos.

pythonsearch6.py

Ingresaunnombredearchivo:mbox.txt Hay1797líneasdeasunto(subject)enmbox.txt

pythonsearch6.py

Ingresaunnombredearchivo:mbox-short.txt Hay27líneasdeasunto(subject)enmbox-short.txt

Antesdemirarlasiguientesección,observaelprogramaanteriorypregúntate a timismo,“¿Quéerrorpodríasucederaquí?”o“¿Quépodríanuestroamigable usuariohacerquecausequenuestropequeñoprogramaterminenoexitosamente conunerror,haciéndonosverno-muy-genialesantelosojosdenuestrosusuarios?”

7.7Utilizando try,except, y open

Tedijequenomiraras.Estaestuúltimaoportunidad.

¿Quétalsinuestrousuarioescribealgoquenoesunnombredearchivo?

pythonsearch6.py

Ingresaunnombredearchivo:missing.txt Traceback(mostrecentcalllast): File"search6.py",line2,in<module>

88 CHAPTER7.ARCHIVOS

man_a=open(narchivo)

FileNotFoundError:[Errno2]Nosuchfileordirectory:'missing.txt'

pythonsearch6.py

Ingresaunnombredearchivo:nanabooboo

Traceback(mostrecentcalllast): File"search6.py",line2,in<module> man_a=open(narchivo)

FileNotFoundError:[Errno2]Nosuchfileordirectory:'nanabooboo'

Noterías.Losusuarioseventualmenteharáncualquiercosaquepuedanpara estropeartusprogramas,seaapropósitoosinintencionesmaliciosas.De hecho, unaparteimportantedecualquierequipodedesarrollodesoftwareesunapersona ogrupollamado QualityAssurance (ControldeCalidad)(oQAeninglés)cuyo trabajoesprobarlascosasmáslocasposiblesenunintentodehacerfallarel softwarequeelprogramadorhacreado.

ElequipodeQA(ControldeCalidad)esresponsabledeencontrarlosfallosen losprogramasantesdeéstosseanentregadosalosusuariosfinales,quepodrían comprarnuestrosoftwareopagarnuestrosalarioporescribirlo.Asíque elequipo deQAeselmejoramigodeunprogramador.

Ahoraquevemoseldefectoenelprograma,podemosarreglarlodeformaelegante utilizandolaestructura try/except.Necesitamosasumirquelallamadaa open podríafallaryagregarcódigoderecuperaciónparaesefallo,así:

narchivo = input('Ingresaunnombredearchivo:') try: man_a = open(narchivo) except: print('Nosepuedeabrirelarchivo:',narchivo) exit() contador = 0 for linea in man_a: if linea.startswith('Subject:'): contador = contador + 1 print('Hay',contador, 'líneasdeasunto(subject)en',narchivo)

#Código:https://es.py4e.com/code3/search7.py

Lafunción exit terminaelprograma.Esunafunciónquellamamosquenunca retorna.Ahoracuandonuestrousuario(oelequipodeQA)introduzcaalgosin sentidoounnombredearchivoincorrecto,vamosa“capturarlo”yrecuperarnos deformaelegante:

pythonsearch7.py

Ingresaunnombredearchivo:mbox.txt Hay1797líneasdeasunto(subject)enmbox.txt pythonsearch7.py

Ingresaunnombredearchivo:nanabooboo Nosepuedeabrirelarchivo:nanabooboo

7.7.UTILIZANDO TRY,EXCEPT, Y OPEN 89

Protegerlallamadaa open esunbuenejemplodelusocorrectode try y except enunprogramadePython.Utilizamoseltérmino“Pythónico”cuandoestamos haciendoalgosegúnel“estilodePython”.Podríamosdecirqueelejemploanterior esunaformaPythónicadeabrirunarchivo.

UnavezqueestésmásfamiliarizadoconPython,puedesintercambiaropinionescon otrosprogramadoresdePythonparadecidircuáldeentredossolucionesequivalentesaunproblemaes“másPythónica”.Elobjetivodeser“másPythónico” englobalanocióndequeprogramaresenparteingenieríayenpartearte.No siempreestamosinteresadossóloenhacerquealgofuncione,tambiénqueremos quenuestrasoluciónseaeleganteyqueseaapreciadacomoelegantepornuestros compañeros.

7.8Escrituradearchivos

Paraescribirenunarchivo,tienesqueabrirloenmodo“w”(de write,escritura) comosegundoparámetro:

>>> fsal = open('salida.txt', 'w')

>>> print(fsal)

<_io.TextIOWrappername='salida.txt' mode='w' encoding='cp1252'>

Sielarchivoyaexistíapreviamente,abrirloenmododeescrituracausaráquese borretodoelcontenidodelarchivo,asíque¡tencuidado!Sielarchivonoexiste, unnuevoarchivoescreado.

Elmétodo write delmanejadordearchivosescribedatosdentrodelarchivo,devolviendoelnúmerodecaracteresescritos.Elmododeescriturapordefectoes textoparaescribir(yleer)cadenas.

>>> linea1 = "Aquíestáelzarzo,\n"

>>> fsal.write(linea1) 24

Elmanejadordearchivomantieneunseguimientodedóndeestá,asíquesillamas a write denuevo,ésteagregalosnuevosdatosalfinal.

Debemosasegurarnosdegestionarlosfinalesdelaslíneasconformevamosescribiendoenelarchivo,insertandoexplícitamenteelcarácterdesaltodelíneacuando queremosfinalizarunalínea.Lasentencia print agregaunsaltodelíneaautomáticamente,peroelmétodo write noloagregadeformaautomática.

>>> linea2 = 'elsímbolodenuestratierra.\n'

>>> fsal.write(linea2) 24

Cuandoterminasdeescribir,tienesquecerrarelarchivoparaasegurartequela últimapartedelosdatosesescritafísicamenteeneldiscoduro,demodoqueno sepierdanlosdatossilacorrienteeléctricaseinterrumpe.

90 CHAPTER7.ARCHIVOS

>>> fsal.close()

Podríamoscerrarlosarchivosabiertosparalecturatambién,peropodemosser menosrigurosossisóloestamosabriendounospocosarchivospuestoquePython seaseguradequetodoslosarchivosabiertosseancerradoscuandoterminael programa.Encambio,cuandoestamosescribiendoarchivosdebemoscerrarlosde formaexplícitaparanodejarnadaalazar.

7.9Depuración

Cuandoestásleyendoyescribiendoarchivos,puedestenerproblemasconlosespaciosenblanco.Esoserrorespuedenserdifícilesdedepurardebidoaquelos espacios,tabuladores,ysaltosdelíneasoninvisiblesnormalmente:

>>> s = '12\t3\n4'

>>> print(s) 123 4

Lafunciónnativa repr puedeayudarte.Recibecualquierobjetocomoargumento ydevuelveunarepresentacióndelobjetocomounacadena.Enelcasodelas cadenas,representalosespaciosenblancoconsecuenciasdebarrasinvertidas:

>>> print(repr(s)) '12\t3\n4'

Estopuedeserútilparadepurar.

Otroproblemaquepodríasteneresquediferentessistemasusandiferentescaracteresparaindicarelfinaldeunalínea.Algunossistemasusanunsaltodelínea, representadocomo \n.Otrosusanuncarácterderetorno,representadocon \r Otrosusanambos.Simuevesarchivosentrediferentessistemas,esasinconsistenciaspodríancausarteproblemas.

Paralamayoríadelossistemas,hayaplicacionesqueconviertendeun formatoaotro.Puedesencontrarlas(yleermásacercadeesto)en wikipedia.org/wiki/Newline.Otambién,porsupuesto,puedesescribiruna tumismo.

7.10Glosario

archivodetexto Unasecuenciadecaracteresalmacenadosenundispositivode almacenamientopermanentecomoundiscoduro.

capturar(catch) Evitarqueunaexcepciónhagaterminarunprograma,usando lassentencias try y except.

7.9.DEPURACIÓN 91

controldecalidad(QA) Unapersonaoequipoenfocadoenasegurarlacalidad engeneraldeunproducto.ElControldecalidad(QA)esfrecuentemente encargadodeprobarunsoftwareyencontrarposiblesproblemasantesde queelsoftwaresealanzado. pythónico UnatécnicaquefuncionadeformaeleganteenPython.“Utilizartry yexcepteslaforma Pythónica degestionarlosarchivosinexistentes”. saltodelínea Uncarácterespecialutilizadoenarchivosycadenasparaindicar elfinaldeunalínea.

7.11Ejercicios

Ejercicio1:Escribeunprogramaqueleaunarchivoeimprimasucontenido(líneaporlínea),todoenmayúsculas.Alejecutarelprograma, deberíaparecerseaesto:

pythonshout.py

Ingresaunnombredearchivo:mbox-short.txt

FROMSTEPHEN.MARQUARD@UCT.AC.ZASATJAN509:14:162008

RETURN-PATH:<POSTMASTER@COLLAB.SAKAIPROJECT.ORG>

RECEIVED:FROMMURDER(MAIL.UMICH.EDU[141.211.14.90])

BYFRANKENSTEIN.MAIL.UMICH.EDU(CYRUSV2.3.8)WITHLMTPA; SAT,05JAN200809:14:16-0500

Puedesdescargarelarchivodesde www.py4e.com/code3/mbox-short.txt

Ejercicio2:Escribeunprogramaquesoliciteunnombredearchivo ydespuésleaesearchivobuscandolaslíneasquetenganlasiguiente forma:

X-DSPAM-Confidence:0.8475

**Cuandoencuentresunalíneaquecomiencecon“X-DSPAM-Confidence:”ponla aparteparaextraerelnúmerodecimaldelalínea.Cuentaesaslíneasydespués calculaeltotalacumuladodelosvaloresde“spam-confidence”.Cuandolleguesal finaldelarchivo,imprimeelvalormediode“spamconfidence”.

Ingresaunnombredearchivo:mbox.txt

Promediospamconfidence:0.894128046745

Ingresaunnombredearchivo:mbox-short.txt

Promediospamconfidence:0.750718518519

Pruebatuprogramaconlosarchivos mbox.txt y mbox-short.txt.

Ejercicio3:Algunasvecescuandolosprogramadoresseaburreno quierendivertirseunpoco,agreganuninofensivo HuevodePascua asuprograma.Modificaelprogramaquepreguntaalusuariopor el nombredearchivoparaqueimprimaunmensajedivertidocuando el usuarioescriba“nanabooboo”comonombredearchivo.Elprograma deberíafuncionarnormalmenteparacualquierarchivoqueexistaono exista.Aquíestáunejemplodelaejecucióndelprograma:

92 CHAPTER7.ARCHIVOS

pythonhuevo.py

Ingresaunnombredearchivo:mbox.txt Hay1797líneassubjectenmbox.txt

pythonhuevo.py

Ingresaunnombredearchivo:inexistente.tyxt Elarchivonopuedeserabierto:inexistente.tyxt

pythonhuevo.py

Ingresaunnombredearchivo:nanabooboo NANABOOBOOPARATI-Teheatrapado!

NoteestamosaconsejandoponerHuevosdePascuaentusprogramas; essólounejercicio.

7.11.EJERCICIOS 93
94 CHAPTER7.ARCHIVOS

Chapter8 Listas

8.1Unalistaesunasecuencia

Asícomounacadena,una lista esunasecuenciadevalores.Enunacadena,los valoressoncaracteres;enunalista,puedensercualquiertipo.Losvaloresenuna listasonllamados elementos oaveces ítems

Hayvariasformasdecrearunanuevalista;lamássimpleesencerrarloselementos encorchetes(“["y“]”):

[10, 20, 30, 40] ['ranacrujiente', 'vejigadecarnero', 'vómitodealondra']

Elprimerejemploesunalistade4enteros.Lasegundaesunalistadetrescadenas. Loselementosdeunalistanotienenqueserdelmismotipo.Lasiguientelista contieneunacadena,unflotante,unentero,y(¡mira!)otralista:

['spam', 2.0, 5,[10, 20]]

Unalistadentrodeotralistaestá anidada

Unalistaquenocontieneelementosesllamadaunalistavacía;puedescrearuna concorchetesvacíos, [].

Comopuedesver,puedesasignarlosvaloresdeunalistaavariables:

>>> quesos = ['Cheddar', 'Edam', 'Gouda']

>>> numeros = [17, 123]

>>> vacia = []

>>> print(quesos,numeros,vacia)

['Cheddar', 'Edam', 'Gouda'][17, 123][]

95

8.2Laslistassonmutables

Lasintaxisparaaccesarelementosdeunalistaeslamismaqueparaaccesar loscaracteresdeunacadena:eloperadorcorchete.Laexpresióndentrodelos corchetesespecifícaelíndice.Recordemosquelosíndicesempiezanen0:

>>> print(quesos[0])

Cheddar

Adiferenciadelascadenas,laslistassonmutablesporquepuedencambiarel ordendeloselementosenunalistaoreasignarunelementoenunalista.Cuando eloperadorcorcheteapareceenelladoizquierdodeunaasignación,ésteidentifica elelementodelalistaqueseráasignado.

>>> numeros = [17, 123]

>>> numeros[1] = 5

>>> print(numeros) [17, 5]

Elelementoenlaposiciónunode numeros,elcualsolíaser123,esahora5.

Puedespensarenunalistacomounarelaciónentreíndicesyelementos.Esta relaciónesllamada mapeo;cadaíndice“mapeaa”unodeloselementos.

Losíndicesenunalistafuncionandelamismamaneraquelosíndicesdeuna cadena:

•Cualquierformadeenteropuedeserutilizadacomoíndice.

•Sitratasdeleeroescribirunelementoquenoexiste,obtendrásun IndexError

•Siuníndicetieneunvalornegativo,éstecuentahaciaatrásdesdeelfinalde lalista.

Eloperador in funcionatambiénenlistas.

>>> quesos = ['Cheddar', 'Edam', 'Gouda']

>>> 'Edam' in quesos

True

>>> 'Brie' in quesos

False 8.3Recorriendounalista

Laformamáscomúnderecorrerloselementosdeunalistaesconunbucle for. Lasintaxiseslamismaqueparalascadenas:

96 CHAPTER8.LISTAS

for queso in quesos: print(queso)

Estofuncionabiensisolamentenecesitasleerloselementosdelalista.Perosi quieresescribiroactualizarloselementos,necesitaslosíndices.Unaformacomún dehaceresoescombinandolasfunciones range y len:

for i in range(len(numeros)): numeros[i] = numeros[i] * 2

Estebuclerecorrelalistayactualizacadaelemento. len regresaelnúmerode elementosenunalista. range regresaunalistadeíndicesdesde0hasta n 1, donde n eslalongituddelalista.Cadavezquepasaatravésdelrecorrido, i obtieneelíndicedelsiguienteelemento.Lasentenciadeasignacióndentrodel bucleutiliza i paraleerelvalororiginaldelelementoyasignarunnuevovalor.

Unbucle for atravésdeunalistavacíanuncaejecutaelcódigocontenidoenel cuerpo: for x in vacia: print('Estonuncasucede.')

Aunqueunalistapuedecontenerotralista,laslistasanidadassiguencontando comounsoloelemento.Eltamañodeestalistaescuatro: ['spam', 1,['Brie', 'Roquefort', 'PolleVeq'],[1, 2, 3]]

8.4Operacionesdelistas

Eloperador + concatenalistas:

>>> a = [1, 2, 3]

>>> b = [4, 5, 6] >>> c = a + b >>> print(c) [1, 2, 3, 4, 5, 6]

Deigualforma,eloperador * repiteunalistaundeterminadonúmerodeveces:

>>> [0] * 4 [0, 0, 0, 0]

>>> [1, 2, 3] * 3 [1, 2, 3, 1, 2, 3, 1, 2, 3]

Enelprimerejemploserepitecuatroveces.Enelsegundoejemploserepitela listatresveces.

8.4.OPERACIONESDELISTAS 97

8.5Rebanadodelistas

Eloperadorderebanadotambiénfuncionaenlistas:

>>> t = ['a', 'b', 'c', 'd', 'e', 'f']

>>> t[1:3]

['b', 'c']

>>> t[:4]

['a', 'b', 'c', 'd']

>>> t[3:]

['d', 'e', 'f']

Siomiteselprimeríndice,elrebanadocomienzadesdeeliniciodelalista.Si omiteselsegundo,elrebanadosevahastaelfinal.Asíquesiomitesambos,el rebanadoesunacopiadelalistacompleta.

>>> t[:]

['a', 'b', 'c', 'd', 'e', 'f']

Comolaslistassonmutables,avecesesútilhacerunacopiaantesdehaceroperacionesquedoblan,pegan,ocortanlistas.

Unoperadorderebanadoalladoizquierdodeunaasignaciónpuedeactualizar múltipleselementos:

>>> t = ['a', 'b', 'c', 'd', 'e', 'f']

>>> t[1:3] = ['x', 'y']

>>> print(t)

['a', 'x', 'y', 'd', 'e', 'f']

8.6Métodosdelistas

Pythonproveemétodosqueoperanenlistas.Porejemplo, append agregaunnuevo elementoalfinaldeunalista:

>>> t = ['a', 'b', 'c']

>>> t.append('d')

>>> print(t)

['a', 'b', 'c', 'd']

extend tomaunalistacomoargumentoyagregatodosloselementos:

>>> t1 = ['a', 'b', 'c']

>>> t2 = ['d', 'e']

>>> t1.extend(t2)

>>> print(t1)

['a', 'b', 'c', 'd', 'e']

98 CHAPTER8.LISTAS

Esteejemplodeja t2 sinmodificar.

sort ordenaloselementosdelalistademenoramayor:

>>> t = ['d', 'c', 'e', 'b', 'a']

>>> t.sort()

>>> print(t) ['a', 'b', 'c', 'd', 'e']

Lamayoríademétodosnoregresannada;modificanlalistayregresan None.Si accidentalmentesescribes t=t.sort(),vasadecepcionarteconelresultado.

8.7Eliminandoelementos

Hayvariasformasdeeliminarelementosdeunalista.Sisabeselíndicedelelemento quequieres,puedesusar pop:

>>> t = ['a', 'b', 'c']

>>> x = t.pop(1)

>>> print(t) ['a', 'c'] >>> print(x) b

pop modificalalistayregresaelelementoquefueremovido.Sinoproveesun índice,lafuncióneliminayretornaelúltimoelemento.

Sinonecesitaselvalorremovido,puedesusareloperador del:

>>> t = ['a', 'b', 'c']

>>> del t[1]

>>> print(t) ['a', 'c']

Sisabesquéelementoquieresremover(peronosabeselíndice),puedesusar remove:

>>> t = ['a', 'b', 'c']

>>> t.remove('b')

>>> print(t) ['a', 'c']

Elvalorderetornode remove es None

Pararemovermásdeunelemento,puedesusar del conuníndicederebanado:

>>> t = ['a', 'b', 'c', 'd', 'e', 'f']

>>> del t[1:5]

>>> print(t) ['a', 'f']

Comosiempre,elrebanadoseleccionatodosloselementoshasta,peroexcluyendo, elsegundoíndice.

8.7.ELIMINANDOELEMENTOS 99

8.8Listasyfunciones

Hayunciertonúmerofuncionesinternasquepuedenserutilizadasenlaslistasque tepermitenmirarrápidamenteatravésdeunalistasinescribirtuspropiosbucles:

>>> nums = [3, 41, 12, 9, 74, 15]

>>> print(len(nums)) 6 >>> print(max(nums)) 74 >>> print(min(nums)) 3 >>> print(sum(nums)) 154 >>> print(sum(nums)/len(nums)) 25

Lafunción sum() solamentefuncionacuandoloselementosdelalistasonnúmeros. Lasotrasfunciones(max(), len(),etc.)funcionanconlistasdecadenasyotros tiposquepuedensercomparadosentresí.

Podríamosreescribirunprogramaanteriorquecalculabaelpromediodeunalista denúmerosingresadosporelusuarioutilizandounalista.

Primero,elprogramaparacalcularunpromediosinunalista:

total = 0 contador = 0 while (True): inp = input('Ingresaunnúmero:') if inp == 'fin': break valor = float(inp) total = total + valor contador = contador + 1 promedio = total / contador print('Promedio:',promedio)

#Código:https://es.py4e.com/code3/avenum.py

Enesteprograma,tenemoslasvariables contador y total paraalmacenarla cantidadyeltotalactualdelosnúmerosdelusuariosegúnelusuariovaingresando losnúmerosrepetidamente.

Podríamossimplementerecordarcadanúmerocomoelnúmeroloingresó,yutilizar funcionesinternasparacalcularlasumayeltotaldenúmerosalfinal.

numlista = list() while (True): inp = input('Ingresaunnúmero:') if inp == 'fin': break

100 CHAPTER8.LISTAS

valor = float(inp) numlista.append(valor)

promedio = sum(numlista) / len(numlista) print('Promedio:',promedio)

#Código:https://es.py4e.com/code3/avelist.py

Creamosunalistavacíaantesdequecomienceelbucle,yluegocadavezque tengamosunnúmero,loagregamosalalista.Alfinaldelprograma,simplemente calculamoslasumadelosnúmerosenlalistayladividimosporeltotaldenúmeros enlalistaparaobtenerelpromedio.

8.9Listasycadenas

Unacadenaesunasecuenciadecaracteresyunalistaesunasecuenciadevalores, perounalistadecaracteresnoeslomismoqueunacadena.Paraconvertiruna cadenaenunalistadecaracteres,puedesusar list:

>>> s = 'spam'

>>> t = list(s)

>>> print(t) ['s', 'p', 'a', 'm']

Debidoaque list eselnombredeunafuncióninterna,debesevitarusarlacomo unnombredevariable.Yotratodeevitartambiénlaletra“l”porqueseparece muchoalnúmero“1”.Asíqueporesoutilizo“t”.

Lafunción list divideunacadenaenletrasindividuales.Siquieresdividiruna cadenaenpalabras,puedesutilizarelmétodo split:

>>> s = 'suspirandoporlosfiordos'

>>> t = s.split()

>>> print(t)

['suspirando', 'por', 'los', 'fiordos']

>>> print(t[2]) the

Unavezquehayasutilizado split paradividirunacadenaenunalistadepalabras, puedesutilizareloperadoríndice(corchetes)paraverunapalabraenparticular enlalista.

Puedesllamar split conunargumentoopcionalllamado delimitador queespecifica quécaracteresusarparadelimitarlaspalabras.Elsiguienteejemploutilizaun guiónmediocomodelimitador:

>>> s = 'spam-spam-spam'

>>> delimiter = '-'

>>> s.split(delimiter)

['spam', 'spam', 'spam']

8.9.LISTASYCADENAS 101

join eselinversode split.Estetomaunalistadecadenasyconcatenalos elementos. join esunmétododecadenas,asíquetienesqueinvocarloenel delimitadorypasarlalistacomounparámetro:

>>> t = ['suspirando', 'por', 'los', 'fiordos']

>>> delimiter = ''

>>> delimiter.join(t) 'suspirandoporlosfiordos'

Enestecasoeldelimitadoresuncaracterdeespacio,asíque join agregaun espacioentrelaspalabras.Paraconcatenarcadenassinespacios,puedesusarla cadenavacía,“”,comodelimitador.

8.10Analizandolíneas

Normalmentecuandoestamosleyendounarchivoqueremoshaceralgoconlas líneasquenoseasolamenteimprimirlaslíneascomoson.Frecuentementequeremosencontrarlas“líneasinteresantes”ydespués analizar lalíneaparaencontrar alguna“parteinteresante”enlalínea.¿Quétalsiquisiéramosimprimireldía de lasemanadelaslíneasquecomienzancon“From”?

Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

Elmétodo split esmuyefectivocuandonosencontramosestetipodeproblemas. Podemosescribirunpequeñoprogramaquebuscalíneasdondelalíneacomienza con“From”, split (dividir)esaslíneas,yfinalmenteimprimirlatercerpalabrade lalínea: man_a = open('mbox-short.txt') for linea in man_a: linea = linea.rstrip() if not linea.startswith('From'): continue palabras = linea.split() print(palabras[2])

#Código:https://es.py4e.com/code3/search5.py

Elprogramaproducelosiguiente: Sat Fri Fri Fri Mástarde,aprenderemostécnicasmuysofisticadasparaobtenerlaslíneasque queremosparatrajarsobreellasycómosacarelfragmentoexactodeinformación queestamosbuscando.

102 CHAPTER8.LISTAS

8.11Objetosyvalores

Siejecutamoslassiguientessentenciasdeasignación:

a = 'banana' b = 'banana'

sabemosqueambos a y b serefierenaunacadena,peronosabemossiserefieren oapuntanala misma cadena.Haydosestadosposibles: a b ‘banana’ ‘banana’ a b ‘banana’

Figure8.1:Variablesyobjetos

Porunlado, a y b serefierenadosobjetosdiferentesquetienenelmismovalor. Porotrolado,apuntanalmismoobjeto.

Pararevisarsidosvariablesapuntanalmismoobjeto,puedesutilizareloperador is.

>>> a = 'banana'

>>> b = 'banana'

>>> a is b True

Enesteejemplo,Pythonsolamentecreóunobjetodecadena,yambos a y b apuntanaél.

Perocuandocreasdoslistas,obtienesdosobjetosdiferentes:

>>> a = [1, 2, 3]

>>> b = [1, 2, 3]

>>> a is b False

Enestecasopodríamosdecirquelasdoslistasson equivalentes,porquetienen losmismoselementos,perono idénticas,porquenosonelmismoobjeto.Sidos objetossonidénticos,sontambiénequivalentes,perosisonequivalentes,no son necesariamenteidénticos.

Hastaahora,hemosestadousando“objeto”y“valor”deformaintercambiable, peroesmásprecisodecirqueunobjetotieneunvalor.Siejecutas a=[1,2,3], a serefiereaunalistadeobjetoscuyovaloresunasecuenciaparticulardeelementos. Siotralistatienelosmismoselementos,diríamosquetieneelmismovalor.

8.11.OBJETOSYVALORES 103

8.12Alias

Si a serefiereaunobjectoytuasignasb=a,entoncesambasvariablesserefieren almismoobjeto:

>>> a = [1, 2, 3]

>>> b = a

>>> b is a True

Laasociacióndeunavariableaunobjetoesllamadauna referencia.Eneste ejemplo,haydosreferenciasalmismoobjeto.

Unobjetoconmásdeunareferenciatienemásdeunnombre,asíquedecimosque elobjetoesun alias

Sielaliasdelobjetoesmutable,loscambioshechosaunaliasafectanalotro:

>>> b[0] = 17

>>> print(a) [17, 2, 3]

Aunqueestecomportamientopuedeserútil,espropensoaerrores.Engeneral,es másseguroevitarusaraliascuandoestástrabajandoconobjetosmutables.

Paraobjetosinmutablescomocadenas,losaliasnosonunproblemarealmente. Enesteejemplo:

a = 'banana' b = 'banana'

casinuncahaydiferenciasi a y b apuntanalamismacadenaono.

8.13Listascomoargumentos

Cuandopasasunalistaaunafunción,lafunciónobtieneunapuntadoralalista. Silafunciónmodificaunparámetrodelalista,elcódigoquehallamadolafunción tambiénveráelcambio.Porejemplo, remover_primero eliminaelprimerelemento deunalista:

def remover_primero(t): del t[0]

Aquíestáelejemplodecómoseusa:

>>> letras = ['a', 'b', 'c']

>>> remover_primero(letras)

>>> print(letras) ['b', 'c']

104 CHAPTER8.LISTAS

Elparámetro t ylavariable letras sonaliasparaelmismoobjeto.

Esimportantedistinguirentreoperacionesquemodificanlistasyoperaciones que creannuevaslistas.Porejemplo,elmétodo append modificaunalista,peroel operador + creaunanuevalista:

>>> t1 = [1, 2]

>>> t2 = t1.append(3)

>>> print(t1) [1, 2, 3]

>>> print(t2) None

>>> t3 = t1 + [3]

>>> print(t3) [1, 2, 3]

>>> t2 is t3 False

Estadiferenciaesimportantecuandoescribesfuncionesquenoestándestinadasa modificarlistas.Porejemplo,estafunción no eliminaelprimerelementodeuna lista:

def mal_eliminar_primero(t): t = t[1:] #¡EQUIVOCADO!

Eloperadorderebanadocreaunanuevalistayelasignamientohaceque t apunte alalista,peronadadeestotieneefectoenlalistaquefuepasadacomoargumento.

Unaalternativaesescribirunafunciónquecreeyregreseunanuevalista.Por ejemplo, cola regresatodoexceptoelprimerelementodeunalista:

def cola(t): return t[1:]

Estafuncióndejalalistaoriginalsinmodificar.Aquíestácomoesqueseusa:

>>> letras = ['a', 'b', 'c']

>>> resto = cola(letras)

>>> print(resto) ['b', 'c']

**Ejercicio1:Escribeunafunciónllamada recortar quetomaunalistaylamodifica,removiendoelprimeryúltimoelemento,yregresa None.Despuésescribeuna funciónllamada medio quetomaunalistayregresaunanuevalistaquecontiene todoexceptoelprimeroyúltimoelementos.

8.13.LISTASCOMOARGUMENTOS 105

8.14Depuración

Elusodescuidadodelistas(yotrosobjetosmutables)puedellevaralargashoras dedepuración.Aquíestánalgumosdeloserroresmáscomunesylasformasde evitarlos:

1.Noolvidesquelamayoríademétodosdelistasmodificanelargumentoy regresan None.Estoesloopuestoalosmétodosdecadenas,queregresan unanuevacadenaydejanlaoriginalsinmodificar. Siestásacostumbradoaescribircódigodecadenascomoeste: palabra = palabra.strip()

Estáspropensoaescribircódigodelistascomoeste: t = t.sort() #¡EQUIVOCADO!

Debidoaque sort regresa None,lasiguienteoperaciónquehagascon t es probablequefalle.

Antesdeusarmétodosyoperadoresdelistas,deberíasleerladocumentación cuidadosamenteydespuésprobarlosenmodointeractivo.Losmétodosy operadoresquelaslistascompartenconotrassecuencias(comocadenas) estándocumentadosen: docs.python.org/library/stdtypes.html#common-sequence-operations Losmétodosyoperadoresquesolamenteaplicanasecuenciasmutablesestán documentadosen: docs.python.org/library/stdtypes.html#mutable-sequence-types

2.Eligeunestiloyapégateaél.

Partedelproblemaconlistasesquehaydemasiadasformasdehacerlas cosas.Porejemplo,pararemoverunelementodeunalista,puedesutilizar pop, remove, del,oinclusounaasignaciónporrebanado. Paraagregarunelemento,puedesutilizarelmétodo append oeloperador + Peronoolvidesqueesostambiénsoncorrectos: t.append(x) t = t + [x] Yesossonincorrectos: t.append([x])

Pruebacadaunodeesosejemplosenmodointeractivoparaasegurarteque entiendesloquehacen.Notaquesolamentelaúltimaprovocaunerroren tiempodeejecución(runtimeerror);losotrostressonválidos,perohacenla funciónequivocada.

106 CHAPTER8.LISTAS
#¡EQUIVOCADO!
#¡EQUIVOCADO!
#¡EQUIVOCADO!
t = t.append(x)
t + [x]
t = t + x #¡EQUIVOCADO!

3.Hacercopiasparaevitaralias.

Siquieresutilizarunmétodocomo sort quemodificaelargumento,pero necesitasmantenerlalistaoriginaltambién,puedeshacerunacopia.

orig = t[:] t.sort()

Enesteejemplopodríastambienusarlafuncióninterna sorted,lacual regresaunalistanuevayordenada,ydejalaoriginalsinmodificar.¡Peroen esecasodeberíasevitarusar sorted comounnombredevariable!

4.Listas, split,yarchivos

Cuandoleemosyanalizamosarchivos,haymuchasoportunidadesdeencontrarentradasquepuedenhacerfallaranuestroprograma,asíqueesuna buenaidearevisarelpatrón guardián cuandoescribimosprogramasqueleen atravésdeunarchivoybuscanuna“agujaenunpajar”.

Vamosarevisarnuestroprogramaquebuscaporeldíadelasemanaenlas líneasquecontienen“from”enelarchivo“:

Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

Puestoqueestamosdividiendoestalíneaenpalabras,podríamosapañarnos conelusode startswith ysimplementebuscarlaprimerpalabradela líneaparadeterminarsiestamosinteresadosenesalíneaono.Podemosusar continue parasaltarnoslíneasquenotienen“From”comolaprimerpalabra, talcomosigue:

manejador = open('mbox-short.txt') for linea in manejador: palabras = linea.split() if palabras[0] != 'From' : continue print(palabras[2])

Estosevemuchomássimpleynisiquieranecesitamoshacer rstrip para removerelsaltodelíneaalfinaldelarchivo.Pero,¿esmejor?

pythonsearch8.py Sat

Traceback(mostrecentcalllast): File"search8.py",line5,in<module> ifpalabras[0]!='From':continue IndexError:listindexoutofrange

Dealgunamanerafuncionayvemoseldíadelaprimerlínea(Sat),pero luegoelprogramafallaconunerror.¿Quéfueloquefalló?¿Quédatos estropearonehicieronfallaranuestroelegante,inteligente,ymuyPythónico programa?

Puedesmirarelcódigoporunlargotiempoytratarderesolverloopreguntaraalguienmás,peroelmétodomásrápidoeinteligenteesagregaruna sentencia print.Elmejorlugarparaagregarlasentencia“print”esjusto

8.14.DEPURACIÓN 107

antesdelalíneadondeelprogramafalló,eimprimirlosdatosqueparece quecausanlafalla.

Ahorabien,estemétodopodríagenerarmuchaslíneasdesalida,peroal menostendrásinmediatamentealgunapistadecuáleselproblema.Así queagregamosunprintalavariable palabras justoantesdelalíneacinco.

Inclusopodemosagregarunprefijo“Depuración:”alalíneademodoque mantenemosnuestrasalidaregularseparadadelasalidademensajesde depuración.

for linea in manejador: palabras = line.split() print('Depuración:',palabras) if palabras[0] != 'From' : continue print(palabras[2])

Cuandoejecutamoselprograma,segeneranmuchosmensajesdesalidaen lapantalla,peroalfinal,vemosnuestrasalidadedepuraciónyelmensajede error,demodoquesabemosquésucediójustoantesdelerror.

Debug:['X-DSPAM-Confidence:','0.8475']

Debug:['X-DSPAM-Probability:','0.0000']

Debug:[] Traceback(mostrecentcalllast): File"search9.py",line6,in<module> ifpalabras[0]!='From':continue IndexError:listindexoutofrange

Cadalíneadedepuraciónimprimelalistadepalabrasqueobtuvimoscuando lafunción split dividiólalíneaenpalabras.Cuandoelprogramafalla,la listadepalabrasestávacía [].Siabrimoselarchivoenuneditordetextoy miramoselarchivo,enesepuntosevelosiguiente:

X-DSPAM-Result:Innocent

X-DSPAM-Processed:SatJan509:14:162008

X-DSPAM-Confidence:0.8475

X-DSPAM-Probability:0.0000

Details:http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772

¡Elerrorocurrecuandonuestroprogramaencuentraunalíneavacía!Por supuesto,hay“ceropalabras”enunalistavacía.¿Porquénopensamoseneso cuandoestábamosescribiendoelcódigo?Cuandoelcódigobuscalaprimera palabra(palabras[0])pararevisarsicoincidecon“From”,obtenemosun error“indexoutofrange”(índicefueraderango).

Estees,porsupuesto,ellugarperfectoparaagregaralgode códigoguardián paraevitarrevisarlaprimerpalabrasilaprimerpalabranoexiste.Hay muchasmanerasdeprotegerestecódigo;vamosaoptarporrevisarelnúmero depalabrasquetenemosantesdemiraralaprimerpalabra:

manejador = open('mbox-short.txt') contador = 0

108 CHAPTER8.LISTAS

for linea in manejador: palabras = linea.split() #print'Depuración:',palabras if len(palabras) == 0 : continue if palabras[0] != 'From' : continue print(palabras[2])

Primerocomentamoslasentenciadedepuraciónenvezderemoverla,encaso dequenuestramodificaciónfalleytengamosquedepurardenuevo.Luego, agregamosunasentenciaguardiánquerevisasitenemosceropalabras,y siasífuera,utilizamos continue parasaltarnosalasiguientelíneaenel archivo.

Podemospensarenlasdossentencias continue paraayudarnosaredefinir eljuegodelíneasqueson“interesantes”paranosotrosycuálesqueremos procesarmás.Unalíneaquenotengapalabras“noesinteresante”para nosotrosasíquesaltamosalasiguientelínea.Unalíneaquenotenga“From” comosuprimerapalabratampoconosinteresaasíquelasaltamos.

Elprogramamodificadoejecutaexitosamente,asíquequizásescorrecto. Nuestrasentenciaguardiánseaseguradeque palabras[0] nuncafalle,pero quizánoseasuficiente.Cuandoestamosprogramando,siempredebemos pensar,“¿quépodríasalirmal?”

Ejercicio2:Encontrarquelíneadelprogramadearribanoestáprotegida(métodoguardián)propiamente.Tratadeconstruirunarchivode textoquecausequeelprogramafalleydespuésmodificaelprogramade modoquelalíneaespropiamenteprotegidaypruébaloparaasegurarte queelprogramaescapazdemanejartunuevoarchivodetexto.

Ejercicio3:Reescribeelcódigoguardiánenelejemplodearribasinlas dossentencias if.Envezdeeso,utilizaunaexpresiónlógicacompuesta utilizandoeloperadorlógico or conunasolasentencia if.

8.15Glosario

alias Unacircunstanciadondedosomásvariablesapuntanalmismoobjeto. delimitador Uncaracterocadenautilizadoparaindicardóndeunacadenadebe serdividida.

elemento Unodelosvaloresenunalista(uotrasecuencia);tambiénllamados ítems.

equivalente Quetieneelmismovalor. idéntico Serelmismoobjeto(locualimplicaequivalencia). índice Unvalorenteroqueindicaunelementoenunalista.

lista Unasecuenciadevalores. listaanidada Unalistaqueesunodeloselementosdeotralista. objeto Algoaloqueunavariablepuedereferirse.Unobjetotieneuntipoyun valor.

recorridodelista Accesosecuencialacadaelementodeunalista. referencia Laasociaciónentreunavariableysuvalor.

8.15.GLOSARIO 109

8.16Ejercicios

Ejercicio4:Descargarunacopiadeunarchivo www.py4e.com/code3/romeo.txt. Escribirunprogramaparaabrirelarchivo romeo.txt yleerlolínea porlínea.Paracadalínea,dividirlalíneaenunalistadepalabras utilizandolafunción split.Paracadapalabra,revisarsilapalabraya seencuentrapreviamenteenlalista.Silapalabranoestáenlalista, agregarlaalalista.Cuandoelprogramatermine,ordenareimprimir laspalabrasresultantesenordenalfabético.

Ingresarnombredearchivo:romeo.txt ['Arise','But','It','Juliet','Who','already', 'and','breaks','east','envious','fair','grief', 'is','kill','light','moon','pale','sick','soft', 'sun','the','through','what','window', 'with','yonder']

Ejercicio5:Escribirunprogramaparaleeratravésdedatosdeunabandejadeentradadecorreoycuandoencuentresunalíneaquecomience con“From”,dividirlalíneaenpalabrasutilizandolafunción split. Estamosinteresadosenquiénenvióelmensaje,locualeslasegunda palabraenlaslíneasquecomienzanconFrom.

Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

TendrásqueanalizarlalíneaFromeimprimirlasegundapalabrade cadalíneaFrom,despuéstendrásquecontarelnúmerodelíneas From (noincluirFrom:)eimprimireltotalalfinal.Esteesunbuenejemplo desalidaconalgunaslíneasdesalidaremovidas:

pythonfromcuenta.py

Ingresaunnombredearchivo:mbox-short.txt stephen.marquard@uct.ac.za louis@media.berkeley.edu zqian@umich.edu

[...líneasdesalidaremovidas...]

ray@media.berkeley.edu cwen@iupui.edu cwen@iupui.edu cwen@iupui.edu Hay27lineasenelarchivoconlapalabraFromalinicio

Ejercicio6:Reescribeelprogramaquepidealusuariounalistade númeroseimprimeelmáximoyelmínimodelosnúmerosalfinalcuando elusuarioingresa“hecho”.Escribeelprogramaparaalmacenarlos númerosqueelusuarioingreseenunalista,yutilizalasfunciones max() y min() paracalcularelmáximoyelmínimodespuésdequeelbucle termine.

110 CHAPTER8.LISTAS

Ingresaunnúmero:6

Ingresaunnúmero:2

Ingresaunnúmero:9

Ingresaunnúmero:3

Ingresaunnúmero:5

Ingresaunnúmero:hecho Máximo:9.0 Minimo:2.0

8.16.EJERCICIOS 111
112 CHAPTER8.LISTAS

Diccionarios

Un diccionario escomounalista,peromásgeneral.Enunalista,losíndicesde posicionestienenqueserenteros;enundiccionario,losíndicespuedenser(casi) cualquiertipo.

Puedespensarenundiccionariocomounaasociaciónentreunconjuntodeíndices (quesonllamados claves)yunconjuntodevalores.Cadaclaveapuntaaunvalor. Laasociacióndeunaclaveyunvaloresllamada parclave-valor oaveces elemento. Comoejemplo,vamosaconstruirundiccionarioqueasociapalabrasdeInglésa Español,asíquetodaslasclavesylosvaloressoncadenas.

Lafunción dict creaunnuevodiccionariosinelementos.Debidoaque dict esel nombredeunafuncióninterna,deberíasevitarusarlocomounnombredevariable.

>>> eng2sp = dict() >>> print(eng2sp) {}

Lasllaves, {},representanundiccionariovacío.Paraagregarelementosaun diccionario,puedesutilizarcorchetes:

>>> eng2sp['one'] = 'uno'

Estalíneacreaunelementoasociandoalaclave 'one' elvalor“uno”.Siimprimimoseldiccionariodenuevo,vamosaverunparclave-valorcondospuntosentre laclaveyelvalor:

>>> print(eng2sp) {'one': 'uno'}

Esteformatodesalidaestambiénunformatodeentrada.Porejemplo,puedes crearunnuevodiccionariocontreselementos.Perosiimprimes eng2sp,tevasa sorprender:

Chapter9
113

>>> eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}

>>> print(eng2sp)

{'one': 'uno', 'three': 'tres', 'two': 'dos'}

Elordendelosparesclave-elementonoeselmismo.Dehecho,situescribeseste mismoejemploentucomputadora,podríasobtenerunresultadodiferente.En general,elordendeloselementosenundiccionarioesimpredecible.

Peroesenoesunproblemaporqueloselementosdeundiccionarionuncason indexadosconíndicesenteros.Envezdeeso,utilizaslasclavesparaencontrarlos valorescorrespondientes:

>>> print(eng2sp['two']) 'dos'

Laclave 'two' siempreseasociaalvalor“dos”,asíqueelordendeloselementos noimporta.

Silaclavenoestáeneldiccionario,obtendrásunaexcepción(exception):

>>> print(eng2sp['four'])

KeyError: 'four'

Lafunción len funcionaendiccionarios;éstaregresaelnúmerodeparesclavevalor:

>>> len(eng2sp) 3

Eloperador in funcionaendiccionarios;éstetedicesialgoaparececomouna clave eneldiccionario(aparecercomovalornoessuficiente).

>>> 'one' in eng2sp True

>>> 'uno' in eng2sp False

Paraversialgoaparececomovalorenundiccionario,puedesusarelmétodo values,elcualretornalosvalorescomounalista,ydespuéspuedesusareloperador in:

>>> vals = list(eng2sp.values())

>>> 'uno' in vals True

Eloperador in utilizadiferentesalgoritmosparalistasydiccionarios.Paralistas, utilizaunalgoritmodebúsquedalineal.Conformelalistasevuelvemásgrande, el tiempodebúsquedasevuelvemáslargoenproporciónaltamañodelalista.Para diccionarios,Pythonutilizaunalgoritmollamado tablahash (hashtable,eninglés)

114 CHAPTER9.DICCIONARIOS

quetieneunapropiedadimportante:eloperador in tomalamismacantidadde tiemposinimportarcuántoselementoshayaeneldiccionario.Novoyaexplicar porquélasfuncioneshashsontanmágicas,peropuedesleermásalrespectoen es.wikipedia.org/wiki/Tabla_hash

Ejercicio1:Descargarunacopiadelarchivo www.py4e.com/code3/words.txt

Escribeunprogramaqueleelaspalabrasen words.txt ylasalmacena comoclavesenundiccionario.Noimportaquévalorestenga.Luego puedesutilizareloperador in comounaformarápidaderevisarsiuna cadenaestáeneldiccionario.

9.1Diccionariocomounconjuntodecontadores

Supongamosquerecibesunacadenayquierescontarcuántasvecesaparececada letra.Hayvariasformasenquepuedeshacerlo:

1.Puedescrear26variables,unaporcadaletradelalfabeto.Luegopuedes recorrerlacadena,yparacadacaracter,incrementarelcontadorcorrespondiente,probablementeutilizandovarioscondicionales.

2.Puedescrearunalistacon26elementos.Despuéspodríasconvertircada caracterenunnúmero(usandolafuncióninterna ord),usarelnúmerocomo índicedentrodelalista,eincrementarelcontadorcorrespondiente.

3.Puedescrearundiccionarioconcaracterescomoclavesycontadorescomo losvalorescorrespondientes.Laprimeravezqueencuentresuncaracter, agregaríasunelementoaldiccionario.Despuésdeesoincrementaríaselvalor delelementoexistente.

Cadaunadeesasopcioneshacelamismaoperacióncomputacional,perocadauna deellasimplementaesaoperaciónenformadiferente.

Una implementación esunaformadellevaracabounaoperacióncomputacional; algunasimplementacionessonmejoresqueotras.Porejemplo,unaventajadela implementacióndeldiccionarioesquenotenemosquesaberconantelaciónqué letrasaparecenenlacadenaysolamentenecesitamosespacioparalasletrasque síaparecen.

Aquíestáunejemplodecomoseveríaesecódigo:

palabra = 'brontosaurio' d = dict() for c in palabra: if c notin d: d[c] = 1 else: d[c] = d[c] + 1 print(d)

9.1.DICCIONARIOCOMOUNCONJUNTODECONTADORES 115

Realmenteestamoscalculandoun histograma,elcualesuntérminoestadístico paraunconjuntodecontadores(ofrecuencias).

Elbucle for recorrelacadena.Cadavezqueentramosalbucle,sielcaracter c no estáeneldiccionario,creamosunnuevoelementoconlaclave c yelvalorinicial 1(debidoaquehemosvistoestaletrasolounavez).Si c yaestápreviamenteen eldiccionarioincrementamos d[c]

Aquíestálasalidadelprograma: {'b':1,'r':2,'o':3,'n':1,'t':1,'s':1,'a':1,'u':1,'i':1}

Elhistogramaindicaquelasletras“a”y“b”aparecensolounavez;“o”aparece dos,yasísucesivamente.

Losdiccionariostienenunmétodollamado get quetomaunaclaveyunvalorpor defecto.Silaclaveapareceeneldiccionario, get regresaelvalorcorrespondiente; sino,regresaelvalorpordefecto.Porejemplo:

>>> cuentas = { 'chuck' : 1 , 'annie' : 42, 'jan': 100}

>>> print(cuentas.get('jan', 0)) 100

>>> print(cuentas.get('tim', 0)) 0

Podemosusar get paraescribirnuestrobucledehistogramamásconciso.Puesto queelmétodo get automáticamentemanejaelcasoenqueunaclavenoestáenel diccionario,podemosreducircuatrolíneasaunayeliminarlasentencia if. palabra = 'brontosaurio' d = dict() for c in palabra: d[c] = d.get(c,0) + 1 print(d)

Elusodelmétodo get parasimplificarestebuclecontadorterminasiendoun “idioma”muyutilizadoenPythonyvamosautilizarlomuchasvecesenelresto dellibro.Asíquedeberíastomarunmomentoparacompararelbucleutilizando lasentencia if yeloperador in conelbucleutilizandoelmétodo get.Ambos hacenexactamentelomismo,perounoesmásbreve.

9.2Diccionariosyarchivos

Unodelosusosmáscomunesdeundiccionarioescontarlasocurrenciasdepalabras enunarchivoconalgúntextoescrito.Vamoscomenzandoconunarchivode palabrasmuysimpletomadodeltextode RomeoyJulieta. Paraelprimerconjuntodeejemplos,vamosausarunaversiónmáscortaymás simplificadadeltextosinsignosdepuntuación.Despuéstrabajaremosconeltexto delaescenaconsignosdepuntuaciónincluidos.

116 CHAPTER9.DICCIONARIOS

Butsoftwhatlightthroughyonderwindowbreaks

ItistheeastandJulietisthesun Arisefairsunandkilltheenviousmoon Whoisalreadysickandpalewithgrief

VamosaescribirunprogramadePythonparaleeratravésdelaslíneasdelarchivo, dividiendocadalíneaenunalistadepalabras,ydespuésiterandoatravésdecada unadelaspalabrasenlalíneaycontandocadapalabrautilizandoundiccionario.

Verásquetenemosdosbucles for.Elbucleexternoestáleyendolaslíneasdel archivoyelbucleinternoestáiterandoatravésdecadaunadelaspalabrasen esalíneaenparticular.Esteesunejemplodeunpatrónllamado buclesanidados porqueunodelosbucleseselbucle externo yelotrobucleeselbucle interno.

Comoelbucleinternoejecutatodassusiteracionescadavezqueelbucleexterno haceunasolaiteración,consideramosqueelbucleinternoitera“másrápido”yel bucleexternoiteramáslento.

Lacombinacióndelosdosbuclesanidadosaseguraquecontemoscadapalabraen cadalíneadelarchivodeentrada.

fname = input('Ingresaelnombredearchivo:') try: fhand = open(fname) except: print('Elarchivonosepuedeabrir:',fname) exit() counts = dict() for line in fhand: words = line.split() for word in words: if word notin counts: counts[word] = 1 else: counts[word] += 1 print(counts)

#Código:https://es.py4e.com/code3/count1.py

Ennuestrasentencia else,utilizamoslaalternativamáscompactaparaincrementarunavariable. counts[word]+=1 esequivalentea counts[word]= counts[word]+1.Cualquieradelosdosmétodospuedeusarseparacambiarel valordeunavariableencualquiercantidad.Existenalternativassimilarespara -= , *=,y /=.

Cuandoejecutamoselprograma,vemosunasalidasinprocesarquecontiene todosloscontadoressinordenar.(elarchivo romeo.txt estádisponibleen es.py4e.com/code3/romeo.txt)

pythoncount1.py

9.2.DICCIONARIOSYARCHIVOS 117

Ingresaelnombredearchivo:romeo.txt {'and':3,'envious':1,'already':1,'fair':1, 'is':3,'through':1,'pale':1,'yonder':1, 'what':1,'sun':2,'Who':1,'But':1,'moon':1, 'window':1,'sick':1,'east':1,'breaks':1, 'grief':1,'with':1,'light':1,'It':1,'Arise':1, 'kill':1,'the':3,'soft':1,'Juliet':1}

Esunpocoinconvenienteveratravésdeldiccionarioparaencontrarlaspalabras máscomunesysuscontadores,asíquenecesitamosagregarunpocomásdecódigo paramostrarunasalidaquenossirvamás.

9.3Buclesydiccionarios

Siutilizasundiccionariocomounasecuenciaparaunasentencia for,estarecorre lasclavesdeldiccionario.Estebucleimprimecadaclaveysuvalorcorrespondiente:

contadores = { 'chuck' : 1 , 'annie' : 42, 'jan': 100} for clave in contadores: print(clave,contadores[clave])

Aquíestáloquemuestradesalida: jan100 chuck1 annie42

Denuevo,lasclavesnoestánenningúnordenenparticular.

Podemosutilizarestepatrónparaimplementarvariosidiomasdebuclesquehemos descritopreviamente.Porejemplo,siqueremosencontrartodaslasentradasen undiccionarioconvalormayoradiez,podemosescribirelsiguientecódigo:

contadores = { 'chuck' : 1 , 'annie' : 42, 'jan': 100} for clave in contadores: if contadores[clave] > 10 : print(clave,contadores[clave])

Elbucle for iteraatravésdelas claves deldiccionario,asíquedebemosutilizarel operadoríndiceparaobtenerel valor correspondienteparacadaclave.Aquíestá lasalidadelprograma: jan100 annie42

Vemossolamentelasentradasquetienenunvalormayora10.

Siquieresimprimirlasclavesenordenalfabético,primerohacesunalistadelas claveseneldiccionarioutilizandoelmétodo keys disponibleenlosobjetosde diccionario,ydespuésordenaresalistaeiteraratravésdelalistaordenada,buscandocadaclaveeimprimiendoparesclave-valorordenados,talcomosemuestra acontinuación:

118 CHAPTER9.DICCIONARIOS

contadores = { 'chuck' : 1 , 'annie' : 42, 'jan': 100} lst = list(contadores.keys()) print(lst) lst.sort() for clave in lst: print(clave,contadores[clave])

Asísemuestralasalida: ['jan','chuck','annie'] annie42 chuck1 jan100

Primerosevelalistadeclavessinordenarcomolaobtuvimosdelmétodo keys. Despuésvemoslosparesclave-valorenordendesdeelbucle for 9.4Análisisavanzadodetexto

Enelejemploanteriorutilizandoelarchivo romeo.txt,hicimoselarchivotansimple comofueposibleremoviendolossignosdepuntuaciónamano.Eltextrealtiene muchossignosdepuntuación,comosemuestraabajo.

But,soft!whatlightthroughyonderwindowbreaks? Itistheeast,andJulietisthesun. Arise,fairsun,andkilltheenviousmoon, Whoisalreadysickandpalewithgrief,

Puestoquelafunción split enPythonbuscaespaciosytratalaspalabrascomo piezasseparadasporesosespacios,trataríamosalaspalabras“soft!”y“soft”como diferentes palabrasycrearíamosunaentradaindependienteparacadapalabraen eldiccionario.

Además,comoelarchivotieneletrasmayúsculas,trataríamos“who”y“Who” comodiferentespalabrascondiferentescontadores.

Podemosresolverambosproblemasutilizandolosmétodosdecadenas lower, punctuation,y translate.Elmétodo translate eselmássutildelosmétodos. Aquíestaladocumentaciónpara translate:

line.translate(str.maketrans(fromstr,tostr,deletestr))

Reemplazaloscaracteresen fromstr conelcaracterenlamismaposiciónen tostr yeliminatodosloscaracteresqueestánen deletestr.Losparámetros fromstr y tostr puedensercadenasvacíasyelparámetro deletestr esopcional.

Novamosaespecificarelvalorde tostr perovamosautilizarelparámetro deletestr paraeliminartodoslossignosdepuntuación.Inclusovamosadejarque Pythonnosdigalalistadecaracteresqueconsideracomo“signosdepuntuación”:

9.4.ANÁLISISAVANZADODETEXTO 119

>>> importstring

>>> string.punctuation '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

Losparámetrosutilizadospor translate erandiferentesenPython2.0. Hacemoslassiguientesmodificacionesanuestroprograma:

importstring

fname = input('Ingresaelnombredearchivo:') try: fhand = open(fname) except: print('Elarchivonosepuedeabrir:',fname) exit() counts = dict() for line in fhand: line = line.rstrip() line = line.translate(line.maketrans('', '',string.punctuation)) line = line.lower() words = line.split() for word in words: if word notin counts: counts[word] = 1 else: counts[word] += 1 print(counts) #Código:https://es.py4e.com/code3/count2.py

Partedeaprenderel“ArtedePython”o“PensamientoPythónico”esentenderque Pythonmuchasvecestienefuncionesinternasparamuchosproblemasdeanálisisde datoscomunes.Atravésdeltiempo,verássuficientescódigosdeejemployleerás losuficienteenladocumentaciónparasaberdóndebuscarsialguienescribióalgo quehagatutrabajomásfácil.

Losiguienteesunaversiónreducidadelasalida:

Ingresaelnombredearchivo:romeo-full.txt {'swearst':1,'all':6,'afeard':1,'leave':2,'these':2, 'kinsmen':2,'what':11,'thinkst':1,'love':24,'cloak':1, a':24,'orchard':2,'light':5,'lovers':2,'romeo':40, 'maiden':1,'whiteupturned':1,'juliet':32,'gentleman':1, 'it':22,'leans':1,'canst':1,'having':1,...}

Interpretarlosdatosatravésdeestasalidaesaúndifícil,ypodemosutilizar Pythonparadarnosexactamenteloqueestamosbuscando,peroparaquesea así,necesitamosaprenderacercadelas tuplas enPython.Vamosaretomareste ejemplounavezqueaprendamossobretuplas.

120 CHAPTER9.DICCIONARIOS

9.5Depuración

Conformetrabajesconconjuntosdedatosmásgrandespuedesercomplicadodepurarimprimiendoyrevisandolosdatosamano.Aquíhayalgunassugerenciaspara depurargrandesconjuntosdedatos:

Reducirlaentrada Siesposible,tratadereducireltamañodelconjuntode datos.Porejemplo,sielprogramaleeunarchivodetexto,comienzasolamenteconlasprimeras10líneas,oconelejemplomáspequeñoquepuedas encontrar.Puedesyaseaeditarlosarchivosdirectamente,o(mejor)modificarelprogramaparaquesolamentelealasprimeras n númerodelíneas.

Sihayunerror,puedesreducir n alvalormáspequeñoqueproduceelerror,ydespuésincrementarlogradualmenteconformevayasencontrandoy corrigiendoerrores.

Revisarextractosytipos Enlugardeimprimiryrevisarelconjuntodedatos completo,consideraimprimirextractosdelosdatos:porejemplo,elnúmero deelementosenundiccionariooeltotaldeunalistadenúmeros.

Unacausacomúndeerroresentiempodeejecuciónesunvalorquenoesel tipocorrecto.Paradepurarestetipodeerror,generalmenteessuficientecon imprimireltipodeunvalor.

Escribeauto-verificaciones Algunasvecespuedesescribircódigopararevisar erroresautomáticamente.Porejemplo,siestáscalculandoelpromediode unalistadenúmeros,podríasverificarqueelresultadonoseamásgrande queelelementomásgrandedelalistaoqueseamenorqueelelementomás pequeñodelalista.Estoesllamado“pruebadesanidad”porquedetecta resultadosqueson“completamenteilógicos”.

Otrotipodepruebacomparalosresultadosdedosdiferentescálculospara versisonconsistentes.Estoesconocidocomo“pruebadeconsistencia”.

Imprimirunasalidaordenada Darunformatoalosmensajesdedepuración puedefacilitarencontrarunerror.

Denuevo,eltiempoqueinviertashaciendounabuenaestructurapuedereducirel tiempoqueinviertasendepurar.

9.6Glosario

buclesanidados Cuandohayunoomásbucles“dentro”deotrobucle.Los buclesinternosterminandeejecutarcadavezqueelbucleexternoejecuta unavez.

búsqueda Unaoperacióndediccionarioquetomaunaclaveyencuentrasuvalor correspondiente. clave Unobjetoqueapareceenundiccionariocomolaprimerapartedeunpar clave-valor.

diccionario Unaasociacióndeunconjuntodeclavesasusvalorescorrespondientes.

9.5.DEPURACIÓN 121

elemento Otronombreparaunparclave-valor. funciónhash Unafunciónutilizadaporunatablahashparacalcularlalocalizacióndeunaclave. histograma Unsetdecontadores. implementación Unaformadellevaracabouncálculo. parclave-valor Larepresentacióndeunaasociacióndeunaclaveaunvalor. tablahash ElalgoritmoutilizadoparaimplementardiccionariosenPython. valor Unobjetoqueapareceenundiccionariocomolasegundapartedeunpar clave-valor.Estadefiniciónesmásespecíficaquenuestrousopreviodela palabra“valor”.

9.7Ejercicios

Ejercicio2:Escribirunprogramaqueclasificacadamensajede correo dependiendodeldíadelasemanaenqueserecibió.Parahacer esto buscalaslíneasquecomienzancon“From”,despuésbuscapor latercer palabraymanténuncontadorparacadaunodelosdíasdelasemana. Alfinaldelprogramaimprimeloscontenidosdetudiccionario(elorden noimporta).

Líneadeejemplo: Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

Ejemplodeejecución: pythondow.py

Ingresaunnombredearchivo:mbox-short.txt {'Fri':20,'Thu':6,'Sat':1}

Ejercicio3:Escribeunprogramaparaleeratravésdeunhistorialde correos,construyeunhistogramautilizandoundiccionarioparacontar cuántosmensajeshanllegadodecadadireccióndecorreoelectrónico,e imprimeeldiccionario.

Ingresaunnombredearchivo:mbox-short.txt {'gopal.ramasammycook@gmail.com':1,'louis@media.berkeley.edu':3, 'cwen@iupui.edu':5,'antranig@caret.cam.ac.uk':1, 'rjlowe@iupui.edu':2,'gsilver@umich.edu':3, 'david.horwitz@uct.ac.za':4,'wagnermr@iupui.edu':1, 'zqian@umich.edu':4,'stephen.marquard@uct.ac.za':2, 'ray@media.berkeley.edu':1}

Ejercicio4:Agregacódigoalprogramaanteriorparadeterminarquién tienelamayoríademensajesenelarchivo.Despuésdequetodoslos datoshayansidoleídosyeldiccionariohayasidocreado,miraatravés deldiccionarioutilizandounbuclemáximo(veCapítulo5:Buclesmáximosymínimos)paraencontrarquiéntienelamayoríademensajese imprimircuántosmensajestieneesapersona.

122 CHAPTER9.DICCIONARIOS

Ingresaunnombredearchivo:mbox-short.txt cwen@iupui.edu5

Ingresaunnombredearchivo:mbox.txt zqian@umich.edu195

Ejercicio5:Esteprogramaalmacenaelnombredeldominio(envezde ladirección)desdedondefueenviadoelmensajeenvezdequién envió elmensaje(esdecir,ladireccióndecorreoelectrónicacompleta).Al finaldelprograma,imprimeelcontenidodetudiccionario.

pythonschoolcount.py

Ingresaunnombredearchivo:mbox-short.txt {'media.berkeley.edu':4,'uct.ac.za':6,'umich.edu':7, 'gmail.com':1,'caret.cam.ac.uk':1,'iupui.edu':8}

9.7.EJERCICIOS 123
124 CHAPTER9.DICCIONARIOS

Chapter10 Tuplas

10.1LasTuplassoninmutables

Unatupla1 esunasecuenciadevaloressimilaraunalista.Losvaloresguardados enunatuplapuedenserdecualquiertipo,ysonindexadospornúmerosenteros. Laprincipaldiferenciaesquelastuplasson inmutables.Lastuplasademásson comparables y dispersables (hashables)demodoquelaslistasdetuplassepueden ordenarytambiénusartuplascomovaloresparalasclavesendiccionariosde Python.

Sintácticamente,unatuplaesunalistadevaloresseparadosporcomas:

>>> t = 'a', 'b', 'c', 'd', 'e'

Aunquenoesnecesario,escomúnencerrarlastuplasentreparéntesisparaayudarnosaidentificarlasrápidamentecuandorevisemoscódigodePython:

>>> t = ('a', 'b', 'c', 'd', 'e')

Paracrearunatuplaconunsoloelemento,esnecesarioincluirunacomaalfinal:

>>> t1 = ('a',)

>>> type(t1)

<type 'tuple'>

Sinlacoma,Pythonconsidera ('a') comounaexpresiónconunacadenaentre paréntesisqueesevaluadacomodetipocadena(string):

>>> t2 = ('a')

>>> type(t2)

<type 'str'>

1 Datocurioso:Lapalabra“tuple”provienedelosnombresdadosasecuenciasdenúmerosde distintaslongitudes:simple,doble,triple,cuádruple,quíntuple,séxtuple,séptuple,etc.

125

Otraformadeconstruirunatuplaesutilizandolafuncióninterna tuple.Sin argumentos,éstacreaunatuplavacía:

>>> t = tuple()

>>> print(t) ()

Sielargumentoesunasecuencia(cadena,lista,otupla),elresultadodelallamada a tuple esunatuplaconloselementosdelasecuencia:

>>> t = tuple('altramuces')

>>> print(t)

('a', 'l', 't', 'r', 'a', 'm', 'u', 'c', 'e', 's')

Dadoque tuple eselnombredeunconstructor,deberíaevitarsesuusocomo nombredevariable.

Lamayoríadelosoperadoresdelistastambiénfuncionanentuplas.Eloperador corcheteindexaunelemento:

>>> t = ('a', 'b', 'c', 'd', 'e')

>>> print(t[0]) 'a'

Yeloperadorderebanado(slice)seleccionaunrangodeelementos.

>>> print(t[1:3]) ('b', 'c')

Perosiseintentamodificarunodeloselementosdelatupla,seproduceunerror:

>>> t[0] = 'A'

TypeError:objectdoesn'tsupportitemassignment

Nosepuedemodificarloselementosdeunatupla,perosísepuedereemplazaruna tuplaporotra:

>>> t = ('A',) + t[1:]

>>> print(t)

('A', 'b', 'c', 'd', 'e')

10.2Comparacióndetuplas

Losoperadoresdecomparaciónfuncionancontuplasyotrassecuencias.Python comienzacomparandoelprimerelementodecadasecuencia.Siamboselementos soniguales,pasaalsiguienteelementoyasísucesivamente,hastaqueencuentra elementosdiferentes.Loselementossubsecuentesnosonconsiderados(aunque seanmuygrandes).

126 CHAPTER10.TUPLAS

>>> (0, 1, 2) < (0, 3, 4)

True

>>> (0, 1, 2000000) < (0, 3, 4)

True

Lafunción sort funcionadelamismamanera.Ordenainicialmenteporelprimer elemento,peroenelcasodequeamboselementosseaniguales,ordenaporel segundoelemento,yasísucesivamente.

Estacaracterísticaseprestaaunpatróndediseñollamado DSU,que

Decorate(Decora) unasecuencia,construyendounalistadetuplasconunoo másíndicesordenadosprecediendoloselementosdelasecuencia, Sort(Ordena) lalistadetuplasutilizandolafuncióninterna sort,y Undecorate(Quitaladecoración) extrayendoloselementosordenadosdela secuencia.

Porejemplo,suponiendounalistadepalabrasquesequierenordenardelamás largaalamáscorta:

txt = 'Peroquéluzsedejaverallí' palabras = txt.split() t = list() for palabra in palabras: t.append((len(palabra),palabra)) t.sort(reverse=True) res = list() for longitud,palabra in t: res.append(palabra)

print(res) #Código:https://es.py4e.com/code3/soft.py

Elprimerbuclegeneraunalistadetuplas,dondecadatuplaesunapalabraprecedidaporsulongitud.

sort comparaelprimerelemento(longitud)primero,ysolamenteconsiderael segundoelementoparadesempatar.Elargumentoclave reverse=True indicaa sort quedebeirenordendecreciente.

Elsegundobuclerecorrelalistadetuplasyconstruyeunalistadepalabrasen ordendescendentesegúnlalongitud.Laspalabrasdecuatroletrasestánordenadas enordenalfabético inverso,asíque“deja”apareceantesque“allí”enlasiguiente lista.

Lasalidadelprogramaeslasiguiente: ['deja','allí','Pero','ver','qué','luz','se']

10.2.COMPARACIÓNDETUPLAS 127

Porsupuesto,lalíneapierdemuchodesuimpactopoéticocuandoseconvierteen unalistadePythonysealmacenaenordendescendentesegúnlalongituddelas palabras.

10.3Asignacióndetuplas

UnadelascaracterísticassintácticasúnicasdellenguajePythoneslacapacidadde tenerunatuplaenelladoizquierdodeunasentenciadeasignación.Estopermite asignarmásdeunavariablealavezcuandohayunasecuenciadelladoizquierdo.

Enesteejemplotenemosunalistadedoselementos(lacualesunasecuencia)y asignamoselprimerysegundoelementosdelasecuenciaalasvariables x y y en unaúnicasentencia.

>>> m = [ 'pásalo', 'bien' ]

>>> x,y = m >>> x 'pásalo' >>> y 'bien' >>>

Noesmagia,Pythontraduce aproximadamente lasintaxisdeasignacióndela tupladeestemodo::2

>>> m = [ 'pásalo', 'bien' ]

>>> x = m[0] >>> y = m[1]

>>> x 'pásalo' >>> y 'bien' >>>

Estilísticamente,cuandoseutilizaunatuplaenelladoizquierdodelaasignación, seomitenlosparéntesis,peroloquesemuestraacontinuaciónesunasintaxis igualmenteválida:

>>> m = [ 'pásalo', 'bien' ]

>>> (x,y) = m

>>> x 'pásalo' >>> y 'bien'

>>> 2 Pythonnotraducelasintaxisliteralmente.Porejemplo,si setratadehacerestoconun diccionario,novaafuncionarcomosepodríaesperar.

128 CHAPTER10.TUPLAS

Unaaplicaciónparticularmenteingeniosadeasignacióncontuplaspermite intercambiar losvaloresdedosvariablesenunasolasentencia:

>>> a,b = b,a

Ambosladosdelasentenciasontuplas,peroelladoizquierdoesunatuplade variables;elladoderechoesunatupladeexpresiones.Cadavalorenelladoderecho esasignadoasurespectivavariableenelladoizquierdo.Todaslasexpresionesen elladoderechosonevaluadasantesderealizarcualquierasignación.

Elnúmerodevariablesenelladoizquierdoyelnúmerodevaloresenellado derechodebenseriguales:

>>> a,b = 1, 2, 3

ValueError:toomanyvaluestounpack

Generalizandomás,elladoderechopuedesercualquiertipodesecuencia(cadena, lista,otupla).Porejemplo,paradividirunadireccióndee-mailennombrede usuarioydominio,sepodríaescribir:

>>> dir = 'monty@python.org'

>>> nombreus,dominio = dir.split('@')

Elvalorderetornode split esunalistacondoselementos;elprimerelementoes asignadoa nombreus,elsegundoa dominio.

>>> print(nombreus) monty

>>> print(dominio) python.org

10.4Diccionariosytuplas

Losdiccionariostienenunmétodollamado items queretornaunalistadetuplas, dondecadatuplaesunparclave-valor:

>>> d = {'a':10, 'b':1, 'c':22}

>>> t = list(d.items())

>>> print(t) [('b', 1),('a', 10),('c', 22)]

Comoseríadeesperarenundiccionario,loselementosnotienenningúnordenen particular.

Aunasí,puestoquelalistadetuplasesunalista,ylastuplassoncomparables, ahorasepuedeordenarlalistadetuplas.Convertirundiccionarioenunalistade tuplasesunaformadeobtenerelcontenidodeundiccionarioordenadosegúnsus claves:

10.4.DICCIONARIOSYTUPLAS 129

>>> d = {'a':10, 'b':1, 'c':22}

>>> t = list(d.items())

>>> t

[('b', 1),('a', 10),('c', 22)]

>>> t.sort()

>>> t

[('a', 10),('b', 1),('c', 22)]

Lanuevalistaestáordenadaenordenalfabéticoascendentedeacuerdoalvalorde susclaves.

10.5Asignaciónmúltiplecondiccionarios

Lacombinaciónde items,asignacióndetuplas,y for,produceunbuenpatrónde diseñodecódigopararecorrerlasclavesyvaloresdeundiccionarioenunúnico bucle:

for clave,valor in list(d.items()): print(valor,clave)

Estebucletienedos variablesdeiteración,debidoaque items retornaunalista detuplasy clave,valor esunaasignaciónentuplaqueiterasucesivamentea travésdecadaunodelosparesclave-valordeldiccionario.

Paracadaiteraciónatravésdelbucle,tanto clave y valor vanpasandoalsiguiente parclave-valordeldiccionario(todavíaenordendedispersión).

Lasalidadeestebuclees: 10a 1b 22c

Denuevo,lasclavesestánenordendedispersión(esdecir,ningúnordenenparticular).

Sisecombinanesasdostécnicas,sepuedeimprimirelcontenidodeundiccionario ordenadoporel valor almacenadoencadaparclave-valor.

Parahaceresto,primerosecreaunalistadetuplasdondecadatuplaes (valor, clave).Elmétodo items daráunalistadetuplas (clave,valor),peroestavez sepretendeordenarporvalor,noporclave.Unavezquesehaconstruidolalista conlastuplasclave-valor,essencilloordenarlalistaenordeninversoeimprimir lanuevalistaordenada.

>>> d = {'a':10, 'b':1, 'c':22}

>>> l = list()

>>> for clave,valor in d.items(): ...l.append((valor,clave))

130 CHAPTER10.TUPLAS
...

>>> l

[(10, 'a'),(1, 'b'),(22, 'c')]

>>> l.sort(reverse=True)

>>> l [(22, 'c'),(10, 'a'),(1, 'b')]

>>>

Alconstruircuidadosamentelalistadetuplasparatenerelvalorcomoelprimer elementodecadatupla,esposibleordenarlalistadetuplasyobtenerelcontenido deundiccionarioordenadoporvalor.

10.6Laspalabrasmáscomunes

Volviendoalejemploanteriordeltextode RomeoyJulieta,Acto2,Escena2, podemosmejorarnuestroprogramaparahacerusodeestatécnicaparaimprimir lasdiezpalabrasmáscomuneseneltexto,comoseveacontinuación:

importstring manejador = open('romeo-full.txt') contadores = dict() for linea in manejador: linea = linea.translate(str.maketrans('', '',string.punctuation)) linea = linea.lower() palabras = linea.split() for palabra in palabras: if palabra notin contadores: contadores[palabra] = 1 else: contadores[palabra] += 1

#Ordenareldiccionarioporvalor lst = list() for clave,valor in list(contadores.items()): lst.append((valor,clave)) lst.sort(reverse=True)

for clave,valor in lst[:10]: print(clave,valor)

#Código:https://es.py4e.com/code3/count3.py

Laprimerapartedelprograma,lacualleeunarchivoyconstruyeundiccionario quemapeacadapalabraconlacantidaddevecesqueserepiteesapalabraenel documento,nohacambiado.Peroenlugardeimprimirsimplemente contadores yterminarelprograma,ahoraconstruimosunalistadetuplas (val,key) yluego seordenalalistaenordeninverso.

Puestoqueelvalorestáprimero,seráutilizadoparalascomparaciones.Sihay másdeunatuplaconelmismovalor,setendráencuentaelsegundoelemento(la

10.6.LASPALABRASMÁSCOMUNES 131

clave),deformaquelastuplascuyovaloreselmismoserántambiénordenadasen ordenalfabéticosegúnsuclave.

Alfinalescribimosunelegantebucle for quehaceunaiteraciónconasignación múltipleeimprimelasdiezpalabrasmáscomunes,iterandoatravésdeunaparte delalista(lst[:10]).

Ahoralasalidafinalmentetieneelaspectoquequeríamosparanuestroanálisisde frecuenciadepalabras.

61i 42and 40romeo 34to 34the 32thou 32juliet 30that 29my 24thee

Elhechodequeestecomplejoanálisisyprocesadodedatospuedaserrealizado conunprogramadePythonde19líneasfácildeentender,esunarazóndeporqué Pythonesunabuenaeleccióncomolenguajeparaexplorarinformación.

10.7Usodetuplascomoclavesendiccionarios

Dadoquelastuplasson dispersables (hashable) ylaslistasno,sisequierecrear unaclave compuesta parausarenundiccionario,sedebeutilizarunatuplacomo clave.

Usaríamosporejemplounaclavecompuestasiquisiéramoscrearundirectorio telefónicoquemapeaparesappellido,nombreconnúmerostelefónicos.Asumiendo quehemosdefinidolasvariables apellido, nombre,y número,podríamosescribir unasentenciadeasignacióndediccionariocomosigue:

directorio[apellido,nombre] = numero

Laexpresiónentrecorchetesesunatupla.Podríamosutilizarasignacióndetuplas enunbucle for pararecorrerestediccionario.

for apellido,nombre in directorio: print(nombre,apellido,directorio[apellido,nombre])

Estebuclerecorrelasclavesen directorio,lascualessontuplas.Asignalos elementosdecadatuplaa apellido y nombre,despuésimprimeelnombreyel númerotelefónicocorrespondiente.

132 CHAPTER10.TUPLAS

10.8Secuencias:cadenas,listas,ytuplas-¡Dios mío!

Meheenfocadoenlistasdetuplas,perocasitodoslosejemplosdeestecapítulo funcionantambiénconlistasdelistas,tuplasdetuplas,ytuplasdelistas.Para evitarenumerartodaslascombinacionesposibles,avecesesmássencillohablar desecuenciasdesecuencias.

Enmuchoscontextos,losdiferentestiposdesecuencias(cadenas,listas,ytuplas) puedenintercambiarse.Asíque,¿cómoyporquéelegirunouotro?

Paracomenzarconlomásobvio,lascadenasestánmáslimitadasqueotrassecuencias,debidoaqueloselementostienenquesercaracteres.Además,soninmutables. Sinecesitaslacapacidaddecambiarloscaracteresenunacadena(envezdecrear unanueva),quizáprefierasutilizarunalistadecaracteres.

Laslistassonmáscomunesquelastuplas,principalmenteporquesonmutables. Perohayalgunoscasosdondeespreferibleutilizartuplas:

1.Enalgunoscontextos,comounasentenciareturn,resultasintácticamente mássimplecrearunatuplaqueunalista.Enotroscontextos,esposibleque prefierasunalista.

2.Siquieresutilizarunasecuenciacomounaclaveenundiccionario,debesusar untipoinmutablecomounatuplaounacadena.

3.Siestáspasandounasecuenciacomoargumentodeunafunción,elusode tuplasreducelaposibilidaddecomportamientosinesperadosdebidoala creacióndealias.

Dadoquelastuplassoninmutables,noproporcionanmétodoscomo sort y reverse,quemodificanlistasyaexistentes.Sinembargo,Pythonproporcionalas funcionesinternas sorted y reversed,quetomanunasecuenciacomoparámetro ydevuelvenunasecuencianuevaconlosmismoselementosenunordendiferente.

10.9Depuración

Laslistas,diccionariosytuplassonconocidasdeformagenéricacomo estructuras dedatos;enestecapítuloestamoscomenzandoaverestructurasdedatoscompuestas,comolistasdetuplas,ydiccionariosquecontienentuplascomoclavesylistas comovalores.Lasestructurasdedatoscompuestassonútiles,perotambiénson propensasaloqueyollamo erroresdemodelado;esdecir,errorescausadoscuando unaestructuradedatostieneeltipo,tamañoocomposiciónincorrecto,oquizás alescribirunapartedelcódigosenosolvidócómoeraelmodeladodelosdatos yseintrodujounerror.Porejemplo,siestásesperandounalistaconunenteroy recibesunenterosolamente(noenunalista),nofuncionará.

10.8.SECUENCIAS:CADENAS,LISTAS,YTUPLAS-¡DIOSMÍO! 133

10.10Glosario

comparable Untipoenelcualunvalorpuedeserrevisadoparaversiesmayor que,menorque,oigualaotrovalordelmismotipo.Lostiposqueson comparablespuedenserpuestosenunalistayordenados. estructuradedatos Unacolleccióndevaloresrelacionados,normalmenteorganizadosenlistas,diccionarios,tuplas,etc. DSU Abreviaturade“decorate-sort-undecorate(decorar-ordenar-quitarladecoración)”,unpatróndediseñoqueimplicaconstruirunalistadetuplas,ordenarlas,yextraerpartedelresultado. reunir Laoperacióndetratarunasecuenciacomounalistadeargumentos. hashable(dispersable) Untipoquetieneunafuncióndedispersión.Lostipos inmutables,comoenteros,flotantesycadenassondispersables(hashables); lostiposmutablescomolistasydiccionariosnoloson. dispersar Laoperacióndetratarunasecuenciacomounalistadeargumentos. modelado(deunaestructuradedatos) Unresumendeltipo,tamaño,y composicióndeunaestructuradedatos. singleton Unalista(uotrasecuencia)conunúnicoelemento. tupla Unasecuenciainmutabledeelementos. asignaciónportuplas Unaasignaciónconunasecuenciaenelladoderechoy unatupladevariablesenelizquierdo.Elladoderechoesevaluadoyluego suselementossonasignadosalasvariablesenelladoizquierdo.

10.11Ejercicios

Ejercicio1:Revisaelprogramaanteriordeestemodo:Leeyanaliza laslíneas“From”yextraelasdireccionesdecorreo.Cuentael número demensajesdecadapersonautilizandoundiccionario.

Despuésdequetodoslosdatoshayansidoleídos,imprimelapersonacon másenvíos,creandounalistadetuplas(contador,email)deldiccionario. Despuésordenalalistaenordeninversoeimprimelapersonaquetiene másenvíos.

Líneadeejemplo: Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

Ingresaunnombredearchivo:mbox-short.txt cwen@iupui.edu5

Ingresaunnombredearchivo:mbox.txt zqian@umich.edu195

Ejercicio2:Esteprogramacuentaladistribucióndelahoradeldía paracadaunodelosmensajes.Puedesextraerlahoradelalínea “From”buscandolacadenahorariayluegodividiendolacadenaen partesutilizandoelcaráctercolon.Unavezquehayasacumuladolas cuentasparacadahora,imprimelascuentas,unaporlínea,ordenadas porhoratalcomosemuestradebajo.

134 CHAPTER10.TUPLAS

pythontimeofday.py Ingresaunnombredearchivo:mbox-short.txt 043 061 071 092 103 116 141 152 164 172 181 191

Ejercicio3:Escribeunprogramaqueleeunarchivoeimprimelas letras enorderdecrecientedefrecuencia.Elprogramadebeconvertir todaslasentradasaminúsculasycontarsolamentelasletrasa-z. Elprogramanodebecontarespacios,dígitos,signosdepuntuación, ocualquiercosaquenoseanlasletrasa-z.Encuentraejemplosde textoenidiomasdiferentes,yobservacómolafrecuenciadeletras es diferenteencadaidioma.Comparatusresultadosconlastablasen https://es.wikipedia.org/wiki/Frecuencia_de_aparici%C3%B3n_de_letras.

10.11.EJERCICIOS 135
136 CHAPTER10.TUPLAS

Expresionesregulares

Hastaahorahemosleídoarchivos,buscandopatronesyextrayendovariassecciones delíneasquehemosencontradointeresantes.Hemosusadométodosdecadenas como split y find,asícomorebanadodelistasycadenasparaextraertrozosde laslíneas.

EstatareadebuscaryextraerestancomúnquePythontieneunalibreríamuy poderosallamada expresionesregulares quemanejavariasdeestastareasdemanerabastanteelegante.Larazónporlaquenopresentamoslasexpresionesregulares antessedebeaque,aunquesonmuypoderosas,sonunpocomáscomplicadasy tomaalgodetiempoacostumbrarseasusintaxis.

Lasexpresionesregularescasisonsupropiolenguajedeprogramaciónenminiatura parabuscaryanalizarcadenas.Dehecho,sehanescritolibrosenterossobrelas expresionesregulares.Enestecapítulo,solocubriremoslosaspectosbásicosdelas expresionesregulares.Paramásinformaciónalrespecto,recomendamosver: https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular https://docs.python.org/library/re.html

Sedebeimportarlalibreríadeexpresionesregulares re atuprogramaantesdeque puedasusarlas.Laformamássimpledeusarlalibreríadeexpresionesregulares eslafunción search() (N.delT.:“search”significabúsqueda).Elsiguiente programademuestraunaformamuysencilladeusarestafunción.

#Búsquedadelíneasquecontengan'From' importre

man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() if re.search('From:',linea): print(linea)

#Código:https://es.py4e.com/code3/re01.py

Abrimoselarchivo,revisamoscadalínea,yusamoslaexpresiónregular search() paraimprimirsololaslíneasquecontenganlacadena“From”.Esteprograma no

Chapter11
137

tomaventajadelauténticopoderdelasexpresionesregulares,yaquepodríamos simplementehaberusado line.find() paralograrelmismoresultado.

Elpoderdelasexpresionesregularessemanifiestacuandoagregamoscaracteres especialesalacadenadebúsquedaquenospermitecontrolardemaneramásprecisa quélíneascalzanconlacadena.Agregarestoscaracteresespecialesanuestra expresiónregularnospermitirábuscarcoincidenciasyextraerdatosusandounas pocaslíneasdecódigo.

Porejemplo,elsignodeintercalación(N.delT.:“caret”eninglés,corresponde alsignoˆ)seutilizaenexpresionesregularesparaencontrar“elcomienzo”deuna lína.Podríamoscambiarnuestroprogramaparaquesoloretornelíneasenque tengan“From:”alcomienzo,delasiguientemanera:

#Búsquedadelíneasquecontengan'From' importre man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() if re.search('^From:',linea): print(linea)

#Código:https://es.py4e.com/code3/re02.py

Ahorasoloretornarálíneasque comiencencon lacadena“From:”.Estesiguesiendo unejemplomuysencilloquepodríamoshaberimplementadousandoelmétodo startswith() delalibreríadecadenas.Perosirveparapresentarlaideadeque lasexpresionesregularescontienencaracteresespecialesquenosdanmayorcontrol sobrequécoincidenciasretornarálaexpresiónregular.

11.1Coincidenciadecaracteresenexpresiones regulares

Existenvarioscaracteresespecialesquenospermitenconstruirexpresionesregularesinclusomáspoderosas.Elmáscomúneselpunto,quecoincideconcualquier carácter.

Enelsiguienteejemplo,laexpresiónregular F..m: coincidiríaconlascadenas “From:”,“Fxxm:”,“F12m:”,o“F!@m:”,yaqueloscaracteresdepuntoenla expresiónregularcoincidenconcualquiercarácter.

##Búsquedadelíneasquecomiencencon'F',seguidasde #2caracteres,seguidosde'm:' importre man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() if re.search('^F..m:',linea): print(linea)

#Código:https://es.py4e.com/code3/re03.py

138 CHAPTER11.EXPRESIONESREGULARES

Estoresultaparticularmentepoderosocuandoselecombinaconlahabilidadde indicarqueuncarácterpuederepetirsecualquiercantidaddevecesusandolos caracteres * o + entuexpresiónregular.Estoscaracteresespecialesindicanque enlugardecoincidirconunsolocarácterenlacadenadebúsqueda,coincidencon ceroomáscaracteres(enelcasodelasterisco)oconunoomáscaracteres(enel casodelsignodesuma).

Podemosreducirmáslaslíneasquecoincidanusandouncarácter comodín enel siguienteejemplo:

#BúsquedadelíneasquecomienzanconFromytienenunaarroba importre man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() if re.search('^From:.+@',linea): print(linea)

#Código:https://es.py4e.com/code3/re04.py

Lacadena ˆFrom:.+@ retornarácoincidenciasconlíneasqueempiecencon“From:”, seguidasdeunoomáscaracteres(.+),seguidasdeuncarácter@.Porlotanto,la siguientelíneacoincidirá:

From:stephen.marquard@uct.ac.za

Puedeconsiderarsequeelcomodín .+ seexpandeparaabarcartodosloscaracteres entrelossignos:y@.

From:.+@

Convieneconsiderarquelossignosdesumaylosasteriscos“empujan”.Porejemplo, lasiguientecadenamarcaríaunacoincidenciaconelúltimosigno@,yaqueel .+ “empujan”haciaafuera,comosemuestraacontinuación:

From:stephen.marquard@uct.ac.za,csev@umich.edu,andcwen@iupui.edu

Esposibleindicaraunasteriscoosignodesumaquenodebesertan“ambicioso” agregandootrocarácter.Revisaladocumentaciónparaobtenerinformaciónsobre cómodesactivarestecomportamientoambicioso.

SiqueremosextraerdatosdeunacadenaenPythonpodemosusarelmétodo findall() paraextraertodaslassubcadenasquecoincidanconunaexpresión regular.Usemoselejemplodequererextraercualquiersecuenciaqueparezcauna direcciónemailencualquierlínea,sinimportarsuformato.Porejemplo,queremos extraerladirecciónemaildecadaunadelassiguienteslíneas:

11.2.EXTRAYENDODATOSUSANDOEXPRESIONESREGULARES 139
11.2Extrayendodatosusandoexpresionesregulares

Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

Return-Path:<postmaster@collab.sakaiproject.org> for<source@collab.sakaiproject.org>; Received:(fromapache@localhost)

Author:stephen.marquard@uct.ac.za

Noqueremosescribircódigoparacadatipodelíneas,dividiendoyrebanandode maneradistintaencadauna.Elsiguienteprogramausa findall() paraencontrar laslíneasquecontienendireccionesdeemailyextraerunaomásdireccionesde cadalínea.

importre

s = 'Unanotadecsev@umich.eduacwen@iupui.edusobreunareunión@2PM' lst = re.findall(r'\S+@\S+',s) print(lst)

#Código:https://es.py4e.com/code3/re05.py

Elmétodo findall() buscaenlacadenaenelsegundoargumentoyretornauna listadetodaslascadenasqueparecenserdireccionesdeemail.Estamosusando unasecuenciadedoscaracteresquecoincideconuncarácterdistintoaunespacio enblanco(\S).

Elresultadodelaejecucióndelprogramadebieraser:

['csev@umich.edu','cwen@iupui.edu']

Traduciendolaexpresiónregularalcastellano,estamosbuscandosubcadenasque tenganalmenosuncarácterquenoseaunespacio,seguidodeuna@,seguidodeal menosuncarácterquenoseaunespacio.Laexpresión \S+ coincidiráconcuantos caracteresdistintosdeunespacioseaposible.

Laexpresiónregularretornaríadoscoincidencias(csev@umich.eduycwen@iupui.edu), peronocoincidiríaconlacadena“@2PM”porquenohaycaracteresquenosean espaciosenblanco antes delsigno@.Podemosusarestaexpresiónregularenun programaparaleertodaslaslíneasenunarchivoeimprimircualquiersubcadena quepudieraserunadireccióndeemaildelasiguientemanera:

#Búsquedadelíneasquetenganunaarrobaentrecaracteres importre man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() x = re.findall(r'\S+@\S+',linea) if len(x) > 0: print(x)

#Código:https://es.py4e.com/code3/re06.py

Conesto,leemoscadalíneayluegoextraemoslassubcadenasquecoincidancon nuestraexpresiónregular.Dadoque findall() retornaunalista,simplemente

140 CHAPTER11.EXPRESIONESREGULARES

revisamossielnúmerodeelementosenéstaesmayoraceroeimprimirsololíneas dondeencontramosalmenosunasubcadenaquepudieraserunadireccióndeemail.

Siejecutamoselprogramaen mbox.txt obtendremoselsiguienteresultado:

['wagnermr@iupui.edu']

['cwen@iupui.edu']

['<postmaster@collab.sakaiproject.org>']

['<200801032122.m03LMFo4005148@nakamura.uits.iupui.edu>']

['<source@collab.sakaiproject.org>;'] ['<source@collab.sakaiproject.org>;'] ['<source@collab.sakaiproject.org>;'] ['apache@localhost)']

['source@collab.sakaiproject.org;']

Algunasdelasdireccionestienencaracteresincorrectoscomo“<”o“;”alcomienzo oalfinal.Declaremosquesoloestamosinteresadosenlapartedelacadenaque comienceytermineconunaletraounnúmero.

Paralograresto,usamosotracaracterísticadelasexpresionesregulares.Los corchetesseusanparaindicarunconjuntodecaracteresquequeremosaceptar comocoincidencias.Lasecuencia \S retornaráelconjuntode“caracteresqueno seanunespacioenblanco”.Ahoraseremosunpocomásexplícitosencuantoalos caracteresrespectodeloscualesbuscamoscoincidencias.

Estaseránuestranuevaexpresiónregular:

[a-zA-Z0-9]\S*@\S*[a-zA-Z]

Estoseestácomplicandounpoco;puedesverporquédecimosquelasexpresiones regularessonunlenguajeensímismas.Traduciendoestaexpresiónregular,estamosbuscandosubcadenasquecomiencencon una letraminúscula,letramayúscula, onúmero“[a-zA-Z0-9]”,seguidadeceroomáscaracteresquenoseanunespacio (\S*),seguidosdeunsigno@,seguidodeceroomáscaracteresquenoseanespaciosenblanco(\S*),seguidosporunaletramayúsculaominúscula.Nóteseque hemoscambiadode + a * paraindicarceroomáscaracteresquenoseanespacios, yaque [a-zA-Z0-9] implicauncarácterdistintodeunespacio.Recuerdaqueel * o + seaplicaalcarácterinmediatamentealaizquierdadelsignodesumaodel asterisco.

11.2.EXTRAYENDODATOSUSANDOEXPRESIONESREGULARES 141
#Búsquedadelíneasquetenganunaarrobaentrecaracteres
Siusamosestaexpresiónennuestroprogramas,nuestrosdatosquedaránmucho másdepurados:
#Loscaracteresdebenserunaletraounnúmero importre man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() x = re.findall(r'[a-zA-Z0-9]\S+@\S+[a-zA-Z]',linea) if len(x) > 0: print(x) #Código:https://es.py4e.com/code3/re07.py

...

['wagnermr@iupui.edu'] ['cwen@iupui.edu']

['postmaster@collab.sakaiproject.org'] ['200801032122.m03LMFo4005148@nakamura.uits.iupui.edu']

['source@collab.sakaiproject.org'] ['source@collab.sakaiproject.org'] ['source@collab.sakaiproject.org'] ['apache@localhost']

Nótesequeenlaslíneasdondeaparece source@collab.sakaiproject.org,nuestraexpresiónregulareliminódoscaracteresalfinaldelacadena(“>;”).Esto sedebeaque,cuandoagregamos [a-zA-Z] alfinaldenuestraexpresiónregular, estamosdeterminandoquecualquiercadenaquelaexpresiónregularencuentreal analizareltextodebeterminarconunaletra.Porlotanto,cuandoveael“>” alfinalde“sakaiproject.org>;”,simplementesedetieneenelúltimocarácterque hayaencontradoquecoincidaconesecriterio(enestecaso,la“g”fuelaúltima coincidencia).

NótesetambiénqueelresultadodelaejecucióndelprogramaesunalistadePython quetieneunacadenacomosuúnicoelemento.

11.3Combinandobúsquedayextracción

Siquisiéramosencontrarlosnúmerosenlaslíneasqueempiecenconlacadena “X-”,comoporejemplo:

X-DSPAM-Confidence:0.8475

X-DSPAM-Probability:0.0000

noqueremoscualquiernúmerodecomaflotantecontenidosencualquierlínea.Solo queremosextraerlosnúmerosdelaslíneasquetienenlasintaxisyamencionada.

Podemosconstruirlasiguienteexpresiónregularparaseleccionarlaslíneas: ^X-.*:[0-9.]+

Traduciendoesto,estamosdiciendoquequeremoslíneasqueempiecencon X-, seguidoporceroomáscaracteres(.*),seguidoporuncarácterdedospuntos (:)yluegounespacio.Despuésdelespacio,buscamosunoomáscaracteresque sean,obienundígito(0-9),obienunpunto [0-9.]+.Nótesequealinteriorde loscorcheteselpuntoefectivamentecorrespondeaunpunto(esdecir,nofunciona comocomodínentrecorchetes).

Lasiguienteesunaexpresiónbastantecomprimidaquesoloretornarálaslíneas quenosinteresan:

#Búsquedadelíneasquecomiencencon'X'seguidadecualquiercaracterque #noseaespacioy':'seguidodeunespacioycualquiernúmero. #Elnúmeroincluyedecimales.

142 CHAPTER11.EXPRESIONESREGULARES

importre

man = open('mbox-short.txt')

for linea in man: linea = linea.rstrip() if re.search(r'^X\S*:[0-9.]+',linea): print(linea)

#Código:https://es.py4e.com/code3/re10.py

Cuandoejecutamoselprograma,vemosquelosdatoshansidoprocesados, mostrandosololaslíneasquebuscamos.

X-DSPAM-Confidence:0.8475

X-DSPAM-Probability:0.0000

X-DSPAM-Confidence:0.6178

X-DSPAM-Probability:0.0000

Ahora,debemosresolverelproblemadeextraerlosnúmueros.Aunqueseríabastantesencillousar split,podemosecharmanoaotrafuncióndelasexpresiones regularesparabuscaryanalizarlalíneaalavez.

Losparéntesissonotroscaracteresespecialesenlasexpresionesregulares.Alagregarparéntesisaunaexpresiónregular,sonignoradosalahoradehacercoincidir lacadena.Perocuandoseusa findall(),losparéntesisindicanque,aunquese quierequetodalaexpresióncoincida,solointeresaextraerunapartedelasubcadenaquecoincidaconlaexpresiónregular.

Entonces,hacemoslossiguientescambiosanuestroprograma:

#Búsquedadelíneasquecomiencencon'X'seguidadecualquiercaracterque #noseaespacioenblancoy':'seguidodeunespacioyunnúmero. #Elnúmeropuedeincluirdecimales. #Despuésimprimirelnúmerosiesmayoracero.

importre

man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() x = re.findall(r'^X\S*:([0-9.]+)',linea) if len(x) > 0: print(x)

#Código:https://es.py4e.com/code3/re11.py

Enlugardeusar search(),agregamosparéntesisalrededosdelapartedelaexpresiónregularquerepresentaalnúmerodecomaflotanteparaindicarquesolo queremosque findall() retornelapartecorrespondienteanúmerosdecoma flotantedelacadenaretornada.

Elresultadodeesteprogramaeselsiguiente: ['0.8475']

11.3.COMBINANDOBÚSQUEDAYEXTRACCIÓN 143

['0.0000']

['0.6178']

['0.0000'] ['0.6961'] ['0.0000'] ..

Losnúmerossiguenestandoenunalistaydebenserconvertidosdecadenasa númerosdecomaflotante,perohemosusadolasexpresionesregularesparabuscar yextraerlainformaciónqueconsideramosinteresante.

Otroejemplodeestatécnica:sirevisanestearchivo,veránunaseriedelíneasen elformulario:

Detalles:http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772

Siquisiéramosextraertodoslosnúmerosderevisión(elnúmeroenteroalfinalde esaslíneas)usandolamismatécnicadelejemploanterior,podríamosescribirel siguienteprograma:

#Búsquedadelíneasquecomiencencon'Details:rev=' #seguidodenúmerosy'.' #Despuésimprimirelnúmerosiesmayoracero importre man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() x = re.findall('^Details:.*rev=([0-9.]+)',linea) if len(x) > 0: print(x)

#Código:https://es.py4e.com/code3/re12.py

Traduccióndelaexpresiónregular:estamosbuscandolíneasqueempiecencon Details:,seguidadecualquiernúmerodecaracteres(.*),seguidade rev=,y despuésdeunoomásdígitos.Queremosencontrarlíneasquecoincidancontoda laexpresiónperosoloqueremosextraerelnúmeroenteroalfinaldelalínea,por loqueponemos [0-9]+ entreparéntesis.

Alejecutarelprograma,obtenemoselsiguienteresultado:

['39772']

['39771']

['39770'] ['39769']

Recuerdaquelaexpresión [0-9]+ es“ambiciosa”eintentaráformarunacadenade dígitoslomáslargaposibleantesdeextraerlos.Estecomportamiento“ambicioso” eslarazónporlaqueobtenemosloscincodígitosdecadanúmero.Laexpresiones

144 CHAPTER11.EXPRESIONESREGULARES

regularseexpandeenambasdireccioneshastaqueencuentra,obienuncarácter quenoseaundígito,obienelcomienzoofinaldeunalínea.

Ahorapodemosusarexpresionesregularesparavolveraresolverunejercicioque hicimosantes,enelquenosinteresabalahoradecadaemail.Ensumomento, buscamoslaslíneas:

Fromstephen.marquard@uct.ac.zaSatJan509:14:162008

conlaintencióndeextraerlahoradeldíaencadalínea.Anteslogramosesto haciendodosllamadasa split.Primerosedividíalalíneaenpalabrasyluego tomábamoslaquintapalabrayladividíamosdenuevoenelcarácter“:”para obtenerlosdoscaracteresquenosinteresaban.

Aunqueestasoluciónfunciona,eselresultadodecódigobastantefrágil,quedependedeasumirquelaslíneastienenelformatoadecuado.Sibienpuedesagregar chequeos(oungranbloquedetry/except)paraasegurartequeelprogramano fallealencontrarlíneasmalformateadas,estoharáqueelprogramaaumente a10 o15líneasdecódigo,queademásserándifícilesdeleer.

Podemoslograrelresultadodeformamuchomássimpleutilizandolasiguiente expresiónregular:

^From.*[0-9][0-9]:

Latraduccióndeestaexpresiónregularseríaqueestamosbuscandolíneasque empiecencon From (nóteseelespacio),seguidodecualquiernúmerodecaracteres (.*),seguidosdeunespacioenblanco,seguidodedosdígitos [0-9][0-9],seguidos deuncarácter“:”.Esaesladefinicióndelaclasedelíneasquebuscamos.

Paraextraersololahorausando findall(),agregamosparéntesisalrededorde losdosdígitos,delasiguientemanera:

^From.*([0-9][0-9]):

Estoresultaráenelsiguienteprograma:

#BúsquedadelíneasquecomienzanconFromyuncaracterseguido #deunnúmerodedosdígitosentre00y99seguidode':' #Despuésimprimirelnúmerosiesteesmayoracero importre

man = open('mbox-short.txt') for linea in man: linea = linea.rstrip() x = re.findall('^From.*([0-9][0-9]):',linea) if len(x) > 0:print(x)

#Código:https://es.py4e.com/code3/re13.py

Alejecutarelprograma,obtendremoselsiguienteresultado:

11.3.COMBINANDOBÚSQUEDAYEXTRACCIÓN 145

['09'] ['18'] ['16'] ['15'] 11.4EscapadodeCaracteres

Dadoqueenexpresionesregularesusamoscaracteresespecialesparaencontrarel comienzoofinaldeunalíneaoespecificarcomodines,necesitamosunaformade indicarqueesoscaracteresson“normales”yqueremosencontrarlacoincidencia conelcarácterespecífico,comoun“$”o“ˆ”.

Podemosindicarquequeremosencontrarlacoincidenciaconuncarácteranteponiéndoleunabarrainvertida.Porejemplo,podemosencontrarcantidadesde dineroutilizandolasiguienteexpresiónregular:

importre x = 'Wejustreceived$10.00forcookies.' y = re.findall('\$[0-9.]+',x)

Dadoqueantepusimoslabarrainvertidaalsigno“$”,encuentraunacoincidencia conelsignoenlacadenaenlugardeconelfinaldelalínea,yelrestodela expresiónregularcoincideconunoomásdígitosdelcarácter“.” Nota: dentrode loscorchetes,loscaracteresnoseconsideran“especiales”.Portanto,alescribir [0-9.],efectivamentesignificadígitosounpunto.Cuandonoestáentrecorchetes, elpuntoeselcarácter“comodín”quecoincideconcualquiercarácter.Cuandoestá dentrodecorchetes,unpuntoesunpunto.

11.5Resumen

Aunquesolohemosescarbadolasuperficiedelasexpresionesregulares,hemos aprendidounpocosobresulenguaje.Soncadenasdebúsquedaconcaracteresespecialesensuinterior,losquecomunicantusdeseosalsistemadeexpresionesregularesrespectodequéseconsideraunacoincidenciayquéinformaciónesextraída delascadenascoincidentes.Acontinuacióntenemosalgunosdeestoscaracteresy secuenciasespeciales: ˆ

Coincideconelcomienzodelalínea.

$ Coincideconelfinaldelalínea

. Coincideconcualquiercarácter(uncomodín).

\s Coincideconunespacioenblanco.

\S Coincideconuncarácterquenoseaunespacioenblanco(elopuestoa\s).

* Seaplicaalcarácterocaracteresinmediatamenteanteriores,indicandoque puedencoincidirceroomásveces.

146 CHAPTER11.EXPRESIONESREGULARES

*? Seaplicaalcarácterocaracteresinmediatamenteanteriores,indicandoque coincidenceroomásvecesenmodo“noambicioso”.

+ Seaplicaalcarácterocaracteresinmediatamenteanteriores,indicandoque puedencoincidirunaomásveces.

+? Seaplicaalcarácterocaracteresinmediatamenteanteriores,indicandoque puedencoincidirunaomásvecesenmodo“noambicioso”.

? Seaplicaalcarácterocaracteresinmediatamenteanteriores,indicandoque puedecoincidirceroounavez.

?? Seaplicaalcarácterocaracteresinmediatamenteanteriores,indicandoque puedecoincidirceroounavezenmodo“noambicioso”.

[aeiou] Coincideconunsolocarácter,siemprequeésteseencuentredentrodel conjuntoespecificado.Enestecaso,coincidiríacon“a”,“e”,“i”,“o”,o“u”,pero noconotroscaracteres.

[a-z0-9] Sepuedenespecificarrangosdecaracteresutilizandoelsignomenos.En estecaso,seríaunsolocarácterquedebeserunaletraminúsculaoundígito.

[ˆA-Za-z] Cuandoelprimercarácterenlanotacióndelconjuntoes“ˆ”,invierte lalógica.Enesteejemplo,habríacoincidenciaconunsolocarácterque nosea una letramayúsculaounaletraminúscula.

() Cuandoseagreganparéntesisaunaexpresiónregular,sonignoradospara propósitosdeencontrarcoincidencias,peropermitenextraerunsubconjuntodeterminadodelacadenaenqueseencuentralacoincidencia,enlugardetodala cadenacomocuandoseutiliza findall()

\b Coincideconunacadenavacía,perosoloalcomienzooalfinaldeunapalabra.

\B Concideconunacadenavacía,peronoalcomienzooalfinaldeunapalabra.

\d Coincideconcualquierdígitodecimal;equivalentealconjunto[0-9].

\D Coincideconcualquiercarácterquenoseaundígito;equivalentealconjunto [ˆ0-9]. 11.6SecciónadicionalparausuariosdeUnix/

Elsoporteparabuscararchivosusandoexpresionesregularesvieneincluidoenel sistemaoperativoUnixdesdeladécadade1960,yestádisponibleenprácticamente todosloslenguajesdeprogramacióndeunauotraforma.

Dehecho,hayunprogramadelíneadecomandosincluidoenUnixllamado grep (GeneralizedRegularExpressionParser//AnalizadorGeneralizadodeExpresiones Regulares)quehaceprácticamentelomismoquelosejemplosquehemosdadoen estecapítuloqueutilizan search().Portanto,siusasunsistemaMacintosho Linux,puedesprobarlossiguientescomandosentuventanadelíneadecomandos.

$ grep '^From:' mbox-short.txt

From:stephen.marquard@uct.ac.za

11.6.SECCIÓNADICIONALPARAUSUARIOSDEUNIX/LINUX 147
Linux

From:louis@media.berkeley.edu

From:zqian@umich.edu

From:rjlowe@iupui.edu

Estoordenaa grep mostrarlaslíneasquecomienzanconlacadena“From:”en elarchivo mbox-short.txt.Siexperimentasunpococonelcomando grep yleessu documentación,encontrarásalgunassutilesdiferenciasentreelsoportedeexpresionesregularesenPythonyen grep.Porejemplo, grep noreconoceelcarácter denoespacioenblanco \S,porloquedeberásusarlanotacióndeconjuntos [ˆ], queesunpocomáscompleja,yquesignificaqueencontraráunacoincidenciacon cualquiercarácterquenoseaunespacioenblanco.

11.7Depuración

Pythonincluyeunadocumentaciónsimpleyrudimentariaquepuedeserdegran ayudasinecesitasrevisarparaencontrarelnombreexactodealgúnmétodo.Esta documentaciónpuederevisarseenelintérpretedePythonenmodointeractivo.

Paramostrarelsistemadeayudainteractivo,seutilizaelcomando help().

>>> help() help> modules

Sisabesquémétodoquieresusar,puedesutilizarelcomando dir() paraencontrar losmétodosquecontieneelmódulo,delasiguientemanera:

>>> importre

>>> dir(re)

[.. 'compile', 'copy_reg', 'error', 'escape', 'findall', 'finditer' , 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse' , 'sub', 'subn', 'sys', 'template']

Tambiénpuedesobtenerunapequeñaporcióndeladocumentacióndeunmétodo enparticularusandoelcomandodir.

>>> help(re.search)

Helponfunctionsearch in modulere:

search(pattern,string,flags=0)

Scanthroughstringlooking for amatchtothepattern,returning amatchobject, or None if nomatchwasfound.

>>>

Ladocumentaciónincluidanoesmuyexhaustiva,peropuedeserútilsiestáscon prisaonotienesaccesoaunnavegadoromotordebúsqueda.

148 CHAPTER11.EXPRESIONESREGULARES

11.8Glosario

códigofrágil Códigoquefuncionacuandolosdatosseencuentranenunformato específicoperotienearompersesiéstenosecumple.Lollamamos“código frágil”porqueserompeconfacilidad. coincidenciaambiciosa Laideadequeloscaracteres + y * enunaexpresión regularseexpandenhaciaafueraparacoincidirconlamayorcadenaposible.

grep UncomandodisponibleenlamayoríadelossistemasUnixquebuscaen archivosdetexto,buscandolíneasquecoincidanconexpresionesregulares. Elnombredelcomandosignifica“GeneralizedRegularExpressionParser,o bien”AnalizadorGeneralizadodeExpresionesRegulares“.

expresiónregular Unlenguajeparaencontrarcadenasmáscomplejasenuna búsqueda.Unaexpresiónregularpuedecontenercaracteresespecialesque indiquenqueunabúsquedasolocoincidaalcomienzooalfinaldeunalínea, juntoconmuchasotrascapacidadessimilares. comodín Uncarácterespecialquecoincideconcualquiercarácter.Enexpresiones regulares,elcaráctercomodíneselpunto.

11.9Ejercicios

Ejerciciouno:escribeunprogramasimplequesimulelaoperacióndel comando grep enUnix.Debepediralusuarioqueingreseunaexpresión regularycuenteelnúmerodelíneasquecoincidanconésta: $pythongrep.py

Ingresaunaexpresiónregular:^Author mbox.txttiene1798líneasquecoincidencon^Author

$pythongrep.py

Ingresaunaexpresiónregular:^Xmbox.txttiene14368líneasquecoincidencon^X$pythongrep.py

Ingresaunaexpresiónregular:java$ mbox.txttiene4175líneasquecoincidenconjava$

Ejercicio2:escribeunprogramaquebusquelíneasenlaforma: NewRevision:39772

Extraeelnúmerodecadalíneausandounaexpresiónregularyel método findall().Registraelpromediodeesosnúmeroseimprímelo.

Ingresanombredearchivo:mbox.txt 38444.0323119

Ingresanombredearchivo:mbox-short.txt 39756.9259259

11.8.GLOSARIO 149
150 CHAPTER11.EXPRESIONESREGULARES

Programasenred

Aunquemuchosdelosejemplosenestelibrosehanenfocadoenleerarchivosy buscardatosenellos,haymuchasfuentesdeinformacióndiferentessisetieneen cuentaelInternet.

Enestecapítulofingiremosserunnavegadorwebyrecuperaremospáginasweb utilizandoelProtocolodeTransportedeHipertexto(HyperTextTransferProtocol -HTTP).Luegorevisaremoslosdatosdeesaspáginaswebylosanalizaremos.

12.1ProtocolodeTransportedeHipertextoHTTP Elprotocoloderedquehacefuncionarlawebesenrealidadbastantesimple,y existeunsoporteintegradoenPythonllamado sockets,elcualhacequeresulte muyfácilrealizarconexionesderedyrecuperardatosatravésdeesasconexiones desdeunprogramadePython.

Unsocketesmuyparecidoaunarchivo,aexcepcióndequeproporcionauna conexióndedoblesentidoentredosprogramas.Esposibletantoleercomoescribir enunmismosocket.Siseescribealgoenunsocket,esenviadoalaaplicaciónque estáalotroladodeéste.Siseleedesdeelsocket,seobtienenlosdatosquelaotra aplicaciónhaenviado.

Perosiintentasleerunsocketcuandoelprogramaqueestádelotroladodelsocket nohaenviadoningúndato,puedessentarteyesperar.Silosprogramasenambos extremosdelsocketsimplementeesperanpordatossinenviarnada,vanaesperar pormucho,muchotiempo,asíqueunaparteimportantedelosprogramasquese comunicanatravésdeinternetconsisteenteneralgúntipodeprotocolo.

Unprotocoloesunconjuntodereglasprecisasquedeterminanquiénvaprimero, quédebehacer,cuálessonlasrespuestassiguientesparaesemensaje,quiénenvíaa continuación,etcétera.Enciertosentidolasaplicacionesaambosladosdelsocket estáninterpretandounbaileycadaunadebeestarseguradenopisarlospiesde laotra.

Chapter12
151

Haymuchosdocumentosquedescribenestosprotocolosdered.ElProtocolode TransportedeHipertextestádescritoenelsiguientedocumento: https://www.w3.org/Protocols/rfc2616/rfc2616.txt

Setratadeundocumentolargoycomplejode176páginas,conunmontónde detalles.Siloencuentrasinteresante,siéntetelibredeleerlocompleto.Perosi echasunvistazoalrededordelapágina36delRFC2616,encontraráslasintaxis paralaspeticionesGET.Parapedirundocumentoaunservidorweb,hacemos unaconexiónalservidor www.pr4e.org enelpuerto80,yluegoenviamosunalínea comoesta: GEThttp://data.pr4e.org/romeo.txtHTTP/1.0

enlacualelsegundoparámetroeslapáginawebqueestamossolicitando,ya continuaciónenviamosunalíneaenblanco.Elservidorwebresponderáconuna cabeceraquecontieneinformaciónacercadeldocumentoyunalíneaenblanco, seguidoporelcontenidodeldocumento.

12.2Elnavegadorwebmássencillodelmundo

QuizálamaneramássencilladedemostrarcómofuncionaelprotocoloHTTP seaescribirunprogramaenPythonmuysencillo,querealiceunaconexiónaun servidorwebysigalasreglasdelprotocoloHTTPparasolicitarundocumentoy mostrarloqueelservidorenvíaderegreso.

importsocket

misock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) misock.connect(('data.pr4e.org', 80)) cmd = 'GEThttp://data.pr4e.org/romeo.txtHTTP/1.0\r\n\r\n'.encode() misock.send(cmd)

while True: datos = misock.recv(512) if len(datos) < 1: break print(datos.decode(),end='')

misock.close()

#Código:https://es.py4e.com/code3/socket1.py

Enprimerlugar,elprogramarealizaunaconexiónalpuerto80delservidor www.py4e.com.Puestoquenuestroprogramaestájugandoelrolde“navegador web”,elprotocoloHTTPdicequedebemosenviarelcomandoGETseguidode unalíneaenblanco. \r\n representaunsaltodelínea(endofline,oEOLen inglés),asíque \r\n\r\n significaquenohaynadaentredossecuenciasdesalto delínea.Eseeselequivalentedeunalíneaenblanco.

Unavezqueenviamosesalíneaenblanco,escribimosunbuclequerecibelosdatos desdeelsocketenbloquesde512caracteresylosimprimeenpantallahastaque

152 CHAPTER12.PROGRAMASENRED

Tu Programa

socket connect send recv

C T

www.py4e.com Páginas Web . Port 80

Figure12.1:Conexióndeunsocket

noquedanmásdatosporleer(esdecir,lallamadaarecv()devuelveunacadena vacía).

Elprogramaproducelasalidasiguiente:

HTTP/1.1200OK

Date:Wed,11Apr201818:52:55GMT

Server:Apache/2.4.7(Ubuntu)

Last-Modified:Sat,13May201711:22:22GMT

ETag:"a7-54f6609245537"

Accept-Ranges:bytes Content-Length:167 Cache-Control:max-age=0,no-cache,no-store,must-revalidate Pragma:no-cache Expires:Wed,11Jan198405:00:00GMT Connection:close Content-Type:text/plain

Butsoftwhatlightthroughyonderwindowbreaks

ItistheeastandJulietisthesun Arisefairsunandkilltheenviousmoon Whoisalreadysickandpalewithgrief

Lasalidacomienzaconlacabeceraqueelservidorenvíaparadescribireldocumento.Porejemplo,lacabecera Content-Type indicaqueeldocumentoesun documentodetextosinformato(text/plain).

Despuésdequeelservidornosenvíalacabecera,añadeunalíneaenblancopara indicarelfinaldelacabecera,ydespuésenvíalosdatosrealesdelarchivo romeo.txt.

Esteejemplomuestracómohacerunaconexióndereddebajonivelconsockets. Lossocketspuedenserusadosparacomunicarseconunservidorweb,conun servidordecorreo,oconmuchosotrostiposdeservidores.Todoloquesenecesita esencontrareldocumentoquedescribeelprotocolocorrespondienteyescribirel códigoparaenviaryrecibirlosdatosdeacuerdoaeseprotocolo.

Sinembargo,comoelprotocoloqueseusaconmásfrecuenciaeselprotocoloweb HTTP,Pythontieneunalibreríaespecialdiseñadaespecialmenteparatrabajar conéstepararecibirdocumentosydatosatravésdelaweb.

12.2.ELNAVEGADORWEBMÁSSENCILLODELMUNDO 153

UnodelosrequisitosparautilizarelprotocoloHTTPeslanecesidaddeenviary recibirdatoscomoobjectosbinarios,envezdecadenas.Enelejemploanterior,los métodos encode() y decode() conviertencadenasenobjectosbinariosyviceversa.

Elsiguienteejemploutilizalanotación b'' paraespecificarqueunavariabledebe seralmacenadacomounobjetobinario. encode() y b'' sonequivalentes.

>>>b'Holamundo' b'Holamundo'

>>>'Holamundo'.encode() b'Holamundo'

12.3RecepcióndeunaimagenmedianteHTTP

Enelejemploanterior,recibimosunarchivodetextosinformatoqueteníasaltos delíneaensuinterior,yloúnicoquehicimoscuandoelprogramaseejecutófue copiarlosdatosalapantalla.Podemosutilizarunprogramasimilarpara recibir unaimagenutilizandoHTTP.Envezdecopiarlosdatosalapantallaconforme vafuncionandoelprograma,vamosaguardarlosdatosenunacadena,remover lacabecera,ydespuésguardarlosdatosdelaimagenenunarchivotalcomose muestraacontinuación:

importsocket importtime

SERVIDOR = 'data.pr4e.org' PUERTO = 80 misock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) misock.connect((SERVIDOR,PUERTO)) misock.sendall(b'GEThttp://data.pr4e.org/cover3.jpgHTTP/1.0\r\n\r\n') contador = 0 imagen = b""

while True: datos = misock.recv(5120) if len(datos) < 1: break #time.sleep(0.25) contador = contador + len(datos) print(len(datos),contador) imagen = imagen + datos

misock.close()

#Búsquedadelfinaldelacabecera(2CRLF) pos = imagen.find(b"\r\n\r\n") print('Headerlength',pos) print(imagen[:pos].decode())

#Ignorarlacaberayguardarlosdatosdelaimagen imagen = imagen[pos+4:]

154 CHAPTER12.PROGRAMASENRED

fhand = open("cosa.jpg", "wb") fhand.write(imagen) fhand.close()

#Código:https://es.py4e.com/code3/urljpeg.py

Cuandoelprogramacorre,producelasiguientesalida:

$pythonurljpeg.py 51205120 512010240 424014480 512019600 5120214000 3200217200 5120222320 5120227440 3167230607 Headerlength394 HTTP/1.1200OK

Date:Fri,21Feb202001:45:41GMT Server:Apache/2.4.18(Ubuntu) Last-Modified:Mon,15May201712:27:40GMT ETag:"38342-54f8f2e5b6277"

Accept-Ranges:bytes Content-Length:230210 Vary:Accept-Encoding

Cache-Control:max-age=0,no-cache,no-store,must-revalidate

Pragma:no-cache

Expires:Wed,11Jan198405:00:00GMT

Connection:close Content-Type:image/jpeg

Puedesobservarqueparaestaurl,lacabecera Content-Type indicaqueelcuerpo deldocumentoesunaimagen(image/jpeg).Unavezqueelprogramatermina, puedesverlosdatosdelaimagenabriendoelarchivo cosa.jpg enunvisorde imágenes.

Alejecutarelprograma,sepuedeverquenoseobtienen5120caracterescadavez quellamamoselmétodo recv().Seobtienentantoscaracterescomohayansido transferidosporelservidorwebhacianosotrosatravésdelaredenelmomentode lallamadaa recv().Enesteemeplo,seobtienenalmenos3200caracterescada vezquesolicitamoshasta5120caracteresdedatos.

Losresultadospuedenvariardependiendodetuvelocidaddeinternet.Además, observaqueenlaúltimallamadaa recv() obtenemos3167bytes,locualesel finaldelacadena,yenlasiguientellamadaa recv() obtenemosunacadenade longitudceroqueindicaqueelservidoryahallamado close() ensuladodel socket,yporlotantonoquedanmásdatospendientesporrecibir.

Podemosretardarlasllamadassucesivasa recv() aldescomentarlallamadaa time.sleep().Deestaforma,esperamosuncuartodesegundodespuésdecada llamadademodoqueelservidorpuede“adelantarse”anosotrosyenviarnosmás

12.3.RECEPCIÓNDEUNAIMAGENMEDIANTEHTTP 155

datosantesdequellamemosdenuevoa recv().Conelretraso,estavezel programaseejecutaasí:

$pythonurljpeg.py 51205120 512010240 512015360 ... 5120225280 5120230400 208230608

Headerlength394 HTTP/1.1200OK

Date:Fri,21Feb202001:57:31GMT

Server:Apache/2.4.18(Ubuntu)

Last-Modified:Mon,15May201712:27:40GMT

ETag:"38342-54f8f2e5b6277"

Accept-Ranges:bytes

Content-Length:230210

Vary:Accept-Encoding

Cache-Control:max-age=0,no-cache,no-store,must-revalidate

Pragma:no-cache

Expires:Wed,11Jan198405:00:00GMT

Connection:close Content-Type:image/jpeg

Ahoratodaslasllamadasa recv(),exceptolaprimeraylaúltima,nosdan5120 caracterescadavezquesolicitamosmásdatos.

Existeunbufferentreelservidorquehacelaspeticiones send() ynuestraaplicaciónquehacelaspeticiones recv().Cuandoejecutamoselprogramaconel retrasoactivado,enalgúnmomentoelservidorpodríallenarelbufferdelsockety verseforzadoadetenersehastaquenuestroprogramaempieceavaciaresebuffer. Ladetencióndelaaplicaciónqueenvíalosdatosodelaquelosrecibesellama “controldeflujo”.

12.4Recepcióndepáginaswebcon urllib

AunquepodemosenviaryrecibirdatosmanualmentemedianteHTTPutilizando lalibreríasocket,existeunaformamuchomássimplepararealizarestahabitual tareaenPython,utilizandolalibrería urllib

Utilizando urllib,esposibletratarunapáginawebdeformaparecidaaunarchivo. Sepuedeindicarsimplementequépáginawebsedesearecuperary urllib seencargarádemanejartodoslosdetallesreferentesalprotocoloHTTPyalacabecera. Elcódigoequivalenteparaleerelarchivo romeo.txt desdelawebusando urllib eselsiguiente: importurllib.request man_a = urllib.request.urlopen('http://data.pr4e.org/romeo.txt')

156 CHAPTER12.PROGRAMASENRED

for linea in man_a: print(linea.decode().strip())

#Código:https://es.py4e.com/code3/urllib1.py

Unavezquelapáginawebhasidoabiertacon urllib.urlopen,sepuedetratar comounarchivoyleeratravésdeellautilizandounbucle for.

Cuandoelprogramaseejecuta,ensusalidasólovemoselcontenidodelarchivo. Lascabecerassiguenenviándose,peroelcódigode urllib seencargademanejarlas ysolamentenosdevuelvelosdatos.

Butsoftwhatlightthroughyonderwindowbreaks ItistheeastandJulietisthesun Arisefairsunandkilltheenviousmoon

Whoisalreadysickandpalewithgrief

Comoejemplo,podemosescribirunprogramaparaobtenerlosdatosde romeo.txt ycalcularlafrecuenciadecadapalabraenelarchivodelaformasiguiente:

importurllib.request,urllib.parse,urllib.error man_a = urllib.request.urlopen('http://data.pr4e.org/romeo.txt') contadores = dict() for linea in man_a: palabras = linea.decode().split() for palabra in palabras: contadores[palabra] = contadores.get(palabra, 0) + 1 print(contadores)

#Código:https://es.py4e.com/code3/urlwords.py

Denuevovemosque,unavezabiertalapáginaweb,sepuedeleercomosifuera unarchivolocal.

12.5Leyendoarchivosbinarioscon urllib

Avecessedeseaobtenerunarchivoquenoesdetexto(obinario)talcomouna imagenounarchivodevideo.Losdatosenesosarchivosgeneralmentenoson útilesparaserimpresosenpantalla,perosepuedehacerfácilmenteunacopiade unaURLaunarchivolocaleneldiscoduroutilizando urllib.

ElmétodoconsisteenabrirladirecciónURLyutilizar read paradescargartodoel contenidodeldocumentoenunacadena(img)paradespuésescribiresainformación aunarchivolocal,talcomosemuestraacontinuación:

12.5.LEYENDOARCHIVOSBINARIOSCON URLLIB 157

importurllib.request,urllib.parse,urllib.error

img = urllib.request.urlopen('http://data.pr4e.org/cover3.jpg').read() man_a = open('portada.jpg', 'wb') man_a.write(img) man_a.close()

#Código:https://es.py4e.com/code3/curl1.py

Esteprogramaleetodoslosdatosquerecibedelaredylosalmacenaenlavariable img enlamemoriaprincipaldelacomputadora.Después,abreelarchivo portada.jpg yescribelosdatoseneldisco.Elargumento wb enlafunción open() abreunarchivobinarioenmododeescriturasolamente.Esteprogramafuncionará siempreycuandoeltamañodelarchivoseamenorqueeltamañodelamemoria delacomputadora.

Aúnasi,siesunarchivograndedeaudioovideo,esteprogramapodríafallaro al menosejecutarsesumamentelentocuandolamemoriadelacomputadorasehaya agotado.Paraevitarquelamemoriasetermine,almacenamoslosdatosenbloques (obuffers)yluegoescribimoscadabloqueeneldiscoantesdeobtenerelsiguiente bloque.Deestaforma,elprogramapuedeleerarchivosdecualquiertamañosin utilizartodalamemoriadisponibleenlacomputadora.

importurllib.request,urllib.parse,urllib.error

img = urllib.request.urlopen('http://data.pr4e.org/cover3.jpg') man_a = open('portada.jpg', 'wb') tamano = 0 while True: info = img.read(100000) if len(info) < 1: break tamano = tamano + len(info) man_a.write(info)

print(tamano, 'caracterescopiados.') man_a.close()

#Código:https://es.py4e.com/code3/curl2.py

Enesteejemplo,leemossolamente100,000caracteresalavez,ydespuéslosescribimosalarchivo portada.jpg antesdeobtenerlossiguientes100,000caracteres dedatosdesdelaweb.

Esteprogramaseejecutacomoseobservaacontinuación:

pythoncurl2.py 230210caracterescopiados.

158 CHAPTER12.PROGRAMASENRED

12.6AnálisistheHTMLyrascadodelaweb

Unodelosusosmáscomunesdelascapacidadesde urllib enPythones rascar laweb.Elrascadodelawebescuandoescribimosunprogramaquepretendeser unnavegadorwebyrecuperapáginas,examinandoluegolosdatosdeesaspáginas paraencontrarciertospatrones.

Porejemplo,unmotordebúsquedacomoGooglebuscaráelcódigodeunapágina web,extraerálosenlacesaotraspaginasylasrecuperará,extrayendolosenlaces quehayaenellasyasísucesivamente.Utilizandoestatécnica,las arañas deGoogle alcanzanacasitodaslaspáginasdelaweb.

Googleutilizatambiénlafrecuenciaconquelaspáginasqueencuentraenlazanhaciaunapáginaconcretaparacalcularla“importancia”deesapágina,ylaposición enlaquedebeaparecerdentrodesusresultadosdebúsqueda.

12.7AnálisisdeHTMLmedianteexpresionesregulares

UnaformasencilladeanalizarHTMLconsisteenutilizarexpresionesregulares parahacerbúsquedasrepetitivasqueextraigansubcadenascoincidentesconun patrónenparticular.

Aquítenemosunapáginawebsimple:

<h1>LaPrimeraPágina</h1> <p> Siquieres,puedesvisitarla <a href="http://www.dr-chuck.com/page2.htm"> SegundaPágina</a>. </p>

Podemosconstruirunaexpresiónregularbienformadaparabuscaryextraerlos valoresdelosenlacesdeltextoanterior,deestaforma: href="http[s]?://.+?"

Nuestraexpresiónregularbuscacadenasquecomiencencon“href="http://”o “href="https://”,seguidodeunoomáscaracteres(.+?),seguidosporotracomilla doble.Elsignodeinterrogacióndespuésde [s]? indicaquelacoincidenciadebe serhechaenmodo“no-codicioso”,envezdeenmodo“codicioso”.Unabúsqueda no-codiciosaintentaencontrarlacadenacoincidente máspequeña posible,mientras queunabúsquedacodiciosaintentaríalocalizarlacadenacoincidente másgrande Añadimosparéntesisanuestraexpresiónregularparaindicarquépartedelacadenalocalizadaqueremosextraer,yobtenemoselsiguienteprograma:

#BúsquedadevaloresdeenlacesdentrodeunaURLingresada importurllib.request,urllib.parse,urllib.error

12.6.ANÁLISISTHEHTMLYRASCADODELAWEB 159

importre importssl

#IgnorarerroresdecertificadoSSL

ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

url = input('Introduzca-') html = urllib.request.urlopen(url).read() enlaces = re.findall(b'href="(http[s]?://.*?)"',html) for enlace in enlaces: print(enlace.decode())

#Código:https://es.py4e.com/code3/urlregex.py

Lalibrería ssl permiteanuestroprogramaaccederalossitioswebqueestrictamenterequierenHTTPS.Elmétodo read devuelvecódigofuenteenHTMLcomo unobjetobinarioenvezdedevolverunobjetoHTTPResponse.Elmétodode expresionesregulares findall nosdaunalistadetodaslascadenasquecoincidenconlaexpresiónregular,devolviendosolamenteeltextodelenlaceentrelas comillasdobles.

CuandocorremoselprogramaeingresamosunaURL,obtenemoslosiguiente:

Introduzca-https://docs.python.org https://docs.python.org/3/index.html https://www.python.org/ https://devguide.python.org/docquality/#helping-with-documentation https://docs.python.org/3.9/ https://docs.python.org/3.8/ https://docs.python.org/3.7/ https://docs.python.org/3.6/ https://docs.python.org/3.5/ https://docs.python.org/2.7/ https://www.python.org/doc/versions/ https://www.python.org/dev/peps/ https://wiki.python.org/moin/BeginnersGuide https://wiki.python.org/moin/PythonBooks https://www.python.org/doc/av/ https://devguide.python.org/ https://www.python.org/ https://www.python.org/psf/donations/ https://docs.python.org/3/bugs.html https://www.sphinx-doc.org/

LasexpresionesregularesfuncionanmuybiencuandoelHTMLestábienformateadoyespredecible.PerodadoqueahíafuerahaymuchaspáginasconHTML “defectuoso”,unasoluciónquesoloutiliceexpresionesregularespodríaperderalgunosenlacesválidos,obienterminarobteniendodatoserróneos.

EstosepuederesolverutilizandounalibreríarobustadeanálisisdeHTML.

160 CHAPTER12.PROGRAMASENRED

12.8AnálisisdeHTMLmedianteBeautifulSoup

ApesardequeHTMLesparecidoaXML1 yquealgunaspáginassonconstruidas cuidadosamenteparaserXML,lamayoríadelHTMLgeneralmenteestáincompleto,demodoquepuedecausarqueunanalizadordeXMLrechaceunapágina HTMLcompletaporestarformadainadecuadamente.

HayvariaslibreríasenPythonquepuedenayudarteaanalizarHTMLyextraer datosdelaspáginas.Cadaunatienesusfortalezasydebilidades,porloquepuedes elegirunabasadaentusnecesidades.

Porejemplo,vamosaanalizarunaentradaHTMLcualquierayaextraerenlaces utilizandolalibrería BeautifulSoup.BeautifulSouptoleracódigoHTMLbastante defectuosoyaúnasítedejaextraerlosdatosquenecesitas.Puedesdescargare instalarelcódigodeBeautifulSoupdesde: https://pypi.python.org/pypi/beautifulsoup4

LainformaciónacercadelainstalacióndeBeautifulSouputilizandolaherramienta dePythonPackageIndex(ÍndicedePaquetedePython) pip,disponibleen: https://packaging.python.org/tutorials/installing-packages/

Vamosautilizar urllib paraleerlapáginaydespuésutilizaremos BeautifulSoup paraextraerlosatributos href delasetiquetasdeanclaje(a).

#ParaejecutaresteprogramadescargaBeautifulSoup #https://pypi.python.org/pypi/beautifulsoup4

#Odescargaelarchivo #http://www.py4e.com/code3/bs4.zip #ydescomprimeloenelmismodirectorioqueestearchivo importurllib.request,urllib.parse,urllib.error frombs4importBeautifulSoup importssl

#IgnorarerroresdecertificadoSSL ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

url = input('Introduzca-') html = urllib.request.urlopen(url,context=ctx).read() sopa = BeautifulSoup(html, 'html.parser')

#Recuperartodaslasetiquetasdeanclaje etiquetas = sopa('a') for etiqueta in etiquetas: print(etiqueta.get('href', None))

#Código:https://es.py4e.com/code3/urllinks.py

1 ElformatoXMLesdescritoenelsiguientecapítulo.

12.8.ANÁLISISDEHTMLMEDIANTEBEAUTIFULSOUP 161

Elprogramasolicitaunadirecciónweb,luegolaabre,leelosdatosyselospasaal analizadorBeautifulSoup.Luego,recuperatodaslasetiquetasdeanclajeeimprime enpantallaelatributo href decadaunadeellas.

Cuandoelprogramaseejecuta,producelosiguiente:

Introduzca-https://docs.python.org genindex.html py-modindex.html https://www.python.org/ # whatsnew/3.8.html whatsnew/index.html tutorial/index.html library/index.html reference/index.html using/index.html howto/index.html installing/index.html distributing/index.html extending/index.html c-api/index.html faq/index.html py-modindex.html genindex.html glossary.html search.html contents.html bugs.html https://devguide.python.org/docquality/#helping-with-documentation about.html license.html copyright.html download.html https://docs.python.org/3.9/ https://docs.python.org/3.8/ https://docs.python.org/3.7/ https://docs.python.org/3.6/ https://docs.python.org/3.5/ https://docs.python.org/2.7/ https://www.python.org/doc/versions/ https://www.python.org/dev/peps/ https://wiki.python.org/moin/BeginnersGuide https://wiki.python.org/moin/PythonBooks https://www.python.org/doc/av/ https://devguide.python.org/ genindex.html py-modindex.html https://www.python.org/ # copyright.html https://www.python.org/psf/donations/ https://docs.python.org/3/bugs.html https://www.sphinx-doc.org/

162 CHAPTER12.PROGRAMASENRED

Estalistaesmuchomáslargaporquealgunasdelasetiquetasdeanclajesonrutas relativas(e.g.,tutorial/index.html)oreferenciasdentrodelapágina(p.ej.,‘#’) quenoincluyen“http://”o“https://”,locualeraunrequerimientoennuestra expresiónregular.

TambiénpuedesutilizarBeautifulSoupparaextraervariaspartesdecadaetiqueta deestemodo:

#ParaejecutaresteprogramadescargaBeautifulSoup #https://pypi.python.org/pypi/beautifulsoup4

#Odescargaelarchivo

#http://www.py4e.com/code3/bs4.zip #ydescomprimeloenelmismodirectorioqueestearchivo

fromurllib.requestimporturlopen frombs4importBeautifulSoup importssl

#IgnorarerroresdecertificadoSSL ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

url = input('Introduzca-') html = urlopen(url,context=ctx).read() sopa = BeautifulSoup(html, "html.parser")

#Obtenertodaslasetiquetasdeanclaje etiquetas = sopa('a') for etiqueta in etiquetas: #Lookatthepartsofatag print('ETIQUETA:',etiqueta) print('URL:',etiqueta.get('href', None)) print('Contenido:',etiqueta.contents[0]) print('Atributos:',etiqueta.attrs)

#Código:https://es.py4e.com/code3/urllink2.py pythonurllink2.py Introduzca-http://www.dr-chuck.com/page1.htm

ETIQUETA:<ahref="http://www.dr-chuck.com/page2.htm"> SecondPage</a> URL:http://www.dr-chuck.com/page2.htm Contenido: SecondPage

Atributos:{'href':'http://www.dr-chuck.com/page2.htm'}

html.parser eselanalizadordeHTMLincluidoenlalibreríaestándardePython 3.ParamásinformaciónacercadeotrosanalizadoresdeHTML,lee: http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser

12.8.ANÁLISISDEHTMLMEDIANTEBEAUTIFULSOUP 163

EstosejemplotansólomuestranunpocodelapotenciadeBeautifulSoupcuando setratadeanalizarHTML.

12.9SecciónextraparausuariosdeUnix/Linux

SitienesunacomputadoraLinux,Unix,oMacintosh,probablementetienescomandosnativosdetusistemaoperativoparaobtenertantoarchivosdetexto planocomoarchivosbinariosutilizandolosprocolosHTTPodeTransferencia deArchivos(FileTransfer-FTP).Unodeesoscomandoses curl:

$ curl -Ohttp://www.py4e.com/cover.jpg

Elcomando curl esunaabreviaciónde“copiarURL”yporesarazónlosdos ejemplosvistosanteriormenteparaobtenerarchivosbinarioscon urllib sonastutamentellamados curl1.py y curl2.py en www.py4e.com/code3 debidoaque ellosimplementanunafuncionalidadsimilaraladelcomando curl.Existetambiénunprogramadeejemplo curl3.py querealizalamismatareadeformaun pocomáseficiente,encasodequequierasusardeverdadestediseñoenalgún programaqueestésescribiendo.

Unsegundocomandoquefuncionadeformasimilares wget:

$ wget http://www.py4e.com/cover.jpg

Amboscomandoshacenqueobtenerpáginaswebyarchivosremotossevuelvauna tareafácil.

12.10Glosario

BeautifulSoup UnalibreríadePythonparaanalizardocumentosHTMLyextraerdatosdeellos,quecompensalamayoríadelasimperfeccionesquelos navegadoresHTMLnormalmenteignoran.Puedesdescargarelcódigode BeautifulSoupdesde www.crummy.com.

puerto Unnúmeroquegeneralmenteindicaquéaplicaciónestáscontactando cuandorealizasunaconexiónconunsocketenunservidor.Porejemplo,el tráficowebnormalmenteusaelpuerto80,mientrasqueeltráficodelcorreo electrónicousaelpuerto25.

rascado Cuandounprogramasimulaserunnavegadorwebyrecuperaunapágina web,paraluegorealizarunabúsquedaensucontenido.Amenudolosprogramassiguenlosenlacesenunapáginaparaencontrarlasiguiente,demodo quepuedenatravesarunareddepáginasounaredsocial.

rastrear Laaccióndeunmotordebúsquedawebqueconsisteenrecuperaruna páginayluegotodaslaspáginasenlazadasporella,continuandoasísucesivamentehastaquetienencasitodaslaspáginasdeInternet,queusana continuaciónparaconstruirsuíndicedebúsqueda.

socket Unaconexiónderedentredosaplicaciones,enlacualdichasaplicaciones puedenenviaryrecibirdatosenambasdirecciones.

164 CHAPTER12.PROGRAMASENRED

12.11Ejercicios

Ejercicio1:Cambiaelprogramadelsocket socket1.py paraquelepidaal usuariolaURL,demodoquepuedaleercualquierpáginaweb.Puedes usar split('/') paradividirlaURLenlaspartesquelacomponen,de modoquepuedasextraerelnombredelhostparalallamadaa connect delsocket.Añadecomprobacióndeerroresutilizando try y except para contemplarlaposibilidaddequeelusuariointroduzcaunaURL mal formadaoinexistente.

Ejercicio2:Cambiaelprogramadelsocketparaquecuenteelnúmero decaracteresqueharecibidoysedetenga,conuntextoenpantalla, despuésdequesehayanmostrado3000caracteres.Elprogramadebe recuperareldocumentocompletoycontarelnúmerototaldecaracteres, mostrandoesetotalalfinaldeldocumento.

Ejercicio3:Utiliza urllib pararehacerelejercicioanteriordemodoque (1)recibaeldocumentodeunaURL,(2)muestrehasta3000caracteres, y(3)cuentelacantidadtotaldecaractereseneldocumento.Note preocupesdelascabecerasenesteejercicio,simplementemuestalos primeros3000caracteresdelcontenidodeldocumento.

Ejercicio4:Cambiaelprograma urllinks.py paraextraerycontarlas etiquetasdepárrafo(p)deldocumentoHTMLrecuperadoymostrar eltotaldepárrafoscomosalidadelprograma.Nomuestreseltextode lospárrafos,sólocuéntalos.Pruebaelprogramaenvariaspáginasweb pequeñas,ytambiénenotrasmásgrandes.

Ejercicio5:(Avanzado)Cambiaelprogramadelsocketdemodoque solamentemuestradatosdespuésdequesehayarecibidolacabeceray lalíneaenblanco.Recuerdaque recv recibecaracteres(saltosdelínea incluidos),nolíneas.

12.11.EJERCICIOS 165
166 CHAPTER12.PROGRAMASENRED

UnavezquerecuperardocumentosatravésdeHTTPyanalizarlosusandoprogramasseconvirtióenalgosencillo,nosetardómuchoendesarrollarunmodelo consistenteenlaproduccióndedocumentosespecíficamentediseñadosparaserconsumidosporotrosprogramas(esdecir,noúnicamenteHTMLparasermostrado enunnavegador).

Existendosformatoshabitualesqueseusanparaelintercambiodedatosatravés delaweb.El“eXtensibleMarkupLanguage”(lenguajeextensibledemarcas),o XML,hasidoutilizadodurantemuchotiempo,yeselmásadecuadoparaintercambiardatosdeltipodocumento.Cuandolosprogramassimplementequieren intercambiardiccionarios,listasuotrainformacióninterna,usan“JavaScriptObjectNotation”,oJSON(NotacióndeObjetosJavascript;consultawww.json.org). Nosotrosexaminaremosambosformatos.

Chapter13
UsodeServiciosWeb
13.1eXtensibleMarkupLanguage-XML XMLtieneunaspectosimilaraHTML,peromásestructurado.Esteesunejemplo deundocumentoXML: <person> <name>Chuck</name> <phone type="intl"> +17343034456 </phone> <email hide="yes" /> </person> Cadapardeetiquetasdeapertura(p.ej.,‘’)ydecierre(p.ej.,‘’)representan un elemento o nodo conelmismonombredelaetiqueta(p.ej.,‘person’).Cada
167
elementopuedecontenertexto,atributos(p.ej.,‘hide’)yotroselementosanidados. SiunelementoXMLestávacío(esdecir,notienecontenido),puederepresentarse conunaetiquetaauto-cerrada(p.ej.,‘’).

AmenudoresultaútilpensarenundocumentoXMLcomoenlaestructuradeun árbol,dondehayunaetiquetasuperior(enestecaso‘person’),yotrasetiquetas como‘phone’quesemuestrancomo hijas desusnodos padres

nombre Chuck

telefono +1 734 303 4456

tipo=intl email oculto=si

Figure13.1:ATreeRepresentationofXML

13.2AnálisisdeXML

HeaquíunaaplicaciónsencillaqueanalizaunarchivoXMLyextraealgunos elementosdeél:

importxml.etree.ElementTreeasET

datos = ''' <persona> <nombre>Chuck</nombre> <telefonotype="intl"> +17343034456 </telefono> <emailoculto="si"/> </persona>'''

arbol = ET.fromstring(datos)

print('Nombre:',arbol.find('nombre').text) print('Atributo:',arbol.find('email').get('oculto'))

#Código:https://es.py4e.com/code3/xml1.py

Tantolatriplecomillasimple(‘”‘’)comolatriplecomilladoble(’“”“’)permiten lacreacióndecadenasqueabarquenvariaslíneas.

Lallamadaa‘fromstring’conviertelarepresentacióndecadenadelXMLenun “árbol”denodosXML.UnaveztenemoselXMLcomounárbol,disponemosde unaseriedemétodosquepodemosllamarparaextraerporcionesdedatosdeese XML.Lafunción‘find’buscaatravésdelárbolXMLyrecuperaelnodoque coincideconlaetiquetaespecificada.

168 CHAPTER13.USODESERVICIOSWEB

Nombre:Chuck

Atributo:si

ElusarunanalizadordeXMLcomo‘ElementTree’tienelaventajadeque,apesar dequeelXMLdeesteejemploesbastantesencillo,resultaquehaymuchasreglas relativasalavalidezdelXML,yelusode‘ElementTree’nospermiteextraerdatos delXMLsinpreocuparnosporesasreglasdesintaxis.

13.3Desplazamientoatravésdelosnodos

AmenudoelXMLtienemúltiplesnodosytenemosqueescribirunbuclepara procesarlostodos.Enelprogramasiguiente,usamosunbuclepararecorrertodos losnodos‘usuario’:

importxml.etree.ElementTreeasET

datos = ''' <cosa> <usuarios> <usuariox="2"> <id>001</id> <nombre>Chuck</nombre> </usuario> <usuariox="7"> <id>009</id> <nombre>Brent</nombre> </usuario> </usuarios> </cosa>''' cosa = ET.fromstring(datos) lst = cosa.findall('usuarios/usuario') print('Totaldeusuarios:',len(lst))

for item in lst: print('Nombre',item.find('nombre').text) print('Id',item.find('id').text) print('Atributo',item.get('x'))

#Código:https://es.py4e.com/code3/xml2.py

Elmétodo‘findall’devuelveunalistadesubárbolesquerepresentanlasestructuras ‘usuario’delárbolXML.Acontinuaciónpodemosescribirunbucle‘for’quebusque encadaunodelosnodosusuario,eimprimaeltextodeloselementos‘nombre’e ‘id’,ademásdelatributo‘x’decadanodousuario.

Contadordeusuarios:2 NombreChuck

13.3.DESPLAZAMIENTOATRAVÉSDELOSNODOS 169

Id001 Atributo2 NombreBrent Id009 Atributo7

Esimportanteincluirtodosloselementosbaseenladeclaraciónde‘findall’exceptuandoaquelqueseencuentraenelnivelsuperior(p.ej.,‘usuarios/usuario’).De locontrario,Pythonnoencontraráningunodelosnodosquebuscamos.

importxml.etree.ElementTreeasET

input = '''

<cosa> <usuarios> <usuariox="2"> <id>001</id> <nombre>Chuck</nombre> </usuario> <usuariox="7"> <id>009</id> <nombre>Brent</nombre> </usuario> </usuarios> </cosa>'''

cosa = ET.fromstring(input)

lst = cosa.findall('usuarios/usuario') print('Cuentadeusuarios:',len(lst))

lst2 = cosa.findall('usuario') print('Cuentadeusuarios:',len(lst2))

‘lst’almacenatodosloselementos‘usuario’anidadosdentrodesubase‘usuarios’. ‘lst2’buscaloselementos‘usuario’quenoseencuentrenanidadosdentrodelelementodenivelsuperior‘cosa’dondenohayninguno.

Cuentadeusuarios:2 Cuentadeusuarios:0

13.4JavaScriptObjectNotation-JSON

ElformatoJSONseinspiróenelformatodeobjetosyarraysqueseusaenel lenguajeJavaScript.PerocomoPythonseinventóantesqueJavaScript,lasintaxis usadaenPythonparalosdiccionariosylistasinfluyeronlasintaxisdeJSON. DemodoqueelformatodelJSONescasiidénticoalacombinacióndelistasy diccionariosdePython.

170 CHAPTER13.USODESERVICIOSWEB

HeaquíunacodificaciónJSONqueesmásomenosequivalentealXMLdelejemplo anterior: {

"name" : "Chuck", "phone" :{ "type" : "intl", "number" : "+17343034456" }, "email" :{ "hide" : "yes" }

}

Sitefijas,encontrarásciertasdiferencias.Primero,enXMLsepuedenañadiratributoscomo“intl”alaetiqueta“phone”.EnJSON,simplementetenemosparejas clave-valor.Además,laetiqueta“person”deXMLhadesaparecido,reemplazada porunconjuntodellavesexteriores.

Engeneral,lasestructurasJSONsonmássimplesquelasdeXML,debidoa queJSONtienemenoscapacidades.PeroJSONtienelaventajadequemapea directamente haciaunacombinacióndediccionariosylistas.Y,dadoquecasi todosloslenguajesdeprogramacióntienenalgoequivalentealosdiccionariosy listasdePython,JSONesunformatomuyintuitivoparaquedosprogramasque vayanacooperarintercambiendatos.

JSONseestáconvirtiendorápidamenteenelformatoelegidoparacasitodoslosintercambiosdedatosentreaplicaciones,debidoasurelativasimplicidadcomparado conXML.

13.5AnálisisdeJSON

ElJSONseconstruyeanidandodiccionariosylistassegúnsenecesite.Eneste ejemplo,vamosarepresentarunalistadeusuariosenlaquecadausuarioesun conjuntodeparejasclave-valor(esdecir,undiccionario).Demodoquetendremos unalistadediccionarios.

Enelprogramasiguiente,usaremoslalibreríaintegrada‘json’paraanalizarel JSONyleerlosdatos.CompáralocuidadosamenteconlosdatosycódigoXML equivalentesqueusamosantes.ElJSONtienemenosdetalles,demodoquepodemossaberdeantemanoquevamosaobtenerunalistayquelalistaesdeusuarios yademásquecadausuarioesunconjuntodeparejasclave-valor.ElJSONesmás conciso(unaventaja),perotambiénesmenosauto-descriptivo(unadesventaja). importjson datos

13.5.ANÁLISISDEJSON 171
= ''' [ {"id":"001", "x":"2",

"nombre":"Chuck" }, {"id":"009", "x":"7", "nombre":"Brent" }

]'''

info = json.loads(datos) print('Totaldeusuarios:',len(info))

for elemento in info: print('Nombre',elemento['nombre']) print('Id',elemento['id']) print('Atributo',elemento['x'])

#Código:https://es.py4e.com/code3/json2.py

SicomparaselcódigoqueextraelosdatosdelJSONanalizadoyeldelXML,verás queloqueobtenemosde‘json.loads()’esunalistadePythonquerecorreremoscon unbuclefor,ycadaelementodentrodeesalistaesundiccionariodePython.Una vezanalizadoelJSON,podemosusareloperadoríndicedePythonparaextraer losdistintosfragmentosdedatosdecadausuario.Notenemosqueusarlalibrería JSONpararebuscaratravésdelJSONanalizado,yaquelosdatosdevueltosson sencillamenteestructurasnativasdePython.

LasalidadeesteprogramaesexactamentelamismaqueladelaversiónXML anterior.

Totaldeusuarios:2 NombreChuck Id001 Atributo2 NombreBrent Id009 Atributo7

Engeneral,hayunatendenciaenlaindustriaaapartarsedelXMLypasaral JSONparalosserviciosweb.ComoelJSONesmássencillo,ysemapeadeforma másdirectahaciaestructurasdedatosnativasqueyatenemosenloslenguajes deprogramación,elcódigodeanálisisyextraccióndedatosnormalmenteesmás sencilloydirectousandoJSON.Sinembargo,XMLesmásauto-descriptivo,y poresohayciertasaplicacionesenlascualesmantienesuventaja.Porejemplo, lamayoríadelosprocesadoresdetextoalmacenansusdocumentosinternamente usandoXMLenvezdeJSON.

13.6Interfacesdeprogramacióndeaplicaciones

AhoratenemoslacapacidaddeintercambiardatosentreaplicacionesusandoelProtocolodeTransportedeHipertexto(HTTP),yunmododerepresentarestructuras

172 CHAPTER13.USODESERVICIOSWEB

dedatoscomplejasparapoderenviaryrecibirlosdatosentreesasaplicaciones,a travésdeleXtensibleMarkupLanguage(XML)odelJavaScriptObjectNotation (JSON).

Elpasosiguienteesempezaradefinirydocumentar“contratos”entreaplicaciones usandoestastécnicas.Elnombrehabitualparaestoscontratosentreaplicaciones es InterfacesdeProgramacióndeAplicaciones (ApplicationProgramInterfaces),o APIs.CuandoseutilizaunaAPI,normalmenteunprogramacreaunconjuntode servicios disponiblesparaquelosusenotrasaplicacionesypublicalasAPIs(esdecir,las“reglas”)quedebenserseguidasparaaccederalosserviciosproporcionados porelprograma.

Cuandocomenzamosaconstruirprogramasconfuncionalidadesqueincluyenel accesoaserviciosproporcionadosporotrosprogramas,elenfoquesedenomina Service-OrientedArchitecture (ArquitecturaOrientadaaServicios),oSOA.Un enfoqueSOAesaquelenelcualnuestraaplicaciónprincipalusalosserviciosde otrasaplicaciones.Unplanteamientono-SOAesaquelenelcualtenemosuna únicaaplicaciónindependientequecontienetodoelcódigonecesarioparasuimplementación.

PodemosencontrarmultituddeejemplosdeSOAscuandoutilizamosservicios delaweb.Podemosiraunúnicositiowebyreservarviajesenavión,hoteles yautomóviles,todoellodesdeelmismositio.Losdatosdeloshotelesnoestán almacenadosenlosequiposdelacompañíaaérea.Envezdeeso,loscomputadores delaaerolíneacontactanconlosserviciosdeloscomputadoresdeloshoteles, recuperanlosdatosdeéstos,yselospresentanalusuario.Cuandoelusuario aceptarealizarunareservadeunhotelusandoelsitiowebdeunaaerolínea,ésta utilizaotroserviciowebenlossistemasdeloshotelespararealizarlareserva real.Ycuandollegaelmomentodecargarentutarjetadecréditoelimportede latransaccióncompleta,haytodavíaotrosequiposdiferentesinvolucradosenel proceso.

13.6.INTERFACESDEPROGRAMACIÓNDEAPLICACIONES 173
Servicio Alquiler Automóviles Servicio Reserva Hoteles Servicio Reserva Vuelos Aplicación de Viajes API API API Figure13.2:Service-orientedarchitecture

UnaArquitecturaOrientadaaServiciostienemuchasventajas,queincluyen:(1) siempresemantieneunaúnicacopiadelosdatos(locualresultaparticularmente importanteenciertasáreascomolasreservashoteleras,dondenoqueremosduplicarexcesivamentelainformación)y(2)lospropietariosdelosdatospueden imponerreglasacercadelusodeesosdatos.Conestasventajas,unsistemaSOA debeserdiseñadocuidadosamenteparatenerbuenrendimientoysatisfacerlas necesidadesdelosusuarios.

CuandounaaplicaciónofreceunconjuntodeserviciosensuAPIdisponiblesa travésdelaweb,losllamamos serviciosweb.

13.7SeguridadyusodeAPIs

Resultabastantefrecuentequesenecesitealgúntipode“claveAPI”parahacer usodeunaAPIcomercial.Laideageneralesqueellosquierensaberquiénestá usandosusserviciosycuántolosutilizacadausuario.Talveztienendistintos niveles(gratuitosydepago)deservicios,ounapolíticaquelimitaelnúmerode peticionesqueunúnicousuariopuederealizarduranteundeterminadoperiodode tiempo.

Enocasiones,unavezquetienestuclaveAPI,tansólodebesincluirlacomoparte delosdatosPOST,otalvezcomoparámetrodentrodelaURLqueusaspara llamaralaAPI.

Otrasveces,elvendedorquiereaumentarlacertezasobreelorigendelaspeticiones, demodoqueademásesperaqueenvíesmensajesfirmadoscriptográficamente,usandoclavescompartidasysecretas.Unatecnologíamuyhabitualqueseutiliza parafirmarpeticionesenInternetsellama OAuth.Puedesleermásacercadel protocoloOAuthen www.oauth.net

Afortunadamente,hayvariaslibreríasOAuthútilesygratuitas,demodoquete puedesahorrareltenerqueescribirunaimplementaciónOAuthdesdeceroleyendo lasespecificaciones.Estaslibreríastienendistintosnivelesdecomplejidad,así comovariedaddecaracterísticas.ElsitiowebOAuthtieneinformaciónsobre variaslibreríasOAuth.

13.8Glossary

API ApplicationProgrammingInterface(InterfazdeProgramacióndeAplicaciones)-Uncontratoentreaplicacionesquedefinelaspautasdeinteracción entreloscomponentesdedosaplicaciones.

ElementTree UnalibreríainternadePythonqueseutilizaparaanalizardatos XML.

JSON JavaScriptObjectNotation(NotacióndeObjetosJavaScript).Unformato quepermiteelenvíodeestructurasdedatosbasadasenlasintaxisdelos ObjetosJavaScript.

SOA Service-OrientedArchitecture(ArquitecturaOrientadaaServicios). Cuandounaaplicaciónestáformadaporcomponentesconectadosatravés deunared.

174 CHAPTER13.USODESERVICIOSWEB

XML eXtensibleMarkupLanguage(LenguajedeMarcaseXtensible).Unformato quepermiteelenvíodedatosestructurados.

13.9AplicaciónNº1:ServiciowebdegeocodificacióndeGoogle

Googletieneunexcelenteserviciowebquenospermitehacerusodesuenorme basededatosdeinformacióngeográfica.Podemosenviarunacadenadebúsqueda geográfica,como“AnnArbor,MI”asuAPIdegeocodificaciónyconseguirque Googlenosdevuelvasumejorsuposiciónsobredondepodríaestarnuestracadena debúsquedaenunmapa,ademásdelospuntosdereferenciaenlosalrededores.

Elserviciodegeocodificaciónesgratuito,perolimitado,demodoquenosepuede hacerunusointensivodeestaAPIenunaaplicacióncomercial.Perositienesciertosdatosestadísticosenloscualesunusuariofinalhaintroducidounalocalización enformatolibreenuncuadrodetexto,puedesutilizarestaAPIparalimpiaresos datosdeformabastanteefectiva.

CuandoseusaunaAPIlibre,comolaAPIdegeocodificacióndeGoogle,sedebe serrespetuosoconelusodelosrecursos.Sihaydemasiadagentequeabusadel servicio,Googlepuedeinterrumpirorestringirsignificativamentesuusogratuito.

Puedesleerladocumentaciónonlinedeesteservicio,peroesbastantesencilloy puedesinclusoprobarlodesdeunnavegador,simplementetecleandolasiguiente URLenél:

http://maps.googleapis.com/maps/api/geocode/json?address=Ann+Arbor%2C+MI

AsegúratedelimpiarlaURLyeliminarcualquierespaciodeellaantesdepegarla entunavegador.

Lasiguienteesunaaplicaciónsencillaquepidealusuariounacadenadebúsqueda, llamaalaAPIdegeocodificacióndeGoogleyextraeinformacióndelJSONque nosdevuelve.

13.9.APLICACIÓNNº1:SERVICIOWEBDEGEOCODIFICACIÓNDEGOOGLE175
importurllib.request,urllib.parse,urllib.error importjson importssl clave_api = False #SitienesunaclaveAPIdeGooglePlaces,ingresalaaquí #clave_api='AIzaSy___IDByT70' #https://developers.google.com/maps/documentation/geocoding/intro if clave_api is False: clave_api = 42 url_de_servicio = 'http://py4e-data.dr-chuck.net/json?' else : url_de_servicio = 'https://maps.googleapis.com/maps/api/geocode/json?' #IgnorarerroresdecertificadoSSL

ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

while True: direccion = input('Ingresaunaubicación:') if len(direccion) < 1: break parms = dict() parms['address'] = direccion if clave_api isnot False:parms['key'] = clave_api url = url_de_servicio + urllib.parse.urlencode(parms)

print('Recuperando',url) uh = urllib.request.urlopen(url,context=ctx) datos = uh.read().decode() print('Recuperados',len(datos), 'caracteres') try: js = json.loads(datos) except: js = None if not js or 'status' notin js or js['status'] != 'OK': print('====ErroralRecuperar====') print(datos) continue print(json.dumps(js,indent=4)) lat = js['results'][0]['geometry']['location']['lat'] lng = js['results'][0]['geometry']['location']['lng'] print('lat',lat, 'lng',lng) location = js['results'][0]['formatted_address'] print(location)

#Código:https://es.py4e.com/code3/geojson.py

ElprogramatomalacadenadebúsquedayconstruyeunaURLcodificándola comoparámetrodentrodeella,utilizandoluego‘urllib’pararecuperareltextode laAPIdegeocodificacióndeGoogle.Adiferenciadeunapáginawebestática,los datosqueobtengamosdependerándelosparámetrosqueenviemosydelosdatos geográficosalmacenadosenlosservidoresdeGoogle.

UnavezrecuperadoslosdatosJSON,losanalizamosconlalibrería‘json’yrevisamosparaasegurarnosdequehemosrecibidodatosválidos.Finalmente,extraemoslainformaciónquebuscábamos.

Lasalidadelprogramaeslasiguiente(partedelJSONrecibidohasidoeliminado):

$python3geojson.py

176 CHAPTER13.USODESERVICIOSWEB

Enterlocation:AnnArbor,MI Retrievinghttp://py4e-data.dr-chuck.net/json?address=Ann+Arbor%2C+MI&key=42 Retrieved1736characters

{ "results": [ {

"address_components": [ { "long_name": "AnnArbor", "short_name": "AnnArbor", "types": [ "locality", "political" ] }, { "long_name": "WashtenawCounty", "short_name": "WashtenawCounty", "types": [ "administrative_area_level_2", "political" ] }, { "long_name": "Michigan", "short_name": "MI", "types": [ "administrative_area_level_1", "political" ] }, { "long_name": "UnitedStates", "short_name": "US", "types": [ "country", "political" ] } ], "formatted_address": "AnnArbor,MI,USA", "geometry":{ "bounds":{ "northeast":{ "lat": 42.3239728, "lng": -83.6758069 }, "southwest":{ "lat": 42.222668, "lng": -83.799572

13.9.APLICACIÓNNº1:SERVICIOWEBDEGEOCODIFICACIÓNDEGOOGLE177

}

}, "location":{ "lat": 42.2808256, "lng": -83.7430378 }, "location_type": "APPROXIMATE", "viewport":{ "northeast":{ "lat": 42.3239728, "lng": -83.6758069 }, "southwest":{ "lat": 42.222668, "lng": -83.799572 } } }, "place_id": "ChIJMx9D1A2wPIgR4rXIhkb5Cds", "types": [ "locality", "political" ] } ], "status": "OK" } lat42.2808256lng-83.7430378 AnnArbor,MI,USA

Enterlocation: Puedesdescargar www.py4e.com/code3/geoxml.py pararevisarlasvariantesJSON yXMLdelaAPIdegeocodificacióndeGoogle.

Ejercicio1:Modifica geojson.py o geoxml.py paraimprimirenpantalla elcódigodepaísdedoscaracteresdelosdatosrecuperados.Añade comprobacióndeerrores,demodoquetuprogramanorastreelos datos sielcódigodelpaísnoestápresente.Unavezquelotengasfuncionando, busca“OcéanoAtlántico”yasegúratedequeescapazdegestionar ubicacionesquenoesténdentrodeningúnpaís.

13.10Aplicación2:Twitter

AmedidaquelaAPIdeTwittersevuelvemásvaliosa,TwitterpasódeunaAPI públicayabiertaaunaquerequiereelusodefirmasOAuthencadasolicitud. Paraelprogramadeejemplosiguiente,descargalosarchivos twurl.py, hidden.py, oauth.py y twitter1.py desde www.py4e.com/code yponlostodosenunamisma carpetaentuequipo.

178 CHAPTER13.USODESERVICIOSWEB

ParausarestosprogramasdebestenerunacuentadeTwitter,yautorizaratu códigoPythoncomoaplicaciónpermitida,estableciendodiversosparámetros(key, secret,tokenytokensecret).Luegodeberáseditarelarchivo hidden.py ycolocar esascuatrocadenasenlasvariablesapropiadasdentrodelarchivo:

#Mantenerestearchivoseparado

#https://apps.twitter.com/ #CrearnuevaAppyobtenerlascuatrocadenas

def oauth():

return {"consumer_key": "h7Lu...Ng", "consumer_secret" : "dNKenAC3New...mmn7Q", "token_key" : "10185562-eibxCp9n2...P4GEQQOSGI", "token_secret" : "H0ycCFemmC4wyf1...qoIpBo"}

#Código:https://es.py4e.com/code3/hidden.py

SepuedeaccederalserviciowebdeTwittermedianteunaURLcomoésta: https://api.twitter.com/1.1/statuses/user_timeline.json

Perounavezañadidalainformacióndeseguridad,laURLseparecerámásaesto:

https://api.twitter.com/1.1/statuses/user_timeline.json?count=2 &oauth_version=1.0&oauth_token=101...SGI&screen_name=drchuck &oauth_nonce=09239679&oauth_timestamp=1380395644 &oauth_signature=rLK...BoD&oauth_consumer_key=h7Lu...GNg &oauth_signature_method=HMAC-SHA1

PuedesleerlaespecificaciónOAuthsiquieressabermásacercadelsignificadode losdistintosparámetrosquehemosañadidoparacumplirconlosrequerimientos deseguridaddeOAuth.

ParalosprogramasqueejecutamosconTwitter,ocultamostodalacomplejidad dentrodelosarchivos oauth.py y twurl.py.Simplementeajustamoslosparámetros secretosen hidden.py,enviamoslaURLdeseadaalafunción twurl.augment(),yel códigodelalibreríaañadetodoslosparámetrosnecesariosalaURL.

EsteprogramarecuperalalíneadetiempodeunusuariodeTwitterconcretoynos ladevuelveenformatoJSONcomounacadena.Vamosaimprimirsimplemente losprimeros250caracteresdeesacadena:

importurllib.request,urllib.parse,urllib.error

#https://apps.twitter.com/ #CrearAppyobtenerlascuatrocadenas,luegocolocarlasen hidden.py

TWITTER_URL = 'https://api.twitter.com/1.1/statuses/user_timeline.json'

13.10.APLICACIÓN2:TWITTER 179
importtwurl importssl

#IgnorarerroresdecertificadoSSL ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

while True: print('')

cuenta = input('IngresaunacuentadeTwitter:') if (len(cuenta) < 1): break url = twurl.aumentar(TWITTER_URL, {'screen_name':cuenta, 'count': '2'}) print('Recuperando',url) conexion = urllib.request.urlopen(url,context=ctx) datos = conexion.read().decode() print(datos[:250]) cabeceras = dict(conexion.getheaders()) #Imprimircabeceras print('Restantes',cabeceras['x-rate-limit-remaining'])

#Código:https://es.py4e.com/code3/twitter1.py

Cuandoelprogramaseejecuta,producelasalidasiguiente:

IngresaunacuentadeTwitter:drchuck Recuperandohttps://api.twitter.com/1.1/... [{"created_at":"SatSep2817:30:25+00002013"," id":384007200990982144,"id_str":"384007200990982144", "text":"RT@fixpert:SeehowtheDutchhandletraffic intersections:http:\/\/t.co\/tIiVWtEhj4\n#brilliant", "source":"web","truncated":false,"in_rep Restantes178

IngresaunacuentadeTwitter:fixpert Recuperandohttps://api.twitter.com/1.1/... [{"created_at":"SatSep2818:03:56+00002013", "id":384015634108919808,"id_str":"384015634108919808", "text":"3monthsaftermyfreakbocceballaccident, myweddingringfitsagain!:)\n\nhttps:\/\/t.co\/2XmHPx7kgX", "source":"web","truncated":false, Restantes177

IngresaunacuentadeTwitter:

Juntoconlosdatosdelalíneadeltiempo,Twittertambiéndevuelvemetadatos sobrelapeticiónenlascabecerasderespuestaHTTP.Unacabeceraenparticular, ‘x-rate-limit-remaining’,nosinformasobrecuántaspeticionespodremoshacerantes dequeseamosbloqueadosporuncortoperiododetiempo.Puedesverquecadavez querealizamosunapeticiónalaAPInuestrosintentosrestantesvandisminuyendo.

Enelejemplosiguiente,recuperamoslosamigosdeunusuarioenTwitter,analizamoselJSONdevueltoyextraemospartedelainformaciónsobreesosamigos.

180 CHAPTER13.USODESERVICIOSWEB

DespuésdeanalizarelJSONe“imprimirlobonito”,realizamosunvolcadocompletoconunindentadodecuatrocaracteres,quenospermiteestudiarminuciosamentelosdatosencasodequequeramosextraermáscampos.

importurllib.request,urllib.parse,urllib.error importtwurl importjson importssl

#https://apps.twitter.com/ #CrearAppyobtenerlascuatrocadenas,luegocolocarlasen hidden.py

TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json'

#IgnorarerroresdecertificadoSSL ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

while True: print('') cuenta = input('IngresaunacuentadeTwitter:') if (len(cuenta) < 1): break url = twurl.aumentar(TWITTER_URL, {'screen_name':cuenta, 'count': '5'}) print('Recuperando',url) conexion = urllib.request.urlopen(url,context=ctx) data = conexion.read().decode()

js = json.loads(data) print(json.dumps(js,indent=2))

cabeceras = dict(conexion.getheaders()) print('Restantes',cabeceras['x-rate-limit-remaining'])

for u in js['users']: print(u['screen_name']) if 'status' notin u: print('*Estadonoencontrado') continue s = u['status']['text'] print('',s[:50])

#Código:https://es.py4e.com/code3/twitter2.py

DadoqueelJSONsetransformaenunconjuntodelistasydiccionariosdePython anidados,podemosusarunacombinacióndeloperadoríndicejuntoconbucles‘for’ paramovernosatravésdelasestructurasdedatosdevueltasconmuypococódigo dePython.

Lasalidadelprogramaseparecealasiguiente(partedelosdatossehanacortado

13.10.APLICACIÓN2:TWITTER 181

paraquequepanenlapágina):

IngresaunacuentadeTwitter:drchuck

Recuperandohttps://api.twitter.com/1.1/friends... Restantes14

{

"next_cursor": 1444171224491980205, "users": [ {

"id": 662433, "followers_count": 28725, "status":{ "text": "@jazzychadIjustboughtone.__.", "created_at": "FriSep2008:36:34+00002013", "retweeted": false, },

"location": "SanFrancisco,California", "screen_name": "leahculver", "name": "LeahCulver", }, {

"id": 40426722, "followers_count": 2635, "status":{ "text": "RT@WSJ:BigemployerslikeGoogle...", "created_at": "SatSep2819:36:37+00002013", }, "location": "VictoriaCanada", "screen_name": "_valeriei", "name": "ValerieIrvine", } ],

"next_cursor_str": "1444171224491980205" }

leahculver

@jazzychadIjustboughtone.__. _valeriei

RT@WSJ:BigemployerslikeGoogle,AT&amp;Tareh ericbollens

RT@lukew:sneakpeek:myLONGtakeonthegood&a halherzog

LearningObjectsis10.WehadacakewiththeLO, scweeker

@DeviceLabDCloveit!NowwheresoIgetthat"etc

IngresaunacuentadeTwitter:

Elúltimotrozodelasalidaesdondepodemosvercómoelbucleforleeloscinco “amigos”másnuevosdelacuentadeTwitter @drchuck eimprimeelestadomás

182 CHAPTER13.USODESERVICIOSWEB

recientedecadaunodeellos.HaymuchosmásdatosdisponiblesenelJSON devuelto.Simiraslasalidadelprograma,podrásverqueel“encuentraalos amigos”deunacuentaparticulartieneunalimitacióndeusosdistintaaladel númerodeconsultasdelíneasdetiempoqueestápermitidorealizarduranteun periododetiempo.

EstasclavesdeseguridaddelaAPIpermitenaTwittertenerlacertezadeque sabequiénestáusandosuAPIdedatos,yaquénivel.Elenfoquedelímitede usosnospermitehacercapturasdedatossencillas,peronocrearunproductoque extraigadatosdeesaAPImillonesdevecesaldía.

13.10.APLICACIÓN2:TWITTER 183
184 CHAPTER13.USODESERVICIOSWEB

ProgramaciónOrientadaa Objetos

14.1Manejandoprogramasmásgrandes

Alcomienzodeestelibro,vimoscuatropatronesbásicosdeprogramaciónque utilizamosparaconstruirprogramas:

•Códigosecuencial

•Códigocondicional(declaraciones if)

•Códigorepetitivo(bucles)

•Almacenaryreutilizar(funciones)

Encapítulosposteriores,exploramoslasvariablessimples,asícomoestructurasde datosdecolecciones,talescomolistas,tuplasydiccionarios.

Amedidaqueconstruimosprogramas,diseñamosestructurasdedatosyescribimoscódigoparamanipularlas.Haymuchasformasdeescribirprogramasy,a estasalturas,probablementehayasescritoalgunosprogramas“nomuyelegantes” yotrosqueson“máselegantes”.Aunquetusprogramasaúnseanpequeños,estás empezandoaverquealescribircódigohayunapartedearteydeconsideraciones estéticas.

Amedidaquelosprogramascrecenhastaabarcarmillonesdelíneasdecódigo, sevuelvecadavezmásimportantequeésteresultefácildeentender.Siestás trabajandoenunprogramadeunmillóndelíneas,esimposiblemantenertodo elprogramaentumentealavez.Necesitamosmanerasdedividirprogramas grandesenvariaspiezasmáspequeñasparaquetengamosqueconcentrarnosen unasecciónmenorcuandotengamosqueresolverunproblema,arreglarunbug,o agregarunanuevafuncionalidad.

Enciertomodo,laprogramaciónorientadaaobjetosesunaformadeordenartu códigodetalmaneraquepuedasenfocarteen50líneasdecódigoyentenderlas,e ignorarlasotras999,950mientrastanto.

Chapter14
185

14.2Cómoempezar

Aligualquemuchosaspectosdelaprogramación,esnecesarioaprenderlosconceptosdelaprogramaciónorientadaaobjetosparapoderutilizarlosdemanera efectiva.Deberíasenfocarteenestecapítulocomounaformadeaprenderalgunos términosyconceptosyexaminaralgunosejemplossencillosparasentarlasbases detufuturoaprendizaje.

Elresultadoclavedeestecapítuloseráunacomprensiónanivelbásicodecómo seconstruyenlosobjetos,cómofuncionany,lomásimportante,cómousarlas característicasdelosobjetosquenosdanPythonysuslibrerías.

14.3Usandoobjetos

Curiosamente,enellibrohemosestadoutilizandoobjetostodoestetiempo. Pythoncontienemuchosobjetosincluidos.Heaquíunprogramasencillo,cuyas primeraslíneasdeberíanresultartesumamentesimplesyfamiliares.

cosa = list() cosa.append('python') cosa.append('chuck') cosa.sort() print(cosa[0]) print(cosa.__getitem__(0)) print(list.__getitem__(cosa,0))

#Código:https://es.py4e.com/code3/party1.py

Enlugardeenfocarnosenelresultadoqueobtienenestaslíneas,enfoquémonosen loqueestápasandodesdeelpuntodevistadelaprogramaciónorientadaaobjetos. Notepreocupessilossiguientespárrafosnoparecentenersentidolaprimeravez queloslees,puesnohemosdefinidotodosestostérminosaún.

Laprimeralínea construye unobjetodetipo list,lasegundayterceralíneas llaman al método append,lacuartalíneallamaalmétodo sort() ylaquintalínea recupera elelementoenposición0.

Lasextalíneallamaalmétodo __getitem__() enlalista cosa conunparámetro decero.

print(cosa.__getitem__(0))

Laséptimalíneaesunamanerainclusomásverbosadeobtenerelelementoen posición0delalista.

print(list.__getitem__(cosa,0))

Enesteprograma,llamamosalmétodo __getitem__ enlaclase lista y pasamos lalistayelelementoquequeremosrecuperardeéstacomoparámetros.

186 CHAPTER14.PROGRAMACIÓNORIENTADAAOBJETOS

Lasúltimastreslíneasdelprogramasonequivalentes,peroesmásconveniente simplementeusarcorchetesparabuscarunelementoenunaposiciónespecífica dentrodeunalista.

Podemosverlascapacidadesdeunobjetomirandoelresultadodelafunción dir():

>>>cosa=list()

>>>dir(cosa) ['__add__','__class__','__contains__','__delattr__', '__delitem__','__dir__','__doc__','__eq__', '__format__','__ge__','__getattribute__','__getitem__', '__gt__','__hash__','__iadd__','__imul__','__init__', '__iter__','__le__','__len__','__lt__','__mul__', '__ne__','__new__','__reduce__','__reduce_ex__', '__repr__','__reversed__','__rmul__','__setattr__', '__setitem__','__sizeof__','__str__','__subclasshook__', 'append','clear','copy','count','extend','index', 'insert','pop','remove','reverse','sort']

>>>

Elrestodeestecapítuloestarádedicadoadefinirestostérminos,asíqueasegúrate devolveraleerlospárrafosanterioresunavezqueterminesdeleerlo,paraasegurartedehaberlocomprendidocorrectamente.

14.4Comenzandoconprogramas

Ensuformamásbásica,unprogramatomaalgúndatodeentrada,loprocesa yluegoproduceunresultado.Nuestroprogramadeconversióndeunelevador muestraunamaneramuycorta,perocompleta,dellevaracaboestostrespasos.

usf = input('IngresaelNúmerodePisoUS:') wf = int(usf) - 1 print('NúmerodePisoNo-USes',wf) #Código:https://es.py4e.com/code3/elev.py

Sipensamosunpocomássobreesteprograma,existeun“mundoexterior”yel programa.Esconlosdatosdeentradaydesalidaqueelprogramainteractúacon elmundoexterior.Dentrodelprogramautilizamostantoelcódigocomolosdatos paracumplirlatareaqueelprogramaestádiseñadopararesolver.

Unaformadepensarenlaprogramaciónorientadaaobjetosesqueseparanuestro programaenvarias“zonas”.Cadazonacontienealgodecódigoydatos(comoun programa)ytieneinteraccionesbiendefinidastantoconelmundoexteriorcomo conlasotraszonasdelprograma.

Simiramoslaaplicacióndeextraccióndeenlacesenlaqueusamoslalibrería BeautifulSoup,podemosverunprogramaquefueconstruidoconectandodistintos objetosparacumplirunatarea:

14.4.COMENZANDOCONPROGRAMAS 187

Program

Output Input

Figure14.1:AProgram

#ParaejecutaresteprogramadescargaBeautifulSoup #https://pypi.python.org/pypi/beautifulsoup4

#Odescargaelarchivo #http://www.py4e.com/code3/bs4.zip #ydescomprimeloenelmismodirectorioqueestearchivo

importurllib.request,urllib.parse,urllib.error frombs4importBeautifulSoup importssl

#IgnorarerroresdecertificadoSSL ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

url = input('Introduzca-') html = urllib.request.urlopen(url,context=ctx).read() sopa = BeautifulSoup(html, 'html.parser')

#Recuperartodaslasetiquetasdeanclaje etiquetas = sopa('a') for etiqueta in etiquetas: print(etiqueta.get('href', None))

#Código:https://es.py4e.com/code3/urllinks.py

ConvertimoslaURLenunacadenayluegopasamosaéstapor urllib para recuperarlosdatosdelaweb.Lalibrería urllib utilizalalibrería socket para llevaracabolaconexiónquerecuperalosdatos.Tomamoslacadenaqueretorna urllib yselaentregamosaBeautifulSoupparasuanálisis.BeautifulSouputiliza elobjeto html.parser1 yretornaunobjeto.Luego,llamamosalmétodo tags() enelobjetoretornado,loqueretornaundiccionariodeetiquetas.Nosdesplazamos porlasetiquetasyllamamoselmétodo get() porcadaetiquetaparaimprimirel atributo href.

Podemoshacerundiagramadeesteprogramaycómolosobjetosfuncionanen conjunto.

1 https://docs.python.org/3/library/html.parser.html

188 CHAPTER14.PROGRAMACIÓNORIENTADAAOBJETOS

String Object

String Object Output Input Dictionary Object BeautifulSoup Object

Urllib Object html.parser Object

Socket Object

Figure14.2:AProgramasNetworkofObjects

Loimportanteahoranoesentenderperfectamentecomofuncionaesteprograma, sinoquevercómoconstruimosunareddeobjetosqueinteractúenentresíyorquestamoselmovimientodeinformaciónentreesosobjetosparacrearunprograma. Tambiénesimportantenotarque,cuandovisteelprogramahacevarioscapítulos, pudisteentenderperfectamentecómofuncionabasinsiquierapercatartedeque estaba“orquestandoelmovimientodedatosentreobjetos”.Eransololíneas de códigoquecumplíanunatarea.

14.5Subdividiendounproblema

Unadelasventajasdelenfoqueorientadoaobjetosesquepuedeocultarlacomplejidaddeunprograma.Porejemplo,aunquenecesitamossabercómousarel códigode urllib yBeautifulSoup,nonecesitamossabercómofuncionaninternamenteesaslibrerías.Estonospermiteenfocarnosenlapartedelproblemaque necesitamosresolvereignorarlasotraspartesdelprograma.

String Object Output Input Dictionary Object String Object

Figure14.3:IgnoringDetailWhenUsinganObject

Estacapacidaddeenfocarnosexclusivamenteenlapartedelprogramaquenos preocupaeignorarelrestotambiénlesirvealosdesarrolladoresdelosobjetos queutilizamos.Porejemplo,losprogramadoresquedesarrollanBeautifulSoup nonecesitansabercómorecuperamosnuestrapáginaHTML,quépartesdeésta queremosleer,oquéqueremoshacerconlosdatosqueobtengamosdelapágina web.

14.5.SUBDIVIDIENDOUNPROBLEMA 189

Figure14.4:IgnoringDetailWhenBuildinganObject

14.6NuestroprimerobjetodePython

Enunnivelelemental,unobjetoessimplementeuntrozodecódigomásestructurasdedatos,máspequeñosqueunprogramacompleto.Definirunafunciónnos permitealmacenaruntrozodecódigo,darleunnombreyluegoinvocarlousando elnombredelafunción.

Unobjetopuedecontenervariasfunciones(alasquellamaremos métodos),así comolosdatosutilizadosporesasfunciones.Llamamos atributos alosdatosque sonpartedelobjeto.

Usamoslapalabraclave class paradefinirlosdatosyelcódigoquecompondrán cadaobjeto.Lapalabraclaveclassincluyeelnombredelaclaseydainicioaun bloquedecódigoindentadoenelqueincluiremossusatributos(datos)ymétodos (código).

class GrupoAnimal: x = 0 def grupo(self): self.x = self.x + 1 print("Hastaahora",self.x) an = GrupoAnimal() an.grupo() an.grupo() an.grupo() GrupoAnimal.grupo(an) #Código:https://es.py4e.com/code3/party2.py

Cadamétodopareceunafunción:comienzanconlapalabraclave def yconsisten enunbloquedecódigoindentado.Esteobjetotieneunatributo(x)yunmétodo (grupo).Losmétodostienenunprimerparámetroespecialalque,porconvención, llamamos self.

Talcomolapalabraclave def nocausaqueelcódigodeunafunciónseejecute,la palabraclave class nocreaunobjeto.Envez,lapalabraclave class defineuna plantillaqueindicaquédatosycódigocontendrácadaobjetodetipo GrupoAnimal.

190 CHAPTER14.PROGRAMACIÓNORIENTADAAOBJETOS
BeautifulSoup Object

Laclaseescomounmoldeparagalletasylosobjetoscreadosusándolasonlas galletas2 .Noseleechaelglaseadoalmoldedelasgalletas;seleechaglaseadoa lasgalletasmismas,conloquesepuedeponerunglaseadodistintoencadagalleta.

Figure14.5:AClassandTwoObjects

Siseguimosconesteprogramadeejemplo,veremoslaprimeralíneaejecutablede código: an = GrupoAnimal()

EsaquíqueleordenamosaPythonconstruir(esdecir,crear)un objeto o instancia delaclase GrupoAnimal.Sevecomosifueraunallamadadefunciónalaclase misma.Pythonconstruyeelobjetoconlosdatosymétodosadecuados,asignándolo luegoalavariable an.Enciertomodo,estoesmuysimilaralasiguientelínea, quehemosestadousandotodoestetiempo: counts = dict()

AquíleordenamosaPythonconstruirunobjetousandolaplantilla dict (que vieneincluidaenPython),devolverlainstanciadeldiccionario,yasignarlaala variable counts.

Cuandoseusalaclase GrupoAnimal paraconstruirunobjeto,lavariable an seusa paraseñalareseobjeto.Usamos an paraaccederalcódigoydatosdeesainstancia específicadelaclase GrupoAnimal

CadaobjetooinstanciadeGrupoAnimalcontieneunavariable x yunmétodo/ funciónllamado grupo.Llamamosalmétodo grupo enestalínea: an.grupo()

Alllamaralmétodo grupo,elprimerparámetro(alqueporconvenciónllamamos self)apuntaalainstanciaespecíficadelobjetoGrupoAnimaldesdeelquese llamaa grupo.Dentrodelmétodo grupo,vemoslasiguientelínea:

2 CookieimagecopyrightCC-BYhttps://www.flickr.com/photos/dinnerseries/23570475099

14.6.NUESTROPRIMEROBJETODEPYTHON 191

self.x = self.x + 1

Estasintaxisutilizaeloperadorde punto,conloquesignifica‘laxdentrodeself’. Cadavezquesellamaa grupo(),elvalorinternode x seincrementaen1yse imprimesuvalor.

Lasiguientelíneamuestraotramaneradellamaralmétodo grupo dentrodel objeto an:

GrupoAnimal.grupo(an)

Enestavariante,accedemosalcódigodesdeelinteriordelaclaseyexplícitamente pasamoselapuntadordelobjeto an comoelprimerparámetro(esdecir, self dentrodelmétodo).Sepuedepensaren an.grupo() comounaabreviacióndela líneaprecedente.

Alejecutarelprograma,produceelsiguienteresultado:

Sofar1 Sofar2 Sofar3 Sofar4

Elobjetoesconstruido,yelmétodo grupo esllamadocuatroveces,incrementando eimprimiendoelvalorde x dentrodelobjeto an.

14.7Clasescomotipos

Comohemosvisto,enPythontodaslasvariablestienenuntipo.Podemosusarla función dir incluidaenPythonparaexaminarlascaracterísticasdeunavariable. Tambiénpodemosusar type y dir conlasclasesquecreemos.

class GrupoAnimal: x = 0

def grupo(self): self.x = self.x + 1 print("Hastaahora",self.x)

an = GrupoAnimal() print("Type",type(an)) print("Dir",dir(an)) print("Type",type(an.x)) print("Type",type(an.grupo))

#Código:https://es.py4e.com/code3/party3.py

Alejecutaresteprograma,produceelsiguienteresultado:

192 CHAPTER14.PROGRAMACIÓNORIENTADAAOBJETOS

Type<class'__main__.GrupoAnimal'>

Dir['__class__','__delattr__',... '__sizeof__','__str__','__subclasshook__', '__weakref__','grupo','x']

Type<class'int'> Type<class'method'>

Puedesverque,usandolapalabraclave class,hemoscreadounnuevotipo.En elresultadodeusar dir,puedesverquetantoelatributodetipoentero x comoel método grupo estándisponiblesdentrodelobjeto.

14.8Ciclodevidadeunobjeto

Enlosejemplosanteriores,definimosunaclase(plantilla),lausamosparacrearuna instanciadeella(objeto)yluegousamosesainstancia.Alfinalizarelprograma, todaslasvariablessondescartadas.Normalmente,nonospreocupamosmuchode lacreaciónydestruccióndevariables,peroamenudo,cuandonuestrosobjetosse vuelvenmáscomplejos,resultanecesarioefectuaralgunospasosdentrodelobjeto paraconfigurarlaconstruccióndeéstey,posiblemente,ordenarcuandoelobjeto esdescartado.

Siqueremosquenuestroobjetoseaconscientedeesosmomentosdecreacióny destrucción,debemosagregarlemétodosespecialmentenombradosalefecto:

class GrupoAnimal: x = 0

def __init__(self): print('Estoyconstruido')

def grupo(self): self.x = self.x + 1 print('Hastaahora',self.x)

def __del__(self): print('Estoydestruido', self.x) an = GrupoAnimal() an.grupo() an.grupo() an = 42 print('ancontiene',an)

#Código:https://es.py4e.com/code3/party4.py

Alejecutaresteprograma,produceelsiguienteresultado:

Estoyconstruido Hastaahora1

14.8.CICLODEVIDADEUNOBJETO 193

Hastaahora2 Estoydestruido2 ancontiene42

CuandoPythonconstruyeelobjeto,llamaanuestrométodo __init__ paradarnos laoportunidaddeconfiguraralgunosvalorespordefectooinicialesparaéste. CuandoPythonencuentralalínea: an=42

efectivamente“tiraalabasura”elobjetoparareutilizarlavariable an,almacenandoelvalor 42.Justoenelmomentoenquenuestroobjeto an estásiendo “destruido”sellamaanuestrocódigodestructor(__del__).Nopodemosevitar quenuestravariableseadestruida,peropodemosefectuarlaconfiguraciónque resultenecesariaantesdequeelobjetodejedeexistir.

Aldesarrollarobjetos,esbastantecomúnagregarlesunconstructorquefijesus valoresiniciales.Esrelativamenteraronecesitarundestructorparaunobjeto.

14.9Múltiplesinstancias

Hastaahorahemosdefinidounaclase,construidounsoloobjeto,usadoeseobjeto,y luegodescartadoelobjeto.Sinembargo,elauténticopotencialdelaprogramación orientadaaobjetossemanifiestaalconstruirmúltiplesinstanciasdenuestraclase. Alconstruirmúltiplesinstanciasdenuestraclase,puedequequeramosfijardistintosvaloresinicialesparacadaobjeto.Podemospasardatosalosconstructores paradaracadaobjetoundistintovalorinicial:

class GrupoAnimal: x = 0 nombre = '' def __init__(self,nom): self.nombre = nom print(self.nombre,'construido')

def grupo(self): self.x = self.x + 1 print(self.nombre,'recuentogrupal',self.x)

s = GrupoAnimal('Sally') j = GrupoAnimal('Jim')

s.grupo() j.grupo() s.grupo()

#Código:https://es.py4e.com/code3/party5.py

194 CHAPTER14.PROGRAMACIÓNORIENTADAAOBJETOS

Elconstructortienetantounparámetro self,queapuntaalainstanciadelobjeto, comoparámetrosadicionales,quesepasanalconstructoralmomentodeconstruir elobjeto: s=GrupoAnimal('Sally')

Dentrodelconstructor,lasegundalíneacopiaelparámetro(nom),elquesepasa alatributo nombre dentrodelobjeto. self.nombre=nom

Elresultadodelprogramamuestraquecadaobjeto(s y j)contienensuspropias copiasindependientesde x y nom:

Sallyconstruido

Jimconstruido Sallyrecuentogrupal1 Jimrecuentogrupal1 Sallyrecuentogrupal2 14.10Herencia

Otrapoderosacaracterísticadelaprogramaciónorientadaaobjetoseslacapacidad decrearunanuevaclaseextendiendounaclaseyaexistente.Alextenderunaclase, llamamosalaclaseoriginalla clasepadre yalanuevaclase clasehija.

Porejemplo,podemosmoveranuestraclase GrupoAnimal asupropioarchivo. Luego,podemos‘importar’laclase GrupoAnimal enunnuevoarchivoyextenderla, delasiguientemanera:

frompartyimportGrupoAnimal class GrilloFan(GrupoAnimal): puntos = 0 def seis(self): self.puntos = self.puntos + 6 self.grupo() print(self.nombre,"puntos",self.puntos) s = GrupoAnimal("Sally") s.grupo() j = GrilloFan("Jim") j.grupo() j.seis() print(dir(j))

#Código:https://es.py4e.com/code3/party6.py

14.10.HERENCIA 195

Cuandodefinimoslaclase GrilloFan,indicamosqueestamosextendiendolaclase GrupoAnimal.Estosignificaquetodaslasvariables(x)ymétodos(grupo)dela clase GrupoAnimal son heredados porlaclase GrilloFan.Porejemplo,dentro delmétodo six enlaclase GrilloFan,llamamosalmétodo grupo delaclase GrupoAnimal

Alejecutarelprograma,creamos s y j comoinstanciasindependientesde GrupoAnimal y GrilloFan.Elobjeto j tienecaracterísticasadicionalesquevan másalládeaquellasquetieneelobjeto s.

Sallyconstruido

Sallyrecuentogrupal1 Jimconstruido Jimrecuentogrupal1 Jimrecuentogrupal2 Jimpuntos6 ['__class__','__delattr__',...'__weakref__', 'nombre','grupo','puntos','seis','x']

Enelresultadodellamara dir sobreelobjeto j (instanciadelaclase GrilloFan), vemosquetienelosatributosymétodosdelaclasepadre,ademásdelosatributosy métodosquefueronagregadoscuandolaextendimosparacrearlaclase GrilloFan

14.11Resumen

Estaesunaintroducciónmuysuperficialalaprogramaciónorientadaaobjetos, enfocadaprincipalmenteenlaterminologíaysintaxisnecesariasparadefiniryusar objetos.Vamosareseñarrápidamenteelcódigoquevimosalcomienzodelcapítulo. Aestasalturasdeberíasentendercompletamenteloqueestápasando.

cosa = list() cosa.append('python') cosa.append('chuck') cosa.sort() print(cosa[0]) print(cosa.__getitem__(0)) print(list.__getitem__(cosa,0))

#Código:https://es.py4e.com/code3/party1.py

Laprimeralíneaconstruyeun objeto declase list.CuandoPythoncreaelobjeto declase list llamaalmétodo constructor (llamado __init__)paraconfigurarlos atributosinternosdedatosqueseutilizaránparaalmacenarlosdatosdelalista. Aúnnohemospasadoningúnparámetroal constructor.Whenelconstructor retorna,usamoslavariable cosa paraapuntarlainstanciaretornadadelaclase list.

Lasegundayterceralíneasllamanalmétodo append conunparámetropara agregarunnuevoobjetoalfinaldelalistaactualizandolosatributosalinterior

196 CHAPTER14.PROGRAMACIÓNORIENTADAAOBJETOS

de cosa.Luego,enlacuartalínea,llamamosalmétodo sort sindarleningún parámetroparaordenarlosdatosdentrodelobjeto cosa

Luego,imprimimoselprimerobjetoenlalistausandoloscorchetes,losqueson unaabreviaturaparallamarelmétodo __getitem__ dentrode cosa.Estoes equivalenteallamadoalmétodo __getitem__ dentrodela clase list ypasarel objeto cosa comoprimerparámetroylaposiciónquenecesitamoscomosegundo parámetro.

Alfinaldelprograma,elobjeto cosa esdescartado,peronoantesdellamaral método destructor (llamado __del__)demaneratalqueelobjetopuedaatar cabossueltosencasoderesultarnecesario.

Estossonlosaspectosbásicosdelaprogramaciónorientadaaobjetos.Haymuchosdetallesadicionalessobrecómousarunenfoquedeprogramaciónorientada aobjetosaldesarrollaraplicaciones,asícomolibrerías,lasquevanmás alládel ámbitodeestecapítulo.3

14.12Glosario

atributo Unavariablequeespartedeunaclase. clase Unaplantillaquepuedeusarseparaconstruirunobjeto.Definelosatributos ymétodosqueformaránadichoobjeto. clasehija Unanuevaclasecreadacuandounaclasepadreesextendida.Laclase hijaheredatodoslosatributosymétodosdelaclasepadre. clasepadre Laclasequeestásiendoextendidaparacrearunanuevaclasehija. Laclasepadreaportatodossusmétodosyatributosalanuevaclasehija.

constructor Unmétodoopcionalconunnombreespecial(__init__)queesllamadoalmomentoenqueseutilizaunaclaseparaconstruirunobjeto.Normalmenteseutilizaparadeterminarlosvaloresinicialesdelobjeto.

destructor Unmétodoopcionalconunnombreespecial(__del__)queesllamado justounmomentoantesdequeunobjetoseadestruido.Losdestructores raravezsonutilizados.

herencia Cuandocreamosunanuevaclase(hija)extendiendounaclaseexistente (padre).Laclasehijatienetodoslosatributosymétodosdelaclasepadre, máslosatributosymétodosadicionalesdefinidosporlaclasehija.

método Unafuncióncontenidadentrodeunaclaseydelosobjetosconstruidos desdeesaclase.Algunospatronesdediseñoorientadosaobjetosdescriben esteconceptocomo‘mensaje’enlugarde‘método’.

objeto Unainstanciaconstruidadeunaclase.Unobjetocontienetodoslosatributosymétodosdefinidosporlaclase.Enalgunoscasosdedocumentación orientadaaobjetosseutilizaeltérmino‘instancia’demaneraintercambiable con‘objeto’.

3 Siquieressaberdondeseencuentradefinidalaclase list,echaunvistazoa(ojalálaURL nocambie)https://github.com/python/cpython/blob/master/Objects/listobject.c-laclaselist estáescritaenunlenguajellamado“C”.Siveselcódigofuenteysientescuriosidad,quizáte convengabuscaralgunoscursossobreCienciasdelaComputación.

14.12.GLOSARIO 197
198 CHAPTER14.PROGRAMACIÓNORIENTADAAOBJETOS

BasesdedatosySQL

15.1¿Quéesunabasededatos?

Una basededatos esunarchivoqueestáorganizadoparaalmacenardatos.La mayoríadelasbasesdedatosestánorganizadascomodiccionarios,enelsentidode querealizanasociacionesentreclavesyvalores.Ladiferenciamásimportantees quelabasededatosseencuentraeneldisco(uotroalmacenamientopermanente), demodoquesucontenidoseconservadespuésdequeelprogramafinaliza.Gracias aquelabasededatosseguardaenalmacenamientopermanente,puedealmacenar muchosmásdatosqueundiccionario,queestálimitadoaltamañodememoria quetengalacomputadora.

Comoundiccionario,elsoftwaredeunabasededatosestádiseñadoparaconseguir quelainserciónyaccesoalosdatosseanmuyrápidos,inclusoparagrandescantidadesdedatos.Estesoftwaremantienesurendimientomediantelaconstrucción deíndices,comodatosañadidosalabasededatosquepermitenalequiposaltar rápidamentehastaunaentradaconcreta.

Existenmuchossistemasdebasesdedatosdiferentes,queseutilizanparauna ampliavariedaddepropósitos.Algunosdeellosson:Oracle,MySQL,Microsoft SQLServer,PostgreSQL,ySQLite.EnestelibronosenfocaremosenSQLite, yaquesetratadeunabasededatosmuycomúnyyavieneintegradadentrode Python.SQLiteestádiseñadaparaser incrustada dentrodeotrasaplicaciones,de modoqueproporcionesoporteparabasesdedatosdentrodelaaplicación.Por ejemplo,elnavegadorFirefoxesunodelosqueutilizanlabasededatosSQLite internamente,aligualquemuchosotrosproductos.

http://sqlite.org/

SQLiteesmuyadecuadoparaciertosproblemasdemanipulacióndedatosque nosencontramoseninformática,comoenlaaplicaciónderastreodeTwitterque hemosdescritoenelcapítuloanterior.

Chapter15
199

15.2Conceptossobrebasesdedatos

Cuandoseveporprimeravezunabasededatos,separeceaunahojadecálculo conmúltipleshojas.Lasestructurasdedatosprimariasenunabasededatosson: tablas, files,and columnas 2.3

Table row

Enlasdescripcionestécnicasdelasbasesdedatosrelacionales,losconceptosde tabla,filaycolumnarecibenlosnombresmásformalesde relación, tupla,y atributo,respectivamente.Nosotrosutilizaremoslostérminosmenosformaleseneste capítulo.

15.3NavegadordebasesdedatosparaSQLite

ApesardequeenestecapítulonosenfocaremosenutilizarPythonparatrabajar condatosenarchivosdebasesdedatosSQLite,muchasoperacionespuedenser hechasdeformamáseficazusandounprogramadesoftwarellamado Database BrowserforSQLite,quesepuededescargargratisdesde:

http://sqlitebrowser.org/

Utilizandoelnavegadorsepuedencreartablas,insertardatos,editardatos,o ejecutarconsultasSQLsencillassobrelabasededatos.

Enciertomodo,elnavegadordebasededatosesparecidoauneditordetexto quetrabajaconarchivosdetexto.Cuandoquieresrealizarunoodoscambiosen unarchivodetexto,lomássencilloesabrirloenuneditordetextoyrealizarlos cambiosquequieres.Cuandodebesrealizarmuchasmodificacionesenelarchivo, amenudohabráqueescribirunprogramaenPythonsencillo.Elmismoenfoque sepuedeaplicaraltrabajoconbasesdedatos.Serealizaránlasoperacionesmás sencillasenelgestordebasesdedatos,yparaotrasmáscomplejasserámás convenienteusarPython.

200 CHAPTER15.BASESDEDATOSYSQL
column 2.3 Relation tuple attribute Figure15.1:Basesdedatosrelacionales

15.4Creacióndeunatablaenunabasededatos

LasbasesdedatosnecesitanunaestructuramásdefinidaquelaslistasodiccionariosdePython1

Cuandocreamosuna tabla,debemosindicardeantemanoalabasededatoslos nombresdecadaunadelas columnas deesatablayeltipodedatoquesevaa almacenarencadaunadeellas.Cuandoelsoftwaredelabasededatosconoceel tipodedatodecadacolumna,puedeelegirelmodomáseficientedealmacenary buscarenellas,basándoseeneltipodedatoquecontendrán.

PuedesrevisarlosdistintostiposdedatossoportadosporSQLiteenlasiguiente dirección: http://www.sqlite.org/datatypes.html

Eltenerquedefinirdeantemanounaestructuraparalosdatospuedeparecer incómodoalprincipio,perolarecompensaconsisteenobtenerunaccesorápidoa losdatos,inclusocuandolabasededatoscontieneunagrancantidaddeellos. Elcódigoparacrearunarchivodebasededatosyunatablallamada Canciones condoscolumnasenlabasededatoseselsiguiente:

importsqlite3 conn = sqlite3.connect('musica.sqlite') cur = conn.cursor()

cur.execute('DROPTABLEIFEXISTSCanciones') cur.execute('CREATETABLECanciones(tituloTEXT,reproduccionesINTEGER)') conn.close() #Código:https://es.py4e.com/code3/db1.py

Laoperación connect realizaunaconexiónconlabasededatosalmacenadaenel archivo musica.sqlite eneldirectorioactual.Sielarchivonoexiste,secreará unonuevo.Larazóndequeselellameuna“conexión”esqueaveceslabase dedatossealmacenaenun“servidordebasesdedatos”,distintodelservidoren elcualestáfuncionandonuestraaplicación.Ennuestrosejemplos,dadoqueson sencillos,labasededatosserásimplementeunarchivolocalenelmismodirectorio enelqueestáfuncionandoelcódigodePython.

Un cursor escomounmanejadordearchivos,ysepuedeusarpararealizaroperacionesenlosdatosalmacenadosenlabasededatos.Lallamadaa cursor() esmuysimilarconceptualmentealallamada open() cuandoseestátratandocon archivosdetexto.

Unavezquetenemoselcursor,podemoscomenzaraejecutarcomandossobreel contenidodelabasededatos,usandoelmétodo execute()

1 SQLiteenrealidadpermiteciertaflexibilidadrespectoaltipodedatoquesealmacenaen cadacolumna,peroenestecapítulonosotrosvamosamantenerlostiposdedatosestrictos,para quelosconceptosqueaprendamospuedanserigualmenteaplicadosaotrasbasesdedatoscomo MySQL.

15.4.CREACIÓNDEUNATABLAENUNABASEDEDATOS 201

execute fetchone fetchall close

Your Program

C U R S O R

Users Members

Courses

Figure15.2:Uncursordebasesdedatos

Loscomandosdelasbasesdedatosseexpresanenunlenguajeespecialqueha sidoestandarizadoentrevariosproveedoresdebasesdedatosdiferentesparapermitirnosaprenderunúnicolenguajeparatodasellas.Estelenguajerecibeelnombre de LenguajedeConsultasEstructurado (StructuredQueryLanguage),o SQL.

https://es.wikipedia.org/wiki/SQL

Ennuestroejemplo,estamosejecutandodoscomandosSQLsobrelabasededatos. Porconvención,mostraremoslaspalabrasclavesdeSQLenmayúsculaylaspartes deloscomandosqueañadamosnosotros(comolosnombresdelastablasylas columnas)iránenminúsculas.

ElprimercomandoSQLeliminalatabla Canciones siyaexiste.Este planteamientoseutilizasimplementeparapermitirnosejecutarelmismoprogramaparacrearlatabla Canciones unayotravezsinprovocarunerror. Observaqueelcomando DROPTABLE eliminalatablaytodosucontenidodela basededatos(esdecir,aquínoexistelaopción“deshacer”).

cur.execute('DROPTABLEIFEXISTSCanciones')

Elsegundocomandocreaunatablallamada Canciones conunacolumnadetexto llamada titulo yunacolumnadeenterosllamada reproducciones

cur.execute('CREATETABLECanciones(tituloTEXT,reproduccionesINTEGER)')

Ahoraqueyahemoscreadolatablallamada Canciones,podemosguardaralgunos datosenellausandolaoperacióndeSQL INSERT.Empezaremosrealizandootra vezunaconexiónconlabasededatosyobteniendoel cursor.Luegopodemos ejecutarcomandosSQLusandoesecursor.

Elcomando INSERT deSQLindicaquétablaseestáutilizandoyluegodefineunafilanueva,enumerandoloscamposquesedeseanincluir (titulo, reproducciones) seguidosporlosvalores(VALUES)quequeremoscolocarenesa fila.Nosotrosvamosaespecificarlosvalorescomosignosdeinterrogación (?,?) paraindicarlequelosvaloresrealesseránpasadoscomounatupla ('MyWay', 15) enelsegundoparámetrodelallamadaa execute().

202 CHAPTER15.BASESDEDATOSYSQL

importsqlite3

conn = sqlite3.connect('musica.sqlite') cur = conn.cursor()

cur.execute('INSERTINTOCanciones(titulo,reproducciones)VALUES(?,?)', ('Thunderstruck', 20)) cur.execute('INSERTINTOCanciones(titulo,reproducciones)VALUES(?,?)', ('MyWay', 15)) conn.commit()

print('Canciones:')

cur.execute('SELECTtitulo,reproduccionesFROMCanciones') for fila in cur: print(fila)

cur.execute('DELETEFROMCancionesWHEREreproducciones<100') conn.commit() cur.close() #Código:https://es.py4e.com/code3/db2.py

Primeroinsertamos(INSERT)dosfilasenlatablayusamos commit() paraforzar aquelosdatosseanescritosenelarchivodelabasededatos.

Tracks

title plays My Way Thunderstruck 15 20

Figure15.3:Columnasenunatabla

Despuésusamoselcomando SELECT pararecuperarlasfilasqueacabamosdeinsertarenlatabla.Enelcomando SELECT,indicamosquécolumnasnosgustaría obtener (titulo,reproducciones),ytambiéndesdequétablaqueremosrecuperarlosdatos.Despuésdeejecutarlasentencia SELECT,elcursorseconvierte enalgoconloquepodemositerarmedianteunasentencia for.Poreficiencia,el cursornoleetodoslosdatosdelabasededatoscuandoseejecutalasentencia SELECT.Enlugardeello,losdatosvansiendoleídosamedidaquesevanpidiendo lasfilasdesdeelbuclecreadoconlasentencia for

Lasalidadelprogramaeslasiguiente:

Canciones: ('Thunderstruck',20) ('MyWay',15)

15.4.CREACIÓNDEUNATABLAENUNABASEDEDATOS 203

Nuestrobucle for encuentradosfilas,ycadafilaesunatupladePythoncuyo primervaloresel titulo yelsegundoeselnúmerode reproducciones

Nota:Puedequeveascadenascomenzandocon u' enotroslibrosoenInternet. EstoesunaindicaciónenPython2quedicequelascadenasson cadenas Unicode quesoncapacesdealmacenarcaracteresno-latinos.EnPython3,todaslascadenas sondeltipo Unicode pordefecto.

Alfinaldelprograma,ejecutamosuncomandoSQLparaborrar(DELETE)lasfiles queacabamosdecrear,demodoquepodamosejecutarelprogramaunayotravez. Elcomando DELETE nosmuestraelusodelacláusula WHERE,lacualnospermite expresaruncriteriodeselección,demodoquepodemospediralabasededatos queapliqueelcomandosolamentealasfilasquecumplanesecriterio.Eneste ejemplo,elcriterioescumplidoportodaslasfilas,asíquevaciamoslatablapara quepodamosejecutarelprogramadenuevorepetidamente.Despuésdequeseha realizadoel DELETE,llamamosdenuevoa commit() paraforzaralosdatosaser eliminadosdelabasededatos.

15.5ResumendeLenguajedeConsultasEstructurado

Hastaahora,hemosestadousandoelLenguajedeConsultasEstructurado(SQL) ennuestrosejemplosdePythonyhemosutilizadomuchosdeloscomandosbásicos deSQL.Enestasección,noscentraremosenellenguajeSQLenparticulary echaremosunvistazoasusintaxis.

Debidoaquehaymuchosproveedoresdebasesdedatos,elLenguajedeConsultas Estructurado(SQL)estáestandarizado,paraquepodamoscomunicarnosdeuna formasimilarconsistemasdebasesdedatosdemúltiplesvendedores.

Unabasededatosrelacionalestácompuestaportablas,filas,ycolumnas.Las columnastienengeneralmenteuntipodedatosquepuedesertexto,números,o datosdefechas.Cuandosecreaunatabla,seindicanlosnombresytiposdecada columna:

CREATETABLE Canciones(tituloTEXT,reproducciones INTEGER)

Parainsertarunafilaenunatabla,usamoselcomandodeSQL INSERT:

INSERTINTO Canciones(titulo,reproducciones) VALUES ('MyWay', 15)

Lasentencia INSERT especifícaelnombredelatabla,seguidoporunalistade loscampos/columnasquesequierenestablecerenlafilanueva,acontinuaciónla palabraclave VALUES,yunalistadelosvalorescorrespondientesparacadaunode loscampos.

ElcomandodeSQL SELECTseutilizapararecuperarfilasycolumnasdesdeuna basededatos.Lasentencia SELECT permiteespecificarquécolumnassequieren recibir,juntoconunaclausula WHERE paraindicarquéfilassedeseanobtener. Tambiénpermiteunaclausulaopcional, ORDERBY paracontrolarelordendelas filesdevueltas.

204 CHAPTER15.BASESDEDATOSYSQL

SELECT * FROM Canciones WHERE titulo= 'MyWay'

Elusode * indicaquesedeseaquelabasededatosdevuelvatodaslascolumnas paracadalíneaquecumplalacondicióndelaclausula WHERE. Hayquenotarque,adiferenciadeloqueocurreenPython,enSQLlaclausula WHERE utilizaunúnicosignoigualparaindicarunacomprobacióndeigualdad,en lugardeutilizarunsignodobleigual.Otrasoperacioneslógicasquesepermiten enunaclausula WHERE son <, >, <=, >=, !=,asícomotambién AND y OR,yparéntesis paraconstruirexpresioneslógicas.

Sepuedesolicitarquelascolumnasdevueltasvenganordenadasporunodelos campos,deestemodo:

SELECT titulo,reproducciones FROM Canciones ORDERBY titulo

Paraeliminarunafila,esnecesariousarunaclausula WHERE enunasentencia DELETE deSQL.Laclausula WHERE determinaquéfilasseráneliminadas:

DELETEFROM Canciones WHERE titulo= 'MyWay'

Esposibleactualizar(UPDATE)unacolumnaovariasdeunaomásfilasenuna tablausandolasecuenciadeSQL UPDATE,comosemuestraacontinuación:

UPDATE Canciones SET reproducciones= 16 WHERE titulo= 'MyWay'

Lasentencia UPDATE especifícaunatabla,acontinuaciónunalistadecamposy valoresacambiardetrásdelapalabraclave SET,yfinalmenteunaclausulaopcional WHERE paraelegirlasfilasquevanaseractualizadas.Unaúnicasentencia UPDATE cambiarátodaslasfilasquecoincidanconlaclausula WHERE.Sinosehaespecificado ningunaclausula WHERE,serealizarálaactualización(UPDATE)detodaslasfilasde latabla.

ExistencuatrocomandosbásicosdeSQL(INSERT,SELECT,UPDATE,y DELETE),quenospermitenrealizarlascuatrooperacionesbásicasnecesarias paracrearymantenerdatos.

Enestasección,crearemosunprogramaarañasencilloquesemoveráatravésde cuentasdeTwitteryconstruiráunabasededatosdeellas. Nota:Tenmucho cuidadocuandoalejecutaresteprograma.Siextraesdemasiadosdatosoejecutas elprogramadurantedemasiadotiempopuedenterminarcortándoteelaccesoa Twitter.

Unodelosproblemasdecualquiertipodeprogramaarañaesquesenecesita poderlodeeneryvolveraponerenmarchamuchasveces,ynosequierenperderlos datosquesehayanrecuperadohastaesemomento.Noquerrástenerqueempezar siemprelarecuperacióndedatosdesdeelprincipio,demodoquenecesitaremos

15.6.RASTREOENTWITTERUSANDOUNABASEDEDATOS 205
15.6RastreoenTwitterusandounabasededatos

almacenarlosdatossegúnlosvamosrecuperandoparaquenuestroprogramapueda usaresacopiadeseguridadyreanudarlarecoleccióndedatosdesdedondelodejó laúltimavez.

VamosacomenzarporrecuperarlosamigosdeTwitterdeunapersonaysusestados,moviéndonosatravésdelalistadeamigosyañadiendocadaunodeellosala basededatosparapoderrecuperarlosenelfuturo.Despuésdehaberprocesado todoslosamigosdeesapersona,consultaremoslabasededatosyrecuperaremos losamigosdeunodeesosamigos.Continuaremoshaciendoestounayotravez, recogiendocualquierpersona“novisitada”,recuperandosulistadeamigosyañadiendoaquellosquenotengamosyaennuestralistaparaunapróximavisita.

Tambiénvamosacontarcuántasveceshemosvistounamigoconcretoenlabase dedatos,paratenerunaideadesu“popularidad”.

Estamosalmacenandonuestralistadecuentasdeconocidos,sihemosrecuperado lacuentaono,ylapopularidaddecadacuenta.Altenertodoelloguardadoen unabasededatosennuestroPC,podremosdeteneryreanudarelprogramatantas vecescomoqueramos.

Esteprogramaesunpococomplejo.Estábasadoenelcódigodeunejercicio anteriordellibroqueusalaAPIdeTwitter.

AquíestáelcódigofuenteparanuestraaplicaciónarañadeTwitter:

fromurllib.requestimporturlopen importurllib.error importtwurl importjson importsqlite3 importssl

TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json' conn = sqlite3.connect('arana.sqlite') cur = conn.cursor() cur.execute(''' CREATETABLEIFNOTEXISTSTwitter (nombreTEXT,recuperadoINTEGER,amigosINTEGER)''')

#IgnorarerroresdecertificadoSSL ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

while True: cuenta = input('IngresaunacuentadeTwitter,osalir:') if (cuenta == 'salir'): break if (len(cuenta) < 1): cur.execute('''SELECTnombreFROMTwitter WHERErecuperado=0LIMIT1''') try:

206 CHAPTER15.BASESDEDATOSYSQL

cuenta = cur.fetchone()[0] except: print('NosehanencontradocuentasdeTwitterporrecuperar') continue

url = twurl.aumentar(TWITTER_URL,{'screen_name':cuenta, 'count': '5'}) print('Recuperando',url) conexion = urlopen(url,context=ctx) datos = conexion.read().decode() cabeceras = dict(conexion.getheaders())

print('Restante',cabeceras['x-rate-limit-remaining']) js = json.loads(datos) #Depuración #printjson.dumps(js,indent=4)

cur.execute('''UPDATETwitter

SETrecuperado=1WHEREnombre=?''',(cuenta,)) contnuevas = 0 contantiguas = 0 for u in js['users']: amigo = u['screen_name'] print(amigo)

cur.execute('SELECTamigosFROMTwitterWHEREnombre=?LIMIT1', (amigo,)) try: contador = cur.fetchone()[0] cur.execute('UPDATETwitterSETamigos=?WHEREnombre=?', (contador+1,amigo)) contantiguas = contantiguas + 1 except: cur.execute('''INSERTINTOTwitter(nombre,recuperado,amigos) VALUES(?,0,1)''',(amigo,)) contnuevas = contnuevas + 1 print('Cuentasnuevas=',contnuevas, 'yavisitadas=',contantiguas) conn.commit()

cur.close()

#Código:https://es.py4e.com/code3/twspider.py

Nuestrabasededatosestáalmacenadaenelarchivo arana.sqlite ytieneuna tablallamada Twitter.Cadafilaenlatabla Twitter contieneunacolumnapara elnombredelacuenta,otraparaindicarsihemosrecuperadolosamigosdeesa cuenta,yotraparaguardarcuántasvecessehavistoesacuentaañadidaenlalista deamigosdelasdemás.

Enelbucleprincipaldelprograma,pedimosalusuarioelnombredeunacuentade Twittero“salir”parafinalizarelprograma.Sielusuariointroduceunacuentade Twitter,recuperamoslalistadeamigosdeeseusuarioysusestados,yañadimos

15.6.RASTREOENTWITTERUSANDOUNABASEDEDATOS 207

cadaamigoalabasededatos,sinoestabayaenella.Sielamigoyaestabaenla lista,aumentamosen1elcampo amigos enlafilacorrespondientedelabasede datos.

Sielusuariopresionaintro,buscamosenlabasededatoslasiguientecuentade Twitterquenohayasidoaúnrecuperada,recuperamoslosamigosdeesacuenta ysusestados,yluegolosañadimosalabasededatosolosactualizamos,eincrementamossucontadorde amigos.

Unavezhemosrecuperadolalistadeamigosysusestados,nosmovemosatravés deloselementos user delJSONdevueltoyrecuperamosel screen_name (nombre amostrar)decadausuario.Luegousamoslasentencia SELECT paracomprobar siyatenemosalmacenadoesenombreconcretoenlabasededatosysiesasí recuperamossucontadordeamigos(amigos).

contnuevas = 0 contantiguas = 0 for u in js['users']: amigo = u['screen_name'] print(amigo)

cur.execute('SELECTamigosFROMTwitterWHEREnombre=?LIMIT1', (amigo,)) try: contador = cur.fetchone()[0] cur.execute('UPDATETwitterSETamigos=?WHEREnombre=?', (contador+1,amigo)) contantiguas = contantiguas + 1 except: cur.execute('''INSERTINTOTwitter(nombre,recuperado,amigos) VALUES(?,0,1)''',(amigo,)) contnuevas = contnuevas + 1 print('Cuentasnuevas=',contnuevas, 'yavisitadas=',contantiguas) conn.commit()

Unavezqueelcursorejecutalasentencia SELECT,tenemosquerecuperarlasfilas. Podríamoshacerloconunasentencia for,perodadoquesóloestamosrecuperando unaúnicafila(LIMIT1),podemostambiénusarelmétodo fetchone() paraextraerlaprimera(yúnica)filaquedacomoresultadolaoperación SELECT.Dado que fetchone() devuelvelafilacomouna tupla (inclusosisólocontieneuncampo), tomamoselprimervalordelatuplamediante[0],paraalmacenarasídentrodela variable contador elvalordelcontadordeamigosactual.

Siestaoperacióntieneéxito,usamoslasentencia UPDATE deSQLconunaclausula WHERE paraañadir1alacoluma amigos deaquellafilaquecoincidaconlacuenta delamigo.Fíjatequehaydosmarcadoresdeposición(esdecir,signosdeinterrogación)enelSQL,yqueelsegundoparámetrode execute() esunatupladedos elementosquecontienelosvaloresqueseránsustituidosporesasinterrogaciones dentrodelasentenciaSQL.

Sielcódigoenelbloque try falla,sedeberáprobablementeaqueningúnregistro coincideconloespecificadoenlaclausula WHEREnombre=? delasetenciaSELECT.Asíqueenelbloque except,usamoslasentenciadeSQL INSERT para

208 CHAPTER15.BASESDEDATOSYSQL

añadirelnombreamostrar(screen_name)delamigoalatabla,juntoconuna indicacióndequenolohemosrecuperadoaún,yfijamossucontadordeamigosa cero.

LaprimeravezqueelprogramafuncionaeintroducimosunacuentadeTwitter, mostraráalgosimilaraesto:

IngresaunacuentadeTwitter,osalir:drchuck Recuperandohttp://api.twitter.com/1.1/friends... Cuentasnuevas=20yavisitadas=0 IngresaunacuentadeTwitter,osalir:salir

Dadoqueeslaprimeravezqueejecutamoselprograma,labasededatosestávacía, asíquecreamoselarchivo arana.sqlite yañadimosunatablallamada Twitter alabasededatos.Acontinuaciónrecuperamosalgunosamigosylosañadimosa labasededatos,yaqueéstaestávacía.

Enestepunto,talvezseaconvenienteescribirunprogramadevolcadodedatos sencillo,paraecharunvistazoaloquehaydentrodelarchivo spider.sqlite: importsqlite3 conn = sqlite3.connect('arana.sqlite') cur = conn.cursor() cur.execute('SELECT*FROMTwitter') contador = 0 for fila in cur: print(fila) contador = contador + 1 print(contador, 'filas.') cur.close()

#Código:https://es.py4e.com/code3/twdump.py

Esteprogramasimplementeabrelabasededatosyseleccionatodaslascolumnas detodaslasfilasdelatabla Twitter,luegosemueveatravésdelasfilaseimprime enpantallasucontenido.

Siejecutamosesteprogramadespuésdelaprimeraejecucióndenuestraarañade Twitter,lasalidaquemostraráserásimilaraesta:

('opencontent',0,1)

('lhawthorn',0,1)

('steve_coppin',0,1) ('davidkocher',0,1) ('hrheingold',0,1)

20filas.

Vemosunafilaparacadanombre,queaúnnohemosrecuperadolosdatosde ningunodeesosnombres,yquetodoelmundoenlabasededatostieneunamigo.

15.6.RASTREOENTWITTERUSANDOUNABASEDEDATOS 209

Enestemomentolabasededatosmuestralarecuperacióndelosamigosdenuestra primeracuentadeTwitter(drchuck).Podemosejecutardenuevoelprogramay pedirlequerecuperelosamigosdelasiguientecuenta“sinprocesar”,simplemente pulsandointroenvezdeescribirelnombredeunacuenta:

IngresaunacuentadeTwitter,osalir: Recuperandohttp://api.twitter.com/1.1/friends...

Cuentasnuevas=18yavisitadas=2 IngresaunacuentadeTwitter,osalir: Recuperandohttp://api.twitter.com/1.1/friends... Cuentasnuevas=17yavisitadas=3 IngresaunacuentadeTwitter,osalir:salir

Comohemospulsadointro(esdecir,nohemosespecificadootracuentadeTwitter), sehaejecutadoelcódigosiguiente:

if (len(cuenta) < 1 ): cur.execute('SELECTnombreFROMTwitterWHERErecuperado=0LIMIT1') try: cuenta = cur.fetchone()[0] except: print('NosehanencontradocuentasdeTwitterporrecuperar') continue

UsamoslasentenciadeSQL SELECT paraobtenerelnombredelprimerusuario (LIMIT1)queaúntienesuvalorde“hemosrecuperadoyaesteusuario”acero. Tambiénusamoselpatrón fetchone()[0] enunbloquetry/exceptparaextraer el“nombreamostrar”(screen_name)delosdatosrecuperados,obienmostrarun mensajedeerroryvolveralprincipio.

Sihemosobtenidoconéxitoelnombredeunacuentaqueaúnnohabíasido procesada,recuperamossusdatosdeestemodo:

url=twurl.augment(TWITTER_URL,{'screen_name':cuenta,'count': '20'}) print('Recuperando',url) conexion = urllib.urlopen(url) datos = conexion.read() js = json.loads(datos)

cur.execute('UPDATETwitterSETrecuperado=1WHEREnombre=?',(cuenta,))

Unavezrecuperadoscorrectamentelosdatos,usamoslasentencia UPDATE para ponerlacolumna recuperado a1,loqueindicaquehemosterminadolaextracción deamigosdeesacuenta.Estoimpidequerecuperemoslosmismosdatosunay otravez,ynospermiteiravanzandoatravésdelareddeamigosdeTwitter.

Siejecutamoselprogramadeamigosypulsamosintrodosvecespararecuperarlos amigosdelsiguienteamigonovisitado,yluegoejecutamosdenuevoelprograma devolcadodedatos,nosmostrarálasalidasiguiente:

210 CHAPTER15.BASESDEDATOSYSQL

('opencontent',1,1) ('lhawthorn',1,1) ('steve_coppin',0,1) ('davidkocher',0,1) ('hrheingold',0,1)

...

('cnxorg',0,2) ('knoop',0,1) ('kthanos',0,2) ('LectureTools',0,1)

...

55filas.

Podemosverquesehanguardadocorrectamentelasvisitasquehemosrealizadoa lhawthorn y opencontent.Además,lascuentas cnxorg y kthanos yatienendos seguidores.Puestoquehemosrecuperadolosamigosdetrespersonas(drchuck, opencontent,y lhawthorn),latablacontiene55filasdeamigosporrecuperar.

Cadavezqueejecutamoselprogramaypulsamosintro,seelegirálasiguiente cuentanovisitada(esdecir,ahoralasiguientecuentasería steve_coppin),recuperarásusamigos,losmarcarácomorecuperadosy,paracadaunodelosamigos de steve_coppin,obienloañadiráalfinaldelabasededatos,obienactualizará sucontadordeamigossiyaestabaenlabasededatos.

Comotodoslosdatosdelprogramaestánalmacenadoseneldiscoenunabasede datos,laactividadderastreopuedesersuspendidayreanudadatantasvecescomo sedesee,sinqueseproduzcaningunapérdidadedatos.

15.7Modeladodedatosbásico

Lapotenciarealdelasbasesdedatosrelacionalessemanifiestacuandoseconstruyenmúltiplestablasysecreanenlacesentreellas.Laaccióndedecidircómo separarlosdatosdetuaplicaciónenmúltiplestablasyestablecerlasrelaciones entreesastablasrecibeelnombrede modeladodedatos.Eldocumentodediseño quemuestralastablasysusrelacionessellama modelodedatos.

Elmodeladodedatosesunahabilidadrelativamentesofisticada,yenestasección sólointroduciremoslosconceptosmásbásicosacercadeltema.Paraobtenermás detallessobremodeladodedatospuedescomenzarcon: http://es.wikipedia.org/wiki/Modelo_relacional

SupongamosqueparanuestraaplicaciónderastreodeTwitter,envezdecontar losamigosdeunapersonasinmás,queremosmantenerunalistadetodaslas relacionesentreellos,demodoquepodamosencontrarunalistadegentequeesté siguiendolacuentadeunapersonaconcreta.

Dadoquetodoelmundopuedetenerpotencialmentemuchascuentassiguiéndole, nopodemosañadirsimplementeunaúnicacolumnaanuestratablade Twitter Demodoquecreamosunatablanuevaquerealiceunseguimientodeparejasde amigos.Acontinuaciónsemuestraunmodosencillodehacerunatabladeeste tipo:

15.7.MODELADODEDATOSBÁSICO 211

CREATETABLE Colegas(desde_amigoTEXT,hacia_amigoTEXT)

Cadavezqueencontremosunapersonadelasqueestásiguiendo drchuck,insertaremosunafiladeestaforma:

INSERTINTO Colegas(desde_amigo,hacia_amigo) VALUES ('drchuck', 'lhawthorn')

Conformavayamosprocesandolos20amigosde drchuck quenosenvíaTwitter, insertaremos20registroscon“drchuck”comoprimerparámetro,demodoque terminaremosduplicandolacadenaunmontóndevecesenlabasededatos.

Estaduplicacióndecadenasdedatosviolaunadelasmejoresprácticasparala normalizacióndebasesdedatos,quebásicamenteconsisteenquenuncasedebe guardarlamismacadenamásdeunavezenlabasededatos.Sisenecesitanlos datosvariasveces,sedebecrearuna clave numéricaparaellosyhacerreferencia alosdatosrealesatravésdeesaclave.

Entérminosprácticos,unacadenaocupaunmontóndeespaciomásqueunentero, tantoeneldiscocomoenlamemoriadelequipo,yademásnecesitamástiempode procesadorparasercomparadayordenada.Sisólosetienenunospocoscientosde entradas,elespacioyeltiempodeprocesadornoimportandemasiado.Perosise tienenunmillóndepersonasenlabasededatosylaposibilidadde100millones deenlacesdeamigos,esimportantesercapazderevisarlosdatostanrápidocomo seaposible.

VamosaalmacenarnuestrascuentasdeTwitterenunatablallamada Personas envezdehacerloenlatabla Twitter queusamosenelejemploanterior.Latabla Personas tieneunacolumnaadicionalparaalmacenarlaclavenuméricaasociada conlafiladecadausuariodeTwitter.SQLitetieneunacaracterísticaquepermite añadirautomáticamenteelvalordelaclaveparacualquierfilaqueinsertemosen latabla,usandountipoespecialdedatosenlacolumna(INTEGERPRIMARYKEY).

Podemoscrearlatabla Personas conesacolumnaadicional, id,comosemuestra acontinuación:

CREATETABLE Personas

(id INTEGER PRIMARYKEY,nombreTEXT UNIQUE,recuperado INTEGER)

Hayquenotarqueyanonecesitamosmanteneruncontadordeamigosencada columnadelatabla Personas.Cuandoelegimos INTEGERPRIMARYKEY como eltipodelacoluma id,estamosindicandoquequeremosqueSQLitecontrole estacolumayasigneautomáticamenteunaclavenuméricaúnicaparacadafila queinsertemos.Tambiénañadimoslapalabraclave UNIQUE,paraindicarqueno vamosapermitiraSQLiteinsertardosfilasconelmismovalorde nombre Ahora,envezdecrearlatabla Colegas comohicimosantes,crearemosunatabla llamada Seguimientos condoscolumnasdetipoentero, desde_id y hacia_id, yunarestricciónenlatablaqueconsistiráenquela combinación de desde_id y hacia_id deberáserúnica(esdecir,nosepodráninsertarfilasenlatablacon estosvaloresduplicados)ennuestrabasededatos.

CREATETABLE Seguimientos

(desde_id INTEGER,hacia_id INTEGER, UNIQUE(desde_id,hacia_id))

212 CHAPTER15.BASESDEDATOSYSQL

Cuandoañadimoslaclausula UNIQUE anuestrastablas,estamoscomunicandoun conjuntodereglasquevamosaexigiralabasededatosquesecumplancuando seintenteninsertarregistros.Estamoscreandoesasreglasporqueleconvienena nuestroprograma,comoveremosdentrodeunmomento.Ambasreglasimpiden quesecometanerroresyhacenmássencilloescribirpartedenuestrocódigo. Enesencia,alcrearestatabla Seguimientos estamosmodelandouna“relación”, enlacualunapersona“sigue”aotrayserepresentaconunpardenúmerosque indicanque(a)ambaspersonasestánconectadasy(b)ladireccióndelarelación.

15.8.PROGRAMACIÓNCONMÚLTIPLESTABLAS 213
People name drchuck opencontent 1 1 retrieved Follows from_id 1 1 3 to_id id 1 2 3 4 lhawthorn steve_coppin 1 0 2 1 4 ... ... Figure15.4:RelacionesEntreTablas 15.8Programaciónconmúltiplestablas AhoravamosarehacerdenuevoelprogramaarañadeTwitterusandodostablas, lasclavesprimarias,ylasclavesdereferencia,comohemosdescritoantes.Heaquí elcódigodelanuevaversióndelprograma: importurllib.request,urllib.parse,urllib.error importtwurl importjson importsqlite3 importssl TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json' conn = sqlite3.connect('amigos.sqlite') cur = conn.cursor()

cur.execute('''CREATETABLEIFNOTEXISTSPersonas (idINTEGERPRIMARYKEY,nombreTEXTUNIQUE,recuperadoINTEGER)''') cur.execute('''CREATETABLEIFNOTEXISTSSeguimientos (desde_idINTEGER,hacia_idINTEGER,UNIQUE(desde_id,hacia_id))''')

#IgnoreSSLcertificateerrors

ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE

while True: cuenta = input('IngresaunacuentadeTwitter,osalir:') if (cuenta == 'salir'): break if (len(cuenta) < 1): cur.execute('''SELECTid,nombreFROMPersonas WHERErecuperado=0LIMIT1''') try: (id,cuenta) = cur.fetchone() except: print('NosehanencontradocuentasdeTwittersinrecuperar') continue else: cur.execute('SELECTidFROMPersonasWHEREnombre=?LIMIT1', (cuenta,)) try: id = cur.fetchone()[0] except: cur.execute('''INSERTORIGNOREINTOPersonas (nombre,recuperado)VALUES(?,0)''',(cuenta,)) conn.commit() if cur.rowcount != 1: print('Errorinsertandocuenta:',cuenta) continue id = cur.lastrowid url = twurl.aumentar(TWITTER_URL, {'screen_name':cuenta, 'count': '100'}) print('Recuperandocuenta',cuenta) try: conexion = urllib.request.urlopen(url,context=ctx) except Exception aserr: print('Falloalrecuperar',err) break datos = conexion.read().decode() cabeceras = dict(conexion.getheaders()) print('Restantes',cabeceras['x-rate-limit-remaining']) try: js = json.loads(datos)

214 CHAPTER15.BASESDEDATOSYSQL

except: print('Falloalanalizarjson') print(datos) break

#Depuración #print(json.dumps(js,indent=4))

if 'users' notin js: print('JSONincorrectorecibido') print(json.dumps(js,indent=4)) continue

cur.execute('UPDATEPersonasSETrecuperado=1WHEREnombre=?',(cuenta, contnuevas = 0 contantiguas = 0 for u in js['users']: amigo = u['screen_name'] print(amigo) cur.execute('SELECTidFROMPersonasWHEREnombre=?LIMIT1', (amigo,)) try: amigo_id = cur.fetchone()[0] contantiguas = contantiguas + 1 except: cur.execute('''INSERTORIGNOREINTOPersonas (nombre,recuperado)VALUES(?,0)''',(amigo,)) conn.commit() if cur.rowcount != 1: print('Errorinsertingaccount:',amigo) continue amigo_id = cur.lastrowid contnuevas = contnuevas + 1 cur.execute('''INSERTORIGNOREINTOSeguimientos (desde_id,hacia_id)VALUES(?,?)''',(id,amigo_id)) print('Cuentasnuevas=',contnuevas, 'yavisitadas=',contantiguas) print('Restantes',cabeceras['x-rate-limit-remaining']) conn.commit() cur.close()

#Código:https://es.py4e.com/code3/twfriends.py

Esteprogramaempiezaaresultarunpococomplicado,peroilustralospatronesde diseñoquedebemosusarcuandoutilizamosclavesdeenterosparaenlazartablas. Esospatronesbásicosson:

1.Creartablasconclavesprimariasyrestricciones.

2.Cuandotenemosunaclavelógicaparaunapersona(esdecir,unnombrede cuenta)ynecesitamoselvalordel id deesapersona,dependientodesiesa

15.8.PROGRAMACIÓNCONMÚLTIPLESTABLAS 215

personayaestáenlatabla Personas ono,tendremosque:(1)buscarla personaenlatabla Personas yrecuperarelvalorde id paraesapersona,o (2)añadirlapersonaalatabla Personas yobtenerelvalordel id parala filareciénañadida.

3.Insertarlafilaqueindicalarelaciónde“seguimiento”. Vamosaexplicartodoslospuntosdeunoenuno.

15.8.1Restriccionesentablasdebasesdedatos

Conformediseñamoslaestructuradelatabla,podemosindicaralsistemadela basededatosquequeremosaplicaralgunasreglas.Estasreglasnosayudarána evitarerroresyaintroducircorrectamentelosdatosenlastablas.Cuandocreamos nuestrastablas:

cur.execute('''CREATETABLEIFNOTEXISTSPersonas (idINTEGERPRIMARYKEY,nombreTEXTUNIQUE,recuperadoINTEGER)''') cur.execute('''CREATETABLEIFNOTEXISTSSeguimientos (desde_idINTEGER,hacia_idINTEGER,UNIQUE(desde_id,hacia_id))''')

Estamosindicandoquelacolumna nombre delatabla Personas debeser UNIQUE (única).Ademásindicamosquelacombinacióndelosdosnúmerosdecadafila delatabla Seguimientos debesertambiénúnica.Estasrestriccionesevitanque cometamoserrorescomoañadirlamismarelaciónentrelasmismaspersonas más deunavez.

Después,podemosaprovecharestasrestriccionesenelcódigosiguiente:

cur.execute('''INSERTORIGNOREINTOPersonas(nombre,recuperado) VALUES(?,0)''',(amigo,))

Aquíañadimoslaclausula ORIGNORE enlasentencia INSERT paraindicarquesi este INSERT enparticularcausaraunaviolacióndelaregla“el nombre debeser único”,elsistemadelabasededatosestáautorizadoaignorarel INSERT.De estaforma,estamosusandolasrestriccionesdelabasededatoscomounaredde seguridadparaasegurarnosdequenohacemosalgoincorrectosindarnoscuenta.

Demanerasimilar,elcódigosiguienteseaseguradequenoañadamosexactamente lamismarelaciónde Seguimiento dosveces.

cur.execute('''INSERTORIGNOREINTOSeguimientos (desde_id,hacia_id)VALUES(?,?)''',(id,amigo_id))

Denuevo,simplementeestamosindicándolealabasededatosqueignorecualquier intentode INSERT siésteviolalarestriccióndeunicidadquehemosespecificado paracadafilade Seguimientos.

216 CHAPTER15.BASESDEDATOSYSQL

15.8.2Recuperary/oinsertarunregistro

CuandopedimosalusuariounacuentadeTwitter,silacuentayaexistedebemos averiguarelvalordesu id.Silacuentanoexisteaúnenlatabla Personas, debemosinsertarelregistroyobtenerelvalordel id delafilareciéninsertada.

Ésteesundiseñomuyhabitualyseutilizadosvecesenelprogramaanterior.Este códigomuestracómosebuscael id delacuentadeunamigo,unavezextraídosu screen_name desdeunnodode usuario delJSONrecuperadodesdeTwitter.

Dadoqueconeltiemposerácadavezmásprobablequelacuentayafigureenla basededatos,primerocomprobaremossielregistroexisteen Personas,usando unasentencia SELECT.

Sitodosalebien2 dentrodelasección try recuperaremoselregistromediante fetchone() yluegoextraeremoselprimer(yúnico)elementodelatupladevuelta, quealmacenaremosen amigo_id

Siel SELECT falla,elcódigo fetchone()[0] tambiénfallará,yelcontrolserá transferidoalasección except. amigo = u['screen_name'] cur.execute('SELECTidFROMPersonasWHEREnombre=?LIMIT1', (amigo,))

try: amigo_id = cur.fetchone()[0] contantiguas = contantiguas + 1 except: cur.execute('''INSERTORIGNOREINTOPersonas(nombre,recuperado) VALUES(?,0)''',(amigo,)) conn.commit() if cur.rowcount != 1 : print('Erroralinsertarcuenta:',amigo) continue amigo_id = cur.lastrowid contnuevas = contnuevas + 1

Siterminamosenelcódigodel except,esosólosignificaquelafilanoseha encontradoenlatable,demodoquedebemosinsertarla.Usamos INSERTOR IGNORE paraevitarposibleserrores,yluegollamamosa commit() paraforzara labasededatosaqueseactualicedeverdad.Despuésdequeseharealizado laescritura,podemoscomprobarelvalorde cur.rowcount,parasabercuántas filassehanvistoafectadas.Comoestamosintentandoinsertarunaúnicafila,siel númerodefilasafectadasesdistintode1,sehabríaproducidounerror.

Siel INSERT tieneéxito,podemosusar cur.lastrowid paraaveriguarelvalorque labasededatoshaasignadoalacolumna id ennuestrafilareciéncreada.

2 Engeneral,cuandounafraseempiezapor“sitodovabien”,es porqueelcódigodelquese hablanecesitautilizartry/except.

15.8.PROGRAMACIÓNCONMÚLTIPLESTABLAS 217

15.8.3Almacenarlasrelacionesentreamigos

UnavezquesabemoselvalordelaclavetantoparaelusuariodeTwittercomopara elamigoquehemosextraídodelJSON,resultasencilloinsertarambosnúmerosen latablade Seguimientos conelcódigosiguiente:

cur.execute('''INSERTORIGNOREINTOSeguimientos (desde_id,hacia_id)VALUES(?,?)''',(id,amigo_id))

Notaquedejamosquesealabasededatosquienseocupedeevitarla“inserción duplicada”deunarelación,mediantelacreacióndeunatablaconunarestricción deunicidad,demodoqueluegoennuestrasentencia INSERT tansóloañadimos o ignoramos.

Aquíestáunejemplodelaejecucióndeesteprograma:

IngresaunacuentadeTwitter,osalir: NosehanencontradocuentasdeTwittersinrecuperar IngresaunacuentadeTwitter,osalir:drchuck Recuperandohttp://api.twitter.com/1.1/friends...

Cuentasnuevas=20yavisitadas=0 IngresaunacuentadeTwitter,osalir: Recuperandohttp://api.twitter.com/1.1/friends...

Cuentasnuevas=17yavisitadas=3

IngresaunacuentadeTwitter,osalir: Recuperandohttp://api.twitter.com/1.1/friends...

Cuentasnuevas=17yavisitadas=3 IngresaunacuentadeTwitter,osalir:salir

Comenzamosconlacuentade drchuck yluegodejamosqueelprogramaescoja deformaautomáticalassiguientesdoscuentaspararecuperaryañadiranuestra basededatos.

Lassiguientessonlasprimerasfilasdelastablas Personas y Seguimientos después determinarlaejecuciónanterior:

Personas: (1,'drchuck',1) (2,'opencontent',1) (3,'lhawthorn',1) (4,'steve_coppin',0) (5,'davidkocher',0) 55filas.

Seguimientos: (1,2) (1,3) (1,4) (1,5) (1,6) 60filas.

Puedesverloscampos id, nombre, visitado delatabla Personas,ytambién losnúmerosdeambosextremosdelarelaciónenlatabla Seguimientos.Enla

218 CHAPTER15.BASESDEDATOSYSQL

tabla Personas,vemosquelasprimerastrespersonasyahansidovisitadasy quesusdatoshansidorecuperados.Losdatosdelatabla Seguidores indican que drchuck (usuario1)esamigodetodaslaspersonasquesemuestranenlas primerascincofilas.Estotienesentido,yaquelosprimerosdatosquerecuperamos yalmacenamosfueronlosamigosdeTwitterde drchuck.Siimprimierasmásfilas delatabla Seguimientos veríastambiénlosamigosdelosusuarios2y3.

15.9Trestiposdeclaves

Ahoraquehemosempezadoaconstruirunmodelodedatos,colocandonuestros datosenmúltiplestablasenlazadas,yhemosenlazadolasfilasdeesastablasusando claves,debemosfijarnosenciertaterminologíaacercadeesasclaves.Generalmente, enunmodelodebasededatoshaytrestiposdeclavesquesepuedenusar.

•Una clavelógica esunaclavequesepodríausarenel“mundoreal”para localizarunafila.Ennuestroejemplodemodeladodedatos,elcampo nombre esunaclavelógica.Eselnombrequesemuestraenpantallaparaelusuarioy, enefecto,usamoselcampo nombre variasvecesenelprogramaparalocalizar lafilacorrespondienteaunusuario.Comprobarásqueamenudotienesentido añadirunarestricción UNIQUE(única) aunaclavelógica.Comolasclaves lógicassonlasqueusamosparabuscarunafiladesdeelmundoexterior, tendríapocosentidopermitirquehubieramúltiplesfilasconelmismovalor enlatabla.

•Una claveprimaria esnormalmenteunnúmeroqueesasignadoautomáticamenteporlabasededatos.Engeneralnotieneningúnsignificadofuera delprogramaysóloseutilizaparaenlazarentresífilasdetablasdiferentes. Cuandoqueremosbuscarunafilaenunatabla,realizarlabúsquedausando laclaveprimariaes,normalmente,elmodomásrápidodelocalizarla.Como lasclavesprimariassonnúmerosenteros,necesitanmuypocoespaciodealmacenamientoypuedensercomparadasyordenadasmuyrápido.Ennuestro modelodedatos,elcampo id esunejemplodeunaclaveprimaria.

•Una claveforánea (foreignkey)esnormalmenteunnúmeroqueapuntaala claveprimariadeunafilaasociadaenunatabladiferente.Unejemplode unaclaveforáneaennuestromodelodedatoseslacolumna desde_id.

Estamosusandocomoconvenciónparalosnombreseldarlesiemprealcampode claveprimariaelnombre id yañadirelsufijo _id acualquiernombredecampo queseaunaclaveforánea.

15.10UsodeJOINpararecuperardatos

Ahoraquehemoscumplidoconlasreglasdelanormalizacióndebasesdedatos yhemosseparadolosdatosendostablas,enlazándolasentresíusandoclaves primariasyforáneas,necesitaremossercapacesdeconstruirun SELECT quevuelva ajuntarlosdatosesparcidosporlastablas.

15.9.TRESTIPOSDECLAVES 219

SQLusalaclausula JOIN paravolveraconectaresastablas.Enlaclausula JOIN seespecificanloscamposqueseutilizanparareconectarlasfilasentrelasdistintas tablas.

Acontinuaciónsemuestraunejemplodeun SELECT conunaclausula JOIN:

SELECT * FROM Seguimientos JOIN Personas ON Seguimientos.desde_id=Personas.id WHERE Personas.id= 1

Laclausula JOIN indicaqueloscamposqueestamosseleccionandomezclanlas tablas Seguimientos y Personas.Laclausula ON indicacómodebenserunidas lasdostablas:Tomacadafilade Seguimientos yañadeunafilade Personas en lacualelcampo desde_id en Seguimientos coincideconelvalor id enlatabla Personas

ElresultadodelJOINconsisteenlacreacióndeuna“meta-fila”extralarga, quecontendrátantoloscamposde Personas comoloscamposdelafilade Seguimientos quecumplanlacondición.Cuandohaymásdeunacoincidencia entreelcampo id de Personas yel desde_id de Seguimientos,JOINcrearáuna meta-filapara cadauna delasparejasdefilasquecoincidan,duplicandolosdatos siesnecesario.

Elcódigosiguientemuestralosdatosquetendremosenlabasededatosdespuésde queelprogramamulti-tablaarañadeTwitteranteriorhayasidoejecutadovarias veces.

220 CHAPTER15.BASESDEDATOSYSQL
People name drchuck opencontent 1 1 retrieved Follows from_id 1 1 3 to_id id 1 2 3 4 lhawthorn steve_coppin 1 0 2 1 4 ... ... name drchuck opencontent id 1 2 3 4 lhawthorn steve_coppin drchuck 1 drchuck 1 to_id name from_id 1 1 1
.
Figure15.5:ConexióndeTablasUsandoJOIN
importsqlite3

conn = sqlite3.connect('amigos.sqlite') cur = conn.cursor()

cur.execute('SELECT*FROMPersonas') contador = 0 print('Personas:') for fila in cur: if contador < 5:print(fila) contador = contador + 1 print(contador, 'filas.')

cur.execute('SELECT*FROMSeguimientos') contador = 0 print('Seguimientos:') for fila in cur: if contador < 5:print(fila) contador = contador + 1 print(contador, 'filas.')

cur.execute('''SELECT*FROMSeguimientosJOINPersonas ONSeguimientos.hacia_id=Personas.id WHERESeguimientos.desde_id=2''') contador = 0 print('Conexionesparaid=2:') for fila in cur: if contador < 5:print(fila) contador = contador + 1 print(contador, 'filas.')

cur.close()

#Código:https://es.py4e.com/code3/twjoin.py

Enesteprograma,enprimerlugarvolcamoselcontenidodelastablas Personas y Seguimientos yacontinuaciónmostramosunsubconjuntodedatosdelastablas unidasentresí.

Aquítenemoslasalidadelprograma: pythontwjoin.py Personas: (1,'drchuck',1) (2,'opencontent',1) (3,'lhawthorn',1) (4,'steve_coppin',0) (5,'davidkocher',0) 55filas. Seguimientos: (1,2) (1,3) (1,4) (1,5)

15.10.USODEJOINPARARECUPERARDATOS 221

(1,6) 60filas.

Conexionesparaid=2: (2,1,1,'drchuck',1) (2,28,28,'cnxorg',0) (2,30,30,'kthanos',0) (2,102,102,'SomethingGirl',0) (2,103,103,'ja_Pac',0) 20filas.

Sepuedenverlascolumnasdelastablas Personas y Seguimientos,seguidosdel últimoconjuntodefilas,queeselresultadodel SELECT conlaclausula JOIN

Enelúltimoselect,buscamoslascuentasqueseanamigasde“opencontent”(es decir,de Personas.id=2).

Encadaunadelas“meta-filas”delúltimoselect,lasprimerasdoscolumnas pertenecenalatabla Seguimientos,mientrasquelascolumnastresacinco pertenecenalatabla Personas.Sepuedeobservartambiéncómolasegunda columna(Seguimientos.hacia_id)coincideconlatercera(Personas.id)en cadaunadelas“meta-filas”unidas.

15.11Resumen

Enestecapítulosehantratadounmontóndetemasparadarteunavisióndedelo necesarioparautilizarunabasededatosenPython.Esmáscomplicadoescribirel códigoparausarunabasededatosquealmacenelosdatosqueutilizardiccionarios dePythonoarchivosplanos,demodoqueexistenpocasrazonesparausaruna basededatos,amenosquetuaplicaciónnecesitedeverdadlascapacidadesque proporciona.Lassituacionesenlascualesunabasededatospuedenresultarbastanteútilson:(1)cuantotuaplicaciónnecesitarealizarmuchoscambiospequeños deformaaleatoriaenunconjuntodedatosgrandes,(2)cuandotienestantosdatos quenocabenenundiccionarioynecesitaslocalizarinformaciónconfrecuencia,o (3)cuandotienesunprocesoquevaafuncionardurantemuchotiempo,ynecesitaspoderdetenerloyvolverloaponerenmarcha,conservandolosdatosentre ejecuciones.

Unabasededatosconunasimpletablapuederesultarsuficienteparacubrirlas necesidadesdemuchasaplicaciones,perolamayoríadelosproblemasnecesitarán variastablasyenlaces/relacionesentrefilasdetablasdiferentes.Cuandoempieces acrearenlacesentretablas,esimportanterealizarundiseñomeditadoyseguir lasreglasdenormalizacióndebasesdedatos,paraconseguirelmejorusodesus capacidades.Comolamotivaciónprincipalparausarunabasededatossueleserel tenergrandescantidadesdedatosconlasquetratar,resultaimportantemodelar losdatosdeformaeficiente,paraquetuprogramafuncionetanrápidamentecomo seaposible.

222 CHAPTER15.BASESDEDATOSYSQL

15.12Depuración

Unplanteamientohabitual,cuandoseestádesarrollandounprogramaenPython queconectaconunabasededatosSQLite,seráejecutarprimeroelprograma yrevisarluegolosresultadosusandoelnavegadordebasesdedatosdeSQLite (DatabaseBrowserforSQLite).Elnavegadortepermiterevisarcuidadosamente losdatos,paracomprobarsituprogramaestáfuncionandocorrectamente.

Debestenercuidado,yaqueSQLiteseencargadeevitarquedosprogramaspuedan cambiarlosmismosdatosalavez.Porejemplo,siabresunabasededatosen elnavegadoryrealizasuncambioenlabasededatos,peronohaspulsadoaún elbotón“guardar”delnavegador,éste“bloqueará”elarchivodelabasededatos yevitaráquecualquierotroprogramaaccedaadichofichero.Concretamente,en esecasotuprogramadePythonnoserácapazdeaccederalarchivo,yaqueéste seencontrarábloqueado.

Demodoquelasoluciónpasaporasegurarsedecerrarlaventanadelnavegador delabasededatos,obienusarelmenú Archivo paracerrarlabasededatos abiertaenelnavegadorantesdeintentaraccederaelladesdePython,paraevitar encontrarseconelproblemadequeelcódigodePythonfalledebidoaquelabase dedatosestábloqueada.

15.13Glosario

atributo Unodelosvaloresdentrodeunatupla.Máscomúnmentellamada “columa”o“campo”.

cursor UncursorpermiteejecutarcomandosSQLenunabasededatosyrecuperarlosdatosdeella.Uncursoressimilaraunsocketenconexionesdered oaunmanejardearchivos.

claveforánea Unaclavenuméricaqueapuntaalaclaveprimariadeunafilaen otratabla.Lasclavesforáneasestablecenrelacionesentrefilasalmacenadas entablasdiferentes.

clavelógica Unaclavequeel“mundoexterior”utilizaparalocalizarunafila concreta.Porejemplo,enunatabladecuentasdeusuario,ladirecciónde e-maildeunapersonaseríaunbuencandidatoautilizarcomoclavelógica paralosdatosdeeseusuario.

claveprimaria Unaclavenuméricaasignadaacadafila,queesutilizadapara referirnosaesafilaconcretadeesatabladesdeotratabladistinta.Amenudo labasededatosseconfiguraparaasignarlasclavesprimariasdeforma automática,segúnsevaninsertandofilas.

índice Datosadicionalesqueelsoftwaredelabasededatosmantienecomofilas einsertaenunatablaparaconseguirquelasbúsquedasseanmuyrápidas. navegadordebasededatos Unprogramaquepermiteconectardirectamente conunabasededatosymanipularla,sintenerqueescribircódigoparaello.

normalización Diseñodeunmodeladodedatosdeformaquenohayadatos duplicados.Sealmacenacadaelementodelosdatosenunlugarconcretode labasededatosysereferenciadesdeotrossitiosusandounaclaveforánea. relación Unáreadentrodeunabasededatosquecontienetuplasyatributos.Se leconocemáshabitualmentecomo“tabla”.

15.12.DEPURACIÓN 223

restricción Cuandolepedimosaunabasededatosqueimpongaunareglaa uncampodeunafilaenunatabla.Unarestricciónhabitualconsisteen especificarquenopuedahabervaloresrepetidosenuncampoconcreto(es decir,quetodoslosvaloresdebanserúnicos). tupla Unaentradaúnicaenunabasededatos,queesunconjuntodeatributos. Seleconocemáshabitualmentecomo“fila”.

224 CHAPTER15.BASESDEDATOSYSQL

Visualizacióndedatos

Hastaelmomento,hemosestadoaprendiendoellenguajedePythonyhemos aprendidocómousarPython,laredylasbasesdedatosparamanipulardatos.

Enestecapítulo,echaremosunvistazoatresaplicacionescompletasqueusantodos estoselementosparagestionaryvisualizardatos.Puedesusarestasaplicaciones comocódigodeejemploquesirvadepuntodepartidapararesolverproblemasdel mundoreal.

CadaaplicaciónesunarchivoZIPquepuedesdescargar,extraerentuequipoy ejecutar.

16.1MapadeGoogleapartirdedatosgeocodifi-

cados

EnesteproyectousaremoslaAPIdegeocodificacióndeGoogleparalimpiarvarias ubicacionesgeográficasdenombresdeuniversidadesintroducidasporlosusuarios, yluegocolocaremoslosdatosenunmapadeGoogle.

Paracomenzar,descargalaaplicacióndesde: www.py4e.com/code3/geodata.zip

ElprimerproblemaaresolveresquelaAPIlibredegeocodificacióndeGoogletiene comolímitedeusounciertonúmerodepeticionesdiarias.Sitienesunmontón dedatos,necesitarásdeteneryreanudarelprocesodebúsquedavariasveces.Por tanto,dividiremoselproblemaendosfases.

Enlaprimerafase,tomaremoscomoentradalosdatos“dereconocimiento”del archivo where.data ylosleeremosunalíneaalavez,recuperandolainformaciónde geocodificacióndesdeGoogleyalmacenándolaenunabasededatos geodata.sqlite AntesdeusarlaAPIdegeocodificaciónparacadaubicaciónintroducidaporel usuario,verificaremossiyatenemoslosdatosparaesaentradaconcreta.Labase dedatosfuncionaráasícomouna“caché”localdedatosdegeocodificación,para asegurarnosdequenuncasolicitamosaGooglelosmismosdatosdosveces.

Chapter16
225

Figure16.1:UnMapadeGoogle

Puedesreiniciarelprocesoencualquiermomentoeliminandoelarchivo geodata.sqlite.

Ejecutaelprograma geoload.py.Esteprogramaleerálaslíneasdeentradadesde where.data yparacadalíneaverificarásiyaestáenlabasededatos.Sino disponemosdedatosparaesaubicación,llamaráalaAPIdegeocodificaciónpara recuperarlosylosalmacenaráenlabasededatos.

Aquítenemosunejemplodeejecucióncuandoyadisponemosdeinformaciónalmacenadaenlabasededatos:

FoundindatabaseNortheasternUniversity

FoundindatabaseUniversityofHongKong,...

FoundindatabaseTechnion

FoundindatabaseViswakarmaInstitute,Pune,India

FoundindatabaseUMD

FoundindatabaseTuftsUniversity

ResolvingMonashUniversity

Retrievinghttp://maps.googleapis.com/maps/api/ geocode/json?address=Monash+University

Retrieved2063characters{"results":[ {'status':'OK','results':...}

ResolvingKokshetauInstituteofEconomicsandManagement

Retrievinghttp://maps.googleapis.com/maps/api/ geocode/json?address=Kokshetau+Inst... Retrieved1749characters{"results":[

226 CHAPTER16.VISUALIZACIÓNDEDATOS

{'status':'OK','results':...} ...

Lasprimerascincoubicacionesyaestánenlabasededatosyporesolasomitimos. Elprogramaexplorahastaqueencuentraubicacionesnuevasyentoncescomienza arecuperarlas.

Elprograma geoload.py puedeserdetenidoencualquiermomento,ydisponede uncontadorquepuedesusarparalimitarelnúmerodellamadasalaAPIde geolocalizaciónencadaejecución.Dadoqueelarchivo where.data solotieneunos pocoscientosdeelementos,nodeberíasllegarallímitediariodeusos,perosi tienesmásdatospuedensernecesariasvariasejecucionesdelprogramadurante variosdíasparatenertodoslosdatosdeentradageolocalizadosennuestrabasede datos.

Unavezquetienespartedelosdatoscargadosen geodata.sqlite,sepuedenvisualizarusandoelprograma geodump.py.Esteprogramaleelabasededatosy escribeelarhivo where.js conlaubicación,latitudylongitudenformadecódigo ejecutabledeJavaScript.

Unaejecucióndelprograma geodump.py seríalasiguiente:

NortheasternUniversity,...Boston,MA02115,USA42.3396998-71.08975 BradleyUniversity,1501...Peoria,IL61625,USA40.6963857-89.6160811 ...

Technion,Viazman87,Kesalsaba,32000,Israel32.777535.0216667 MonashUniversityClayton...VIC3800,Australia-37.9152113145.134682 Kokshetau,Kazakhstan53.283333369.3833333

12recordswrittentowhere.js Openwhere.htmltoviewthedatainabrowser

Elarchivo where.html consisteenHTMLyJavaScriptparamostrarunmapade Google.Leelosdatosmásactualesde where.js paraobtenerlosdatosquese mostrarán.Heaquíelformatodelarchivo where.js:

myData=[

[42.3396998,-71.08975,'NortheasternUni...Boston,MA02115'], [40.6963857,-89.6160811,'BradleyUniversity,...Peoria,IL61625,USA'], [32.7775,35.0216667,'Technion,Viazman87,Kesalsaba,32000,Israel'], ]; SetratadeunavariableJavaScriptquecontieneunalistadelistas.Lasintaxisde laslistasdeconstantesenJavaScriptesmuysimilaralasdePython,demodoque deberíaresultartefamiliar.

Simplementeabre where.html enunnavegadorparaverlasubicaciones.Puedes mantenerelratónsobrecadamarcadelmapaparaverlaubicaciónquelaAPI degeocodificaciónhadevueltoparalaentradaqueelusuariointrodujo.Sino puedesverningúndatocuandoabraselarchivo where.html,puedequedebasrevisar JavaScriptolaconsoladedesarrolladordetunavegador.

16.1.MAPADEGOOGLEAPARTIRDEDATOSGEOCODIFICADOS 227

16.2Visualizaciónderedeseinterconexiones

Enestaaplicación,realizaremosalgunasdelasfuncionesdeunmotordebúsqueda. Primerorastrearemosunapequeñapartedelawebyejecutaremosunaversión simplificadadelalgoritmodeclasificaciónqueusaGoogleparadeterminarqué páginasseencuentranmásconectadas.Luego,visualizaremoslaclasificaciónde laspáginasyconectividaddenuestropequeñorincóndelaweb.Usaremosla libreríadevisualizacióndeJavaScriptD3 http://d3js.org/ paragenerarlaimagen desalida.

Puedesdescargaryextraerestaaplicacióndesde: www.py4e.com/code3/pagerank.zip

Figure16.2:UnaclasificacióndePáginas

Elprimerprograma(spider.py)rastreaunsitiowebyenvíaunaseriedepáginas alabasededatos(spider.sqlite),guardandolosenlacesentrepáginas.Puedes reiniciarelprocesoencualquiermomentoeliminandoelfichero spider.sqlite yejecutandodenuevo spider.py

Enterweburlorenter:http://www.dr-chuck.com/ ['http://www.dr-chuck.com']

Howmanypages:2 1http://www.dr-chuck.com/12 2http://www.dr-chuck.com/csev-blog/57

Howmanypages:

Enestaejecucióndeejemplo,lepedimosquerastreeunsitiowebyquerecupere dospáginas.Sireiniciaselprogramaylepidesquerastreemáspáginas,novolverá

228 CHAPTER16.VISUALIZACIÓNDEDATOS

arevisaraquellasqueyaesténenlabasededatos.Encadareinicioelegiráuna páginaalazarnorastreadaaúnycomenzaráallí.Demodoquecadaejecución sucesivade spider.py iráañadiendopáginasnuevas.

Enterweburlorenter:http://www.dr-chuck.com/ ['http://www.dr-chuck.com']

Howmanypages:3

3http://www.dr-chuck.com/csev-blog57

4http://www.dr-chuck.com/dr-chuck/resume/speaking.htm1

5http://www.dr-chuck.com/dr-chuck/resume/index.htm13

Howmanypages:

Sepuedentenermúltiplespuntosdepartidaenlamismabasededatos—dentro delprograma,éstossonllamados“webs”.Laarañaeligeentretodoslosenlacesno visitadosdelaspáginasexistentesunoalazarcomosiguientepáginaarastrear.

Siquieresverelcontenidodelarchivo spider.sqlite,puedesejecutar spdump.py,que mostraráalgocomoesto:

(5,None,1.0,3,'http://www.dr-chuck.com/csev-blog') (3,None,1.0,4,'http://www.dr-chuck.com/dr-chuck/resume/speaking.htm') (1,None,1.0,2,'http://www.dr-chuck.com/csev-blog/') (1,None,1.0,5,'http://www.dr-chuck.com/dr-chuck/resume/index.htm') 4rows.

Estomuestraelnúmerodeenlaceshacialapágina,laclasificaciónantiguadela página,laclasificaciónnueva,eliddelapágina,ylaurldelapágina.Elprograma spdump.py sólomuestraaquellaspáginasquetienenalmenosunenlacehaciaella.

Unavezquetienesunascuantaspáginasenlabasededatos,puedesejecutarel clasificadorsobreellas,usandoelprograma sprank.py.Simplementedebesindicarle cuántasiteracionesdelclasificadordepáginasdeberealizar.

Howmanyiterations:2 10.546848992536 20.226714939664 [(1,0.559),(2,0.659),(3,0.985),(4,2.135),(5,0.659)]

Puedesvolcarenpantallaelcontenidodelabasededatosdenuevoparaverque laclasificacióndepáginashasidoactualizada:

(5,1.0,0.985,3,'http://www.dr-chuck.com/csev-blog') (3,1.0,2.135,4,'http://www.dr-chuck.com/dr-chuck/resume/speaking.htm') (1,1.0,0.659,2,'http://www.dr-chuck.com/csev-blog/') (1,1.0,0.659,5,'http://www.dr-chuck.com/dr-chuck/resume/index.htm') 4rows.

Puedesejecutar sprank.py tantasvecescomoquieras,ysimplementeirárefinando laclasificacióndepáginascadavezmás.Puedesinclusoejecutar sprank.py varias veces,luegoiralaaraña spider.py arecuperarunascuantaspáginasmásydespués ejecutardenuevo sprank.py paraactualizarlosvaloresdeclasificación.Unmotor

16.2.VISUALIZACIÓNDEREDESEINTERCONEXIONES 229

debúsquedanormalmenteejecutaambosprogramas(elrastreadoryelclasificador) deformaconstante.

Siquieresreiniciarloscálculosdeclasificacióndepáginassintenerquerastrearde nuevolaspáginasweb,puedesusar spreset.py ydespuésreiniciar sprank.py.

Howmanyiterations:50

10.546848992536 20.226714939664 30.0659516187242 40.0244199333 50.0102096489546 60.00610244329379 ...

420.000109076928206 439.91987599002e-05 449.02151706798e-05 458.20451504471e-05 467.46150183837e-05 476.7857770908e-05 486.17124694224e-05 495.61236959327e-05 505.10410499467e-05 [(512,0.0296),(1,12.79),(2,28.93),(3,6.808),(4,13.46)]

Encadaiteracióndelalgoritmodeclasificacióndepáginassemuestraelcambio medioenlaclasificacióndecadapágina.Laredalprincipioestábastantedesequilibrada,demodoquelosvaloresdeclasificaciónparacadapáginacambiarán muchoentreiteraciones.Perodespuésdeunascuantasiteraciones,laclasificación depáginasconverge.Deberíasejecutar prank.py duranteeltiemposuficientepara quelosvaloresdeclasificaciónconverjan.

Siquieresvisualizarlaspáginasmejorclasificadas,ejecuta spjson.py paraleerla basededatosyescribirelrankingdelaspáginasmásenlazadasenformatoJSON, quepuedeservisualizadoenunnavegadorweb.

CreatingJSONoutputonspider.json... Howmanynodes?30 Openforce.htmlinabrowsertoviewthevisualization

Youcanviewthisdatabyopeningthefile force.html inyourwebbrowser.This showsanautomaticlayoutofthenodesandlinks.Youcanclickanddragany nodeandyoucanalsodouble-clickonanodetofindtheURLthatisrepresented bythenode.

Sivuelvesaejecutarlasotrasutilidades,ejecutadenuevo spjson.py ypulsaactualizarenelnavegadorparaobtenerlosdatosactualizadosdesde spider.json.

16.3Visualizacióndedatosdecorreo

Sihasllegadohastaestepuntodellibro,yadebesdeestarbastantefamiliarizado connuestrosficherosdedatos mbox-short.txt y mbox.txt.Ahoraeselmomentode llevarnuestroanálisisdedatosdecorreoelectrónicoalsiguientenivel.

230 CHAPTER16.VISUALIZACIÓNDEDATOS

Enelmundoreal,avecessetienenquedescargardatosdecorreodesdelosservidores.Esopodríallevarbastantetiempoylosdatospodríantenerinconsistencias, estarllenosdeerrores,ynecesitarunmontóndelimpiezayajustes.Enestasección,trabajaremosconlaaplicaciónmáscomplejaquehemosvistohastaahora, quedescargacasiungigabytededatosylosvisualiza.

Figure16.3:UnaNubedePalabrasdesdelaListadeDesarrolladoresdeSakai

Puedesdescargarlaaplicacióndesde: www.py4e.com/code3/gmane.zip

Utilizaremoslosdatosdeunserviciodearchivodelistasdecorreoelectrónicolibre, llamado www.gmane.org.Esteservicioesmuypopularenproyectosdecódigo abierto,debidoaqueproporcionaunbuenalmacenajeconcapacidaddebúsqueda desuactividaddecorreo.Tambiéntienenunapolíticamuyliberalrespectoal accesoalosdatosatravésdesuAPI.Notienenlímitesdeacceso,perotepiden quenosobrecarguessuservicioydescarguessóloaquellosdatosquenecesites. Puedesleerlostérminosycondicionesdegmaneensupágina: http://gmane.org/export.php

Esmuyimportantequehagasusodelosdatosdegname.orgconresponsabilidad, añadiendoretrasosentuaccesoasusserviciosyextendiendolarealizaciónde losprocesosdelargaduraciónaperiodosdetiempolosuficientementelargos.No abusesdeesteserviciolibreyloestropeesparalosdemás.

AlusarestesoftwarepararastrearlosdatosdecorreodeSakai,segenerócasiun gigabytededatos,requiriendounacantidadconsiderabledeejecucionesdurante variosdías.Elarchivo README.txt delZIPanteriorcontieneinstruccionessobre cómodescargarunacopiapre-rastreadadelarchivo content.sqlite conlamayor

16.3.VISUALIZACIÓNDEDATOSDECORREO 231

partedelcontenidodeloscorreosdeSakai,demodoquenotengasquerastrear durantecincodíassóloparahacerfuncionarlosprogramas.Aunquedescarguesel contenidopre-rastreado,deberíasejecutarelprocesoderastreopararecuperarlos mensajesmásrecientes.

Elprimerpasoesrastrearelrepositoriogmane.LaURLbasesepuedemodificar en gmane.py,ypordefectoapuntaalalistadedesarrolladoresdeSakai.Puedes rastrearotrorepositoriocambiandolaurlbase.Asegúratedeborrarelfichero content.sqlite sirealizaselcambiodeurl.

Elarchivo gmane.py operacomounaarañacachéresponsable,quefuncionadespacioyrecuperaunmensajedecorreoporsegundoparaevitarserbloqueadopor gmane.Almacenatodossusdatosenunabasededatosypuedeserinterrumpidoy reanudadotantasvecescomoseannecesarias.Puedellevarmuchashorasdescargar todoslosdatos.Demodoquequizádebasreanudarlovariasveces.

Heaquíunaejecuciónde mane.py recuperandolosúltimoscincomensajesdela listadedesarrolladoresdeSakai:

Howmanymessages:10

http://download.gmane.org/gmane.comp.cms.sakai.devel/51410/514119460 nealcaidin@sakaifoundation.org2013-04-05re:[building... http://download.gmane.org/gmane.comp.cms.sakai.devel/51411/514123379 samuelgutierrezjimenez@gmail.com2013-04-06re:[building... http://download.gmane.org/gmane.comp.cms.sakai.devel/51412/514139903 da1@vt.edu2013-04-05[buildingsakai]melete2.9oracle... http://download.gmane.org/gmane.comp.cms.sakai.devel/51413/51414349265 m.shedid@elraed-it.com2013-04-07[buildingsakai]... http://download.gmane.org/gmane.comp.cms.sakai.devel/51414/514153481 samuelgutierrezjimenez@gmail.com2013-04-07re:... http://download.gmane.org/gmane.comp.cms.sakai.devel/51415/514160

DoesnotstartwithFrom

Elprogramarevisa content.sqlite desdeelprincipiohastaqueencuentraunnúmero demensajequeaúnnohasidorastreadoycomienzaapartirdeahí.Continúa rastreandohastaqueharecuperadoelnúmerodeseadodemensajesohastaque llegaaunapáginaquenocontieneunmensajeadecuadamenteformateado.

Aveces gmane.org noencuentraunmensaje.Talvezlosadministradoresloborraron,oquizássimplementeseperdió.Situarañasedetiene,yparecequese atascaenunmensajequenopuedelocalizar,entraenSQLiteManager,añadeuna filaconelidperdidoylosdemáscamposenblancoyreinicia gmane.py.Asíse desbloquearáelprocesoderastreoypodrácontinuar.Esosmensajesvacíosserán ignoradosenlasiguientefasedelproceso.

Algobuenoesqueunavezquehasrastreadotodoslosmensajesylostienesen content.sqlite,puedesejecutar gmane.py otravezparaobtenerlosmensajesnuevos segúnvansiendoenviadosalalista.

Losdatosen content.sqlite estánguardadosenbruto,conunmodeladodedatosineficienteysincomprimir.Estosehahechoasíintencionadamente,parapermitirte echarunvistazoen content.sqlite usandoSQLiteManagerydepurarproblemas conelprocesoderastreo.Seríamalaideaejecutarconsultassobreestabasede datos,yaquepuederesultarbastantelenta.

232 CHAPTER16.VISUALIZACIÓNDEDATOS

Elsegundoprocesoconsisteenejecutarelprograma gmodel.py.Esteprograma leelosdatosenbrutode content.sqlite yproduceunaversiónlimpiaybienmodeladadelosdatos,queenvíaalfichero index.sqlite.Esteficheroesmuchomás pequeño(puedeser10vecesmenor)que content.sqlite,porquetambiéncomprime lacabecerayeltextodelcuerpo.

Cadavezque gmodel.py seejecuta,borrayreconstruye index.sqlite.Estopermiteajustarsusparámetrosyeditarlastablasdeasignaciónde content.sqlite paraajustarelprocesodelimpiezadedatos.Estoesunejemplodeejecuciónde gmodel.py.Elprogramaimprimeunalíneaenpantallacadavezquesonprocesados 250mensajesdecorreoparaquepuedasversuevolución,yaquepuedequedarse funcionandoduranteunbuenratomientrasprocesaalrededordeunGigabytede datosdecorreo.

Loadedallsenders1588andmapping28dnsmapping1 12005-12-08T23:34:30-06:00ggolden22@mac.com 2512005-12-22T10:03:20-08:00tpamsler@ucdavis.edu 5012006-01-12T11:17:34-05:00lance@indiana.edu

7512006-01-24T11:13:28-08:00vrajgopalan@ucmerced.edu

The gmodel.py programhandlesanumberofdatacleaningtasks.

Losnombresdedominiosontruncadosadosnivelespara.com,.org,.eduy.net. Otrosnombresdedominiosontruncadosatresniveles.Demodoquesi.umich.edu setransformaenumich.edu,ycaret.cam.ac.ukquedacomocam.ac.uk.Lasdireccionesdecorreoelectrónicotambiénsontransformadasaminúsculas,yalgunasde lasdireccionesde@gmane.org,comolasiguiente

arwhyte-63aXycvo3TyHXe+LvDLADg@public.gmane.org

sonconvertidasendireccionesreales,cuandoesadireccióndecorreorealexisteen otrapartedelcuerpodelmensaje.

Enlabasededatos mapping.sqlite existendostablasquetepermitenasignartanto nombresdedominioscomodireccionesdecorreoindividualesquevancambiandoa lolargodeltiempodeexistenciadelalistadecorreo.Porejemplo,SteveGithens hausadolasdireccionesdecorreosiguientes,segúnibacambiandodetrabajoalo largodelaexistenciadelalistadedesarrolladoresdeSakai:

s-githens@northwestern.edu sgithens@cam.ac.uk swgithen@mtu.edu

Podemosañadirdosentradasenlatabladeasignación(Mapping)de mapping.sqlite,demodoquegmodel.pyenlazarálastresdireccionesenuna:

s-githens@northwestern.edu->swgithen@mtu.edu sgithens@cam.ac.uk->swgithen@mtu.edu

PuedescrearentradassimilaresenlatablaDNSMappingsihaymúltiplesnombres DNSquequieresasignaraunaúnicaDNS.EnlosdatosdeSakaiseharealizado lasiguienteasignación:

16.3.VISUALIZACIÓNDEDATOSDECORREO 233

iupui.edu->indiana.edu

demodoquetodaslascuentasdelosdistintoscampusdelasUniversidadesde Indianasonmonitoreadasjuntas.

Puedesvolveraejecutar gmodel.py unayotravezmientrasvasmirandolosdatos, yañadirasignacionesparahacerquelosdatosquedenmásymáslimpios.Cuando lohayashecho,tendrásunabonitaversiónindexadadelcorreoen index.sqlite.Éste eselarchivoqueusaremosparaanalizarlosdatos.Conesearchivo,elanálisisde datosserealizarámuyrápidamente.

Elprimerymássencilloanálisisdedatosconsistiráendeterminar“¿Quiénha enviadomáscorreos?”,y“¿Quéorganizaciónhaenviadomáscorreos?”.Estose realizaráusando gbasic.py:

Howmanytodump?5 Loadedmessages=51330subjects=25033senders=1584

Top5Emaillistparticipants steve.swinsburg@gmail.com2657 azeckoski@unicon.net1742 ieb@tfd.co.uk1591 csev@umich.edu1304 david.horwitz@uct.ac.za1184

Top5Emaillistorganizations gmail.com7339 umich.edu6243 uct.ac.za2451 indiana.edu2258 unicon.net2055

Fijatecómo gbasic.py funcionamuchomásrápidoque gmane.py,einclusoque gmodel.py.Todostrabajanconlosmismosdatos,pero gbasic.py estáusandolos datoscomprimidosynormalizadosde index.sqlite.Sitienesunmontóndedatos quegestionar,unprocesomultipasocomoelqueserealizaenestaaplicaciónpuede sermáslargodedesarrollar,peroteahorraráunmontóndetiempocuandorealmentecomiencesaexploraryvisualizarlosdatos.

Puedesgenerarunavistasencillaconlafrecuenciadecadapalabraenlaslíneas detítulo,usandoelarchivo gword.py:

Rangeofcounts:33229129 Outputwrittentogword.js

Estogeneraelarchivo gword.js,quepuedesvisualizarutilizando gword.htm para producirunanubedepalabrassimilaraladelcomienzodeestasección.

gline.py generatambiénunasegundavista.Enestecasocuentalaparticipación enformadecorreosdelasorganizacionesalolargodeltiempo.

Loadedmessages=51330subjects=25033senders=1584

Top10Oranizations

234 CHAPTER16.VISUALIZACIÓNDEDATOS

['gmail.com','umich.edu','uct.ac.za','indiana.edu', 'unicon.net','tfd.co.uk','berkeley.edu','longsight.com', 'stanford.edu','ox.ac.uk'] Outputwrittentogline.js

Suresultadoesguardadoen gline.js,quesepuedevisualizarusando gline.htm

Figure16.4:ActividaddeCorreodeSakaiporOrganización

Estaaplicaciónesrelativamentecomplejaysofisticada,ydisponedecaracterísticas pararealizarrecuperacióndedatosreales,limpiezayvisualización.

16.3.VISUALIZACIÓNDEDATOSDECORREO 235
236 CHAPTER16.VISUALIZACIÓNDEDATOS

AppendixA Colaboraciones

A.1ContributorListforPythonparatodos

JuanCarlosPerezCastellanos,JuanDougnac,DanielMerinoEcheverría,Jaime BermeoRamírez,andFernandoTardío.

A.2ContributorListforPythonforEverybody

ElliottHauser,StephenCatto,SueBlumenberg,TamaraBrunnock,MihaelaMack, ChrisKolosiwsky,DustinFarley,JensLeerssen,NaveenKT,MirzaIbrahimovic, Naveen(@togarnk),ZhouFangyi,AlistairWalsh,EricaBrody,Jih-ShengHuang, LouisLuangkesorn,andMichaelFudge

Youcanseecontributiondetailsat:

https://github.com/csev/py4e/graphs/contributorshttps://github.com/cseves/py4e/graphs/contributors

BruceShieldsforcopyeditingearlydrafts,SarahHegge,StevenCherry,Sarah KathleenBarbarow,AndreaParker,RadaphatChongthammakun,MeganHixon, KirbyUrner,SarahKathleenBarbrow,KatieKujala,NoahBotimer,Emily Alinder,MarkThompson-Kular,JamesPerry,EricHofer,EytanAdar,Peter Robinson,DeborahJ.Nelson,JonathanC.Anthony,EdenRassette,Jeannette Schroeder,JustinFeezell,ChuanqiLi,GeraldGordinier,GavinThomasStrassel, RyanClement,AlissaTalley,CaitlinHolman,Yong-MiKim,KarenStover, CherieEdmonds,MariaSeiferle,RomerKristiD.Aranas(RK),GrantBoyer,and HedemarrieDussan.

formáticos”
A.3Listadecolaboradoresde“PythonparaIn-
237

A.4Prefaciopara“ThinkPython”

Laextrañahistoriade“ThinkPython”

(AllenB.Downey)

EnEnerode1999,estabapreparándomeparaenseñarunaclasedeintroducciónala programaciónenJava.Habíaimpartidoelcursotresvecesymeestabafrustrando. Latasadefracasoenlaclaseerademasiadoaltae,inclusoaquellosestudiantes queaprobaban,lohacíanconunnivelgeneraldeconocimientosdemasiadobajo.

Medicuentadequeunodelosproblemaseranloslibros.Erandemasiadograndes, condemasiadosdetallesinnecesariosdeJava,ysinsuficienteorientacióndealto nivelsobrecómoprogramar.Ytodosellossufríanelmismoefectotrampilla: comenzabansiendomuyfáciles,avanzabanpocoapoco,yenalgúnlugaralrededor delCapítulo5elsuelodesaparecía.Losestudiantesrecibíandemasiadomaterial nuevodemasiadorápido,yyoteníaquepasarelrestodelsemestrerecogiendolos pedazos.

Dossemanasantesdelprimerdíadeclase,decidíescribirmipropiolibro.Mis objetivoseran:

•Hacerlobreve.Paralosestudiantesesmejorleer10páginasquenotener queleer50.

•Sercuidadosoconelvocabulario.Intentéminimizarlajergaydefinircada términoalusarlolaprimeravez.

•Construirpocoapoco.Paraevitarlastrampillas,tomélostemasmásdifícilesylosdividíenunaseriedepasosmáspequeños.

•Enfocarloalaprogramación,noallenguajedeprogramación.IncluíelsubconjuntodeJavamínimoimprescindibleyexcluíelresto.

Necesitabauntítulo,demodoqueelegícaprichosamente HowtoThinkLikea ComputerScientist (Cómopensarcomouninformático).

Miprimeraversióneratosca,perofuncionaba.Losestudianteslaleían,ycomprendíanlosuficientecomoparaquepudieraempleareltiempodeclaseentratar lostemasdifíciles,lostemasinteresantesy(lomásimportante)dejara losestudiantespracticar.

PubliquéellibrobajoLicenciadeDocumentaciónLibreGNU(GNUFree DocumentationLicense),quepermitealosusuarioscopiar,modificary distribuirellibro.

Loquesucediódespuéseslapartedivertida.JeffElkner,unprofesordeescuela secundariadeVirginia,adoptómilibroylotradujoparaPython.Meenvióuna copiadesutraducción,ytuvelainusualexperienciadeaprenderPythonleyendo mipropiolibro.

Jeffyyorevisamosellibro,incorporamosuncasoprácticorealizadoporChriss Meyers,yen2001publicamos HowtoThinkLikeaComputerScientist:LearningwithPython (Cómopensarcomouninformático:AprendiendoconPython),

238 APPENDIXA.COLABORACIONES

tambiénbajoLicenciadeDocumentaciónLibreGNU(GNUFreeDocumentation License).Publiquéellibrocomo GreenTeaPress ycomencéavendercopias enpapelatravésdeAmazon.comylibreríasuniversitarias.Hayotroslibros de GreenTeaPress disponiblesen greenteapress.com

En2003,comencéaimpartirclasesenelOlinCollegeytuvequeenseñarPython porprimeravez.ElcontrasteconJavafuenotable.Losestudiantesseteníanque esforzarmenos,aprendíanmás,trabajabanenproyectosmásinteresantes,yen generalsedivertíanmuchomás.

Durantelosúltimoscincoañoshecontinuadodesarrollandoellibro,corrigiendo errores,mejorandoalgunosdelosejemplosyañadiendomaterial,especialmente ejercicios.En2008empecéatrabajarenunarevisióngeneral—almismotiempo, sepusoencontactoconmigouneditordelaCambridgeUniversityPressinteresado enpublicarlasiguienteedición.¡Quéoportuno!

Esperoquedisfrutesconestelibro,yqueteayudeaaprenderaprogramarya pensar,almenosunpoquito,comouninformático.

Agradecimientospor“ThinkPython”

(AllenB.Downey)

Loprimeroymásimportante,miagradecimientoaJeffElknerporhabertraducido milibrodeJavaaPython,yaqueesofueloquehizocomenzaresteproyectoyme introdujoenelquesehaconvertidoenmilenguajedeprogramaciónfavorito.

QuierodarlasgraciastambiénaChrisMeyers,quehacontribuídoenvariasseccionesde HowtoThinkLikeaComputerScientist

Yagradezcoala FreeSoftwareFoundation (FundacióndeSoftwareLibre)por haberdesarrolladola GNUFreeDocumentationLicense,quehaayudadoaque micolaboraciónconJeffyChrisfueraposible.

TambienquieroagradeceraloseditoresdeLuluquetrabajaronen HowtoThink LikeaComputerScientist

Doylasgraciasatodoslosestudiantesquetrabajaronconlasprimerasversiones deestelibroyatodosloscolaboradores(listadosenunApéndice)quehanenviado correccionesysugerencias.

Yquierodarlasgraciasamimujer,Lisa,porsutrabajoenestelibro,en Green TeaPress,yportodolodemás,también.

AllenB.Downey

NeedhamMA

AllenDowneyesunProfesorAsociadodeInformáticaenel FranklinW.Olin CollegeofEngineering.

(AllenB.Downey)

A.5.LISTADECOLABORADORESDE“THINKPYTHON” 239
A.5Listadecolaboradoresde“ThinkPython”

Másde100lectoresperspicacesyatentosmehanenviadosugerenciasycorrecciones alolargodelosúltimosaños.Sucontribuciónyentusiasmoporesteproyecto han resultadodegranayuda.

Paraconocerlosdetallessobrelanaturalezadecadaunadelascontribucionesde estaspersonas,miraeneltextode“ThinkPython”.

LloydHughAllen,YvonBoulianne,FredBremmer,JonahCohen,MichaelConlon,BenoitGirard,CourtneyGleasonandKatherineSmith,LeeHarr,James Kaylin,DavidKershaw,EddieLam,Man-YongLee,DavidMayo,ChrisMcAloon, MatthewJ.Moelter,SimonDiconMontford,JohnOuzts,KevinParks,David Pool,MichaelSchmitt,RobinShaw,PaulSleigh,CraigT.Snydal,IanThomas, KeithVerheyden,PeterWinstanley,ChrisWrobel,MosheZadka,ChristophZwerschke,JamesMayer,HaydenMcAfee,AngelArnal,TauhidulHoqueandLex Berezhny,Dr.MicheleAlzetta,AndyMitchell,KalinHarvey,ChristopherP.Smith, DavidHutchins,GregorLingl,JuliePeters,FlorinOprina,D.J.Webre,Ken, IvoWever,CurtisYanko,BenLogan,JasonArmstrong,LouisCordier,Brian Cain,RobBlack,Jean-PhilippeReyatEcoleCentraleParis,JasonMaderat GeorgeWashingtonUniversitymadeanumberJanGundtofte-Bruun,AbelDavid andAlexisDinno,CharlesThayer,RogerSperberg,SamBull,AndrewCheung, C.CoreyCapel,Alessandra,WimChampagne,DouglasWright,JaredSpindor, LinPeiheng,RayHagtvedt,TorstenHübsch,IngaPetuhhov,ArneBabenhauserheide,MarkE.Casida,ScottTyler,GordonShephard,AndrewTurner,Adam Hobart,DarylHammondandSarahZimmerman,GeorgeSass,BrianBingham, LeahEngelbert-Fenton,JoeFunke,Chao-chaoChen,JeffPaine,LubosPintes, GreggLindandAbigailHeithoff,MaxHailperin,ChotipatPornavalai,Stanislaw Antol,EricPashman,MiguelAzevedo,JianhuaLiu,NickKing,MartinZuther, AdamZimmerman,RatnakarTiwari,AnuragGoel,KelliKratzer,MarkGriffiths, RoydanOngie,PatrykWolowiec,MarkChonofsky,RussellColeman,WeiHuang, KarenBarber,NamNguyen,StéphaneMorin,FernandoTardío,yPaulStoop.

240 APPENDIXA.COLABORACIONES

DetallesdelCopyright

Estetrabajoestádistribuidobajounalicencia

Attribution-NonCommercial-ShareAlike3.0UnportedLicense

Esalicenciaestádisponibleen

creativecommons.org/licenses/by-nc-sa/3.0/

HubiéramospreferidopublicarellibrobajolalicenciaCC-BY-SA,queesmenos restrictiva.Pero,pordesgracia,existenunaspocasorganizacionessinescrúpulos quebuscanyencuentranlibrosconlicenciaslibresyluegolospublicanyvenden copiasvirtualmenteidénticasdeesoslibrosenunserviciódeimpresiónbajodemanda,comoLuluoCreateSpace.CreateSpacehaañadido(afortunadamente) unanormaquedapreferenciaalosdeseosdeltitularrealdelcopyrightsobreun titularsinderechosquepretendapublicaruntrabajoconlicencialibre.Pordesgracia,existenmuchosserviciosdeimpresiónbajodemandaymuypocostienen unasnormastanconsideradascomoCreateSpace.

Conpesar,heañadidoelelementoNCalalicenciadeestelibroparapoderrecurrir encasodequealguienintenteclonarellibroyvenderlocomercialmente.Por desgracia,alañadirNCselimitanotrosusosdeestematerialquesímegustaría permitir.Demodoqueheañadidoestaseccióndeldocumentoparadescribir aquellassituacionesespecíficasdeusodelmaterialdeestelibroquealgunospodrían considerarcomercialesyparalascualesdoymipermisoporadelantado.

•Siimprimesunnúmerolimitadodecopiasdetodoopartedeestelibropara usarenuncurso(esdecir,comomaterialparaelcurso),entoncestienes concedidalicenciaCC-BYparausarestematerialparaesepropósito.

•Sieresprofesordeunauniversidad,traducesestelibroaunidiomadistinto delinglésyloutilizasparaenseñar,puedescontactarconmigoyteconcederé unalicenciaCC-BY-SAparaestosmateriales,conrespectoalapublicación detutraducción.Enparticular,tendráspermisoparavendercomercialmente ellibrotraducidoresultante.

Siestásinteresadoentraducirellibro,puedesponerteencontactoconmigopara asegurarnosdequetienestodoslosmaterialesrelacionadosconelcurso,paraque puedastraducirlostambién.

AppendixB
241

Porsupuesto,estásinvitadoaponerteencontactoconmigoypedirmepermisosi estasclausulasnosonsuficientes.Encualquiercaso,elpermisoparareutilizar yremezclarestematerialestáconcedidosiemprequeseproduzcaunclarovalor añadidoobeneficioparalosestudiantesoprofesoresqueseunancomoresultado delnuevotrabajo.

CharlesSeverance www.dr-chuck.com AnnArbor,MI,USA 9deSeptiembrede2013

242 APPENDIXB.DETALLESDELCOPYRIGHT

Index

índice, 79, 109, 113, 223 índices basededatos, 199 ítem, 79 único, 125 abrirfunción, 82 abrirfuncion, 89 acceso, 96 actualización, 59 actualizacion item, 97 actualizar rebanado, 98 acumulador, 67 sum, 64 agregarmetodo, 105 aleatorio,número, 48 algoritmo, 55 alias, 103, 104, 109 copiasparaevitar, 107 referencia, 104 ambiciosa, 149 ambicioso, 139 análisis HTML, 161 análisisHTML, 159 and,operador, 34 anidado,condicional, 37, 42 anidados bucles, 121 API, 174 key, 174 appendmetodo, 98 archivo, 81 abrir, 82 escritura, 90 lectura, 84 archivobinario, 157 archivodetexto, 91 argumento, 45, 49, 52, 53, 55, 104 opcional, 75, 101

argumentoclave, 127 argumentodefunción, 52 argumentoopcional, 75 aritmético,operador, 22 asignación, 29, 95 item, 72 sentencia, 20 asignaciónde tuplas, 128 asignacióndeobjeto, 126 asignaciónitem, 72 asignaciónportuplas, 134 asignacionde elementos, 96 asignaciondeelementos, 96 atributo, 197, 223 búsqueda, 121 regex, 137 bandera, 79 basededatos, 199 BeautifulSoup, 161, 164, 187 bisección,depuraciónpor, 66 booleana,expresión, 33, 43 booleanooperador, 73 booleano,tipo, 33 break,sentencia, 61 bucle, 60 for, 70, 96 infinito, 60, 67 mínimo, 65 máximo, 65 recorrido, 70 while, 59 buclefor, 70, 96 bucles anidados, 117 ydiccionarios, 118 buclesanidados, 117, 121 buclesy diccionarios, 118 bug, 17

243

BY-SA, iv

códigofuente, 17 códigomáquina, 17 cabecera, 49, 55 cache, 225 cadena, 19, 30, 101, 133 comparacion, 73 inmutable, 72 método, 74 operación, 25 rebanado, 71 split, 143 cadenaaformatear, 79 cadenarepresentacion, 91 cadenavacía, 79 cadenavacia, 102 carácter, 69 carácterfinaldelinea, 91 catch, 91 CC-BY-SA, iv celsius, 39 cero,índiceempezandodesde, 69 cero,indicecomenzandocon, 96 cerrarmetodo, 91 choice,función, 49 ciclodevidadelobjeto, 193 clase, 197 clasehija, 197 clasepadre, 197 class, 191 float, 19 int, 19 str, 19 clave, 113, 121 argumento, 127 claveforánea, 223 clavelógica, 223 claveprimaria, 223 clave-valorpar, 113 claves métodode, 118 codicioso, 159 coincidenciaambiciosa, 149 colaboradores, 239 comentarios, 26, 30 comillas, 19, 20, 71 comodín, 138, 149 comparable, 125, 134 comparación operador, 33

tupla, 126 comparacion cadena, 73 compilar, 17 composición, 52, 55 compuesta,sentencia, 34, 43 concatenación, 25, 30 concatenacion, 72, 102 lista, 97, 105 condición, 34, 42, 60 condicional anidado, 37, 42 ejecución, 34 encadenado, 36, 42 sentencia, 34, 43 connect función, 201 construct, 191 constructor, 193, 197 contador, 67, 72, 79, 84, 115 contandoeiterando, 72 continue,sentencia, 62 ControldeCalidad, 89 Controldecalidad, 92 controldeflujo, 156 conversión tipo, 46 conversióndetemperatura, 39 copia rebanado, 71, 98 copias paraevitaralias, 107 corchete operador, 126 corchetes, 113 cortocircuito, 40, 43 CPU, 17 CreativeCommonsLicense, iv cuentamétodo, 76 cuerpo, 43, 49, 55, 60 curl, 164 cursor, 223 función, 201 demodelado error, 133 deordenamiento método, 126 decorate-sort-undecorate patrón, 127 decrementar, 59

244 INDEX

decremento, 67 def,palabraclave, 49 definición función, 49 deloperador, 99 delimitador, 101, 109 depuración, 29, 41, 55, 66, 78, 121, 133 porbisección, 66 depuraciónexperimental, 15 depuracion, 91, 106 depurando, 15 destructor, 193, 197 determinístico, 48, 55 diccionario, 113, 121, 129 dict

función, 113 dir, 192 direccióne-mail, 129 dispersable, 125 dispersar, 134 división

entera, 23, 30, 42 punto-flotante, 23 divisibilidad, 24 divisionmetodo, 101 dos-puntos, 49 DSU patrón, 127 ejecuciónalternativa, 36 elemento, 95, 109 diccionario, 122 elementoeliminación, 99 ElementTree, 168, 174 find, 168 findall, 169 fromstring, 168 get, 169 elif,palabraclave, 36 eliminación,elementodelista, 99 else,palabraclave, 36 encadenado,condicional, 36, 42 encapsulación, 72 encontrar cadena, 138 entera,división, 23, 42 entero, 30 entradadesdeteclado, 25 equivalencia, 103 equivalente, 109 error

runtime, 29, 42 semántico, 20, 29 sintaxis, 29 errordemodelado, 133 errorsemántico, 17 errortipográfico, 15 espacioenblanco, 41, 55 espacioenblanco, 91 especialvalor None, 99 estéril,función, 53, 56 establecermiembro, 115 estilo, 106 estructuradedatos, 133, 134 estructurar, 121 evaluar, 23, 30 excepción

TypeError, 126 ValueError, 129 excepcion IndexError, 96 IOError, 89 exception, 29 IndexError, 70 OverflowError, 42 TypeError, 69, 72, 77 ValueError, 26 expresión, 22, 23, 30 booleana, 33, 43 for, 70 expresionesregulares, 137 extendermetodo, 98 eXtensibleMarkupLanguage, 175

fahrenheit, 39 False,valorespecial, 33 filtropatron, 85 findall, 140 floattype, 19 float,función, 46 flujodeejecución, 51, 56, 60 for,sentencia, 62 formatocadena, 77 formatooperador, 77 frecuencia, 116 frecuencialetras, 135 FreeDocumentationLicense,GNU, 238, 239 función, 49, 56 abrir, 82 choice, 49

INDEX 245

float, 46 int, 46 log, 47 math, 47 print, 17 randint, 48 random, 48 raw, 25 sqrt, 47 str, 46 funciónconnect, 201 funcióncursor, 201 funcióndict, 113 funciónesteril, 53 funciónhash, 122 funciónlen, 114 funciónproductiva, 53 funciónreversed, 133 funciónsorted, 133 funcióntupla, 126 función,definición, 49, 50, 55, 56 función,llamadaa, 45, 56 función,objeto, 50 función,razonespara, 54 función,trigonométrica, 47 funcion

abrir, 89 lista, 101 repr, 91 function len, 70 geocoding, 175 get método, 116 GNUFreeDocumentationLicense, 238, 239 Google, 175 mapa, 225 rangodepáginas, 228 grep, 147, 149 guardián,patrón, 40, 43 guión-bajo,carácter, 21

hardware, 3 arquitectura, 3 hashable, 132, 134 herencia, 197 histograma, 116, 122 HTML, 161, 187 idéntico, 109

identidad, 103 idioma, 116, 118 if,sentencia, 34 imagen

urllib, 154 immutability, 79 implementación, 115, 122 import,sentencia, 56 in operador, 114 inoperador, 73 incrementar, 59 incremento, 67 indentado, 49 index, 69, 96 comenzandoconcero, 96 empezandodesdecero, 69 negative, 70 IndexError, 70, 96 indicador, 25 indicadordelíneadecomandos, 17 indice rebanado, 71, 98 indices recorriendocon, 97 infinito,bucle, 60, 67 inicialización(antesdeactualizar), 59 inicializar variable, 67 inmutabilidad, 72, 104, 125, 133 instance, 191 instancia, 197 inttype, 19 int,función, 46 interactivo,modo, 22, 53 intercambio patrón, 128 interpretar, 17 invocación, 74, 79 IOError, 89 is

operador, 103 item, 72, 95 itemactualizacion, 97 items método, 129 iteración, 59, 67 iterando concadenas, 72 iterandoycontando, 72

246 INDEX

JavaScriptObjectNotation, 170, 174 jpg, 154 imagen, 154 JSON, 170, 174 juntarmetodo, 102

KeyError, 114 excepción, 114 lógico,operador, 33, 34 len función, 114 lenfunction, 70 lenguaje programación, 5 lenguajedealtonivel, 17 lenguajedebajonivel, 17 lenguajedeprogramación, 5 letras frecuencia, 135 limitaruso, 175 listobject, 186 lista, 95, 101, 109, 133 anidada, 95, 97 argumento, 104 concatenacion, 97, 105 copia, 98 elemento, 96 funcion, 101 indice, 96 membresia, 96 metodo, 98 operaciones, 97 rebanado, 98 recorrido, 96 repeticion, 97 vacía, 95 listaanidada, 95, 97, 109 listavacía, 95 listas comoargumento, 104 log,función, 47

método, 74, 79, 197 cadena, 79 cuenta, 76 pop, 99 remover, 99 métodocadena, 79 métododeclaves, 118 métododeordenamiento, 126

métodoget, 116 métodoitems, 129 métodosplit, 129 métodovalores, 114 módulo, 47, 56 random, 48 módulore, 137 módulosqlite3, 201 módulo,objeto, 47 módulo,operador, 24, 30 manejadorarchivo, 82 math,función, 47 membresia lista, 96 memoriaprincipal, 17 memoriasecundaria, 17, 81 mensaje, 197 mensajedeerror, 20, 29 metodo

agregar, 105 append, 98 cerrar, 91 division, 101 extender, 98 juntar, 102 ordenar, 99 vacío, 99 metodoordenamiento, 106 metodo,lista, 98 miembro diccionario, 114 establecer, 115 mnemónico, 27, 30 modelado, 134 modointeractivo, 6, 17 mutabilidad, 72, 96, 98, 104, 125, 133

número,aleatorio, 48 navegadordebasededatos, 223 negativeindex, 70 no-codicioso, 159 Nonevalorespecial, 99 None,valorespecial, 53, 65 normalización, 223 normalizacióndebasesdedatos, 223 not,operador, 34 notacióndelpunto, 74 notaciónpunto, 47

OAuth, 174 object, 191

INDEX 247

objeto, 79, 103, 109, 197 asignaciónde, 126 función, 50 opcionalargumento, 101 operador, 30 and, 34 aritmético, 22 booleano, 73 cadena, 25 comparación, 33 corchete, 69, 96 del, 99 formato, 77, 79 in, 73, 96 lógico, 33, 34 módulo, 24, 30 not, 34 or, 34 rebanado, 71, 98 operadorcorchete, 69, 96, 126 operadorformato, 79 operadorin, 96, 114 operadoris, 103 operadorrebanado, 105, 126 operando, 22, 30 or,operador, 34 ordendeoperaciones, 24, 29 ordenamiento metodo, 106 ordenarmetodo, 99 orientadaaobjetos, 185 OverflowError, 42

palabraclave, 21, 30 def, 49 elif, 36 else, 36 palabraclaveclass, 190 parclave-valor, 122, 129 parámetro, 52, 56 defunción, 52 paréntesis argumentoin, 45 expresiónregular, 143, 159 invalidarprecedencia, 24 parámetrosentre, 52 tuplas, 125 vacío, 74 vacíos, 49 parametro, 104 parsear, 17

parsing HTML, 187 pass,sentencia, 35 patrón búsqueda, 79 guardián, 40, 43, 79 patróndebúsqueda, 79 patróndecorate-sort-undecorate, 127 patrónDSU, 127, 134 patrónguardián, 79 patrónintercambio, 128 patron filtro, 85 PEMDSR, 24 persistencia, 81 pi, 47 plandedesarrollo programacióndepaseoaleatorio, 15 popmétodo, 99 portabilidad, 17 precedencia, 31 print(función), 17 productiva,función, 53, 56 programa, 12, 17 programacióndepaseoaleatorio, 15 prompt, 17 pruebaconsistencia, 121 pruebasanidad, 121 pseudoaleatorio, 48, 56 puerto, 164 punto,notación, 56 punto-flotante, 30 punto-flotante,división, 23 puntossuspensivos, 49 Python2, 23 Python3, 23 Python3.0, 25 Pythonic, 90, 92

QA, 89, 92 radián, 47 rama, 36, 43 randint,función, 48 random,función, 48 random,módulo, 48 rangodepáginas Visualización, 228 rascado, 164 web, 159 rastrear, 164

248 INDEX

raw, 25 rebanado, 79 actualizar, 98 cadena, 71 copia, 71, 98 lista, 98 operador, 105, 126 tupla, 126 rebanadooperador, 71, 98 recorrer diccionario, 130 recorrido, 70, 79, 116, 118, 127 lista, 96, 109 recorridode diccionario, 130 recorriendo conindices, 97 redes Visualización, 228 referencia, 104, 109 regex, 137 comodín, 138 conjuntosdecaracteres(corchetes), 141 findall, 140 paréntesis, 143, 159 reglasdeprecedencia, 24, 31 relación, 223 removermétodo, 99 repeticion lista, 97 reprfuncion, 91 resolucióndeunproblema, 4, 17 restricción, 224 reunir, 134 reversed función, 133 RomeoyJulieta, 110, 117, 119, 127, 131 runtimeerror, 29, 42

saltodelínea, 26, 92 saltodelinea, 83, 90 script, 10 script,modo, 22, 53 secuencia, 69, 79, 95, 101, 125, 133 secuenciadeformato, 77, 79 semántica, 17 semántico,error, 20, 29 sensibilidadamayúsculas,nombresde variables, 29 sentencia, 22, 31

asignación, 20 break, 61 compuesta, 34, 43 condicional, 34, 43 continue, 62 for, 62, 96 if, 34 import, 56 pass, 35 try, 89 while, 59 ServiceOrientedArchitecture, 175 sine,función, 47 singleton, 134 sintaxis,error, 29 SOA, 175 socket, 164 sorted función, 133 split método, 129 sqlite3 módulo, 201 sqrt,función, 47 str,función, 46 string startswith, 138 stringtype, 19

tablahash, 115, 122 time, 155 time.sleep, 155 tipo, 19, 31 archivo, 81 booleano, 33 dict, 113 tupla, 125 tipo,conversiónde, 46 traceback, 38, 41, 43 trigonométrica,función, 47 True,valorespecial, 33 trysentencia, 89 tupla, 125, 133, 134, 224 único, 125 asignación, 134 comoclaveendiccionario, 132 comparación, 126 entrecorchetes, 132 función, 126 rebanado, 126 tuplas

INDEX 249

asignaciónde, 128 type, 19, 192 lista, 95 TypeError, 69, 72, 77, 126

Unicode, 204 unidadcentraldeprocesamiento, 17 usebeforedef, 29, 51

vacíometodo, 99 vacia cadena, 102 valor, 19, 31, 103, 122 valorderetorno, 45, 56 valorespecial False, 33 None, 53, 65, 99 True, 33 valores método, 114 ValueError, 26, 129 variable, 20, 31 actualización, 59 Visualización mapa, 225

webservice, 175 wget, 164 while,bucle, 59 while,sentencia, 59

XML, 175

250 INDEX
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.