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’)
sí
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&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