python para todos repasa aspectos esenciales de

220

Upload: others

Post on 31-Jul-2022

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Python para todos repasa aspectos esenciales de
Page 3: Python para todos repasa aspectos esenciales de

Python para todos es un tutorial básico del lenguaje de programación Pythonescrito por Raúl González Duque y distribuido gratuitamente bajo licenciaCreativeCommons.Adecuadoparacualquiernivel,Pythonparatodosrepasaaspectosesencialesdeeste lenguaje: tipos básicos, control de flujo, funciones, orientación a objetos,programaciónfuncional,excepciones,entrada/salida,etcétera.La introducción te permitirá conocer las características principales de Python,cómoinstalarloyporquéhacerlo.

Page 4: Python para todos repasa aspectos esenciales de

RaúlGonzálezDuque

Pythonparatodos

ePubr1.0Titivillus10.12.2017

Page 5: Python para todos repasa aspectos esenciales de

Títulooriginal:PythonparatodosRaúlGonzálezDuque,2008Imagendeportada:IanChien

Editordigital:TitivillusePubbaser1.2

Page 6: Python para todos repasa aspectos esenciales de

PythonparatodosporRaúlGonzálezDuque

Este libro se distribuye bajo una licencia Creative Commons Reconocimiento2.5España.Ustedeslibrede:

copiar,distribuirycomunicarpúblicamentelaobra

hacerobrasderivadas

Page 7: Python para todos repasa aspectos esenciales de

Bajolascondicionessiguientes:

Reconocimiento.Debereconocerydarcréditoalautororiginal(RaúlGonzálezDuque)

Puede descargar la versiónmás reciente de este libro gratuitamente en lawebhttp://mundogeek.net/tutorial-python/

LaimagendeportadaesunafotografíadeunapitónverdedelaespecieMoreliaviridis cuyo autor es Ian Chien. La fotografía está licenciada bajo CreativeCommonsAttributionShareAlike2.0

Page 8: Python para todos repasa aspectos esenciales de

INTRODUCCIÓN

Page 9: Python para todos repasa aspectos esenciales de

¿QuéesPython?Python es un lenguaje de programación creado por Guido van Rossum aprincipios de los años 90 cuyo nombre está inspirado en el grupo de cómicosingleses “MontyPython”.Esun lenguaje similar aPerl, pero conuna sintaxismuylimpiayquefavoreceuncódigolegible.Se trata de un lenguaje interpretado o de script, con tipado dinámico,fuertementetipado,multiplataformayorientadoaobjetos.

LenguajeinterpretadoodescriptUn lenguaje interpretado o de script es aquel que se ejecuta utilizando unprograma intermedio llamado intérprete, en lugar de compilar el código alenguaje máquina que pueda comprender y ejecutar directamente unacomputadora(lenguajescompilados).Laventajade los lenguajescompiladosesquesuejecuciónesmásrápida.Sinembargoloslenguajesinterpretadossonmásflexiblesymásportables.

Page 10: Python para todos repasa aspectos esenciales de

Python tiene, no obstante, muchas de las características de los lenguajescompilados, por lo que se podría decir que es semi interpretado. En Python,comoenJavaymuchosotroslenguajes,elcódigofuentesetraduceaunpseudocódigo máquina intermedio llamado bytecode la primera vez que se ejecuta,generando archivos .pyc o .pyo (bytecode optimizado), que son los que seejecutaránensucesivasocasiones.

TipadodinámicoLacaracterísticadetipadodinámicoserefiereaquenoesnecesariodeclarareltipo de dato que va a contener una determinada variable, sino que su tipo sedeterminaráentiempodeejecuciónsegúneltipodelvaloralqueseasigne,yeltipodeestavariablepuedecambiarsiseleasignaunvalordeotrotipo.

FuertementetipadoNosepermitetrataraunavariablecomosifueradeuntipodistintoalquetiene,es necesario convertir de forma explícita dicha variable al nuevo tipopreviamente. Por ejemplo, si tenemos una variable que contiene un texto(variabledetipocadenaostring)nopodremostratarlacomounnúmero(sumarlacadena“9”yelnúmero8).Enotroslenguajeseltipodelavariablecambiaríapara adaptarse al comportamiento esperado, aunque esto es más propenso aerrores.

MultiplataformaEl intérprete de Python está disponible en multitud de plataformas (UNIX,Solaris,Linux,DOS,Windows,OS/2,MacOS,etc.)porloquesinoutilizamoslibreríasespecíficasdecadaplataformanuestroprogramapodrácorrerentodosestossistemassingrandescambios.

OrientadoaobjetosLa orientación a objetos es un paradigma de programación en el que losconceptosdelmundorealrelevantesparanuestroproblemasetrasladanaclasesyobjetosennuestroprograma.Laejecucióndelprogramaconsisteenunaseriedeinteraccionesentrelosobjetos.Pythontambiénpermite laprogramaciónimperativa,programaciónfuncionalyprogramaciónorientadaaaspectos.

Page 11: Python para todos repasa aspectos esenciales de

¿PorquéPython?Pythonesun lenguajeque todoelmundodebería conocer.Su sintaxis simple,claray sencilla; el tipadodinámico, el gestordememoria, lagran cantidaddelibreríasdisponiblesylapotenciadellenguaje,entreotros,hacenquedesarrollarunaaplicaciónenPythonseasencillo,muyrápidoy,loqueesmásimportante,divertido.La sintaxis de Python es tan sencilla y cercana al lenguaje natural que losprogramaselaboradosenPythonparecenpseudocódigo.Porestemotivosetrataademásdeunodelosmejoreslenguajesparacomenzaraprogramar.Pythonnoesadecuadosinembargopara laprogramacióndebajoniveloparaaplicacionesenlasqueelrendimientoseacrítico.Algunos casos de éxito en el uso de Python son Google, Yahoo, la NASA,IndustriasLight&Magic, y todas las distribucionesLinux, en las quePythoncadavezrepresentauntantoporcientomayordelosprogramasdisponibles.

Page 12: Python para todos repasa aspectos esenciales de

InstalacióndePythonExisten varias implementaciones distintas de Python: CPython, Jython,IronPython,PyPy,etc.CPythones lamásutilizada, lamás rápiday lamásmadura.Cuando lagentehabladePythonnormalmenteserefiereaestaimplementación.EnestecasotantoelintérpretecomolosmódulosestánescritosenC.JythoneslaimplementaciónenJavadePython,mientrasqueIronPythonessucontrapartida en C# (.NET). Su interés estriba en que utilizando estasimplementaciones se pueden utilizar todas las librerías disponibles para losprogramadoresdeJavay.NET.PyPy, por último, como habréis adivinado por el nombre, se trata de unaimplementaciónenPythondePython.CPythonestáinstaladopordefectoenlamayorpartedelasdistribucionesLinuxyenlasúltimasversionesdeMacOS.Paracomprobarsiestáinstaladoabreunaterminalyescribepython.Siestáinstaladoseiniciarálaconsolainteractivade

Page 13: Python para todos repasa aspectos esenciales de

Pythonyobtendremosalgoparecidoalosiguiente:Python2.5.1(r251:54863,May22007,16:56:35)

[GCC4.1.2(Ubuntu4.1.2-0ubuntu4)]onlinux2

Type“help”,“copyright”,“credits”or“license”formoreinformation.

>>>

LaprimeralíneanosindicalaversióndePythonquetenemosinstalada.Alfinalpodemos ver el prompt (>>>) que nos indica que el intérprete está esperandocódigodelusuario.Podemossalirescribiendoexit(),opulsandoControl+D.Sinotemuestraalgoparecidonotepreocupes,instalarPythonesmuysencillo.PuedesdescargarlaversióncorrespondienteatusistemaoperativodesdelawebdePython,enhttp://www.python.org/download/.ExisteninstaladoresparaWindowsyMacOS.SiutilizasLinuxesmuyprobableque puedas instalarlo usando la herramienta de gestión de paquetes de tudistribución,aunquetambiénpodemosdescargarlaaplicacióncompiladadesdelawebdePython.

Page 14: Python para todos repasa aspectos esenciales de

HerramientasbásicasExistendosformasdeejecutarcódigoPython.Podemosescribirlíneasdecódigoen el intérprete y obtener una respuesta del intérprete para cada línea (sesióninteractiva)obienpodemosescribirelcódigodeunprogramaenunarchivodetextoyejecutarlo.A la hora de realizar una sesión interactiva os aconsejo instalar y utilizariPython, en lugar de la consola interactiva de Python. Se puede encontrar enhttp://ipython.scipy.org/. iPython cuenta con características añadidas muyinteresantes, como el autocompletado o el operador ?. (para activar lacaracterísticadeautocompletadoenWindowsesnecesarioinstalarPyReadline,quepuededescargarsedesdehttp://ipython.scipy.org/moin/PyReadline/Intro)Lafuncióndeautocompletadoselanzapulsandoeltabulador.SiescribimosfiypulsamosTabnosmostraráunalistadelosobjetosquecomienzanconfi(file,filteryfinally).Siescribimosfile.ypulsamosTabnosmostraráunalistadelosmétodosypropiedadesdelobjetofile.

Page 15: Python para todos repasa aspectos esenciales de

Eloperador?nosmuestrainformaciónsobrelosobjetos.Seutilizaañadiendoelsímbolodeinterrogaciónalfinaldelnombredelobjetodelcualqueremosmásinformación.Porejemplo:

In[3]:str?

Type:type

BaseClass:

StringForm:

Namespace:Pythonbuiltin

Docstring:

str(object)->string

Returnanicestringrepresentationoftheobject.

Iftheargumentisastring,thereturnvalueisthesameobject.

En el campo de IDEs y editores de código gratuitos PyDEV(http://pydev.sourceforge.net/) se alza como cabeza de serie. PyDEV es unplugin para Eclipse que permite utilizar este IDE multiplataforma paraprogramarenPython.Cuenta conautocompletadodecódigo (con informaciónsobre cada elemento), resaltadode sintaxis, undepuradorgráfico, resaltadodeerrores,exploradordeclases,formateodelcódigo,refactorización,etc.Sindudaeslaopciónmáscompleta,sobretodosiinstalamoslasextensionescomerciales,aunquenecesitadeunacantidadimportantedememoriaynoesdeltodoestable.Otras opciones gratuitas a considerar son SPE o Stani’s Python Editor(http://sourceforge.net/projects/spe/), Eric (http://die-offenbachs.de/eric/), BOAConstructor(http://boa-constructor.sourceforge.net/)oinclusoemacsovim.Si no te importa desembolsar algo de dinero, Komodo(http://www.activestate.com/komodo_ide/) y Wing IDE(http://www.wingware.com/) son tambiénmuy buenas opciones, conmontonesde características interesantes, como PyDEV, pero mucho más estables yrobustos. Además, si desarrollas software libre no comercial puedes contactarconWingWareyobtener,conunpocodesuerte,unalicenciagratuitaparaWingIDEProfessional:)

Page 16: Python para todos repasa aspectos esenciales de

MIPRIMERPROGRAMAENPYTHON

Como comentábamos en el capítulo anterior existen dos formas de ejecutarcódigoPython,bienenunasesióninteractiva(líneaalínea)conelintérprete,obiendelaformahabitual,escribiendoelcódigoenunarchivodecódigofuenteyejecutándolo.ElprimerprogramaquevamosaescribirenPythoneselclásicoHolaMundo,yenestelenguajeestansimplecomo:

print“HolaMundo”

Vamosaprobarloprimeroenel intérprete.Ejecutapythono ipythonsegún tuspreferencias, escribe la línea anterior y pulsa Enter. El intérprete responderámostrandoenlaconsolaeltextoHolaMundo.Vamos ahora a crearun archivode texto con el código anterior, de formaquepudiéramos distribuir nuestro pequeño gran programa entre nuestros amigos.AbretueditordetextopreferidoobienelIDEquehayaselegidoycopialalínea

Page 17: Python para todos repasa aspectos esenciales de

anterior.Guárdalocomohola.py,porejemplo.Ejecutar esteprogramaes tan sencillo como indicarle el nombredel archivo aejecutaralintérpretedePython

pythonhola.py

perovamosavercómosimplificarloaúnmás.Si utilizas Windows los archivos .py ya estarán asociados al intérprete dePython, por lo que basta hacer doble clic sobre el archivo para ejecutar elprograma.Sinembargocomoesteprogramanohacemásqueimprimiruntextoenlaconsola, laejecuciónesdemasiadorápidaparapoderverlosiquiera.Pararemediarlo,vamosaañadirunanueva líneaqueespere laentradadedatosporpartedelusuario.

print“HolaMundo”

raw_input()

De esta forma se mostrará una consola con el texto Hola Mundo hasta quepulsemosEnter.Si utilizas Linux (u otro Unix) para conseguir este comportamiento, es decir,paraqueelsistemaoperativoabraelarchivo.pyconelintérpreteadecuado,esnecesarioañadirunanuevalíneaalprincipiodelarchivo:

#!/usr/bin/python

print“HolaMundo”

raw_input()

A esta línea se le conoce en el mundo Unix como shebang, hashbang osharpbang.Elpardecaracteres#!indicaalsistemaoperativoquedichoscriptsedebe ejecutar utilizando el intérprete especificado a continuación. De esto sedesprende, evidentemente, que si esta no es la ruta en la que está instaladonuestrointérpretedePython,esnecesariocambiarla.Otraopciónesutilizarelprogramaenv(deenvironment,entorno)parapreguntaralsistemaporlarutaalintérpretedePython,deformaquenuestrosusuariosnotengan ningún problema si se diera el caso de que el programa no estuvierainstaladoendicharuta:

#!/usr/bin/envpython

print“HolaMundo”

raw_input()

Por supuesto además de añadir el shebang, tendremos que dar permisos deejecuciónalprograma.

chmod+xhola.py

Page 18: Python para todos repasa aspectos esenciales de

Ylisto,sihacemosdobleclicelprogramaseejecutará,mostrandounaconsolaconeltextoHolaMundo,comoenelcasodeWindows.Tambiénpodríamoscorrer elprogramadesde la consola comosi trataradeunejecutablecualquiera:

./hola.py

Page 19: Python para todos repasa aspectos esenciales de

TIPOSBÁSICOSEnPythonlostiposbásicossedividenen:

Números,comopuedenser3(entero),15.57(decomaflotante)o7+5j(complejos)Cadenasdetexto,como“HolaMundo”Valoresbooleanos:True(cierto)yFalse(falso).

Vamosacrearunpardevariablesamododeejemplo.Unadetipocadenayunadetipoentero:

#estoesunacadena

c=“HolaMundo”

#yestoesunentero

e=23

#podemoscomprobarloconlafuncióntype

type(c)

type(e)

Page 20: Python para todos repasa aspectos esenciales de

ComoveisenPython,adiferenciademuchosotros lenguajes,nosedeclaraeltipodelavariablealcrearla.EnJava,porejemplo,escribiríamos:

Stringc=“HolaMundo”;

inte=23;

Este pequeño ejemplo también nos ha servido para presentar los comentariosinlineenPython:cadenasdetextoquecomienzanconelcarácter#yquePythonignora totalmente.Haymás tipos de comentarios, de los que hablaremosmásadelante.

Page 21: Python para todos repasa aspectos esenciales de

NúmerosComo decíamos, en Python se pueden representar números enteros, reales ycomplejos.

EnterosLosnúmerosenterossonaquellosnúmerospositivosonegativosquenotienendecimales(ademásdelcero).EnPythonsepuedenrepresentarmedianteeltipoint(deinteger,entero)oeltipolong(largo).Laúnicadiferenciaesqueeltipolongpermitealmacenarnúmerosmásgrandes.Esaconsejablenoutilizareltipolongamenosqueseanecesario,paranomalgastarmemoria.EltipointdePythonseimplementaabajonivelmedianteuntipolongdeC.YdadoquePythonutilizaCpordebajo,comoC,yadiferenciadeJava,elrangodelosvaloresquepuederepresentardependedelaplataforma.EnlamayorpartedelasmáquinasellongdeCsealmacenautilizando32bits,es decir, mediante el uso de una variable de tipo int de Python podemos

Page 22: Python para todos repasa aspectos esenciales de

almacenarnúmerosde-231a231-1,o loquees lomismo,de-2.147.483.648a2.147.483.647. En plataformas de 64 bits, el rango es de-9.223.372.036.854.775.808hasta9.223.372.036.854.775.807.El tipo long de Python permite almacenar números de cualquier precisión,estandolimitadossoloporlamemoriadisponibleenlamáquina.Alasignarunnúmeroaunavariableestapasaráatenertipoint,amenosqueelnúmeroseatangrandecomopararequerirelusodeltipolong.

#type(entero)devolveríaint

entero=23

También podemos indicar a Python que un número se almacene usando longañadiendounaLalfinal:

#type(entero)devolveríalong

entero=23L

Elliteralqueseasignaa lavariable tambiénsepuedeexpresarcomounoctal,anteponiendouncero:

#027octal=23enbase10

entero=027

obienenhexadecimal,anteponiendoun0x:#0x17hexadecimal=23enbase10

entero=0x17

RealesLos números reales son los que tienen decimales. En Python se expresanmedianteeltipofloat.Enotros lenguajesdeprogramación,comoC, tenemostambiéneltipodouble,similarafloatperodemayorprecisión(double=dobleprecisión).Python,sinembargo,implementasutipofloatabajonivelmedianteunavariabledetipodoubledeC,esdecir,utilizando64bits, luegoenPythonsiempreseutilizadobleprecisión,yenconcretosesigueelestándarIEEE754:1bitparaelsigno,11paraelexponente,y52paralamantisa.Estosignificaquelos valores que podemos representar van desde ±2,2250738585072020×10-308hasta±1,7976931348623157×10308.Lamayorpartedeloslenguajesdeprogramaciónsiguenelmismoesquemaparalarepresentacióninterna.Perocomomuchossabréisestatienesuslimitaciones,impuestasporelhardware.PoresodesdePython2.4contamostambiénconunnuevo tipoDecimal, para el caso de que se necesite representar fracciones deformamásprecisa.Sinembargoestetipoestáfueradelalcancedeestetutorial,y

Page 23: Python para todos repasa aspectos esenciales de

sólo es necesario para el ámbito de la programación científica y otrosrelacionados.Paraaplicacionesnormalespodéisutilizareltipofloatsinmiedo,comohavenidohaciéndosedesdehaceaños,aunqueteniendoencuentaquelosnúmerosencoma flotanteno sonprecisos (ni enesteni enotros lenguajesdeprogramación).Para representar un número real en Python se escribe primero la parte entera,seguidodeunpuntoyporúltimolapartedecimal.

real=0.2703

Tambiénsepuedeutilizarnotacióncientífica,yañadirunae(deexponente)paraindicarunexponenteenbase10.Porejemplo:

real=0.1e-3

seríaequivalentea0.1×10-3=0.1×0.001=0.0001

ComplejosLosnúmeroscomplejossonaquellosquetienenparteimaginaria.Sinoconocíasdesuexistencia,esmásqueprobablequenuncalovayasanecesitar,porloquepuedes saltarte este apartado tranquilamente. De hecho la mayor parte delenguajesdeprogramación carecende este tipo, aunque seamuyutilizadoporingenierosycientíficosengeneral.Enelcasodequenecesitéisutilizarnúmeroscomplejos,osimplementetengáiscuriosidad, os diré que este tipo, llamado complex en Python, también sealmacenausandocomaflotante,debidoaqueestosnúmerossonunaextensiónde los números reales. En concreto se almacena en una estructura de C,compuesta por dos variables de tipo double, sirviendo una de ellas paraalmacenarlaparterealylaotraparalaparteimaginaria.LosnúmeroscomplejosenPythonserepresentandelasiguienteforma:

complejo=2.1+7.8j

OperadoresVeamosahoraquépodemoshacerconnuestrosnúmerosusandolosoperadorespordefecto.Paraoperacionesmáscomplejaspodemosrecurriralmódulomath.

Operadoresaritméticos

Operador Descripción Ejemplo

Page 24: Python para todos repasa aspectos esenciales de

+ Suma r=3+2#res5

- Resta r=4-7#res-3

- Negación r=-7#res-7

* Multiplicación r=2*6#res12

** Exponente r=2**6#res64

/ División r=3.5/2#res1.75

// Divisiónentera r=3.5//2#res1.0% Módulo r=7%2#res1

Puedequetengáisdudassobrecómofuncionaeloperadordemódulo,ycuálesladiferenciaentredivisiónydivisiónentera.Eloperadordemódulonohaceotracosaquedevolvernoselrestodeladivisiónentre los dos operandos. En el ejemplo, 7/2 sería 3, con 1 de resto, luego elmóduloes1.La diferencia entre división y división entera no es otra que la que indica sunombre.Enladivisiónelresultadoquesedevuelveesunnúmeroreal,mientrasqueenladivisiónenteraelresultadoquesedevuelveessololaparteentera.No obstante hay que tener en cuenta que si utilizamos dos operandos enteros,Python determinará que queremos que la variable resultado también sea unentero,porloqueelresultadode,porejemplo,3/2y3//2seríaelmismo:1.Si quisiéramos obtener los decimales necesitaríamos que almenos uno de losoperandosfueraunnúmeroreal,bienindicandolosdecimales

r=3.0/2

obienutilizandolafunciónfloat(noesnecesarioquesepáisloquesignificaeltérminofunción,niquerecordéisestaforma,loveremosunpocomásadelante):

r=float(3)/2

Estoesasíporquecuandosemezclantiposdenúmeros,Pythonconviertetodoslosoperandosaltipomáscomplejodeentrelostiposdelosoperandos.

OperadoresaniveldebitSinoconocéisestosoperadoresespocoprobablequevayáisanecesitarlos,porloquepodéisobviarestaparte.Siaúnasítenéiscuriosidadosdiréqueestossonoperadoresqueactúansobrelasrepresentacionesenbinariodelosoperandos.

Page 25: Python para todos repasa aspectos esenciales de

Porejemplo,siveisunaoperacióncomo3&2,loqueestáisviendoesunandbitabitentrelosnúmerosbinarios11y10(lasrepresentacionesenbinariode3y2).Eloperadorand(&),delinglés“y”,devuelve1sielprimerbitoperandoes1yelsegundobitoperandoes1.Sedevuelve0encasocontrario.Elresultadodeaplicarandbitabita11y10seríaentonceselnúmerobinario10,oloqueeslomismo,2endecimal(elprimerdígitoes1paraambascifras,mientrasqueelsegundoes1sóloparaunadeellas).El operadoror (|), del inglés “o”, devuelve 1 si el primer operando es 1oelsegundooperandoes1.Paraelrestodecasossedevuelve0.Eloperadorxoruorexclusivo(^)devuelve1siunodelosoperandoses1yelotronoloes.Eloperadornot(~),delinglés“no”,sirveparanegarunoaunocadabit;esdecir,sieloperandoes0,cambiaa1ysies1,cambiaa0.Porúltimolosoperadoresdedesplazamiento(<<y>>)sirvenparadesplazarlosbitsnposicioneshacialaizquierdaoladerecha.

Operador Descripción Ejemplo& and r=3&2#res2

| or r=3|2#res3

^ xor r=3^2#res1

~ not r=~3#res-4

<< Desplazamientoizq. r=3<<1#res6>> Desplazamientoder. r=3>>1#res1

Page 26: Python para todos repasa aspectos esenciales de

CadenasLascadenasnosonmásquetextoencerradoentrecomillassimples(‘cadena’)odobles(“cadena”).Dentrodelascomillassepuedenañadircaracteresespecialesescapándoloscon\,como\n,elcarácterdenuevalínea,o\t,eldetabulación.Una cadena puede estar precedida por el carácteru o el carácterr, los cualesindican, respectivamente, que se trata de una cadena que utiliza codificaciónUnicodeyunacadenaraw(delinglés,cruda).Lascadenasrawsedistinguendelasnormalesenqueloscaracteresescapadosmediantelabarrainvertida(\)nose sustituyen por sus contrapartidas. Esto es especialmente útil, por ejemplo,paralasexpresionesregulares,comoveremosenelcapítulocorrespondiente.

unicode=u“äóè”

raw=r“\n”

Tambiénesposibleencerrarunacadenaentretriplescomillas(simplesodobles).De esta forma podremos escribir el texto en varias líneas, y al imprimir lacadena,serespetaránlossaltosdelíneaqueintrodujimossintenerquerecurriralcarácter\n,asícomolascomillassintenerqueescaparlas.

Page 27: Python para todos repasa aspectos esenciales de

triple=“““primeralinea

estoseveraenotralinea”””

Lascadenas tambiénadmitenoperadorescomo+,que funciona realizandounaconcatenacióndelascadenasutilizadascomooperandosy*,enlaqueserepitela cadena tantas veces como lo indique el número utilizado como segundooperando.

a=“uno”

b=“dos”

c=a+b#ces“unodos”

c=a*3#ces“unounouno”

Page 28: Python para todos repasa aspectos esenciales de

BooleanosComo decíamos al comienzo del capítulo una variable de tipo booleano sólopuede tener dos valores: True (cierto) y False (falso). Estos valores sonespecialmenteimportantesparalasexpresionescondicionalesylosbucles,comoveremosmásadelante.Enrealidadeltipobool(eltipodelosbooleanos)esunasubclasedeltipoint.Puedequeestonotengamuchosentidoparatisinoconoceslostérminosdelaorientación a objetos, que veremos más adelante, aunque tampoco es nadaimportante.Estos son los distintos tipos de operadores con los que podemos trabajar convaloresbooleanos,losllamadosoperadoreslógicosocondicionales:

Page 29: Python para todos repasa aspectos esenciales de

Operador Descripción Ejemploand ¿secumpleayb? r=TrueandFalse#resFalseor ¿secumpleaob? r=TrueorFalse#resTruenot Noa r=notTrue#resFalse

Los valores booleanos son además el resultado de expresiones que utilizanoperadoresrelacionales(comparacionesentrevalores):

Page 30: Python para todos repasa aspectos esenciales de

Operador Descripción Ejemplo== ¿sonigualesayb? r=5==3#resFalse

!= ¿sondistintosayb? r=5!=3#resTrue

< ¿esamenorqueb? r=5<3#resFalse

> ¿esamayorqueb? r=5>3#resTrue

<= ¿esamenoroigualqueb? r=5<=5#resTrue>= ¿esamayoroigualqueb? r=5>=3#resTrue

Page 31: Python para todos repasa aspectos esenciales de

COLECCIONESEn el capítulo anterior vimos algunos tipos básicos, como los números, lascadenas de texto y los booleanos. En esta lección veremos algunos tipos decoleccionesdedatos:listas,tuplasydiccionarios.

Page 32: Python para todos repasa aspectos esenciales de

ListasLa lista es un tipo de colección ordenada. Sería equivalente a lo que en otroslenguajesseconoceporarrays,ovectores.Laslistaspuedencontenercualquiertipodedato:números,cadenas,booleanos,…ytambiénlistas.Crear una lista es tan sencillo como indicar entre corchetes, y separados porcomas,losvaloresquequeremosincluirenlalista:

l=[22,True,“unalista”,[1,2]]

Podemosaccederacadaunodeloselementosdelalistaescribiendoelnombredelalistaeindicandoelíndicedelelementoentrecorchetes.Tenencuentasinembargoqueelíndicedelprimerelementodelalistaes0,yno1:l=[11,False]mi_var=l[0]#mi_varvale11

Siqueremosaccederaunelementodeunalistaincluidadentrodeotralista

Page 33: Python para todos repasa aspectos esenciales de

tendremos que utilizar dos veces este operador, primero para indicar a quéposicióndelalistaexteriorqueremosacceder,yelsegundoparaseleccionarelelementodelalistainterior:

l=[“unalista”,[1,2]]mi_var=l[1][0]#mi_varvale1Tambiénpodemosutilizaresteoperadorparamodificarunelementode la

listasilocolocamosenlaparteizquierdadeunaasignación:l=[22,True]l[0]=99#Conestolvaldrá[99,True]Elusodeloscorchetesparaaccederymodificarloselementosdeunalista

es común enmuchos lenguajes, pero Python nos depara varias sorpresasmuyagradables.

Una curiosidad sobre el operador [] de Python es que podemos utilizartambiénnúmerosnegativos.Siseutilizaunnúmeronegativocomoíndice,estosetraduceenqueelíndiceempiezaacontardesdeelfinal,hacialaizquierda;esdecir, con [-1] accederíamos al último elemento de la lista, con [-2] alpenúltimo,con[-3],alantepenúltimo,yasísucesivamente.

Otra cosa inusual es lo que en Python se conoce como slicing oparticionado,yqueconsisteenampliarestemecanismoparapermitirseleccionarporcionesdelalista.Sienlugardeunnúmeroescribimosdosnúmerosinicioyfin separados por dos puntos (inicio:fin) Python interpretará que queremosuna listaquevayadesde laposicióninicio a la posiciónfin, sin incluir esteúltimo. Si escribimos tres números (inicio:fin:salto) en lugar de dos, elterceroseutilizaparadeterminarcadacuantasposicionesañadirunelementoalalista.

l=[99,True,“unalista”,[1,2]]

mi_var=l[0:2]#mi_varvale[99,True]

mi_var=l[0:4:2]#mi_varvale[99,“unalista”]

Los números negativos también se pueden utilizar en un slicing, con elmismocomportamientoquesecomentóanteriormente.

Hayquemencionarasímismoquenoesnecesarioindicarelprincipioyelfinaldelslicing,sinoque,siestosseomiten,seusaránpordefectolasposicionesdeinicioyfindelalista,respectivamente:

l=[99,True,“unalista”]mi_var=l[1:]#mi_varvale[True,“unalista”]mi_var=l[:2]#mi_varvale[99,True]mi_var=l[:]#mi_varvale[99,True,“unalista”]mi_var=l[::2]#mi_varvale[99,“unalista”]

Page 34: Python para todos repasa aspectos esenciales de

Tambiénpodemosutilizarestemecanismoparamodificarlalista:l=[99,True,“unalista”,[1,2]]l[0:2]=[0,1]#lvale[0,1,“unalista”,[1,2]]pudiendo incluso modificar el tamaño de la lista si la lista de la parte

derechadelaasignacióntieneuntamañomenoromayorqueeldelaseleccióndelaparteizquierdadelaasignación:l[0:2]=[False]#lvale[False,“unalista”,[1,2]]

En todo caso las listas ofrecen mecanismos más cómodos para sermodificadas a través de las funciones de la clase correspondiente, aunque noveremosestosmecanismoshastamásadelante,despuésdeexplicar loquesonlasclases,losobjetosylasfunciones.

Page 35: Python para todos repasa aspectos esenciales de

TuplasTodo lo que hemos explicado sobre las listas se aplica también a las tuplas, aexcepcióndelaformadedefinirla,paraloqueseutilizanparéntesisenlugardecorchetes.

t=(1,2,True,“python”)

En realidad el constructor de la tupla es la coma, no el paréntesis, pero elintérpretemuestralosparéntesis,ynosotrosdeberíamosutilizarlos,porclaridad.

>>>t=1,2,3

>>>type(t)

type“tuple”

Ademáshayquetenerencuentaqueesnecesarioañadirunacomaparatuplasdeunsoloelemento,paradiferenciarlodeunelementoentreparéntesis.

>>>t=(1)

>>>type(t)

type“int”

>>>t=(1,)

>>>type(t)

type“tuple”

Page 36: Python para todos repasa aspectos esenciales de

Parareferirnosaelementosdeunatupla,comoenunalista,seusaeloperador[]:

mi_var=t[0]#mi_vares1

mi_var=t[0:2]#mi_vares(1,2)

Podemosutilizareloperador[]debidoaque las tuplas,al igualque las listas,formanpartedeuntipodeobjetosllamadossecuencias.Permitirmeunpequeño incisopara indicarosque lascadenasde texto tambiénsonsecuencias,porloquenoosextrañaráquepodamoshacercosascomoestas:

c=“holamundo”

c[0]#h

c[5:]#mundo

c[::3]#hauo

Volviendo al tema de las tuplas, su diferencia con las listas estriba en que lastuplas no poseen estosmecanismos demodificación a través de funciones tanútilesdelosquehablábamosalfinaldelaanteriorsección.Además son inmutables, es decir, sus valores no se puedenmodificar una vezcreada;ytienenuntamañofijo.Acambiodeestaslimitacioneslastuplassonmás“ligeras”quelaslistas,porloquesielusoquelevamosadaraunacolecciónesmuybásico,puedesutilizartuplasenlugardelistasyahorrarmemoria.

Page 37: Python para todos repasa aspectos esenciales de

DiccionariosLosdiccionarios,tambiénllamadosmatricesasociativas,debensunombreaqueson colecciones que relacionan una clave y un valor. Por ejemplo, veamos undiccionariodepelículasydirectores:d={“LoveActually”:“RichardCurtis”,“KillBill”:“Tarantino”,“Amélie”:“Jean-PierreJeunet”}

El primer valor se trata de la clave y el segundo del valor asociado a laclave.Comoclavepodemosutilizarcualquiervalor inmutable:podríamosusarnúmeros,cadenas,booleanos,tuplas,…peronolistasodiccionarios,dadoquesonmutables.Esto es así porque losdiccionarios se implementan como tablashash, y a la hora de introducir un nuevo par clave-valor en el diccionario secalcula el hash de la clave para después poder encontrar la entradacorrespondienterápidamente.Sisemodificaraelobjetoclavedespuésdehabersidointroducidoeneldiccionario,evidentemente,suhashtambiéncambiaríaynopodríaserencontrado.

Page 38: Python para todos repasa aspectos esenciales de

Ladiferenciaprincipalentrelosdiccionariosylaslistasolastuplasesquea los valores almacenados en un diccionario se les accede no por su índice,porque de hecho no tienen orden, sino por su clave, utilizando de nuevo eloperador[].

d[“LoveActually”]#devuelve“RichardCurtis”

Aligualqueenlistasytuplastambiénsepuedeutilizaresteoperadorparareasignarvalores.

d[“KillBill”]=“QuentinTarantino”

Sin embargo en este caso no se puede utilizar slicing, entre otras cosasporque los diccionarios no son secuencias, si no mappings (mapeados,asociaciones).

Page 39: Python para todos repasa aspectos esenciales de

CONTROLDEFLUJOEnestalecciónvamosaverloscondicionalesylosbucles.

Page 40: Python para todos repasa aspectos esenciales de

SentenciascondicionalesSi un programa no fuera más que una lista de órdenes a ejecutar de formasecuencial, una por una, no tendría mucha utilidad. Los condicionales nospermitencomprobarcondicionesyhacerquenuestroprogramasecomportedeuna formau otra, que ejecute un fragmentode códigou otro, dependiendodeestacondición.AquíesdondecobransuimportanciaeltipobooleanoylosoperadoreslógicosyrelacionalesqueaprendimosenelcapítulosobrelostiposbásicosdePython.

ifLa forma más simple de un estamento condicional es un if (del inglés si)seguido de la condición a evaluar, dos puntos (:) y en la siguiente línea eindentado,elcódigoaejecutarencasodequesecumpladichacondición.

fav=“mundogeek.net”

#si(if)favesiguala“mundogeek.net”

iffav==“mundogeek.net”:

print“Tienesbuengusto!”

Page 41: Python para todos repasa aspectos esenciales de

print“Gracias”

Comoveisesbastantesencillo.Esosi,asegurarosdequeindentáiselcódigotalcualsehahechoenelejemplo,esdecir,asegurarosdepulsarTabulaciónantesde lasdosórdenesprint,dadoqueestaes la formadePythondesaberquevuestra intenciónes ladeque losdosprintseejecutensóloenelcasodequesecumplalacondición,ynoladequese imprima laprimeracadenasisecumple lacondicióny laotrasiempre,cosaqueseexpresaríaasí:iffav==“mundogeek.net”:

print“Tienesbuengusto!”print“Gracias”

En otros lenguajes de programación los bloques de código se determinanencerrándolos entre llaves, y el indentarlos no se tratamás que de una buenaprácticaparaqueseamássencilloseguirelflujodelprogramaconunsologolpedevista.Porejemplo,elcódigoanteriorexpresadoenJavaseríaalgoasí:

Stringfav=“mundogeek.net”;if(fav.equals(“mundogeek.net”)){System.out.println(“Tienes buen gusto!”);

System.out.println(“Gracias”);}Sin embargo, como ya hemos comentado, en Python se trata de una

obligación,ynodeunaelección.Deestaformaseobligaalosprogramadoresaindentarsucódigoparaqueseamássencillodeleer:)if…else

Vamosaverahorauncondicionalalgomáscomplicado.¿Quéharíamossiquisiéramos que se ejecutaran unas ciertas órdenes en el caso de que lacondiciónnosecumpliera?Sindudapodríamosañadirotroifquetuvieracomocondiciónlanegacióndelprimero:

iffav==“mundogeek.net”:print“Tienesbuengusto!”print“Gracias”

iffav!=“mundogeek.net”:print“Vaya,quelástima”peroelcondicionaltieneunasegundaconstrucciónmuchomásútil:iffav==“mundogeek.net”:

print“Tienesbuengusto!”print“Gracias”

else:print“Vaya,quelástima”

Vemosquelasegundacondiciónsepuedesustituirconunelse(delinglés:

Page 42: Python para todos repasa aspectos esenciales de

sino,encasocontrario).Sileemoselcódigovemosquetienebastantesentido:“sifavesigualamundogeek.net,imprimeestoyesto,sino,imprimeestootro”.

if…elif…elif…elseTodavíaquedaunaconstrucciónmásquever,queeslaquehaceusodelelif.

ifnumero<0:

print“Negativo”

elifnumero>0:

print“Positivo”

else:

print“Cero”

elif es una contracción deelse if, por lo tantoelifnumero>0 puedeleersecomo“sino, sinumeroesmayorque0”.Esdecir,primeroseevalúa lacondicióndelif.Siescierta,seejecutasucódigoysecontinúaejecutandoelcódigoposterioralcondicional;sinosecumple,seevalúalacondicióndelelif.Sisecumplelacondicióndelelifseejecutasucódigoysecontinuaejecutandoel código posterior al condicional; si no se cumple y haymás de un elif secontinúaconelsiguienteenordendeaparición.Sinosecumplelacondicióndelifnideningunodeloselif,seejecutaelcódigodelelse.

AifCelseBTambiénexisteunaconstrucciónsimilaraloperador? deotros lenguajes,

que no es más que una forma compacta de expresar un if else. En estaconstrucciónseevalúaelpredicadoCysedevuelveAsisecumpleoBsinosecumple:AifCelseB.Veamosunejemplo:var=“par”if(num%2==0)else“impar”

Y eso es todo. Si conocéis otros lenguajes de programación puede queesperarais que os hablara ahora del switch, pero en Python no existe estaconstrucción,quepodría emularseconun simplediccionario, asíquepasemosdirectamentealosbucles.

Page 43: Python para todos repasa aspectos esenciales de

BuclesMientras que los condicionales nos permiten ejecutar distintos fragmentos decódigodependiendodeciertascondiciones,losbuclesnospermitenejecutarunmismofragmentodecódigounciertonúmerodeveces,mientrassecumplaunadeterminadacondición.

whileElbuclewhile (mientras) ejecuta un fragmentode códigomientras se cumplaunacondición.

edad=0

whileedad<18:

edad=edad+1

print“Felicidades,tienes“+str(edad)

Lavariableedadcomienzavaliendo0.Comolacondicióndequeedadesmenorque18escierta(0esmenorque18),seentraenelbucle.Seaumentaedaden1y se imprime el mensaje informando de que el usuario ha cumplido un año.Recordad que el operador + para las cadenas funciona concatenando ambas

Page 44: Python para todos repasa aspectos esenciales de

cadenas.Esnecesarioutilizar lafunciónstr(destring,cadena)paracrearunacadena a partir del número, dado que no podemos concatenar números ycadenas,peroyacomentaremosestoymuchomásenpróximoscapítulos.Ahorasevuelveaevaluar lacondición,y1siguesiendomenorque18,porloquesevuelveaejecutarelcódigoqueaumentalaedadenunañoeimprimelaedadenlapantalla.Elbuclecontinuaráejecutándosehastaqueedadseaiguala18, momento en el cual la condición dejará de cumplirse y el programacontinuaríaejecutandolasinstruccionessiguientesalbucle.Ahora imaginemos que se nos olvidara escribir la instrucción que aumenta laedad. En ese caso nunca se llegaría a la condición de que edad fuese igual omayor que 18, siempre sería 0, y el bucle continuaría indefinidamenteescribiendoenpantallaHascumplido0.Estoesloqueseconocecomounbucleinfinito.Sin embargohay situaciones en las queunbucle infinito es útil. Por ejemplo,veamosunpequeñoprogramaque repite todo loqueelusuariodigahastaqueescribaadios.

whileTrue:

entrada=raw_input(“>“)

ifentrada==“adios”:

break

else:

printentrada

Para obtener lo que el usuario escriba en pantalla utilizamos la funciónraw_input. No es necesario que sepáis qué es una función ni cómo funcionaexactamente,simplementeaceptadporahoraqueencadaiteracióndelbuclelavariableentradacontendráloqueelusuarioescribióhastapulsarEnter.Comprobamosentoncessiloqueescribióelusuariofueadios,encuyocasoseejecutalaordenbreakosieracualquierotracosa,encuyocasoseimprimeenpantallaloqueelusuarioescribió.Lapalabraclavebreak(romper)saledelbucleenelqueestamos.Estebuclesepodríahaberescritotambién,noobstante,delasiguienteforma:

salir=False

whilenotsalir:

entrada=raw_input()

ifentrada==“adios”:

salir=True

else:

printentrada

peronoshaservidoparavercómofuncionabreak.

Page 45: Python para todos repasa aspectos esenciales de

Otrapalabraclavequenospodemosencontrardentrodelosbuclesescontinue(continuar).Comohabréisadivinadonohaceotracosaquepasardirectamentealasiguienteiteracióndelbucle.

edad=0

whileedad<18:

edad=edad+1

ifedad%2==0:

continue

print“Felicidades,tienes“+str(edad)

Como veis esta es una pequeña modificación de nuestro programa defelicitaciones.Enestaocasiónhemosañadidounifquecompruebasilaedadespar, en cuyo caso saltamos a la próxima iteración en lugar de imprimir elmensaje. Es decir, con esta modificación el programa sólo imprimiríafelicitacionescuandolaedadfueraimpar.

for…inAlosquehayáistenidoexperienciapreviaconsegúnquelenguajesestebucleosvaasorprendergratamente.EnPythonforseutilizacomounaformagenéricadeiterarsobreunasecuencia.Ycomotalintentafacilitarsuusoparaestefin.EsteeselaspectodeunbucleforenPython:

secuencia=[“uno”,“dos”,“tres”]

forelementoinsecuencia:

printelemento

ComohemosdicholosforseutilizanenPythonpararecorrersecuencias,porloquevamosautilizaruntiposecuencia,comoeslalista,paranuestroejemplo.Leamoslacabeceradelbuclecomosidelenguajenaturalsetratara:“paracadaelementoensecuencia”.Yestoesexactamenteloquehaceelbucle:paracadaelementoquetengamosenlasecuencia,ejecutaestaslíneasdecódigo.Lo que hace la cabecera del bucle es obtener el siguiente elemento de lasecuenciasecuencia y almacenarlo en una variable de nombreelemento. Poresta razón en la primera iteración del bucle elemento valdrá “uno”, en lasegunda“dos”,yenlatercera“tres”.Fácilysencillo.En C o C++, por ejemplo, lo que habríamos hecho sería iterar sobre lasposiciones,ynosobreloselementos:

intmi_array[]={1,2,3,4,5};

inti;

for(i=0;i<5;i++){

printf(“%d\n”,mi_array[i]);

Page 46: Python para todos repasa aspectos esenciales de

}

Esdecir,tendríamosunbucleforquefueraaumentandounavariableiencadaiteración,desde0altamañodelasecuencia,yutilizaríamosestavariableamododeíndiceparaobtenercadaelementoeimprimirlo.ComoveiselenfoquedePythonesmásnaturaleintuitivo.Pero,¿quéocurresiquisiéramosutilizarelforcomosiestuviéramosenCoenJava, por ejemplo, para imprimir los números de 30 a 50?No os preocupéis,porquenonecesitaríaiscrearunalistayañadirunoaunolosnúmerosdel30al50.Pythonproporcionaunafunciónllamadarange(rango)quepermitegeneraruna lista que vaya desde el primer número que le indiquemos al segundo. Loveremos después de ver al fin a qué se refiere ese término tan recurrente: lasfunciones.

Page 47: Python para todos repasa aspectos esenciales de

FUNCIONESUnafunciónesunfragmentodecódigoconunnombreasociadoquerealizaunaseriede tareasydevuelveunvalor.A los fragmentosdecódigoque tienenunnombreasociadoynodevuelvenvaloresselessuelellamarprocedimientos.EnPython no existen los procedimientos, ya que cuando el programador noespecifica un valor de retorno la función devuelve el valor None (nada),equivalentealnulldeJava.Ademásdeayudarnosaprogramarydepurardividiendoelprogramaenparteslasfuncionestambiénpermitenreutilizarcódigo.EnPythonlasfuncionessedeclarandelasiguienteforma:

defmi_funcion(param1,param2):

printparam1

printparam2

Esdecir,lapalabraclavedefseguidadelnombredelafunciónyentreparéntesislosargumentosseparadosporcomas.Acontinuación,enotralínea,indentadoydespués de los dos puntos tendríamos las líneas de código que conforman el

Page 48: Python para todos repasa aspectos esenciales de

códigoaejecutarporlafunción.Tambiénpodemosencontrarnosconunacadenadetextocomoprimeralíneadelcuerpo de la función. Estas cadenas se conocen con el nombre de docstring(cadena de documentación) y sirven, como su nombre indica, a modo dedocumentacióndelafunción.

defmi_funcion(param1,param2):

“““Estafuncionimprimelosdosvalorespasados

comoparametros”””

printparam1

printparam2

Estoesloqueimprimeeloperador?deiPythonolafunciónhelpdellenguajeparaproporcionarunaayudasobreelusoyutilidaddelasfunciones.Todoslosobjetos pueden tener docstrings, no solo las funciones, como veremos másadelante.Volviendoaladeclaracióndefunciones,esimportanteaclararquealdeclararlafunciónloúnicoquehacemosesasociarunnombrealfragmentodecódigoqueconforma la función, de forma que podamos ejecutar dicho códigomás tardereferenciándoloporsunombre.Esdecir,alahoradeescribirestaslíneasnoseejecutalafunción.Parallamaralafunción(ejecutarsucódigo)seescribiría:

mi_funcion(“hola”,2)

Es decir, el nombre de la función a la que queremos llamar seguido de losvaloresquequeramospasarcomoparámetrosentreparéntesis.Laasociacióndelos parámetros y los valores pasados a la función se hace normalmente deizquierda aderecha: comoaparam1 lehemosdadounvalor“hola” yparam2vale2,mi_funcionimprimiríaholaenunalínea,yacontinuación2.Sin embargo también es posible modificar el orden de los parámetros siindicamoselnombredelparámetroalqueasociarelvaloralahoradellamaralafunción:

mi_funcion(param2=2,param1=“hola”)

Elnúmerodevaloresquesepasancomoparámetroalllamaralafuncióntieneque coincidir con el número de parámetros que la función acepta según ladeclaracióndelafunción.EncasocontrarioPythonsequejará:

>>>mi_funcion(“hola”)

Traceback(mostrecentcalllast):

File“<stdin>”,line1,in<module>

TypeError:mi_funcion()takesexactly2arguments(1given)

También es posible, no obstante, definir funciones con un número variable deargumentos,obienasignarvalorespordefectoalosparámetrosparaelcasode

Page 49: Python para todos repasa aspectos esenciales de

quenoseindiqueningúnvalorparaeseparámetroalllamaralafunción.Losvalorespordefectoparalosparámetrossedefinensituandounsignoigualdespuésdelnombredelparámetroyacontinuaciónelvalorpordefecto:

defimprimir(texto,veces=1):

printveces*texto

Enel ejemplo anterior si no indicamosunvalor para el segundoparámetro seimprimiráunasolavezlacadenaquelepasamoscomoprimerparámetro:

>>>imprimir(“hola”)

hola

siseleindicaotrovalor,seráesteelqueseutilice:>>>imprimir(“hola”,2)

holahola

Para definir funciones con un número variable de argumentos colocamos unúltimoparámetroparalafuncióncuyonombredebeprecedersedeunsigno*:

defvarios(param1,param2,*otros):

forvalinotros:

printval

varios(1,2)

varios(1,2,3)

varios(1,2,3,4)

Estasintaxisfuncionacreandounatupla(denombreotrosenelejemplo)enlaque se almacenan los valores de todos los parámetros extra pasados comoargumento.Paralaprimerallamada,varios(1,2),latuplaotrosestaríavacíadadoqueno sehanpasadomásparámetrosque losdosdefinidospordefecto,porlotantonoseimprimiríanada.Enlasegundallamadaotrosvaldría(3,),yenlatercera(3,4).Tambiénsepuedeprecederelnombredelúltimoparámetrocon**,encuyocasoenlugardeunatuplaseutilizaríaundiccionario.Lasclavesdeestediccionarioserían los nombres de los parámetros indicados al llamar a la función y losvaloresdeldiccionario,losvaloresasociadosaestosparámetros.En el siguiente ejemplo se utiliza la función items de los diccionarios, quedevuelveunalistaconsuselementos,paraimprimirlosparámetrosquecontieneeldiccionario.

defvarios(param1,param2,**otros):

foriinotros.items():

printi

varios(1,2,tercero=3)

Losqueconozcáisalgúnotrolenguajedeprogramaciónosestaréispreguntando

Page 50: Python para todos repasa aspectos esenciales de

sienPythonalpasarunavariablecomoargumentodeunafunciónestassepasanpor referencia o por valor. En el paso por referencia lo que se pasa comoargumento es una referencia o puntero a la variable, es decir, la dirección dememoriaenlaqueseencuentraelcontenidodelavariable,ynoelcontenidoensi.Enelpasoporvalor,porelcontrario, loquesepasacomoargumentoeselvalorqueconteníalavariable.Ladiferenciaentreambosestribaenqueenelpasoporvalorloscambiosquesehagansobreelparámetronosevenfueradelafunción,dadoquelosargumentosde la función son variables locales a la función que contienen los valoresindicadosporlasvariablesquesepasaroncomoargumento.Esdecir,enrealidadloqueselepasaalafunciónsoncopiasdelosvaloresynolasvariablesensi.Siquisiéramosmodificarelvalordeunodelosargumentosyqueestoscambiosse reflejaran fuera de la función tendríamos que pasar el parámetro porreferencia.En C los argumentos de las funciones se pasan por valor, aunque se puedesimularelpasoporreferenciausandopunteros.EnJavatambiénseusapasoporvalor,aunqueparalasvariablesquesonobjetosloquesehaceespasarporvalorlareferenciaalobjeto,porloqueenrealidadparecepasoporreferencia.EnPythontambiénseutilizaelpasoporvalordereferenciasaobjetos,comoenJava,aunqueenelcasodePython,adiferenciadeJava,todoesunobjeto(paraserexactosloqueocurreenrealidadesquealobjetoseleasignaotraetiquetaonombreenelespaciodenombreslocaldelafunción).SinembargonotodosloscambiosquehagamosalosparámetrosdentrodeunafunciónPythonsereflejaránfueradeesta,yaquehayquetenerencuentaqueenPythonexistenobjetos inmutables,como las tuplas,por loquesi intentáramosmodificarunatuplapasadacomoparámetroloqueocurriríaenrealidadesquesecrearíaunanueva instancia,por loque loscambiosnoseveríanfuerade lafunción.Veamosunpequeñoprogramaparademostrarlo.Enesteejemplosehaceusodelmétodo append de las listas. Un método no es más que una función queperteneceaunobjeto,enestecasoaunalista;yappend,enconcreto,sirveparaañadirunelementoaunalista.

deff(x,y):

x=x+3

y.append(23)

printx,y

x=22

y=[22]

Page 51: Python para todos repasa aspectos esenciales de

f(x,y)

printx,y

Elresultadodelaejecucióndeesteprogramasería25[22,23]

22[22,23]

Como vemos la variable x no conserva los cambios una vez salimos de lafunciónporquelosenterossoninmutablesenPython.Sinembargolavariableysilosconserva,porquelaslistassonmutables.Enresumen:losvaloresmutablessecomportancomopasoporreferencia,ylosinmutablescomopasoporvalor.Conesto terminamos todo lo relacionadocon losparámetrosde las funciones.Veamosporúltimocómodevolvervalores,paraloqueseutilizalapalabraclavereturn:

defsumar(x,y):

returnx+y

printsumar(3,2)

Comovemosestafuncióntansencillanohaceotracosaquesumarlosvalorespasadoscomoparámetroydevolverelresultadocomovalorderetorno.Tambiénpodríamospasarvariosvaloresqueretornarareturn.

deff(x,y):

returnx*2,y*2

a,b=f(1,2)

Sin embargo esto no quiere decir que las funciones Python puedan devolvervariosvalores, loqueocurreenrealidadesquePythoncreaunatuplaalvuelocuyos elementos son los valores a retornar, y esta única variable es la que sedevuelve.

Page 52: Python para todos repasa aspectos esenciales de

ORIENTACIÓNAOBJETOSEn el capítulo de introducción ya comentábamos que Python es un lenguajemultiparadigmaenelquesepodíatrabajarconprogramaciónestructurada,comoveníamos haciendo hasta ahora, o con programación orientada a objetos oprogramaciónfuncional.LaProgramaciónOrientadaaObjetos(POOuOOPsegúnsussiglaseninglés)es un paradigma de programación en el que los conceptos del mundo realrelevantesparanuestroproblemasemodelanatravésdeclasesyobjetos,yenelquenuestroprogramaconsisteenunaseriedeinteraccionesentreestosobjetos.

Page 53: Python para todos repasa aspectos esenciales de

ClasesyobjetosParaentenderesteparadigmaprimerotenemosquecomprenderquéesunaclasey qué es un objeto. Un objeto es una entidad que agrupa un estado y unafuncionalidadrelacionadas.Elestadodelobjetosedefinea travésdevariablesllamadas atributos, mientras que la funcionalidad se modela a través defuncionesalasqueselesconoceconelnombredemétodosdelobjeto.Unejemplodeobjetopodríaseruncoche,enelquetendríamosatributoscomolamarca,elnúmerodepuertasoeltipodecarburanteymétodoscomoarrancaryparar.Obiencualquierotracombinacióndeatributosymétodossegúnloquefuerarelevanteparanuestroprograma.Unaclase,porotrolado,noesmásqueunaplantillagenéricaapartirdelacualinstanciar los objetos; plantilla que es la que define qué atributos y métodostendránlosobjetosdeesaclase.Volviendoanuestroejemplo:enelmundorealexisteunconjuntodeobjetosalos que llamamos coches y que tienenun conjunto de atributos comunes y un

Page 54: Python para todos repasa aspectos esenciales de

comportamientocomún,estoesaloquellamamosclase.Sinembargo,micochenoesigualqueelcochedemivecino,yaunquepertenecenalamismaclasedeobjetos,sonobjetosdistintos.En Python las clases se definen mediante la palabra clave class seguida delnombredelaclase,dospuntos(:)yacontinuación,indentado,elcuerpodelaclase.Comoenelcasodelasfunciones,silaprimeralíneadelcuerposetratadeuna cadena de texto, esta será la cadena de documentación de la clase odocstring.

classCoche:

“““Abstraccióndelosobjetoscoche.”””

def__init__(self,gasolina):

self.gasolina=gasolina

print“Tenemos”,gasolina,“litros”

defarrancar(self):

ifself.gasolina>0:

print“Arranca”

else:

print“Noarranca”

defconducir(self):

ifself.gasolina>0:

self.gasolina-=1

print“Quedan”,self.gasolina,“litros”

else:

print“Nosemueve”

Loprimeroquellamalaatenciónenelejemploanterioreselnombretancuriosoquetieneelmétodo__init__.Estenombreesunaconvenciónynouncapricho.Elmétodo__init__,conunadoblebarrabajaalprincipioyfinaldelnombre,seejecutajustodespuésdecrearunnuevoobjetoapartirdelaclase,procesoqueseconoceconelnombredeinstanciación.Elmétodo__init__sirve,comosugieresunombre,pararealizarcualquierprocesodeinicializaciónqueseanecesario.Comovemoselprimerparámetrode__init__ydelrestodemétodosdelaclaseessiempreself.EstaesunaideainspiradaenModula-3ysirveparareferirsealobjetoactual.Estemecanismoesnecesarioparapoderaccederalosatributosymétodosdelobjetodiferenciando,porejemplo,unavariablelocalmi_vardeunatributodelobjetoself.mi_var.Si volvemos al método __init__ de nuestra clase Coche veremos cómo seutilizaselfparaasignaralatributogasolinadelobjeto(self.gasolina)elvalorque el programador especificó para el parámetro gasolina. El parámetrogasolinasedestruyealfinaldelafunción,mientrasqueelatributogasolinaseconserva(ypuedeseraccedido)mientraselobjetoviva.Para crear un objeto se escribiría el nombre de la clase seguido de cualquier

Page 55: Python para todos repasa aspectos esenciales de

parámetro que sea necesario entre paréntesis. Estos parámetros son los que sepasaránalmétodo__init__,quecomodecíamoseselmétodoquesellamaalinstanciarlaclase.

mi_coche=Coche(3)

Ospreguntareisentoncescómoesposiblequealahoradecrearnuestroprimerobjetopasemosunsoloparámetroa__init__,elnúmero3,cuandoladefiniciónde la función indica claramente que precisa de dos parámetros (self ygasolina).EstoesasíporquePythonpasaelprimerargumento(lareferenciaalobjetoquesecrea)automáticamente.Ahoraqueyahemoscreadonuestroobjeto,podemosaccederasusatributosymétodosmediantelasintaxisobjeto.atributoyobjeto.metodo():

>>>printmi_coche.gasolina

3

>>>mi_coche.arrancar()

Arranca

>>>mi_coche.conducir()

Quedan2litros

>>>mi_coche.conducir()

Quedan1litros

>>>mi_coche.conducir()

Quedan0litros

>>>mi_coche.conducir()

Nosemueve

>>>mi_coche.arrancar()

Noarranca

>>>printmi_coche.gasolina

0

ComoúltimoapunterecordarqueenPython,comoyasecomentóenrepetidasocasiones anteriormente, todo son objetos. Las cadenas, por ejemplo, tienenmétodoscomoupper(),quedevuelveeltextoenmayúsculasocount(sub),quedevuelveelnúmerodevecesqueseencontrólacadenasubeneltexto.

Page 56: Python para todos repasa aspectos esenciales de

HerenciaHay tres conceptos que son básicos para cualquier lenguaje de programaciónorientadoaobjetos:elencapsulamiento,laherenciayelpolimorfismo.En un lenguaje orientado a objetos cuando hacemos que una clase (subclase)herede de otra clase (superclase) estamos haciendo que la subclase contengatodos los atributos ymétodos que tenía la superclase. No obstante al acto deheredardeunaclasetambiénselellamaamenudo“extenderunaclase”.Supongamosque queremosmodelar los instrumentosmusicales de unabanda,tendremosentoncesunaclaseGuitarra,unaclaseBateria,unaclaseBajo,etc.Cada una de estas clases tendrá una serie de atributos ymétodos, pero ocurreque,porelmerohechodeserinstrumentosmusicales,estasclasescompartiránmuchosdesusatributosymétodos;unejemploseríaelmétodotocar().EsmássencillocrearuntipodeobjetoInstrumentoconlosatributosymétodoscomunes e indicar al programa que Guitarra, Bateria y Bajo son tipos deinstrumentos,haciendoqueheredendeInstrumento.

Page 57: Python para todos repasa aspectos esenciales de

Paraindicarqueunaclaseheredadeotrasecolocaelnombredelaclasedelaqueseheredaentreparéntesisdespuésdelnombredelaclase:

classInstrumento:

def__init__(self,precio):

self.precio=preciodeftocar(self):print“Estamostocandomusica”

defromper(self):

print“Esolopagastu”

print“Son”,self.precio,“$$$”

classBateria(Instrumento):pass

classGuitarra(Instrumento):pass

Como Bateria y Guitarra heredan de Instrumento, ambos tienen unmétodotocar()yunmétodoromper(),yse inicializanpasandounparámetroprecio. Pero, ¿qué ocurriría si quisiéramos especificar un nuevo parámetrotipo_cuerda a la hora de crear un objeto Guitarra?Bastaría con escribir unnuevométodo__init__ para la claseGuitarra que se ejecutaría en lugar del__init__ de Instrumento. Esto es lo que se conoce como sobreescribirmétodos.

Ahorabien,puedeocurrirenalgunoscasosquenecesitemossobreescribirun método de la clase padre, pero que en ese método queramos ejecutar elmétodo de la clase padre porque nuestro nuevo método no necesite más queejecutarunpardenuevasinstruccionesextra.EnesecasousaríamoslasintaxisSuperClase.metodo(self,args)parallamaralmétododeigualnombredelaclasepadre.Porejemplo,parallamaralmétodo__init__deInstrumentodesdeGuitarrausaríamosInstrumento.__init__(self,precio)

Observadqueenestecasosiesnecesarioespecificarelparámetroself.

Page 58: Python para todos repasa aspectos esenciales de

HerenciamúltipleEn Python, a diferencia de otros lenguajes como Java o C#, se permite laherenciamúltiple,esdecir,unaclasepuedeheredardevariasclasesalavez.Porejemplo, podríamos tener una clase Cocodrilo que heredara de la claseTerrestre,conmétodoscomocaminar()yatributoscomovelocidad_caminary de la clase Acuatico, con métodos como nadar() y atributos comovelocidad_nadar. Basta con enumerar las clases de las que se heredaseparándolasporcomas:classCocodrilo(Terrestre,Acuatico):pass

Enelcasodequealgunadelasclasespadretuvieranmétodosconelmismonombreynúmerodeparámetroslasclasessobreescribiríanlaimplementacióndelosmétodosdelasclasesmásasuderechaenladefinición.

Enelsiguienteejemplo,comoTerrestreseencuentramásalaizquierda,seríaladefinicióndedesplazardeestaclaselaqueprevalecería,yporlotantosillamamos al método desplazar de un objeto de tipo Cocodrilo lo que seimprimiríasería“Elanimalanda”.

Page 59: Python para todos repasa aspectos esenciales de

classTerrestre:

defdesplazar(self):print“Elanimalanda”

classAcuatico:defdesplazar(self):print“Elanimalnada”

classCocodrilo(Terrestre,Acuatico):passc=Cocodrilo()c.desplazar()

Page 60: Python para todos repasa aspectos esenciales de

PolimorfismoLapalabrapolimorfismo,delgriegopolymorphos(variasformas),serefierealahabilidaddeobjetosdedistintasclasesderesponderalmismomensaje.Estosepuedeconseguir a travésde laherencia:unobjetodeunaclasederivadaes almismotiempounobjetodelaclasepadre,deformaqueallídondeserequiereunobjetodelaclasepadretambiénsepuedeutilizarunodelaclasehija.Python,alserdetipadodinámico,noimponerestriccionesalostiposqueselepuedenpasaraunafunción,porejemplo,másalládequeelobjetosecomportecomo se espera: si se va a llamar a un método f() del objeto pasado comoparámetro, por ejemplo, evidentemente el objeto tendrá que contar con esemétodo.Poresemotivo,adiferenciadelenguajesdetipadoestáticocomoJavaoC++,elpolimorfismoenPythonnoesdegranimportancia.En ocasiones también se utiliza el término polimorfismo para referirse a lasobrecargademétodos,términoquesedefinecomolacapacidaddellenguajededeterminarquémétodoejecutardeentrevariosmétodosconigualnombresegúnel tipo o número de los parámetros que se le pasa. En Python no existe

Page 61: Python para todos repasa aspectos esenciales de

sobrecargademétodos (elúltimométodosobreescribiría la implementacióndelos anteriores), aunque se puede conseguir un comportamiento similarrecurriendo a funciones con valores por defecto para los parámetros o a lasintaxis *params o **params explicada en el capítulo sobre las funciones enPython,obienusandodecoradores(mecanismoqueveremosmásadelante).

Page 62: Python para todos repasa aspectos esenciales de

EncapsulaciónLa encapsulación se refiere a impedir el acceso a determinados métodos yatributosdelosobjetosestableciendoasíquépuedeutilizarsedesdefueradelaclase.Esto se consigue en otros lenguajes de programación como Java utilizandomodificadoresdeaccesoquedefinensicualquierapuedeaccederaesafunciónovariable(public)osiestárestringidoelaccesoalapropiaclase(private).EnPythonnoexistenlosmodificadoresdeacceso,yloquesesuelehaceresqueel acceso a una variable o función viene determinado por su nombre: si elnombrecomienzacondosguionesbajos(ynoterminatambiéncondosguionesbajos) se tratadeunavariableo funciónprivada,encasocontrarioespública.Los métodos cuyo nombre comienza y termina con dos guiones bajos sonmétodos especiales que Python llama automáticamente bajo ciertascircunstancias,comoveremosalfinaldelcapítulo.Enelsiguienteejemplosóloseimprimirálacadenacorrespondientealmétodo

Page 63: Python para todos repasa aspectos esenciales de

publico(), mientras que al intentar llamar al método __privado() Pythonlanzaráunaexcepciónquejándosedequenoexiste(evidentementeexiste,peronolopodemosverporqueesprivado).

classEjemplo:

defpublico(self):

print“Publico”

def__privado(self):print“Privado”

ej=Ejemplo()ej.publico()

ej.__privado()

Estemecanismosebasaenquelosnombresquecomienzanconundobleguiónbajo se renombran para incluir el nombre de la clase (característica que seconoceconelnombredenamemangling).Estoimplicaqueelmétodooatributonoesrealmenteprivado,ypodemosaccederaélmedianteunapequeñatrampa:ej._Ejemplo__privado() En ocasiones también puede suceder que queramospermitirelaccesoaalgúnatributodenuestroobjeto,peroqueesteseproduzcadeformacontrolada.Paraestopodemosescribirmétodoscuyoúnicocometidosea este, métodos que normalmente, por convención, tienen nombres comogetVariableysetVariable;deahíqueseconozcantambiénconelnombredegettersysetters.

classFecha():

def__init__(self):self.__dia=1

defgetDia(self):returnself.__diadefsetDia(self,dia):

ifdia>0anddia<31:self.__dia=diaelse:

print“Error”

mi_fecha=Fecha()mi_fecha.setDia(33)Estosepodríasimplificarmediantepropiedades,queabstraenalusuariodel

hecho de que se está utilizando métodos entre bambalinas para obtener ymodificarlosvaloresdelatributo:

classFecha(object):

def__init__(self):self.__dia=1

defgetDia(self):returnself.__diadefsetDia(self,dia):

ifdia>0anddia<31:self.__dia=diaelse:

print“Error”

dia=property(getDia,setDia)

mi_fecha=Fecha()mi_fecha.dia=33

Page 64: Python para todos repasa aspectos esenciales de

Clasesde“nuevo-estilo”En el ejemplo anterior os habrá llamado la atención el hecho de que la claseFechaderivedeobject.Larazóndeestoesqueparapoderusarpropiedadeslaclasetienequeserde“nuevo-estilo”,clasesenriquecidasintroducidasenPython2.2 que serán el estándar enPython3.0 pero que aún conviven con las clases“clásicas” por razones de retrocompatibilidad. Además de las propiedades lasclasesdenuevoestiloañadenotrasfuncionalidadescomodescriptoresométodosestáticos.Paraqueunaclaseseadenuevoestiloesnecesario,porahora,queextiendaunaclase de nuevo-estilo. En el caso de que no sea necesario heredar elcomportamientooelestadodeningunaclase,comoennuestroejemploanterior,sepuedeheredardeobject, que esunobjetovacíoque sirve comobaseparatodaslasclasesdenuevoestilo.Ladiferenciaprincipalentrelasclasesantiguasylasdenuevoestiloconsisteenquealahoradecrearunanuevaclaseanteriormentenosedefiníarealmenteunnuevotipo,sinoquetodoslosobjetoscreadosapartirdeclases,fueranestaslas

Page 65: Python para todos repasa aspectos esenciales de

clasesquefueran,erandetipoinstance.

Page 66: Python para todos repasa aspectos esenciales de

MétodosespecialesYa vimos al principio del artículo el uso delmétodo __init__. Existen otrosmétodos con significados especiales, cuyos nombres siempre comienzan yterminancondosguionesbajos.Acontinuaciónselistanalgunosespecialmenteútiles.

__init__(self,args)Métodollamadodespuésdecrearelobjetopara

realizartareasdeinicialización.

__new__(cls,args)

Método exclusivo de las clases de nuevo estilo que se ejecuta antes que__init__yqueseencargadeconstruirydevolverelobjetoensí.EsequivalentealosconstructoresdeC++oJava.Setratadeunmétodoestático,esdecir,queexisteconindependenciadelasinstanciasdelaclase:esunmétododeclase,nodeobjeto,ypor lo tanto elprimerparámetronoesself, sino lapropiaclase:cls.

__del__(self)

Page 67: Python para todos repasa aspectos esenciales de

Métodollamadocuandoelobjetovaaserborrado.Tambiénllamadodestructor,seutilizapararealizartareasdelimpieza.

__str__(self)

Métodollamadoparacrearunacadenadetextoquerepresenteanuestroobjeto.Seutilizacuandousamosprintparamostrarnuestroobjetoocuandousamoslafunciónstr(obj)paracrearunacadenaapartirdenuestroobjeto.

__cmp__(self, otro) Método llamado cuando se utilizan los

operadores de comparación para comprobar si nuestro objeto es

menor,mayoroigualalobjetopasadocomoparámetro.Debedevolver

unnúmeronegativosinuestroobjetoesmenor,cerosisoniguales,

yunnúmeropositivosinuestroobjetoesmayor.Siestemétodono

está definido y se intenta comparar el objeto mediante los

operadores<,<=,>o>=selanzaráunaexcepción.Siseutilizan

losoperadores==o!=paracomprobarsidosobjetossoniguales,

secompruebasisonelmismoobjeto(sitienenelmismoid).

__len__(self)

Métodollamadoparacomprobarlalongituddelobjeto.Seutiliza,porejemplo,cuando se llama a la función len(obj) sobre nuestro objeto. Como es desuponer,elmétododebedevolverlalongituddelobjeto.

Existenbastantesmásmétodosespeciales,quepermiteentreotrascosasutilizarelmecanismodeslicingsobrenuestroobjeto,utilizarlosoperadoresaritméticoso usar la sintaxis de diccionarios, pero un estudio exhaustivo de todos losmétodosquedafueradelpropósitodelcapítulo.

Page 68: Python para todos repasa aspectos esenciales de

REVISITANDOOBJETOSEn los capítulos dedicados a los tipos simples y las colecciones veíamos porprimera vez algunos de los objetos del lenguaje Python: números, booleanos,cadenasdetexto,diccionarios,listasytuplas.Ahoraquesabemosquésonlasclases,losobjetos,lasfunciones,ylosmétodoseselmomentoderevisitarestosobjetosparadescubrirsuverdaderopotencial.Veremosacontinuaciónalgunosmétodosútilesdeestosobjetos.Evidentemente,no es necesario memorizarlos, pero sí, al menos, recordar que existen paracuandoseannecesarios.

Page 69: Python para todos repasa aspectos esenciales de

DiccionariosD.get(k[,d])

Buscaelvalordelaclavekeneldiccionario.EsequivalenteautilizarD[k]peroalutilizarestemétodopodemosindicarunvaloradevolverpordefectosinoseencuentra laclave,mientrasquecon la sintaxisD[k], de no existir la clave selanzaríaunaexcepción.

D.has_key(k) Comprueba si el diccionario tiene la clave k. Es

equivalentealasintaxiskinD.

D.items()Devuelveunalistadetuplasconparesclave-valor.

D.keys()

Devuelveunalistadelasclavesdeldiccionario.

D.pop(k[,d])Borralaclavekdeldiccionarioydevuelvesuvalor.

Si no se encuentra dicha clave se devuelve d si se especificó el

parámetroobienselanzaunaexcepción.

Page 70: Python para todos repasa aspectos esenciales de

D.values()Devuelveunalistadelosvaloresdeldiccionario.

Page 71: Python para todos repasa aspectos esenciales de

CadenasS.count(sub[,start[,end]])

Devuelveelnúmerodevecesqueseencuentrasubenlacadena.Losparámetrosopcionalesstartyenddefinenunasubcadenaenlaquebuscar.

S.find(sub[, start[, end]]) Devuelve la posición en la que se

encontróporprimeravezsubenlacadenao-1sinoseencontró.

S.join(sequence)

Devuelve una cadena resultante de concatenar las cadenas de la secuenciasequenceseparadasporlacadenasobrelaquesellamaelmétodo.

S.partition(sep)

Buscaelseparadorsepenlacadenaydevuelveunatuplaconlasubcadenahastadichoseparador,elseparadorensi,ylasubcadenadelseparadorhastaelfinaldelacadena.Sinoseencuentraelseparador, la tuplacontendrálacadenaensiydoscadenasvacías.

Page 72: Python para todos repasa aspectos esenciales de

S.replace(old,new[,count])Devuelveunacadenaenlaquesehan

reemplazado todas las ocurrencias de la cadena old por la cadena

new. Si se especifica el parámetro count, este indica el número

máximodeocurrenciasareemplazar.

S.split([sep [,maxsplit]]) Devuelve una lista conteniendo las

subcadenasenlasquesedividenuestracadenaaldividirlasporel

delimitadorsep.Enelcasodequenoseespecifiquesep,seusan

espacios.Siseespecificamaxsplit, este indica el número máximo

departicionesarealizar.

Page 73: Python para todos repasa aspectos esenciales de

ListasL.append(object)

Añadeunobjetoalfinaldelalista.

L.count(value)

Devuelveelnúmerodevecesqueseencontróvalueenlalista.

L.extend(iterable)Añadeloselementosdeliterablealalista.

L.index(value[,start[, stop]]) Devuelve la posición en la que se

encontrólaprimeraocurrenciadevalue.Siseespecifican,starty

stopdefinenlasposicionesdeinicioyfindeunasublistaenla

quebuscar.

L.insert(index, object) Inserta el objeto object en la posición

index.

L.pop([index])

Devuelve el valor en la posición index y lo elimina de la lista. Si no se

Page 74: Python para todos repasa aspectos esenciales de

especificalaposición,seutilizaelúltimoelementodelalista.

L.remove(value) Eliminar la primera ocurrencia de value en la

lista.

L.reverse()

Inviertelalista.Estafuncióntrabajasobrelapropialistadesdelaqueseinvocaelmétodo,nosobreunacopia.

L.sort(cmp=None, key=None, reverse=False) Ordena la lista. Si se

especificacmp,estedebeserunafunciónquetomecomoparámetro

dosvaloresxeydelalistaydevuelva-1sixesmenorquey,0

sisonigualesy1sixesmayorquey.

Elparámetroreverse esunbooleanoque indica si sedebeordenar la listadeformainversa,loqueseríaequivalenteallamarprimeroaL.sort()ydespuésaL.reverse().Porúltimo,siseespecifica,elparámetrokeydebeserunafunciónquetomeunelemento de la lista y devuelva una clave a utilizar a la hora de comparar, enlugardelelementoensi.

Page 75: Python para todos repasa aspectos esenciales de

PROGRAMACIÓNFUNCIONALLaprogramaciónfuncionalesunparadigmaenelquelaprogramaciónsebasacasiensutotalidadenfunciones,entendiendoelconceptodefunciónsegúnsudefiniciónmatemática, y no como los simples subprogramas de los lenguajesimperativosquehemosvistohastaahora.En los lenguajes funcionalespurosunprogramaconsiste exclusivamenteen laaplicacióndedistintasfuncionesaunvalordeentradaparaobtenerunvalordesalida.Python, sin ser un lenguaje puramente funcional incluye varias característicastomadasdeloslenguajesfuncionalescomosonlasfuncionesdeordensuperiorolasfuncioneslambda(funcionesanónimas).

Page 76: Python para todos repasa aspectos esenciales de

FuncionesdeordensuperiorElconceptodefuncionesdeordensuperiorserefierealusodefuncionescomosi de un valor cualquiera se tratara, posibilitando el pasar funciones comoparámetrosdeotrasfuncionesodevolverfuncionescomovalorderetorno.Estoesposibleporque,comohemosinsistidoyaenvariasocasiones,enPythontodosonobjetos.Ylasfuncionesnosonunaexcepción.Veamosunpequeñoejemplo

defsaludar(lang):

defsaludar_es():

print“Hola”

defsaludar_en():

print“Hi”

defsaludar_fr():

print“Salut”

lang_func={“es”:saludar_es,

“en”:saludar_en,

“fr”:saludar_fr}

returnlang_func[lang]

Page 77: Python para todos repasa aspectos esenciales de

f=saludar(“es”)

f()

Comopodemosobservarloprimeroquehacemosennuestropequeñoprogramaesllamaralafunciónsaludarconunparámetro“es”.Enlafunciónsaludarsedefinen varias funciones: saludar_es, saludar_en y saludar_fr y acontinuaciónsecreaundiccionarioquetienecomoclavescadenasdetextoqueidentificanacadalenguaje,ycomovaloreslasfunciones.Elvalorderetornodela funciónesunadeestas funciones.La funciónadevolvervienedeterminadaporelvalordelparámetrolangquesepasócomoargumentodesaludar.Comoel valor de retornodesaludar es una función, comohemosvisto, estoquieredecirquefesunavariablequecontieneunafunción.Podemosentoncesllamar a la función a la que se refiere f de la forma en que llamaríamos acualquierotrafunción,añadiendounosparéntesisy,deformaopcional,unaseriedeparámetrosentrelosparéntesis.Esto se podría acortar, ya que no es necesario almacenar la función que nospasancomovalorderetornoenunavariableparapoderllamarla:

>>>saludar(“en”)()

Hi

>>>saludar(“fr”)()

Salut

En este caso el primer par de paréntesis indica los parámetros de la funciónsaludar,yelsegundopar,losdelafuncióndevueltaporsaludar.

Page 78: Python para todos repasa aspectos esenciales de

IteracionesdeordensuperiorsobrelistasUnadelascosasmásinteresantesquepodemoshacerconnuestrasfuncionesdeorden superior es pasarlas como argumentos de las funciones map, filter yreduce.Estasfuncionesnospermitensustituirlosbuclestípicosdeloslenguajesimperativosmedianteconstruccionesequivalentes.

map(function,sequence[,sequence,...])Lafunciónmapaplicaunafunciónacadaelementodeunasecuenciaydevuelveunalistaconelresultadodeaplicarlafunciónacadaelemento.Sisepasancomoparámetrosnsecuencias,lafuncióntendráqueaceptarnargumentos.Sialgunadelassecuenciasesmáspequeñaquelasdemás,elvalorquelellegaalafunciónfunctionparaposicionesmayoresqueeltamañodedichasecuenciaseráNone.

Acontinuaciónpodemosverunejemploenelqueseutilizamapparaelevaralcuadradotodosloselementosdeunalista:

Page 79: Python para todos repasa aspectos esenciales de

defcuadrado(n):returnn**2

l=[1,2,3]l2=map(cuadrado,l)

filter(function,sequence)Lafunciónfilterverificaqueloselementosdeunasecuenciacumplanunadeterminadacondición,devolviendounasecuenciaconloselementosquecumplenesacondición.Esdecir,paracadaelementodesequenceseaplicalafunciónfunction;sielresultadoesTrueseañadealalistayencasocontrariosedescarta.

Acontinuaciónpodemosver un ejemplo en el que se utilizafilterparaconservarsololosnúmerosquesonpares.

defes_par(n):

return(n%2.0==0)l=[1,2,3]

l2=filter(es_par,l)

reduce(function,sequence[,initial])Lafunciónreduceaplicaunafunciónaparesdeelementosdeunasecuenciahastadejarlaenunsolovalor.

Acontinuaciónpodemosver un ejemplo en el que se utilizareduceparasumartodosloselementosdeunalista.

defsumar(x,y):

returnx+yl=[1,2,3]

l2=reduce(sumar,l)

Page 80: Python para todos repasa aspectos esenciales de

FuncioneslambdaEl operador lambda sirve para crear funciones anónimas en línea. Al serfuncionesanónimas,esdecir,sinnombre,estasnopodránserreferenciadasmástarde.Las funciones lambda se construyen mediante el operador lambda, losparámetros de la función separados por comas (atención, SIN paréntesis), dospuntos(:)yelcódigodelafunción.Estaconstrucciónpodríanhabersidodeutilidadenlosejemplosanterioresparareducircódigo.Elprogramaqueutilizamosparaexplicarfilter,porejemplo,podríaexpresarseasí:

l=[1,2,3]

l2=filter(lambdan:n%2.0==0,l)

Comparémosloconlaversiónanterior:defes_par(n):

return(n%2.0==0)l=[1,2,3]l2=filter(es_par,l)

Page 81: Python para todos repasa aspectos esenciales de

Lasfuncioneslambdaestánrestringidasporlasintaxisaunasolaexpresión.

Page 82: Python para todos repasa aspectos esenciales de

ComprensióndelistasEn Python 3 map, filter y reduce perderán importancia. Y aunque estasfuncionessemantendrán,reducepasaráaformarpartedelmódulofunctools,con lo que quedará fuera de las funciones disponibles por defecto, y map yfiltersedesaconsejaránenfavordelaslistcomprehensionsocomprensióndelistas.La comprensión de listas es una característica tomada del lenguaje deprogramaciónfuncionalHaskellqueestápresenteenPythondesdelaversión2.0yconsisteenunaconstrucciónquepermitecrearlistasapartirdeotraslistas.Cadaunadeestasconstruccionesconstadeunaexpresiónquedeterminacómomodificarelelementodelalistaoriginal,seguidadeunaovariasclausulasforyopcionalmenteunaovariasclausulasif.Veamos un ejemplo de cómo se podría utilizar la comprensión de listas paraelevar al cuadrado todos los elementos de una lista, como hicimos en nuestroejemplodemap.

Page 83: Python para todos repasa aspectos esenciales de

l2=[n**2forninl]

Esta expresión se leería como “para cada n en l haz n ** 2”. Como vemostenemosprimerolaexpresiónquemodificalosvaloresdelalistaoriginal(n**2), despuéselfor, elnombrequevamosautilizarpara referirnosal elementoactualdelalistaoriginal,elin,ylalistasobrelaqueseitera.Elejemploqueutilizamospara la funciónfilter (conservar solo losnúmerosquesonpares)sepodríaexpresarconcomprensióndelistasasí:

l2=[nforninlifn%2.0==0]

Veamosporúltimounejemplodecompresióndelistasconvariasclausulasfor:l=[0,1,2,3]

m=[“a”,“b”]

n=[s*vforsinm

forvinl

ifv>0]

Estaconstrucciónseríaequivalenteaunaseriedefor-inanidados:l=[0,1,2,3]

m=[“a”,“b”]

n=[]

forsinm:

forvinl:

ifv>0:

n.append(s*v)

Page 84: Python para todos repasa aspectos esenciales de

GeneradoresLasexpresionesgeneradorasfuncionandeformamuysimilaralacomprensiónde listas. De hecho su sintaxis es exactamente igual, a excepción de que seutilizanparéntesisenlugardecorchetes:

l2=(n**2forninl)

Sin embargo las expresiones generadoras se diferencian de la comprensión delistasenquenosedevuelveunalista,sinoungenerador.

>>>l2=[n**2forninl]

>>>l2

[0,1,4,9]

>>>l2=(n**2forninl)

>>>l2

<generatorobjectat0×00E33210>

Ungeneradoresunaclaseespecialdefunciónquegeneravaloressobrelosqueiterar. Para devolver el siguiente valor sobre el que iterar se utiliza la palabraclaveyieldenlugardereturn.Veamosporejemploungeneradorquedevuelvanúmerosdenamconunsaltos.

Page 85: Python para todos repasa aspectos esenciales de

defmi_generador(n,m,s):

while(n<=m):

yieldn

n+=s

>>>x=mi_generador(0,5,1)

>>>x

<generatorobjectat0×00E25710>

El generador se puede utilizar en cualquier lugar donde se necesite un objetoiterable.Porejemploenunfor-in:

forninmi_generador(0,5,1):

printn

Como no estamos creando una lista completa enmemoria, sino generando unsolovalorcadavezquesenecesita,ensituacionesen lasquenoseanecesariotenerlalistacompletaelusodegeneradorespuedesuponerunagrandiferenciade memoria. En todo caso siempre es posible crear una lista a partir de ungeneradormediantelafunciónlist:

lista=list(mi_generador)

Page 86: Python para todos repasa aspectos esenciales de

DecoradoresUn decorador no es es mas que una función que recibe una función comoparámetro y devuelve otra función como resultado. Por ejemplo podríamosquerer añadir la funcionalidad de que se imprimiera el nombre de la funciónllamadapormotivosdedepuración:

defmi_decorador(funcion):

defnueva(*args):

print“Llamadaalafuncion”,funcion.__name__

retorno=funcion(*args)

returnretorno

returnnueva

Comovemoselcódigodelafunciónmi_decoradornohacemásquecrearunanuevafunciónydevolverla.Estanuevafunciónimprimeelnombredelafunciónalaque“decoramos”,ejecutaelcódigodedichafunción,ydevuelvesuvalorderetorno. Es decir, que si llamáramos a la nueva función que nos devuelvemi_decorador, el resultado sería elmismo que el de llamar directamente a lafunción que le pasamos como parámetro, exceptuando el que se imprimiríaademáselnombredelafunción.

Page 87: Python para todos repasa aspectos esenciales de

Supongamoscomoejemplounafunciónimpquenohaceotracosaquemostrarenpantallalacadenapasadacomoparámetro.

>>>imp(“hola”)

hola

>>>mi_decorador(imp)(“hola”)

Llamadaalafunciónimp

hola

Lasintaxisparallamaralafunciónquenosdevuelvemi_decoradornoesmuyclara, aunque si lo estudiamos detenidamente veremos que no tiene mayorcomplicación.Primerosellamaalafunciónquedecoraconlafunciónadecorar:mi_decorador(imp); y una vez obtenida la función ya decorada se la puedellamar pasando el mismo parámetro que se pasó anteriormente:mi_decorador(imp)(“hola”)

Estosepodríaexpresarmásclaramenteprecediendoladefinicióndelafunciónque queremos decorar con el signo @ seguido del nombre de la funcióndecoradora:

@mi_decorador

defimp(s):

prints

De esta forma cada vez que se llame aimp se estará llamando realmente a laversión decorada. Python incorpora esta sintaxis desde la versión 2.4 enadelante.Siquisiéramosaplicarmásdeundecoradorbastaríaañadirunanuevalíneaconelnuevodecorador.

@otro_decorador

@mi_decorador

defimp(s):

prints

Es importante advertir que los decoradores se ejecutarán de abajo a arriba.Esdecir, en este ejemplo primero se ejecutaría mi_decorador y despuésotro_decorador.

Page 88: Python para todos repasa aspectos esenciales de

EXCEPCIONESLas excepciones son errores detectados por Python durante la ejecución delprograma. Cuando el intérprete se encuentra con una situación excepcional,comoelintentardividirunnúmeroentre0oelintentaraccederaunarchivoquenoexiste,estegeneraolanzaunaexcepción,informandoalusuariodequeexistealgúnproblema.Silaexcepciónnosecapturaelflujodeejecuciónseinterrumpeysemuestralainformaciónasociadaalaexcepciónenlaconsoladeformaqueelprogramadorpuedasolucionarelproblema.Veamosunpequeñoprogramaque lanzaríaunaexcepciónal intentardividir1entre0.

defdivision(a,b):

returna/b

defcalcular():

division(1,0)

calcular()

Page 89: Python para todos repasa aspectos esenciales de

Siloejecutamosobtendremoselsiguientemensajedeerror:$pythonejemplo.pyTraceback(mostrecentcalllast):File“ejemplo.py”,line7,incalcular()File“ejemplo.py”,line5,incalculardivision(1,0)File“ejemplo.py”,line2,indivisiona/bZeroDivisionError:integerdivisionormodulobyzero

Loprimeroquesemuestraeseltrazadodepilaotraceback,queconsisteenuna lista con las llamadas que provocaron la excepción. Como vemos en eltrazadodepila,elerrorestuvocausadoporlallamadaacalcular()delalínea7,queasuvezllamaadivision(1,0)enlalínea5yenúltimainstanciaporlaejecucióndelasentenciaa/bdelalínea2dedivision.

Acontinuaciónvemoseltipodelaexcepción,ZeroDivisionError,juntoauna descripción del error: “integer division or modulo by zero” (módulo odivisiónenteraentrecero).

EnPythonseutilizaunaconstruccióntry-exceptparacapturarytratarlasexcepciones.Elbloquetry (intentar) define el fragmentode código en el quecreemos que podría producirse una excepción. El bloque except (excepción)permite indicar el tratamiento que se llevará a cabo de producirse dichaexcepción. Muchas veces nuestro tratamiento de la excepción consistirásimplementeenimprimirunmensajemásamigableparaelusuario,otrasvecesnosinteresaráregistrarloserroresydevezencuandopodremosestablecerunaestrategiaderesolucióndelproblema.

Enelsiguienteejemplointentamoscrearunobjetofdetipofichero.Denoexistir el archivo pasado como parámetro, se lanza una excepción de tipoIOError,quecapturamosgraciasanuestrotry-except.

try:

f=file(“archivo.txt”)

except:

print“Elarchivonoexiste”

Python permite utilizar variosexcept para un solo bloquetry, de formaquepodamosdaruntratamientodistintoalaexcepcióndependiendodeltipodeexcepcióndelaquesetrate.Estoesunabuenapráctica,yestansencillocomoindicarelnombredeltipoacontinuacióndelexcept.

try:

Page 90: Python para todos repasa aspectos esenciales de

num=int(“3a”)

printno_existe

exceptNameError:

print“Lavariablenoexiste”

exceptValueError:

print“Elvalornoesunnumero”

Cuandoselanzaunaexcepciónenelbloquetry,sebuscaencadaunadelasclausulasexceptunmanejadoradecuadoparaeltipodeerrorqueseprodujo.Encasodequenoseencuentre,sepropagalaexcepción.

Ademáspodemoshacerqueunmismoexceptsirvaparatratarmásdeunaexcepciónusandounatuplaparalistarlostiposdeerrorquequeremosquetrateelbloque:

try:num=int(“3a”)printno_existe

except(NameError,ValueError):print“Ocurriounerror”

La construccióntry-except puede contar además con una clausulaelse,quedefineunfragmentodecódigoaejecutarsólosinosehaproducidoningunaexcepcióneneltry.

try:

num=33

except:

print“Hubounerror!”

else:

print“Todoestabien”

Tambiénexisteunaclausulafinallyqueseejecutasiempre,seproduzcaonounaexcepción.Estaclausulasesueleutilizar,entreotrascosas,paratareasdelimpieza.

try:

z=x/y

exceptZeroDivisionError:

print“Divisionporcero”

finally:

print“Limpiando”

Tambiénesinteresantecomentarquecomoprogramadorespodemoscrearylanzar nuestras propias excepciones. Basta crear una clase que herede deExceptionocualquieradesushijasylanzarlaconraise.

classMiError(Exception):

def__init__(self,valor):

self.valor=valor

def__str__(self):

return“Error“+str(self.valor)

try:

Page 91: Python para todos repasa aspectos esenciales de

ifresultado>20:

raiseMiError(33)

exceptMiError,e:

printe

Porúltimo,acontinuaciónse listanamodode referencia lasexcepcionesdisponibles por defecto, así como la clase de la que deriva cada una de ellasentreparéntesis.

BaseException:Clasedelaqueheredantodaslasexcepciones.

Exception(BaseException):Superclasede todas lasexcepcionesquenoseandesalida.

GeneratorExit(Exception):Sepidequesesalgadeungenerador.

StandardError(Exception):Clasebaseparatodaslasexcepcionesquenotenganqueverconsalirdelintérprete.

ArithmeticError(StandardError): Clase base para los erroresaritméticos.

FloatingPointError(ArithmeticError):Errorenunaoperacióndecomaflotante.

OverflowError(ArithmeticError): Resultado demasiado grande parapoderrepresentarse.

ZeroDivisionError(ArithmeticError): Lanzada cuando el segundoargumentodeunaoperacióndedivisiónomóduloera0.

AssertionError(StandardError): Falló la condición de un estamentoassert.

AttributeError(StandardError):Noseencontróelatributo.

EOFError(StandardError):Seintentóleermásalládelfinaldefichero.

EnvironmentError(StandardError): Clase padre de los erroresrelacionadosconlaentrada/salida.

IOError(EnvironmentError):Errorenunaoperacióndeentrada/salida.

Page 92: Python para todos repasa aspectos esenciales de

OSError(EnvironmentError):Errorenunallamadaasistema.

WindowsError(OSError):ErrorenunallamadaasistemaenWindows.

ImportError(StandardError):No se encuentra elmódulo o el elementodelmóduloquesequeríaimportar.

LookupError(StandardError):Clasepadredeloserroresdeacceso.

IndexError(LookupError):El índicede la secuenciaestá fueradel rangoposible.

KeyError(LookupError):Laclavenoexiste.

MemoryError(StandardError):Noquedamemoriasuficiente.

NameError(StandardError): No se encontró ningún elemento con esenombre.

UnboundLocalError(NameError): El nombre no está asociado a ningunavariable.

ReferenceError(StandardError): El objeto no tiene ninguna referenciafuerteapuntandohaciaél.

RuntimeError(StandardError): Error en tiempo de ejecución noespecificado.

NotImplementedError(RuntimeError): Ese método o función no estáimplementado.

SyntaxError(StandardError):Clasepadreparaloserroressintácticos.

IndentationError(SyntaxError):Errorenlaindentacióndelarchivo.

TabError(IndentationError): Error debido a la mezcla de espacios ytabuladores.

SystemError(StandardError):Errorinternodelintérprete.

TypeError(StandardError):Tipodeargumentonoapropiado.

Page 93: Python para todos repasa aspectos esenciales de

ValueError(StandardError):Valordelargumentonoapropiado.

UnicodeError(ValueError):Clasepadreparaloserroresrelacionadosconunicode.

UnicodeDecodeError(UnicodeError):Errordedecodificaciónunicode.

UnicodeEncodeError(UnicodeError):Errordecodificaciónunicode.

UnicodeTranslateError(UnicodeError):Errordetraducciónunicode.

StopIteration(Exception):Seutilizaparaindicarelfinaldeliterador.

Warning(Exception):Clasepadreparalosavisos.

DeprecationWarning(Warning): Clase padre para avisos sobrecaracterísticasobsoletas.

FutureWarning(Warning): Aviso. La semántica de la construccióncambiaráenunfuturo.

ImportWarning(Warning): Aviso sobre posibles errores a la hora deimportar.

PendingDeprecationWarning(Warning):Avisosobrecaracterísticasquesemarcaráncomoobsoletasenunfuturopróximo.

RuntimeWarning(Warning): Aviso sobre comportamientos dudosos entiempodeejecución.

SyntaxWarning(Warning):Avisosobresintaxisdudosa.

UnicodeWarning(Warning): Aviso sobre problemas relacionados conUnicode,sobretodoconproblemasdeconversión.

UserWarning(Warning): Clase padre para avisos creados por elprogramador.

KeyboardInterrupt(BaseException):Elprogramafueinterrumpidoporelusuario.

Page 94: Python para todos repasa aspectos esenciales de

SystemExit(BaseException): Petición del intérprete para terminar laejecución.

Page 95: Python para todos repasa aspectos esenciales de

MÓDULOSYPAQUETES

Page 96: Python para todos repasa aspectos esenciales de

MódulosPara facilitar el mantenimiento y la lectura los programas demasiado largospuedendividirse enmódulos, agrupandoelementos relacionados.Losmódulosson entidades que permiten una organización y división lógica de nuestrocódigo. Los ficheros son su contrapartida física: cada archivo Pythonalmacenadoendiscoequivaleaunmódulo.Vamos a crear nuestro primer módulo entonces creando un pequeño archivomodulo.pyconelsiguientecontenido:

defmi_funcion():

print“unafuncion”

classMiClase:

def__init__(self):

print“unaclase”

print“unmodulo”

Si quisiéramos utilizar la funcionalidad definida en este módulo en nuestroprograma tendríamos que importarlo. Para importar un módulo se utiliza la

Page 97: Python para todos repasa aspectos esenciales de

palabraclaveimportseguidadelnombredelmódulo,queconsisteenelnombredelarchivomenoslaextensión.Comoejemplo,creemosunarchivoprograma.pyen el mismo directorio en el que guardamos el archivo del módulo (esto esimportante,porque sino seencuentraenelmismodirectorioPythonnopodráencontrarlo),conelsiguientecontenido:

importmodulo

modulo.mi_funcion()

El import no solo hace que tengamos disponible todo lo definido dentro delmódulo,sinoquetambiénejecutaelcódigodelmódulo.Porestarazónnuestroprograma, ademásde imprimir el texto “una funcion”al llamar ami_funcion,también imprimiría el texto “un modulo”, debido al print del móduloimportado.Noseimprimiría,noobstante,eltexto“unaclase”,yaqueloquesehizoenelmódulofuetansolodefinirdelaclase,noinstanciarla.Laclausulaimporttambiénpermiteimportarvariosmódulosenlamismalínea.En el siguiente ejemplo podemos ver cómo se importa con una sola clausulaimport losmódulos de la distribución por defecto de Pythonos, que englobafuncionalidad relativa al sistemaoperativo;sys, con funcionalidad relacionadaconelpropiointérpretedePythonytime,enelquesealmacenanfuncionesparamanipularfechasyhoras.

importos,sys,time

printtime.asctime()

Sindudaoshabréisfijadoenesteyelanteriorejemploenundetalleimportante,y es que, como vemos, es necesario preceder el nombre de los objetos queimportamosdeunmóduloconelnombredelmóduloalquepertenecen,oloqueeslomismo,elespaciodenombresenelqueseencuentran.Estopermitequenosobreescribamosaccidentalmentealgúnotroobjetoquetuvieraelmismonombrealimportarotromódulo.Sinembargoesposibleutilizar laconstrucciónfrom-importparaahorrarnoseltenerqueindicarelnombredelmóduloantesdelobjetoquenosinteresa.Deestaformaseimportaelobjetoolosobjetosqueindiquemosalespaciodenombresactual.

fromtimeimportasctime

printasctime()

Aunque se considera unamala práctica, también es posible importar todos losnombresdelmóduloalespaciodenombresactualusandoelcarácter*:

Page 98: Python para todos repasa aspectos esenciales de

fromtimeimport*

Ahorabien,recordareisquealahoradecrearnuestroprimermóduloinsistíenqueloguardaraisenelmismodirectorioenelqueseencontrabaelprogramaqueloimportaba.Entonces,¿cómopodemosimportarlosmódulosos,sysotimesinoseencuentranlosarchivosos.py,sys.pyytime.pyenelmismodirectorio?AlahoradeimportarunmóduloPythonrecorretodoslosdirectoriosindicadosen la variable de entorno PYTHONPATH en busca de un archivo con el nombreadecuado.Elvalorde lavariablePYTHONPATH sepuedeconsultardesdePythonmediantesys.path

>>>importsys

>>>sys.path

De esta forma para que nuestro módulo estuviera disponible para todos losprogramasdel sistemabastaríaconque locopiáramosaunode losdirectoriosindicadosenPYTHONPATH.En el caso de que Python no encontrara ningún módulo con el nombreespecificado,selanzaríaunaexcepcióndetipoImportError.Por último es interesante comentar que en Python los módulos también sonobjetos;detipomoduleenconcreto.Porsupuestoestosignificaquepuedenteneratributosymétodos.Unodesusatributos,__name__, seutiliza amenudoparaincluircódigoejecutableenunmóduloperoqueestesóloseejecutesisellamaalmódulocomoprograma,ynoalimportarlo.Paralograrestobastasaberquecuando se ejecuta el módulo directamente __name__ tiene como valor“__main__”,mientrasquecuandoseimporta,elvalorde__name__eselnombredelmódulo:

print“Semuestrasiempre”

if__name__==“__main__”:

print“Semuestrasinoesimportacion”

Otroatributointeresantees__doc__,que,comoenelcasodefuncionesyclases,sirve a modo de documentación del objeto (docstring o cadena dedocumentación).Suvaloreseldelaprimeralíneadelcuerpodelmódulo,enelcasodequeestaseaunacadenadetexto;encasocontrariovaldráNone.

Page 99: Python para todos repasa aspectos esenciales de

PaquetesSi los módulos sirven para organizar el código, los paquetes sirven paraorganizarlosmódulos.Lospaquetessontiposespecialesdemódulos(ambossonde tipo module) que permiten agrupar módulos relacionados. Mientras losmódulos se corresponden a nivel físico con los archivos, los paquetes serepresentanmediantedirectorios.Enunaaplicacióncualquierapodríamostener,porejemplo,unpaqueteiuparalainterfazounpaquetebbddparalapersistenciaabasededatos.ParahacerquePythontrateaundirectoriocomounpaqueteesnecesariocrearun archivo __init__.py en dicha carpeta. En este archivo se pueden definirelementosquepertenezcanadichopaquete,comounaconstanteDRIVERparaelpaquetebbdd, aunquehabitualmente se tratarádeunarchivovacío.Parahacerque un ciertomódulo se encuentre dentro de un paquete, basta con copiar elarchivoquedefineelmóduloaldirectoriodelpaquete.Como losmódulos, para importar paquetes también se utiliza import y from-

Page 100: Python para todos repasa aspectos esenciales de

importyelcarácter.parasepararpaquetes,subpaquetesymódulos.importpaq.subpaq.modulo

paq.subpaq.modulo.func()

A lo largo de los próximos capítulos veremos algunosmódulos y paquetes deutilidad.Paraencontraralgúnmóduloopaquetequecubraunaciertanecesidad,puedes consultar la lista de PyPI (Python Package Index) enhttp://pypi.python.org/,quecuentaalahoradeescribirestaslíneas,conmásde4000paquetesdistintos.

Page 101: Python para todos repasa aspectos esenciales de

ENTRADA/SALIDAYFICHEROSNuestros programas serían de muy poca utilidad si no fueran capaces deinteraccionarconelusuario.Encapítulosanterioresvimos,depasada,elusodelapalabraclaveprintparamostrarmensajesenpantalla.Enestalección,ademásdedescribirmásdetalladamentedelusodeprintparamostrar mensajes al usuario, aprenderemos a utilizar las funciones input yraw_input para pedir información, así como los argumentos de línea decomandosy,porúltimo,laentrada/salidadeficheros.

Page 102: Python para todos repasa aspectos esenciales de

EntradaestándarLaformamássencilladeobtenerinformaciónporpartedelusuarioesmediantela función raw_input. Esta función toma como parámetro una cadena a usarcomoprompt (esdecir,como textoamostraralusuariopidiendo laentrada)ydevuelve una cadena con los caracteres introducidos por el usuario hasta quepulsólateclaEnter.Veamosunpequeñoejemplo:nombre=raw_input(“Comotellamas?“)print“Encantado,“+nombre

Si necesitáramos un entero como entrada en lugar de una cadena, porejemplo, podríamos utilizar la función int para convertir la cadena a entero,aunqueseríaconvenientetenerencuentaquepuedelanzarseunaexcepciónsiloqueintroduceelusuarionoesunnúmero.

try:

edad=raw_input(“Cuantosanyostienes?“)dias=int(edad)*365

print“Hasvivido“+str(dias)+“dias”

exceptValueError:

print“Esonoesunnumero”

Lafuncióninputesunpocomáscomplicada.Loquehaceestafunciónes

Page 103: Python para todos repasa aspectos esenciales de

utilizarraw_inputparaleerunacadenadelaentradaestándar,ydespuéspasaaevaluarlacomosidecódigoPythonsetratara;porlotantoinputdeberíatratarseconsumocuidado.

Page 104: Python para todos repasa aspectos esenciales de

ParámetrosdelíneadecomandoAdemásdelusodeinputyraw_inputelprogramadorPythoncuentaconotrosmétodosparaobtenerdatosdelusuario.Unodeelloseselusodeparámetrosalahoradellamaralprogramaenlalíneadecomandos.Porejemplo:

pythoneditor.pyhola.txt

Enestecasohola.txtseríaelparámetro,alquesepuedeaccederatravésdelalista sys.argv, aunque, como es de suponer, antes de poder utilizar dichavariable debemos importar el módulo sys. sys.argv[0] contiene siempre elnombre del programa tal como lo ha ejecutado el usuario, sys.argv[1], siexiste,seríaelprimerparámetro;sys.argv[2]elsegundo,yasísucesivamente.

importsys

if(len(sys.argv)>1):

print“Abriendo“+sys.argv[1]

else:

print“Debesindicarelnombredelarchivo”

Existenmódulos,comooptparse,quefacilitaneltrabajoconlosargumentosde

Page 105: Python para todos repasa aspectos esenciales de

la línea de comandos, pero explicar su uso queda fuera del objetivo de estecapítulo.

Page 106: Python para todos repasa aspectos esenciales de

SalidaestándarLaformamássencillademostraralgoenlasalidaestándaresmedianteelusodelasentenciaprint,comohemosvistomultituddevecesenejemplosanteriores.En su formamás básica a la palabra claveprint le sigue una cadena, que semostraráenlasalidaestándaralejecutarseelestamento.

>>>print“Holamundo”

Holamundo

Despuésdeimprimirlacadenapasadacomoparámetroelpunterosesitúaenlasiguientelíneadelapantalla,porloqueelprintdePythonfuncionaigualqueelprintlndeJava.En algunas funciones equivalentes de otros lenguajes de programación esnecesario añadir un carácter de nueva línea para indicar explícitamente quequeremospasaralasiguientelínea.EsteeselcasodelafunciónprintfdeColapropiafunciónprintdeJava.Ya explicamos el uso de estos caracteres especiales durante la explicación deltipo cadena en el capítulo sobre los tipos básicos de Python. La siguiente

Page 107: Python para todos repasa aspectos esenciales de

sentencia, por ejemplo, imprimiría la palabra “Hola”, seguida de un renglónvacío(doscaracteresdenuevalínea,‘\n’),yacontinuaciónlapalabra“mundo”indentada(uncaráctertabulador,‘\t’).

print“Hola\n\n\tmundo”

Paraque la siguiente impresión se realizara en lamisma línea tendríamosquecolocar una coma al final de la sentencia. Comparemos el resultado de estecódigo:

>>>foriinrange(3):

>>>...printi,

012

Coneldeesteotro,enelquenoutilizaunacomaalfinaldelasentencia:>>>foriinrange(3):

>>>...printi

0

1

2

Estemecanismodecolocarunacomaalfinaldelasentenciafuncionadebidoaqueeselsímboloqueseutilizaparasepararcadenasquequeramosimprimirenlamismalínea.

>>>print“Hola”,“mundo”

Holamundo

Estosediferenciadelusodeloperador+paraconcatenarlascadenasenquealutilizarlascomasprintintroduceautomáticamenteunespacioparasepararcadaunadelascadenas.Estenoeselcasoalutilizareloperador+,yaqueloquelellegaaprintesunsoloargumento:unacadenayaconcatenada.

>>>print“Hola”+“mundo”

Holamundo

Además,alutilizareloperador+tendríamosqueconvertirantescadaargumentoenunacadenadenoserloya,yaquenoesposibleconcatenarcadenasyotrostipos,mientrasquealusarelprimermétodonoesnecesarialaconversión.

>>>print“Cuesta”,3,“euros”

Cuesta3euros

>>>print“Cuesta”+3+“euros”

<type‘exceptions.TypeError’>:cannotconcatenate‘str’and

‘int’objects

La sentencia print, o más bien las cadenas que imprime, permiten tambiénutilizar técnicas avanzadas de formateo, de forma similar al sprintf de C.Veamosunejemplobastantesimple:

print“Hola%s”%“mundo”

print“%s%s”%(“Hola”,“mundo”)

Page 108: Python para todos repasa aspectos esenciales de

Loquehacelaprimeralíneaesintroducirlosvaloresaladerechadelsímbolo%(la cadena “mundo”) en las posiciones indicadas por los especificadores deconversión de la cadena a la izquierda del símbolo%, tras convertirlos al tipoadecuado.Enlasegundalínea,vemoscómosepuedepasarmásdeunvalorasustituir,pormediodeunatupla.Enesteejemplosólotenemosunespecificadordeconversión:%s.Losespecificadoresmás sencillos están formadospor el símbolo% seguidodeunaletraqueindicaeltipoconelqueformatearelvalor.Porejemplo:

Especificador Formato%s Cadena%d Entero%o Octal%x Hexadecimal%f Real

Sepuedeintroducirunnúmeroentreel%yelcarácterqueindicaeltipoalqueformatear,indicandoelnúmeromínimodecaracteresquequeremosqueocupelacadena. Si el tamaño de la cadena resultante es menor que este número, seañadiránespaciosalaizquierdadelacadena.Enelcasodequeelnúmeroseanegativo,ocurriráexactamentelomismo,sóloquelosespaciosseañadiránaladerechadelacadena.

>>>print“%10smundo”%“Hola”

______Holamundo

>>>print“%-10smundo”%“Hola”

Hola_______mundo

Enelcasodelosrealesesposibleindicarlaprecisiónautilizarprecediendolafdeunpuntoseguidodelnúmerodedecimalesquequeremosmostrar:

>>>frommathimportpi

>>>print“%.4f”%pi

3.1416

Lamisma sintaxis sepuedeutilizarpara indicar el númerode caracteresde lacadenaquequeremosmostrar

>>>print“%.4s”%“holamundo”

hola

Page 109: Python para todos repasa aspectos esenciales de

ArchivosLos ficheros en Python son objetos de tipo file creadosmediante la funciónopen (abrir). Esta función toma como parámetros una cadena con la ruta alficheroaabrir,quepuedeserrelativaoabsoluta;unacadenaopcionalindicandoelmododeacceso(sinoseespecificaseaccedeenmodolectura)y,porúltimo,unenteroopcionalparaespecificaruntamañodebufferdistintodelutilizadopordefecto.El modo de acceso puede ser cualquier combinación lógica de los siguientesmodos:

‘r’: read, lectura.Abre el archivo enmodo lectura. El archivo tiene queexistir previamente, en caso contrario se lanzará una excepción de tipoIOError.‘w’:write, escritura.Abre el archivo enmodo escritura. Si el archivo noexistesecrea.Siexiste,sobreescribeelcontenido.

Page 110: Python para todos repasa aspectos esenciales de

‘a’: append, añadir.Abre el archivo enmodoescritura.Sediferenciadelmodo‘w’enqueenestecasonosesobreescribeelcontenidodelarchivo,sinoquesecomienzaaescribiralfinaldelarchivo.‘b’:binary,binario.‘+’:permitelecturayescriturasimultáneas.‘U’: universal newline, saltos de línea universales. Permite trabajar conarchivosquetenganunformatoparalossaltosdelíneaquenocoincideconeldelaplataformaactual(enWindowsseutilizaelcarácterCRLF,enUnixLFyenMacOSCR).

f=open(“archivo.txt”,“w”)

Tras crear el objeto que representa nuestro archivo mediante la función openpodremosrealizarlasoperacionesdelectura/escriturapertinentesutilizandolosmétodosdelobjetoqueveremosenlassiguientessecciones.Unavez terminemosde trabajar con el archivodebemos cerrarlo utilizando elmétodoclose.

LecturadearchivosParalalecturadearchivosseutilizanlosmétodosread,readlineyreadlines.El método read devuelve una cadena con el contenido del archivo o bien elcontenidodelosprimerosnbytes,siseespecificaeltamañomáximoaleer.

completo=f.read()

parte=f2.read(512)

Elmétodoreadlinesirveparaleerlaslíneasdelficherounaporuna.Esdecir,cadavezquesellamaaestemétodo,sedevuelveelcontenidodelarchivodesdeel puntero hasta que se encuentra un carácter de nueva línea, incluyendo estecarácter.

whileTrue:

linea=f.readline()

ifnotlinea:break

printlinea

Por último, readlines, funciona leyendo todas las líneas del archivo ydevolviendounalistaconlaslíneasleídas.

EscrituradearchivosPara la escritura de archivos se utilizan los métodos write y writelines.Mientraselprimerofuncionaescribiendoenelarchivounacadenadetextoque

Page 111: Python para todos repasa aspectos esenciales de

tomacomoparámetro,elsegundotomacomoparámetrounalistadecadenasdetextoindicandolaslíneasquequeremosescribirenelfichero.

Moverelpunterodelectura/escrituraHay situaciones en las que nos puede interesar mover el puntero delectura/escritura a una posición determinada del archivo. Por ejemplo siqueremos empezar a escribir en una posición determinada y no al final o alprincipiodelarchivo.Para esto se utiliza el método seek que toma como parámetro un númeropositivoonegativoautilizarcomodesplazamiento.Tambiénesposibleutilizarun segundo parámetro para indicar desde dónde queremos que se haga eldesplazamiento: 0 indicará que el desplazamiento se refiere al principio delfichero (comportamientopordefecto), 1 se refiere a laposiciónactual, y2, alfinaldelfichero.Para determinar la posición en la que se encuentra actualmente el puntero seutilizaelmétodotell(),quedevuelveunenteroindicandoladistanciaenbytesdesdeelprincipiodelfichero.

Page 112: Python para todos repasa aspectos esenciales de

EXPRESIONESREGULARESLas expresiones regulares, también llamadas regex o regexp, consisten enpatronesquedescribenconjuntosdecadenasdecaracteres.AlgoparecidoseríaescribirenlalíneadecomandosdeWindows

dir*.exe

‘*.exe’ sería una “expresión regular” que describiría todas las cadenas decaracteresqueempiezanconcualquiercosaseguidade‘.exe’,esdecir,todoslosarchivosexe.EltrabajoconexpresionesregularesenPythonserealizamedianteelmódulore,que data de Python 1.5 y que proporciona una sintaxis para la creación depatronessimilaraladePerl.EnPython1.6elmódulosereescribióparadotarlodesoportedecadenasunicodeymejorarsurendimiento.El módulo re contiene funciones para buscar patrones dentro de una cadena(search),comprobarsiunacadenaseajustaaundeterminadocriteriodescritomedianteunpatrón(match),dividirlacadenausandolasocurrenciasdelpatrón

Page 113: Python para todos repasa aspectos esenciales de

comopuntosderuptura(split)oparasustituirtodaslasocurrenciasdelpatrónpor otra cadena (sub). Veremos estas funciones y alguna más en la próximasección, pero por ahora, aprendamos algo más sobre la sintaxis de lasexpresionesregulares.

Page 114: Python para todos repasa aspectos esenciales de

PatronesLaexpresión regularmássencillaconsisteenunacadenasimple,quedescribeun conjunto compuesto tan solo por esamisma cadena. Por ejemplo, veamoscómolacadena“python”coincideconlaexpresiónregular“python”usandolafunciónmatch:

importre

ifre.match(“python”,“python”):

print“cierto”

Si quisiéramos comprobar si la cadena es “python”, “jython”, “cython” ocualquier otra cosa que termine en “ython”, podríamos utilizar el caráctercomodín,elpunto‘.’:

re.match(“.ython”,“python”)

re.match(“.ython”,“jython”)

Laexpresiónregular“.ython”describiríaa todas lascadenasqueconsistanenuncaráctercualquiera,menoseldenuevalínea,seguidode“ython”.Uncaráctercualquieraysolouno.Nocero,nidos,nitres.

Page 115: Python para todos repasa aspectos esenciales de

En el caso de que necesitáramos el carácter ‘.’ en la expresión regular, ocualquier otro de los caracteres especiales que veremos a continuación,tendríamosqueescaparloutilizandolabarrainvertida.Paracomprobarsilacadenaconsisteen3caracteresseguidosdeunpunto,porejemplo,podríamosutilizarlosiguiente:

re.match(“...\.”,“abc.”)

Si necesitáramos una expresión que sólo resultara cierta para las cadenas“python”,“jython”y“cython”yningunaotra,podríamosutilizarelcarácter‘|’paraexpresaralternativaescribiendolostressubpatronescompletos:

re.match(“python|jython|cython”,“python”)

obientansololapartequepuedacambiar,encerradaentreparéntesis,formandoloqueseconocecomoungrupo.Losgrupos tienenunagran importanciaa lahora de trabajar con expresiones regulares y este no es su único uso, comoveremosenlasiguientesección.

re.match(“(p|j|c)ython”,“python”)

Otra opción consistiría en encerrar los caracteres ‘p’, ‘j’ y ‘c’ entre corchetespara formar una clase de caracteres, indicando que en esa posición puedecolocarsecualquieradeloscaracteresdelaclase.

re.match(“[pjc]ython”,“python”)

¿Ysiquisiéramoscomprobarsilacadenaes“python0”,“python1”,“python2”,... , “python9”? En lugar de tener que encerrar los 10 dígitos dentro de loscorchetespodemosutilizarelguión,quesirveparaindicarrangos.Porejemploa-d indicaría todas las letrasminúsculasde la‘a’a la ‘d’;0-9 serían todos losnúmerosde0a9inclusive.

re.match(“python[0-9]”,“python0”)

Siquisiéramos,porejemplo,queelúltimocarácterfueraoundígitoounaletrasimplementeseescribiríandentrodeloscorchetestodosloscriterios,unodetrásdeotro.

re.match(“python[0-9a-zA-Z]”,“pythonp”)

Es necesario advertir que dentro de las clases de caracteres los caracteresespecialesnonecesitanserescapados.Paracomprobarsilacadenaes“python.”o“python,”,entonces,escribiríamos:

re.match(“python[.,]”,“python.”)

yno

Page 116: Python para todos repasa aspectos esenciales de

re.match(“python[\.,]”,“python.”)

yaqueenesteúltimocasoestaríamoscomprobandosilacadenaes“python.”,“python,”o“python\”.

Losconjuntosdecaracterestambiénsepuedennegarutilizandoelsímbolo‘^’.La expresión “python[^0-9a-z]”, por ejemplo, indicaríaquenos interesan lascadenasquecomiencenpor“python”ytengancomoúltimocarácteralgoquenoseaniunaletraminúsculaniunnúmero.

re.match(“python[^0-9a-z]”,“python+”)

Elusode[0-9] para referirse aundígitonoesmuycomún,yaque, al ser lacomprobación de que un carácter es un dígito algomuy utilizado, existe unasecuencia especial equivalente: ‘\d’. Existen otras secuencias disponibles quelistamosacontinuación:

“\d”:undígito.Equivalea[0-9]“\D”:cualquiercarácterquenoseaundígito.Equivalea[^0-9]“\w”:cualquiercarácteralfanumérico.Equivalea[a-zA-Z0-9_]“\W”:cualquiercarácternoalfanumérico.Equivalea[^a-zA-Z0-9_]“\s”:cualquiercarácterenblanco.Equivalea[\t\n\r\f\v]“\S”: cualquier carácter que no sea un espacio en blanco. Equivale a [^\t\n\r\f\v]

Veamosahoracómorepresentarrepeticionesdecaracteres,dadoquenoseríademucha utilidad tener que, por ejemplo, escribir una expresión regular con 30caracteres‘\d’parabuscarnúmerosde30dígitos.Paraestemenestertenemosloscaracteresespeciales+,*y?,ademásdelasllaves{}.Elcarácter+indicaqueloquetenemosalaizquierda,seauncaráctercomo‘a’,unaclasecomo ‘[abc]’ o un subpatrón como(abc), puede encontrarse una omasveces.Porejemplo laexpresión regular“python+”describiría las cadenas“python”, “pythonn” y “pythonnn”, pero no “pytho”, ya que debe haber almenosunan.Elcarácter*essimilara+,peroenestecasoloquesesitúaasuizquierdapuedeencontrarseceroomasveces.Elcarácter?indicaopcionalidad,esdecir,loquetenemosalaizquierdapuedeonoaparecer(puedeaparecer0o1veces).Finalmente las llavessirvenpara indicarelnúmerodevecesexactoquepuede

Page 117: Python para todos repasa aspectos esenciales de

aparecerelcarácterdelaizquierda,obienunrangodevecesquepuedeaparecer.Por ejemplo{3} indicaría que tiene que aparecer exactamente 3 veces, {3,8}indicaríaquetienequeaparecerde3a8veces,{,8}de0a8vecesy{3,}tresvecesomas(lasquesean).Otro elemento interesante en las expresiones regulares, para terminar, es laespecificacióndelasposicionesenquesetienequeencontrarlacadena,esaeslautilidad de ^ y $, que indican, respectivamente, que el elemento sobre el queactúandebeiralprincipiodelacadenaoalfinaldeesta.La cadena “http://mundogeek.net”, por ejemplo, se ajustaría a la expresiónregular“^http”,mientrasquelacadena“Elprotocoloeshttp”noloharía,yaqueelhttpnoseencuentraalprincipiodelacadena.

Page 118: Python para todos repasa aspectos esenciales de

UsandoelmóduloreYahemosvistoporencimacómoseutilizalafunciónmatchdelmóduloreparacomprobarsiunacadenaseajustaaundeterminadopatrón.Elprimerparámetrodelafuncióneslaexpresiónregular,elsegundo,lacadenaacomprobaryexisteuntercerparámetroopcionalquecontienedistintosflagsquesepuedenutilizarparamodificarelcomportamientodelasexpresionesregulares.Algunosejemplosdeflagsdelmóduloresonre.IGNORECASE,quehacequenosetengaencuentasilasletrassonmayúsculasominúsculasore.VERBOSE,quehacequeseignorenlosespaciosyloscomentariosenlacadenaquerepresentalaexpresiónregular.ElvalorderetornodelafunciónseráNoneencasodequelacadenanoseajusteal patrón o un objeto de tipo MatchObject en caso contrario. Este objetoMatchObjectcuentaconmétodosstartyendquedevuelven laposiciónen laquecomienzayfinalizalasubcadenareconocidaymétodosgroupygroupsquepermitenaccederalosgruposquepropiciaronelreconocimientodelacadena.

Page 119: Python para todos repasa aspectos esenciales de

Al llamar al método group sin parámetros se nos devuelve el grupo 0 de lacadena reconocida. El grupo 0 es la subcadena reconocida por la expresiónregularalcompleto,aunquenoexistanparéntesisquedelimitenelgrupo.

>>>mo=re.match(“http://.+\net”,“http://mundogeek.net”)

>>>printmo.group()

http://mundogeek.net

Podríamoscreargruposutilizandolosparéntesis,comoaprendimosenlasecciónanterior,obteniendoasílapartedelacadenaquenosinterese.

>>>mo=re.match(“http://(.+)\net”,“http://mundogeek.net”)

>>>printmo.group(0)

http://mundogeek.net

>>>printmo.group(1)

mundogeek

El método groups, por su parte, devuelve una lista con todos los grupos,exceptuandoelgrupo0,queseomite.

>>>mo=re.match(“http://(.+)\(.{3})”,“http://mundogeek.net”)

>>>printmo.groups()

(‘mundogeek’,‘net’)

Lafunciónsearchdelmódulorefuncionadeformasimilaramatch;contamosconlosmismosparámetrosyelmismovalorderetorno.Laúnicadiferenciaesquealutilizarmatchlacadenadebeajustarsealpatróndesdeelprimercarácterde la cadena,mientras que consearch buscamos cualquier parte de la cadenaque se ajuste al patrón. Por esta razón el método start de un objetoMatchObjectobtenidomediantelafunciónmatchsiempredevolverá0,mientrasqueenelcasodesearchestonotieneporquéserasí.Otra función de búsqueda del módulo re es findall. Este toma los mismosparámetros que las dos funciones anteriores, pero devuelve una lista con lassubcadenasquecumplieronelpatrón.Otra posibilidad, si no queremos todas las coincidencias, es utilizarfinditer,que devuelve un iterador con el que consultar uno a uno los distintosMatchObject.Las expresiones regulares no solo permiten realizar búsquedas ocomprobaciones, sino que, como comentamos anteriormente, también tenemosfuncionesdisponiblesparadividirlacadenaorealizarreemplazos.Lafunciónsplitsinirmáslejostomacomoparámetrosunpatrón,unacadenayun entero opcional indicando el número máximo de elementos en los quequeremosdividirlacadena,yutilizaelpatrónamododepuntosdeseparaciónparalacadena,devolviendounalistaconlassubcadenas.

Page 120: Python para todos repasa aspectos esenciales de

Lafunciónsubtomacomoparámetrosunpatrónasustituir,unacadenaqueusarcomo reemplazo cada vez que encontremos el patrón, la cadena sobre la querealizarlassustituciones,yunenteroopcionalindicandoelnúmeromáximodesustitucionesquequeremosrealizar.Al llamar a estosmétodos lo que ocurre en realidad es que se crea un nuevoobjeto de tipo RegexObject que representa la expresión regular, y se llama amétodos de este objeto que tienen losmismos nombres que las funciones delmódulo.Sivamosautilizarunmismopatrónvariasvecesnospuede interesarcrearunobjeto de este tipo y llamar a sus métodos nosotros mismos; de esta formaevitamosqueelintérpretetengaquecrearunnuevoobjetocadavezqueusemoselpatrónymejoraremoselrendimientodelaaplicación.ParacrearunobjetoRegexObject seutiliza la funcióncompiledelmódulo,alqueselepasacomoparámetrolacadenaquerepresentaelpatrónquequeremosutilizar para nuestra expresión regular y, opcionalmente, una serie de flags deentrelosquecomentamosanteriormente.

Page 121: Python para todos repasa aspectos esenciales de

SOCKETSLa comunicación entre distintas entidades en una red se basa enPython en elclásicoconceptodesockets.Lossocketssonunconceptoabstractoconelquesedesignaalpuntofinaldeunaconexión.Los programas utilizan sockets para comunicarse con otros programas, quepuedenestarsituadosencomputadorasdistintas.UnsocketquedadefinidoporladirecciónIPdelamáquina,elpuertoenelqueescucha,yelprotocoloqueutiliza.Los tipos y funciones necesarios para trabajar con sockets se encuentran enPythonenelmódulosocket,comonopodríaserdeotraforma.Lossocketsseclasificanensocketsdeflujo(socket.SOCK_STREAM)osocketsdedatagramas(socket.SOCK_DGRAM)dependiendodesielservicioutilizaTCP,queesorientadoaconexiónyfiable,oUDP,respectivamente.Enestecapítulosólocubriremoslossocketsdeflujo,quecubrenun90%delasnecesidadescomunes.Los sockets también se pueden clasificar según la familia. Tenemos sockets

Page 122: Python para todos repasa aspectos esenciales de

UNIX(socket.AF_UNIX)quesecrearonantesdelaconcepcióndelasredesysebasan en ficheros, sockets socket.AF_INET que son los que nos interesan,socketssocket.AF_INET6paraIPv6,etc.Paracrearunsocketseutilizaelconstructorsocket.socket()quepuedetomarcomo parámetros opcionales la familia, el tipo y el protocolo. Por defecto seutilizalafamiliaAF_INETyeltipoSOCK_STREAM.Veremosduranteelrestodelcapítulocómocrearunpardeprogramasclienteyservidoramododeejemplo.Loprimeroquetenemosquehacerescrearunobjetosocketparaelservidor

socket_s=socket.socket()Tenemosahoraqueindicarenquépuertosevaamantener

alaescuchanuestroservidorutilizandoelmétodobind.ParasocketsIP,comoes

nuestrocaso,elargumentodebindesunatuplaquecontieneelhostyelpuerto.El

hostsepuededejarvacío,indicandoalmétodoquepuedeutilizarcualquiernombre

queestédisponible.

socket_s.bind((“localhost”, 9999)) Por último utilizamos listen para hacer que el

socket acepte conexiones entrantes y accept para comenzar a escuchar. El método

listen requiere de un parámetro que indica el número de conexiones máximas que

queremosaceptar;evidentemente,estevalordebeseralmenos1.

Elmétodoacceptsemantienealaesperadeconexionesentrantes,bloqueandolaejecuciónhastaquellegaunmensaje.Cuando llega un mensaje, accept desbloquea la ejecución, devolviendo unobjetosocketquerepresentalaconexióndelclienteyunatuplaquecontieneelhostypuertodedichaconexión.

socket_s.listen(10)

socket_c,(host_c,puerto_c)=socket_s.accept()

Unavezquetenemosesteobjetosocketpodemoscomunicarnosconelclienteatravés suyo, mediante los métodos recv y send (o recvfrom y sendfrom enUDP)quepermitenrecibiroenviarmensajesrespectivamente.Elmétodosendtoma como parámetros los datos a enviar,mientras que elmétodo recv tomacomoparámetroelnúmeromáximodebytesaaceptar.

recibido=socket_c.recv(1024)print“Recibido:“,recibiosocket_c.send(recibido)

Una vez que hemos terminado de trabajar con el socket, lo cerramos con elmétodoclose.Crearunclienteesaúnmássencillo.Solotenemosquecrearelobjetosocket,utilizar elmétodoconnect para conectarnos al servidor y utilizar losmétodossendyrecvquevimosanteriormente.Elargumentodeconnectesunatuplaconhostypuerto,exactamenteigualquebind.

Page 123: Python para todos repasa aspectos esenciales de

socket_c = socket.socket() socket_c.connect((“localhost”, 9999))

socket_c.send(“hola”)

Veamospor últimoun ejemplo completo.En este ejemplo el clientemanda alservidorcualquiermensajequeescribaelusuarioyelservidornohacemásquerepetirelmensajerecibido.Laejecuciónterminacuandoelusuarioescribequit.Esteseríaelcódigodelscriptservidor:importsocket

s=socket.socket()s.bind((“localhost”,9999))s.listen(1)

sc,addr=s.accept()whileTrue:recibido=sc.recv(1024)ifrecibido==“quit”:

breakprint“Recibido:”,recibidosc.send(recibido)

print“adios”

sc.close()s.close()Yacontinuacióntenemoseldelscriptcliente:importsocket

s=socket.socket()s.connect((“localhost”,9999))whileTrue:

mensaje=raw_input(“>“)s.send(mensaje)

mensaje==“quit”:

break

print“adios”

s.close()

Page 124: Python para todos repasa aspectos esenciales de

INTERACTUARCONWEBSExistendosmódulosprincipalespara leerdatosdeURLsenPython:urllibyurllib2.Enestalecciónaprenderemosautilizarurllib2yaqueesmuchomáscompleto, aunque urllib tiene funcionalidades propias que no se puedenencontrarenurllib2,porloquetambiénlotocaremosdepasada.urllib2 puede leer datos de unaURL usando varios protocolos comoHTTP,HTTPS,FTP,oGopher.Seutilizaunafunciónurlopenparacrearunobjetoparecidoaunficheroconelque leer de la URL. Este objeto cuenta con métodos como read, readline,readlinesyclose, loscuales funcionanexactamente igualqueen losobjetosfile,aunqueenrealidadestamostrabajandoconunwrapperquenosabstraedeunsocketqueseutilizapordebajo.Elmétodo read, como recordareis, sirve para leer el “archivo” completo o elnúmerodebytesespecificadocomoparámetro,readlineparaleerunalínea,yreadlinesparaleertodaslaslíneasydevolverunalistaconellas.

Page 125: Python para todos repasa aspectos esenciales de

También contamos conun par demétodosgeturl, para obtener laURLde laque estamos leyendo (que puede ser útil para comprobar si ha habido unaredirección)einfoquenosdevuelveunobjetocon lascabecerasde respuestadelservidor(alasquetambiénsepuedeaccedermedianteelatributoheaders).

importurllib2

try:

f=urllib2.urlopen(“http://www.python.org”)printf.read()

f.close()

exceptHTTPError,e:

print“Ocurrióunerror”

printe.code

exceptURLError,e:

print“Ocurrióunerror”

printe.reason

Al trabajar con urllib2 nos podemos encontrar, como vemos, con errores detipo URLError. Si trabajamos con HTTP podemos encontrarnos también conerroresdelasubclasedeURLErrorHTTPError,queselanzancuandoelservidordevuelveuncódigodeerrorHTTP,comoelerror404cuandonoseencuentraelrecurso. También podríamos encontrarnos con errores lanzados por la libreríaque urllib2 utiliza por debajo para las transferenciasHTTP: httplib; o conexcepcioneslanzadasporelpropiomódulosocket.La funciónurlopen cuenta con un parámetro opcionaldata con el que poderenviar información a direcciones HTTP (y solo HTTP) usando POST (losparámetros se envían en la propia petición), por ejemplo para responder a unformulario.Esteparámetroesunacadenacodificadaadecuadamente,siguiendoelformatoutilizadoenlasURLs:‘password=contrase%A4a&usuario=manuel’Lo más sencillo para codificar la cadena es utilizar el método urlencode deurllib,queaceptaundiccionarioounalistadetuplas(clave,valor)ygeneralacadenacodificadacorrespondiente:importurllib,urllib2

params=urllib.urlencode({“usuario”:“manuel”,“password”:“contraseña”})f=urllib2.urlopen(“http://ejemplo.com/login”,params)

SiloúnicoquequeremoshaceresdescargarelcontenidodeunaURLaunarchivo local,podemosutilizar la funciónurlretrievedeurllib en lugar deleerdeunobjetocreadoconurlopenyescribirlosdatosleídos.

La función urlretrieve toma como parámetros la URL a descargar y,opcionalmente, un parámetro filename con la ruta local en la que guardar elarchivo, un parámetro data similar al deurlopen y un parámetro reporthookconunafunciónqueutilizarparainformardelprogreso.

Page 126: Python para todos repasa aspectos esenciales de

A excepción de las ocasiones en las que se utiliza el parámetro data lasconexionessiempreserealizanutilizandoGET(losparámetrosseenvíanen laURL).ParaenviardatosusandoGETbastaconconcatenarlacadenaresultantedeurlencodeconlaURLalaquenosvamosaconectarmedianteelsímbolo?.

params = urllib.urlencode({“usuario”: “manuel”, “password”: “contraseña”}) f =

urllib2.urlopen(“http://ejemplo.com/login”+

“?”+params)

En urllib también se utiliza una función urlopen para crear nuestrospseudo-archivos,peroadiferenciadelaversióndeurllib, lafunciónurlopendeurllib2 tambiénpuede tomarcomoparámetrounobjetoRequest,en lugardelaURLylosdatosaenviar.

La clase Request define objetos que encapsulan toda la informaciónrelativaaunapetición.Atravésdeesteobjetopodemosrealizarpeticionesmáscomplejas,añadiendonuestraspropiascabeceras,comoelUser-Agent.

El constructormás sencillo para el objetoRequest no tomamás que unacadena indicando la URL a la que conectarse, por lo que utilizar este objetocomoparámetrodeurlopenseríaequivalenteautilizarunacadenaconlaURLdirectamente.

Sin embargo el constructor de Request también tiene como parámetrosopcionales una cadena data para mandar datos por POST y un diccionarioheaders con las cabeceras (además de un par de campos origin_req_host yunverifiable,quequedanfueradelpropósitodelcapítuloporserderarouso).

VeamoscómoañadirnuestraspropiascabecerasutilizandocomoejemplolacabeceraUser-Agent.ElUser-Agentesunacabeceraquesirveparaidentificarelnavegador y sistema operativo que estamos utilizando para conectarnos a esaURL. Por defecto urllib2 se identifica como “Python-urllib/2.5”; siquisiéramos identificarnos como un Linux corriendo Konqueror por ejemplo,usaríamosuncódigosimilaralsiguiente:

ua=“Mozilla/5.0(compatible;Konqueror/3.5.8;Linux)”

h={“User-Agent”:ua}

r=urllib2.Request(“http://www.python.org”,headers=h)f=urllib2.urlopen(r)

printf.read()

Para personalizar la forma en que trabaja urllib2 podemos instalar ungrupo de manejadores ( handlers) agrupados en un objeto de la claseOpenerDirector (opener o abridor), que será el que se utilice a partir de esemomentoalllamaraurlopen.

Paraconstruirunopenerseutilizalafunciónbuild_openera laqueselepasalosmanejadoresqueformaránpartedelopener.Elopenerseencargaráde

Page 127: Python para todos repasa aspectos esenciales de

encadenarlaejecucióndelosdistintosmanejadoresenelordendado.Tambiénse puede usar el constructor de OpenerDirector, y añadir los manejadoresusandosumétodoadd_handler.

Parainstalarelopenerunavezcreadoseutilizalafuncióninstall_opener,que toma como parámetro el opener a instalar. También se podría, si sóloqueremosabrirlaURLconeseopenerunasolavez,utilizarelmétodoopendelopener.

urllib2 cuenta con handlers que se encargan de manejar los esquemasdisponibles (HTTP, HTTPS, FTP), manejar la autenticación, manejar lasredirecciones,etc.

Paraañadirautenticación tendríamosque instalarunopenerque incluyeracomo manejador HTTPBasicAuthHandler, ProxyBasicAuthHandler,HTTPDigestAuthHandlery/oProxyDigestAuthHandler.

Para utilizar autenticación HTTP básica, por ejemplo, usaríamosHTTPBasicAuthHandler:

aut_h=urllib2.HTTPBasicAuthHandler()

aut_h.add_password(“realm”, “host”, “usuario”, “password”) opener =

urllib2.build_opener(aut_h)urllib2.install_opener(opener)

f=urllib2.urlopen(“http://www.python.org”)

Siquisiéramosespecificarunproxyenelcódigotendríamosqueutilizarunopener que contuviera el manejador ProxyHandler. El manejador por defectoincluyeunainstanciadeProxyHandlerconstruidollamandoalinicializadorsinparámetros, con lo que se lee la lista de proxies a utilizar de la variable deentorno adecuada. Sin embargo también podemos construir un ProxyHandlerpasando como parámetro al inicializador un diccionario cuyas claves son losprotocolosylosvalores,laURLdelproxyautilizarparadichoprotocolo.

proxy_h = urllib2.ProxyHandler({“http” : “http://miproxy.net:123”}) opener =

urllib2.build_opener(proxy_h)urllib2.install_opener(opener)

f=urllib2.urlopen(“http://www.python.org”)

ParaqueseguardenlascookiesquemandaHTTPutilizamoselmanejadorHTTPCookieProcessor.

cookie_h = urllib2.HTTPCookieProcessor() opener = urllib2.build_opener(cookie_h)

urllib2.install_opener(opener)

f=urllib2.urlopen(“http://www.python.org”)

Si queremos acceder a estas cookies o poder mandar nuestras propiascookies, podemos pasarle como parámetro al inicializador de

Page 128: Python para todos repasa aspectos esenciales de

HTTPCookieProcessorunobjetodetipoCookieJardelmódulocookielib.Para leer las cookiesmandadas basta crear un objeto iterable a partir del

CookieJar(tambiénpodríamosbuscarlascabecerascorrespondientes,peroestesistemaesmásclaroysencillo):

importurllib2,cookielib

cookie_j=cookielib.CookieJar()

cookie_h = urllib2.HTTPCookieProcessor(cookie_j) opener =urllib2.build_opener(cookie_h)

opener.open(“http://www.python.org”)

fornum,cookieinenumerate(cookie_j):printnum,cookie.nameprintcookie.valueprintEn el improbable caso de que necesitáramos añadir una cookie antes de

realizar la conexión, en lugar de conectarnos para que el sitio la mande,podríamosutilizarelmétodoset_cookie deCookieJar, al que lepasamosunobjeto de tipo Cookie. El constructor de Cookie, no obstante, es bastantecomplicado.

Page 129: Python para todos repasa aspectos esenciales de

THREADS

Page 130: Python para todos repasa aspectos esenciales de

¿Quésonlosprocesosylosthreads?Lascomputadorasseríanmuchomenosútilessinopudiéramoshacermásdeunacosa a la vez. Si no pudiéramos, por ejemplo, escuchar música en nuestroreproductordeaudiofavoritomientrasleemosuntutorialdePythonenMundoGeek.Pero, ¿cómoseconseguíaestoencomputadorasantiguasconun solonúcleo /una sola CPU? Lo que ocurría, y lo que ocurre ahora, es que en realidad noestamosejecutandovariosprocesosalavez(sellamaprocesoaunprogramaenejecución),sinoquelosprocesossevanturnandoy,dadalavelocidadalaqueejecutan las instrucciones, nosotros tenemos la impresión de que las tareas seejecutandeformaparalelacomosituviéramosmultitareareal.Cadavezqueunprocesodistintopasaaejecutarseesnecesariorealizarloquesellamauncambiodecontexto,duranteelcualsesalvaelestadodelprogramaqueseestabaejecutandoamemoriaysecargaelestadodelprogramaquevaaentraraejecutarse.

Page 131: Python para todos repasa aspectos esenciales de

En Python podemos crear nuevos procesosmediante la función os.fork, queejecuta la llamada al sistemafork, omediante otras funcionesmás avanzadascomo popen2.popen2, de forma que nuestro programa pueda realizar variastareasdeformaparalela.Sinembargoelcambiodecontextopuedeserrelativamentelento,ylosrecursosnecesariosparamantenerelestadodemasiados,porloqueamenudoesmuchomáseficazutilizarloqueseconocecomothreads,hilosdeejecución,oprocesosligeros.Losthreadssonunconceptosimilaralosprocesos:tambiénsetratadecódigoenejecución. Sin embargo los threads se ejecutan dentro de un proceso, y losthreadsdelprocesocompartenrecursosentresi,comolamemoria,porejemplo.Elsistemaoperativonecesitamenosrecursosparacrearygestionarlosthreads,yalcompartirrecursos,elcambiodecontextoesmásrápido.Además,dadoquelos threads comparten el mismo espacio de memoria global, es sencillocompartir información entre ellos: cualquier variable global que tengamos ennuestroprogramaesvistaportodoslosthreads.

Page 132: Python para todos repasa aspectos esenciales de

ElGILLa ejecución de los threads en Python está controlada por el GIL (GlobalInterpreter Lock) de forma que sólo un thread puede ejecutarse a la vez,independientementedelnúmerodeprocesadoresconelquecuentelamáquina.Esto posibilita que el escribir extensiones en C para Python sea mucho mássencillo,perotieneladesventajadelimitarmuchoelrendimiento,porloqueapesardetodo,enPython,enocasionesnospuedeinteresarmásutilizarprocesosquethreads,quenosufrendeestalimitación.Cada cierto número de instrucciones de bytecode la máquina virtual para laejecucióndelthreadyeligeotrodeentrelosqueestabanesperando.Por defecto el cambio de thread se realiza cada 10 instrucciones de bytecode,aunque se puede modificar mediante la función sys.setcheckinterval.Tambiénsecambiadethreadcuandoelhiloseponeadormircontime.sleepocuando comienza una operación de entrada/salida, las cuales pueden tardarmuchoenfinalizar,yporlotanto,denorealizarelcambio,tendríamosalaCPUdemasiadotiemposintrabajaresperandoaquelaoperacióndeE/Sterminara.

Page 133: Python para todos repasa aspectos esenciales de

Para minimizar un poco el efecto del GIL en el rendimiento de nuestraaplicaciónesconvenientellamaralintérpreteconelflag-O,loqueharáquesegenereunbytecodeoptimizadoconmenosinstrucciones,y,porlotanto,menoscambiosdecontexto.Tambiénpodemosplantearnoselutilizarprocesosenlugardethreads,comoyacomentamos,utilizandoporejemploelmóduloprocessing;escribirelcódigoenelqueel rendimientoseacríticoenunaextensiónenCoutilizarIronPythonoJython,quecarecendeGIL.

Page 134: Python para todos repasa aspectos esenciales de

ThreadsenPythonEl trabajo con threads se lleva a cabo en Pythonmediante elmódulothread.Estemóduloesopcionalydependientedelaplataforma,ypuedesernecesario,aunquenoescomún,recompilarelintérpreteparaañadirelsoportedethreads.Ademásdethread, tambiéncontamosconelmódulothreading que se apoyaenelprimeroparaproporcionarnosunaAPIdemásaltonivel,máscompleta,yorientadaaobjetos.ElmódulothreadingsebasaligeramenteenelmodelodethreadsdeJava.El módulo threading contiene una clase Thread que debemos extender paracrearnuestrospropioshilosdeejecución.Elmétodoruncontendráelcódigoquequeremos que ejecute el thread. Si queremos especificar nuestro propioconstructor, este deberá llamar a threading.Thread.__init__(self) parainicializarelobjetocorrectamente.

importthreading

classMiThread(threading.Thread):

def__init__(self,num):

Page 135: Python para todos repasa aspectos esenciales de

threading.Thread.__init__(self)

self.num=num

defrun(self):

print“Soyelhilo”,self.num

Paraqueelthreadcomienceaejecutarsucódigobastaconcrearunainstanciadelaclasequeacabamosdedefiniryllamarasumétodostart.Elcódigodelhiloprincipalyeldelqueacabamosdecrearseejecutarándeformaconcurrente.

print“Soyelhiloprincipal”

foriinrange(0,10):

t=MiThread(i)

t.start()

t.join()

Elmétodo join se utiliza para que el hilo que ejecuta la llamada se bloqueehastaquefinaliceelthreadsobreelquesellama.Enestecasoseutilizaparaqueel hilo principal no termine su ejecución antes que los hijos, lo cual podríaresultarenalgunasplataformasenlaterminacióndeloshijosantesdefinalizarsuejecución.Elmétodojoinpuedetomarcomoparámetrounnúmeroencomaflotanteindicandoelnúmeromáximodesegundosaesperar.Si se intenta llamar al método start para una instancia que ya se estáejecutando,obtendremosunaexcepción.Laformarecomendadadecrearnuevoshilosdeejecuciónconsisteenextenderla clase Thread, como hemos visto, aunque también es posible crear unainstanciadeThreaddirectamente,eindicarcomoparámetrosdelconstructorunaclase ejecutable (una clase con elmétodo especial__call__) o una función aejecutar, y los argumentos en una tupla (parámetro args) o un diccionario(parámetrokwargs).

importthreading

defimprime(num):

print“Soyelhilo”,num

print“Soyelhiloprincipal”

foriinrange(0,10):

t=threading.Thread(target=imprime,args=(i,))

t.start()

Además de los parámetros target, args y kwargs también podemos pasar alconstructorunparámetrodetipocadenanameconelnombrequequeremosquetome el thread (el thread tendrá un nombre predeterminado aunque no loespecifiquemos);unparámetrodetipobooleanoverboseparaindicaralmóduloque imprimamensajes sobre el estado de los threads para la depuración y unparámetrogroup,queporahoranoadmiteningúnvalorperoqueenelfuturose

Page 136: Python para todos repasa aspectos esenciales de

utilizaráparacreargruposdethreadsypodertrabajaraniveldegrupos.Para comprobar si un thread sigue ejecutándose, se puede utilizar el métodoisAlive.TambiénpodemosasignarunnombrealhiloyconsultarsunombreconlosmétodossetNameygetName,respectivamente.Mediantelafunciónthreading.enumerateobtendremosunalistadelosobjetosThreadqueseestánejecutando,incluyendoelhiloprincipal(podemoscompararelobjetoThreadconlavariablemain_threadparacomprobarsisetratadelhiloprincipal) y con threading.activeCount podemos consultar el número dethreadsejecutándose.Los objetos Thread también cuentan con un método setDaemon que toma unvalorbooleanoindicandosisetratadeundemonio.Lautilidaddeestoesquesisolo quedan threads de tipo demonio ejecutándose, la aplicación terminaráautomáticamente,terminandoestosthreadsdeformasegura.Por último tenemos en el módulo threading una clase Timer que hereda deThreadycuyautilidadesladeejecutarelcódigodesumétodorundespuésdeun periodo de tiempo indicado como parámetro en su constructor. Tambiénincluyeunmétodocancelmediante el que cancelar la ejecución antes de quetermineelperiododeespera.

Page 137: Python para todos repasa aspectos esenciales de

SincronizaciónUno de losmayores problemas a los que tenemos que enfrentarnos al utilizarthreadses lanecesidaddesincronizarelaccesoaciertos recursosporpartedelosthreads.Entrelosmecanismosdesincronizaciónquetenemosdisponiblesenel módulo threading se encuentran los locks, locks reentrantes, semáforos,condicionesyeventos.Loslocks, tambiénllamadosmutex(demutualexclusion),cierresdeexclusiónmutua, cierres o candados, son objetos con dos estados posibles: adquirido olibre.Cuandounthreadadquiereelcandado,losdemásthreadsquelleguenaesepuntoposteriormenteypidanadquirirlosebloquearánhastaqueelthreadquelohaadquiridolibereelcandado,momentoenelcualpodráentrarotrothread.El candado se representamediante la clase Lock. Para adquirir el candado seutilizaelmétodoacquiredelobjeto,alqueselepuedepasarunbooleanoparaindicarsiqueremosesperaraqueselibere(True)ono(False).Siindicamosquenoqueremosesperar, elmétododevolveráTrue oFalse dependiendode si seadquirióonoelcandado,respectivamente.Pordefecto,sinoseindicanada,el

Page 138: Python para todos repasa aspectos esenciales de

hilosebloqueaindefinidamente.Paraliberarelcandadounavezhemosterminadodeejecutarelbloquedecódigoenelquepudieraproducirseunproblemadeconcurrencia,seutilizaelmétodorelease.

lista=[]

lock=threading.Lock()

defanyadir(obj):

lock.acquire()

lista.append(obj)

lock.release()

defobtener():

lock.acquire()

obj=lista.pop()

lock.release()

returnobj

LaclaseRLockfuncionadeformasimilaraLock,peroenestecasoelcandadopuede ser adquirido por el mismo thread varias veces, y no quedará liberadohastaqueelthreadllameareleasetantasvecescomollamóaacquire.Comoen Lock, y como en todas las primitivas de sincronización que veremos acontinuación,esposibleindicaraacquiresiqueremosquesebloqueeono.Lossemáforossonotraclasedecandados.Laclasecorrespondiente,Semaphore,tambiéncuentaconmétodosacquireyrelease,perosediferenciadeunLocknormal en que el constructor de Semaphore puede tomar como parámetroopcionalunenterovalue indicandoelnúmeromáximode threadsquepuedenaccedera laveza laseccióndecódigocrítico.Sinoseindicanadapermiteelaccesoaunsolothread.Cuandounthreadllamaaacquire,lavariablequeindicaelnúmerodethreadsquepuedenadquirirelsemáforodisminuyeen1,porquehemospermitidoentrarenlaseccióndecódigocríticoaunhilomás.Cuandounhilollamaarelease,lavariableaumentaen1.Noeshastaqueestavariabledelsemáforoes0,quellamaraacquireproduciráun bloqueo en el thread que realizó la petición, a la espera de que algún otrothreadllameareleaseparaliberarsuplaza.Esimportantedestacarqueelvalorinicialdelavariabletalcomolopasamosenelconstructor,noesun límitemáximo,sinoquemúltiples llamadasareleasepuedenhacerqueelvalordelavariableseamayorquesuvalororiginal.Sinoesestoloquequeremos,podemosutilizarlaclaseBoundedSemaphoreencuyocaso,ahora si, se consideraría un error llamar a release demasiadas veces, y selanzaríaunaexcepcióndetipoValueErrordesuperarseelvalorinicial.

Page 139: Python para todos repasa aspectos esenciales de

Podríamos utilizar los semáforos, por ejemplo, en un pequeño programa en elquemúltiplesthreadsdescargarandatosdeunaURL,deformaquepudiéramoslimitar el númerode conexiones a realizar al sitiowebparanobombardear elsitioconcientosdepeticionesconcurrentes.

semaforo=threading.Semaphore(4)

defdescargar(url):

semaforo.acquire()

urllib.urlretrieve(url)

semaforo.release()

Las condiciones (clase Condition) son de utilidad para hacer que los threadssólopuedanentrarenlaseccióncríticadedarseunaciertacondiciónoevento.Para esto utilizan un Lock pasado como parámetro, o crean un objeto RLockautomáticamentesinosepasaningúnparámetroalconstructor.Sonespecialmenteadecuadasparaelclásicoproblemadeproductor-consumidor.La clase cuenta conmétodosacquire yrelease, que llamarán a losmétodoscorrespondientesdelcandadoasociado.Tambiéntenemosmétodoswait,notifyynotifyAll.El método wait debe llamarse después de haber adquirido el candado conacquire. Este método libera el candado y bloquea al thread hasta que unallamadaanotifyonotifyAllenotro thread le indicanquesehacumplidolacondiciónporlaqueesperaba.Elthreadqueinformaalosdemásdequesehaproducidolacondición,tambiéndebellamaraacquireantesdellamaranotifyonotifyAll.Al llamar a notify, se informa del evento a un solo thread, y por tanto sedespiertaunsolothread.AlllamaranotifyAllsedespiertantodoslos threadsqueesperabanalacondición.Tanto el thread que notifica como los que son notificados tienenque terminarliberandoellockconrelease.

lista=[]

cond=threading.Condition()

defconsumir():

cond.acquire()

cond.wait()

obj=lista.pop()

cond.release()

returnobj

defproducir(obj):

cond.acquire()

lista.append(obj)

cond.notify()

cond.release()

Page 140: Python para todos repasa aspectos esenciales de

Los eventos, implementados mediante la clase Event, son un wrapper porencimadeCondition y sirvenprincipalmentepara coordinar threadsmedianteseñalesqueindicanquesehaproducidounevento.Loseventosnosabstraendelhecho de que estemos utilizando un Lock por debajo, por lo que carecen demétodosacquireyrelease.El thread que debe esperar el evento llama al método wait y se bloquea,opcionalmentepasandocomoparámetrounnúmeroencomaflotanteindicandoel númeromáximode segundos a esperar.Otrohilo, cuandoocurre el evento,mandalaseñalalosthreadsbloqueadosalaesperadedichoeventoutilizandoelmétodoset.Losthreadsqueestabanesperandosedesbloqueanunavezrecibidala señal.El flagquedetermina si sehaproducidoel evento sepuedevolveraestablecerafalsousandoclear.Comovemos los eventos sonmuy similares a las condiciones, a excepcióndequesedesbloqueantodoslosthreadsqueesperabaneleventoyquenotenemosquellamaraacquireyrelease.

importthreading,time

classMiThread(threading.Thread):

def__init__(self,evento):

threading.Thread.__init__(self)

self.evento=evento

defrun(self):

printself.getName(),“esperandoalevento”

self.evento.wait()

printself.getName(),“terminalaespera”

evento=threading.Event()

t1=MiThread(evento)

t1.start()

t2=MiThread(evento)

t2.start()

#Esperamosunpoco

time.sleep(5)

evento.set()

Porúltimo,unpequeñoextra.SisoisusuariosdeJavasindudaestaréisechandoen falta una palabra clave syncronized para hacer que sólo un thread puedaaccederalmétodosobreelqueseutilizaalavez.UnaconstruccióncomúneselusodeundecoradorparaimplementarestafuncionalidadusandounLock.Seríaalgoasí:

defsynchronized(lock):

defdec(f):

deffunc_dec(*args,**kwargs):

lock.acquire()

try:

returnf(*args,**kwargs)

finally:

Page 141: Python para todos repasa aspectos esenciales de

lock.release()

returnfunc_dec

returndec

classMyThread(threading.Thread):

@synchronized(mi_lock)

defrun(self):

print“metodosincronizado”

Page 142: Python para todos repasa aspectos esenciales de

DatosglobalesindependientesComo ya hemos comentado los threads comparten las variables globales. Sinembargo pueden existir situaciones en las que queramos utilizar variablesglobalesperoqueestasvariablessecomportencomosifueranlocalesaunsolothread. Es decir, que cada uno de los threads tengan valores distintosindependientes,yqueloscambiosdeundeterminadothreadsobreelvalornoseveanreflejadosenlascopiasdelosdemásthreads.Paralograrestecomportamientosepuedeutilizarlaclasethreading.local,quecrea un almacén de datos locales. Primero debemos crear una instancia de laclase,odeunasubclase,paradespuésalmacenaryobtenerlosvaloresatravésdeparámetrosdelaclase.

datos_locales=threading.local()datos_locales.mi_var=“hola”

printdatos_locales.mi_var

Fijémonosenel siguiente código,por ejemplo.Paraelhiloprincipal elobjetolocal tiene un atributo var, y por lo tanto el print imprime su valor sinproblemas.Sinembargoparaelhiloteseatributonoexiste,yporlotantolanza

Page 143: Python para todos repasa aspectos esenciales de

unaexcepción.local=threading.local()deff():printlocal.varlocal.var=“hola”

t=threading.Thread(target=f)printlocal.var

t.start()

t.join()

Page 144: Python para todos repasa aspectos esenciales de

CompartirinformaciónParacompartirinformaciónentrelosthreadsdeformasencillapodemosutilizarlaclaseQueue.Queue,queimplementaunacola(unaestructuradedatosdetipoFIFO)consoportemultihilo.Estaclaseutilizalasprimitivasdethreadingparaahorrarnostenerquesincronizarelaccesoalosdatosnosotrosmismos.El constructor de Queue toma un parámetro opcional indicando el tamañomáximodelacola.Sinoseindicaningúnvalornohaylímitedetamaño.Paraañadirunelementoalacolaseutilizaelmétodoput(item);paraobtenerelsiguiente elemento, get(). Ambos métodos tienen un parámetro booleanoopcional block que indica si queremos que se espere hasta que haya algúnelementoenlacolaparapoderdevolverloohastaquelacoladejedeestarllenaparapoderintroducirlo.También existe un parámetro opcional timeout que indica, en segundos, eltiempo máximo a esperar. Si el timeout acaba sin poder haber realizado laoperacióndebidoaquelacolaestaballenaovacía,obiensiblockeraFalse,se

Page 145: Python para todos repasa aspectos esenciales de

lanzaráunaexcepcióndetipoQueue.FulloQueue.Empty,respectivamente.Conqsize obtenemos el tamañode la colay conempty()yfull() podemoscomprobarsiestávacíaollena.

q=Queue.Queue()

classMiThread(threading.Thread):

def__init__(self,q):

self.q=q

threading.Thread.__init__(self)

defrun(self):

whileTrue:

try:

obj=q.get(False)

exceptQueue.Empty:

print“Fin”

break

printobj

foriinrange(10):

q.put(i)

t=MiThread(q)

t.start()

t.join()

Page 146: Python para todos repasa aspectos esenciales de

SERIALIZACIÓNDEOBJETOSAlgunas veces tenemos la necesidad de guardar un objeto a disco para poderrecuperarlomástarde,opuedequenosseanecesariomandarunobjetoatravésdelared,aotroprogramaenPythonejecutándoseenotramáquina.Al procesode transformar el estadodeunobjeto enun formatoque se puedaalmacenar,recuperarytransportarseleconoceconelnombredeserializaciónomarshalling.EnPythontenemosvariosmódulosquenosfacilitanestatarea,comomarshal,pickle,cPickleyshelve.Elmódulomarshaleselmásbásicoyelmásprimitivodelostres,yesque,dehecho,supropósitoprincipalysurazóndesernoeseldeserializarobjetos,sinotrabajarconbytecodePython(archivos.pyc).marshalsólopermiteserializarobjetossimples(lamayoríadelostiposincluidospor defecto en Python), y no proporciona ningún tipo de mecanismo deseguridad ni comprobaciones frente a datos corruptos o mal formateados. Es

Page 147: Python para todos repasa aspectos esenciales de

más, el formato utilizado para guardar el bytecode (y por tanto el formatoutilizadoparaguardarlosobjetosconmarshal)puedecambiarentreversiones,porloquenoesadecuadoparaalmacenardatosdelargaduración.pickle, por su parte, permite serializar casi cualquier objeto (objetos de tiposdefinidos por el usuario, colecciones que contienen colecciones, etc) y cuentacon algunos mecanismos de seguridad básicos. Sin embargo, al ser máscomplejoquemarshal,y,sobretodo,alestarescritoenPythonenlugardeenC,comomarshal,tambiénesmuchomáslento.La solución, si la velocidad de la serialización es importante para nuestraaplicación,esutilizarcPickle,quenoesmásqueesunaimplementaciónenCdepickle.cPickleeshasta1000vecesmásrápidoquepickle,yprácticamenteigualderápidoquemarshal.Si intentamos importar cPickle y se produce un error por algún motivo, selanzará una excepción de tipo ImportError. Para utilizar cPickle si estádisponible y pickle en caso contrario, podríamos usar un código similar alsiguiente:

try:

importcPickleaspickleexceptImportError:

importpickle

as en un import sirve para importar el elemento seleccionado utilizando otronombreindicado,enlugardesunombre.La formamás sencilla de serializar un objeto usandopickle esmediante unallamadaa la funcióndumppasandocomoargumentoelobjetoaserializaryunobjetoarchivoenelqueguardarlo(ocualquierotrotipodeobjetosimilaraunarchivo,siemprequeofrezcamétodosread,readlineywrite).

try:

importcPickleaspickleexceptImportError:

importpickle

fichero=file(“datos.dat”,“w”)animales=[“piton”,“mono”,“camello”]

pickle.dump(animales,fichero)fichero.close()

La funcióndump también tiene un parámetro opcional protocol que indica elprotocolo a utilizar al guardar. Por defecto su valor es 0, que utiliza formatotexto y es el menos eficiente. El protocolo 1 es más eficiente que el 0, peromenosqueel2.Tantoelprotocolo1comoel2utilizanunformatobinarioparaguardarlosdatos.

try:

importcPickleaspickleexceptImportError:

importpickle

Page 148: Python para todos repasa aspectos esenciales de

fichero=file(“datos.dat”,“w”)animales=[“piton”,“mono”,“camello”]

pickle.dump(animales,fichero,2)fichero.close()

Paravolveracargarunobjetoserializadoseutilizalafunciónload,alaqueselepasaelarchivoenelqueseguardó.

try:

importcPickleaspickleexceptImportError:

importpickle

fichero=file(“datos.dat”,“w”)animales=[“piton”,“mono”,“camello”]

pickle.dump(animales,fichero)

fichero.close()

fichero=file(“datos.dat”)

animales2=pickle.load(fichero)

printanimales2

Supongamosahoraquequeremosalmacenarunpardelistasenunfichero.Estosería tansencillocomo llamarunavezadumpporcada lista,y llamardespuésunavezaloadporcadalista.

fichero=file(“datos.dat”,“w”)animales=[“piton”,“mono”,“camello”]

lenguajes=[“python”,“mono”,“perl”]

pickle.dump(animales,fichero)pickle.dump(lenguajes,fichero)

fichero = file(“datos.dat”) animales2 = pickle.load(fichero) lenguajes2 =

pickle.load(fichero)printanimales2

printlenguajes2

Pero,¿ysihubiéramosguardado30objetosyquisiéramosaccederalúltimodeellos?¿osinorecordáramosenquéposiciónlohabíamosguardado?Elmóduloshelve extiendepickle /cPickle para proporcionar una forma de realizar laserialización más clara y sencilla, en la que podemos acceder a la versiónserializadadeunobjetomedianteunacadenaasociada,atravésdeunaestructuraparecidaaundiccionario.La única función que necesitamos conocer del módulo shelve es open, quecuentaconunparámetrofilenamemedianteelqueindicarlarutaaunarchivoenelqueguardarlosobjetos(enrealidadsepuedecrearmásdeunarchivo,connombresbasadosenfilename,peroestoestransparentealusuario).Lafunciónopentambiéncuentaconunparámetroopcionalprotocol,conelqueespecificarelprotocoloquequeremosqueutilicepicklepordebajo.Como resultado de la llamada aopen obtenemos un objetoShelf, con el quepodemos trabajar como si deundiccionarionormal se tratase (a excepcióndeque las claves sólo pueden ser cadenas) para almacenar y recuperar nuestros

Page 149: Python para todos repasa aspectos esenciales de

objetos.Como un diccionario cualquiera la clase Shelf cuenta con métodos get,has_key,items,keys,values,…Una vez hayamos terminado de trabajar con el objeto Shelf, lo cerraremosutilizandoelmétodoclose.

importshelve

animales=[“piton”,“mono”,“camello”]

lenguajes=[“python”,“mono”,“perl”]

shelf=shelve.open(“datos.dat”)shelf[“primera”]=animales

shelf[“segunda”]=lenguajes

printshelf[“segunda”]

shelf.close()

Page 150: Python para todos repasa aspectos esenciales de

BASESDEDATOSExisten problemas para los que guardar nuestros datos en ficheros de textoplano,enarchivosXML,omedianteserializaciónconpickleoshelvepuedenser soluciones poco convenientes. En ocasiones no queda más remedio querecurrir a las bases de datos, ya sea por cuestiones de escalabilidad, deinteroperabilidad,decoherencia,deseguridad,deconfidencialidad,etc.AlolargodeestecapítuloaprenderemosatrabajarconbasesdedatosenPython.Sinembargoseasumenunaseriedeconocimientosbásicos,comopuedeserelmanejo elemental de SQL. Si este no es el caso, existen miles de recursos adisposición del lector en Internet para introducirse en el manejo de bases dedatos.

Page 151: Python para todos repasa aspectos esenciales de

DBAPI

Existen cientos de bases de datos en el mercado, tanto comerciales comogratuitas.Tambiénexistendecenasdemódulosdistintosparatrabajarcondichasbases de datos en Python, lo que significa decenas de APIs distintas poraprender.EnPython,comoenotroslenguajescomoJavaconJDBC,existeunapropuestadeAPIestándarparaelmanejodebasesdedatos,de formaqueelcódigoseaprácticamente igual independientemente de la base de datos que estemosutilizandopordebajo.EstaespecificaciónrecibeelnombredePythonDatabaseAPIoDB-APIyserecogeenelPEP249(http://www.python.org/dev/peps/pep-0249/).DB-API se encuentra en estos momentos en su versión 2.0, y existenimplementacionesparalasbasesdedatosrelacionalesmásconocidas,asícomoparaalgunasbasesdedatosnorelacionales.A lo largo de este capítulo utilizaremos la base de datos SQLite para losejemplos, ya que no se necesita instalar y ejecutar un proceso servidorindependiente con el que se comunique el programa, sino que se trata de unapequeñalibreríaenCqueseintegraconlaaplicaciónyquevieneincluidaconPythonpordefectodesdelaversión2.5.DesdelamismaversiónPythontambiénincorpora un módulo compatible con esta base de datos que sigue laespecificacióndeDBAPI2.0:sqlite3,porloquenonecesitaremosningúntipodeconfiguraciónextra.Nada impide al lector, no obstante, instalar y utilizar cualquier otra base dedatos,comoMySQL,conlacualpodemostrabajaratravésdeldrivercompatibleconDBAPI2.0MySQLdb(http://mysql-python.sourceforge.net/).

VariablesglobalesAntesdecomenzaratrabajarconsqlite3,vamosaconsultaralgunosdatosinteresantessobreelmódulo.TodoslosdriverscompatiblesconDB-API2.0debentener3variablesglobalesquelosdescriben.Asaber:

apilevel:unacadenaconlaversióndeDBAPIqueutiliza.Actualmentesólo puede tomar como valor “1.0” o “2.0”. Si la variable no existe se

Page 152: Python para todos repasa aspectos esenciales de

asumequees1.0.threadsafety:setratadeunenterode0a3quedescribeloseguroqueeselmóduloparaelusoconthreads.Sies0nosepuedecompartirelmóduloentrethreadssinutilizaralgúntipodemecanismodesincronización;sies1,pueden compartir el módulo pero no las conexiones; si es 2, módulos yconexiones pero no cursores y, por último, si es 3, es totalmente thread-safe.paramstyle: informasobrelasintaxisautilizarparainsertarvaloresenlaconsultaSQLdeformadinámica.

qmark:interrogaciones.sql=“selectallfromtwherevalor=?”

numeric:unnúmeroindicandolaposición.sql=“selectallfromtwherevalor=:1”

named:elnombredelvalor.sql=“selectallfromtwherevalor=:valor”

format:especificadoresdeformatosimilaresalosdelprintfdeC.sql=“selectallfromtwherevalor=%s”

pyformat:similaralanterior,peroconlasextensionesdePython.sql=“selectallfromtwherevalor=%(valor)”

Veamoslosvalorescorrespondientesasqlite3:>>>importsqlite3asdbapi>>>printdbapi.apilevel2.0>>>printdbapi.threadsafety1>>>printdbapi.paramstyleqmark

ExcepcionesA continuación podéis encontrar la jerarquía de excepciones que deben

proporcionarlosmódulos,juntoconunapequeñadescripcióndecadaexcepción,amododereferencia.

StandardError

|__Warning

|__Error

|__InterfaceError

|__DatabaseError

|__DataError

|__OperationalError

Page 153: Python para todos repasa aspectos esenciales de

|__IntegrityError

|__InternalError

|__ProgrammingError

|__NotSupportedError

StandardError:SuperclaseparatodaslasexcepcionesdeDBAPI.Warning:Excepciónqueselanzaparaavisosimportantes.Error:Superclasedeloserrores.InterfaceError:Erroresrelacionadosconlainterfazdelabasededatos,ynoconlabasededatosensí.DatabaseError:Erroresrelacionadosconlabasededatos.DataError: Errores relacionados con los datos, como una división entrecero.OperationalError:Erroresrelacionadosconelfuncionamientodelabasededatos,comounadesconexióninesperada.IntegrityError:Erroresrelacionadosconlaintegridadreferencial.InternalError:Errorinternodelabasededatos.ProgrammingError: Errores de programación, como errores en el códigoSQL.NotSupportedError:Excepciónqueselanzacuandosesolicitaunmétodoquenoestásoportadoporlabasededatos.

UsobásicodeDB-APIPasemosahoraavercómotrabajarconnuestrabasededatosatravésdeDB-API.

Lo primero que tendremos que hacer es realizar una conexión con elservidorde labasededatos.Estosehacemediante la funciónconnect,cuyosparámetros no están estandarizados y dependen de la base de datos a la queestemosconectándonos.

En el casode sqlite3 sólonecesitamospasar comoparámetrouna cadenaconlarutaalarchivoenelqueguardarlosdatosdelabasededatos,obienlacadena “:memory:” para utilizar la memoria RAM en lugar de un fichero endisco.

Por otro lado, en el caso deMySQLdb, connect toma como parámetros lamáquinaenlaquecorreelservidor(host),elpuerto(port),nombredeusuarioconelqueautenticarse (user),contraseña(password)ybasededatosa laqueconectarnosdeentrelasqueseencuentranennuestroSGBD(db).

LafunciónconnectdevuelveunobjetodetipoConnectionquerepresenta

Page 154: Python para todos repasa aspectos esenciales de

laconexiónconelservidor.>>>bbdd=dbapi.connect(“bbdd.dat”)>>>printbbdd

<sqlite3.Connectionobjectat0x00A71DA0>

Las distintas operaciones que podemos realizar con la base de datos serealizanatravésdeunobjetoCursor.Paracrearesteobjetoseutilizaelmétodocursor()delobjetoConnection:c=bbdd.cursor()

Las operaciones se ejecutan a través del método execute de Cursor,pasandocomoparámetrounacadenaconelcódigoSQLaejecutar.

Comoejemplocreemosunanuevatablaempleadosenlabasededatos:c.execute(“““createtableempleados(dnitext,nombretext,departamentotext)”””)yacontinuación,insertemosunatuplaennuestranuevatabla:c.execute(“““insertintoempleados

values(‘12345678-A’,‘ManuelGil’,‘Contabilidad’)”””)Sinuestrabasededatossoportatransacciones,siestasestánactivadas,ysi

la característica de auto-commit está desactivada, será necesario llamar almétodo commit de la conexión para que se lleven a cabo las operacionesdefinidasenlatransacción.

Si en estas circunstancias utilizáramos una herramienta externa paracomprobarelcontenidodenuestrabasededatossinhacerprimeroelcommitnosencontraríamosentoncesconunabasededatosvacía.

SicomprobáramoselcontenidodelabasededatosdesdePython,sincerrarelcursornilaconexión,recibiríamoselresultadodelcontextodelatransacción,porloquepareceríaquesehanllevadoacaboloscambios,aunquenoesasí,yloscambiossóloseaplican,comocomentamos,alllamaracommit.

Para bases de datos que no soporten transacciones el estándar dicta quedebeproporcionarseunmétodocommitconimplementaciónvacía,porloquenoes mala idea llamar siempre a commit aunque no sea necesario para podercambiardesistemadebasededatosconsolomodificarlalíneadelimport.

Si nuestra base de datos soporta la característica de rollback tambiénpodemoscancelarlatransacciónactualcon:

bbdd.rollback()

Silabasededatosnosoportarollbackllamaraestemétodoproduciráunaexcepción.

Veamosahoraunejemplocompletodeuso:

Page 155: Python para todos repasa aspectos esenciales de

importsqlite3asdbapi

bbdd=dbapi.connect(“bbdd.dat”)cursor=bbdd.cursor()

cursor.execute(“““createtableempleados(dnitext,nombretext,departamentotext)”””)

cursor.execute(“““insert into empleados values (‘12345678-A’, ‘ManuelGil’,‘Contabilidad’)”””)bbdd.commit()

cursor.execute(“““select * from empleados wheredepartamento=’Contabilidad’”””)fortuplaincursor.fetchall():printtupla

Comovemos,para realizarconsultasa labasededatos tambiénseutilizaexecute. Para consultar las tuplas resultantes de la sentencia SQL se puedellamar a los métodos de Cursor fetchone, fetchmany o fetchall o usar elobjetoCursorcomouniterador.

cursor.execute(“““select*fromempleadoswheredepartamento=’Contabilidad’”””)for

resultadoincursor:printtupla

Elmétodofetchone devuelve la siguiente tupla del conjunto resultado oNone cuando no existenmás tuplas, fetchmany devuelve el número de tuplasindicadoporelenteropasadocomoparámetroobienelnúmeroindicadoporelatributoCursor.arraysizesinosepasaningúnparámetro(Cursor.arraysizevale1pordefecto)yfetchalldevuelveunobjetoiterablecontodaslastuplas.

A la hora de trabajar con selects u otros tipos de sentencias SQL esimportante tener en cuenta que no deberían usarse los métodos de cadenahabituales para construir las sentencias, dado que esto nos haría vulnerables aataquesdeinyecciónSQL,sinoqueensulugardebeusarselacaracterísticadesustitucióndeparámetrosdeDBAPI.

Supongamos que estamos desarrollando una aplicación web con Pythonparaunbancoyquesepudieraconsultarunalistadesucursalesdelbancoenunaciudad determinada con una URL de la formahttp://www.mibanco.com/sucursales?ciudad=Madrid Podríamos tener unaconsultacomoesta:

cursor.execute(“““select*fromsucursaleswhereciudad=’”+ciudad+“’”””)

Aprimeravistapodríaparecerquenoexisteningúnproblema:nohacemosmásqueobtener las sucursalesque seencuentrenen la ciudad indicadapor lavariableciudad.Pero,¿quéocurriríasiunusuariomalintencionadoaccedieraa

Page 156: Python para todos repasa aspectos esenciales de

unaURLcomo“http://www.mibanco.com/sucursales?ciudad=Madrid’;SELECT*FROMcontrasenyas”?

Como no se realiza ninguna validación sobre los valores que puedecontener la variable ciudad, sería sencillo que alguien pudiera hacerse con elcontroltotaldelaaplicación.

Locorrectosería,comodecíamos,utilizarlacaracterísticadesustitucióndeparámetros de DB API. El valor de paramstyle para el módulo sqlite3 eraqmark.Estosignificaquedebemosescribirunsignodeinterrogaciónenellugaren el que queramos insertar el valor, y basta pasar un segundo parámetro aexecuteenformadesecuenciaomappingconlosvaloresautilizarparaqueelmódulocreelasentenciapornosotros.

cursor.execute(“““select*fromsucursaleswhereciudad=?”””,(ciudad,))

Porúltimo,alfinaldelprogramasedebecerrarelcursorylaconexión:cursor.close()bbdd.close()

TiposSQLEn ocasiones podemos necesitar trabajar con tipos de SQL, y almacenar,

porejemplo, fechasuhorasusandoDateyTimeynoconcadenas.LaAPIdebasesdedatosdePythonincluyeunaseriedeconstructoresautilizarparacrearestostipos.Estosson:

Date(year,month,day):Paraalmacenarfechas.Time(hour,minute,second):Paraalmacenarhoras.Timestamp(year,month,day,hour,minute,second):Paraalmacenartimestamps(unafechaconsuhora).DateFromTicks(ticks):Paracrearunafechaapartirdeunnúmeroconlossegundos transcurridos desde el epoch (el 1 de Enero de 1970 a las00:00:00GMT).TimeFromTicks(ticks):Similaralanterior,parahorasenlugardefechas.TimestampFromTicks(ticks):Similaralanterior,paratimestamps.Binary(string):Valorbinario.

Page 157: Python para todos repasa aspectos esenciales de

OtrasopcionesPor supuesto no estamos obligados a utilizar DB-API, ni bases de datosrelacionales. En Python existen módulos para trabajar con bases de datosorientadas a objetos, como ZODB (Zope Object Database) y motores paramapeoobjeto-relacional(ORM)comoSQLAlchemy,SQLObjectoStorm.Además,siutilizamosIronPythonenlugardeCPythontenemoslaposibilidaddeutilizar lasconexionesabasesdedatosde .NET,ysiutilizamosJython, lasdeJava.

Page 158: Python para todos repasa aspectos esenciales de

DOCUMENTACIÓN

Page 159: Python para todos repasa aspectos esenciales de

DocstringsEncapítulosanterioresyacomentamosenvariasocasionesquetodoslosobjetoscuentanconunavariableespecial__doc__mediantelaqueindicarelpropósitoyusodelobjeto.Estossonlosllamadosdocstringsocadenasdedocumentación.A estos atributos se les puede asociar el texto correspondiente explícitamente,asignándoloalliteralcadenacorrespondiente,comoconcualquierotravariable.Sin embargo, por conveniencia, Python ofrece un mecanismo mucho mássencilloyesquesielprimerestamentodeladefinicióndelobjetoesunacadena,estaseasociaalavariable__doc__automáticamente.

defhaz_algo(arg):

“““Esteeseldocstringdelafuncion.”””

printarg

printhaz_algo.__doc__

haz_algo.__doc__=“““Esteesunnuevodocstring.”””

Page 160: Python para todos repasa aspectos esenciales de

printhaz_algo.__doc__Como vemos lo interesante de estas cadenas es que, a diferencia de los

comentarios normales de Python y de los comentarios de otros lenguajes, lascadenas de documentación no se eliminan del bytecode, por lo que se puedenconsultar en tiempo de ejecución, usando, por ejemplo, la función help dellenguaje,outilizandolasentenciaprintcomoenelejemploanterior.

>>>help(haz_algo)Helponfunctionhaz_algoinmodule__main__:haz_algo(arg)

Esteesunnuevodocstring.

Page 161: Python para todos repasa aspectos esenciales de

PydocLa función help, que comentamos brevemente con anterioridad, utiliza elmódulo pydoc para generar la documentación de un objeto a partir de sudocstringy losdocstringsdesusmiembros.Estemódulo, incluidopordefectoconPythondesdelaversión2.1,sepuedeimportarennuestrocódigoPythonyutilizarseprogramáticamente,obiensepuedeutilizarcomounaherramientadelíneadecomandosque sería el equivalente a la aplicación JavadocdelmundoJava.pydocpuedemostrarlainformacióncomotextoenlaconsola,talcomoloutilizahelp, pero tambiénpuedegenerar archivosHTMLcomo javadoco facilitar lainformaciónatravésdeunpequeñoservidorwebincluidoconelmódulo.Pydocesmuysencillodeutilizar.Con

pydoc.pynombre1[nombre2...]

semuestraladocumentacióndeltema,módulo,clase,paquete,funciónopalabraclave indicada de forma similar a la funciónhelp. Si el nombre eskeywords,

Page 162: Python para todos repasa aspectos esenciales de

topics o modules se listarán las distintas palabras claves, temas y módulosrespectivamente.Si se pasa el flag -w, el script guardará la documentación en uno o variosarchivoshtmlenlugardemostrarlaporpantalla.

pydoc.py-wnombre1[nombre2...]

Elflag-ksirveparabuscarunadeterminadapalabraenlassinopsisdetodoslosmódulos disponibles. La sinopsis es la primera línea de la cadena dedocumentación.

pydoc.py-kxml

Con-ppodemosiniciarelservidorHTTPenelpuertoindicado.pydoc.py-ppuerto

Unavezhechoestopodemosaccederaladocumentacióndetodoslosmódulosdisponiblesabriendolapáginahttp://localhost:puertoennuestronavegador.Porúltimo,medianteelflag-gpodemoslanzarunainterfazgráficaparabuscardocumentaciónqueutilizaelservidorHTTPparamostrarlosresultados.

Page 163: Python para todos repasa aspectos esenciales de

EpydocyreStructuredTextElproblemadepydoc esqueesmuysimple,ynopermiteañadir semánticaomodificarestilosdeladocumentación.Nopodemos,porejemplo,indicarqueenuna línea en concreto de entre las líneas de documentación de la funcióndescribeunparámetrodelafunciónomostrarunciertotérminoencursiva.Existen proyectos para generar documentación con funcionalidades másavanzadas como Docutils, Epydoc o Sphinx, aunque es necesario aprendersintaxisespeciales.Docutils es un proyecto desarrollado porDavidGoodger que incluye distintasherramientas para generar documentación utilizando el formatoreStructuredText,unformatodetextoplanocreadoporelmismoautor,yqueesel formatomás utilizado en la comunidad Python. reStructuredText se utiliza,entreotros,paralacreacióndelosPEPs(PythonEnhancementProposals).Sinembargo,actualmenteDocutilsesmásindicadoparagenerardocumentosapartirdearchivosdetexto,ynoapartirdedocstringsextraídosdecódigofuente

Page 164: Python para todos repasa aspectos esenciales de

Python, ya que el parser encargado de este trabajo dista mucho de estarterminado.EpyDocesunadelasherramientasdegeneracióndedocumentaciónparaPythonmásutilizadas.Ademásdetextoplanoydesupropioformato,llamadoepytext,soporta reStructuredText y sintaxis Javadoc, cosa que los programadores Javaagradecerán.AlolargodelrestodelcapítuloutilizaremosreStructuredTextcomolenguajedemarcadoyEpyDocparagenerarlosdocumentosfinales.EpydocsepuededescargardesdesupáginawebenformadeinstaladorexeparaWindows,paqueteRPMparaFedoraosimilares,oenarchivoszipytar.gzqueincluyen scripts de instalación: http://epydoc.sourceforge.net/. También seencuentraenlosrepositoriosdevariasdistribucionesLinux.UnavezhayamosinstaladoEpydocsiguiendoelmétodoadecuadoparanuestrosistemaoperativotendremosaccesoasufuncionalidadatravésdedosinterfacesdeusuariodistintas:elscriptepydoc,queconsisteenunaaplicacióndelíneadecomandos, y el script epydocgui (epydoc.pyw en Windows), que ofrece unainterfazgráfica.Ademástambiénpodemosaccederalafuncionalidaddeepydocprogramáticamente,comoenelcasodepydoc.Vamos a crear un pequeño módulo con un par de clases para ver primero elresultado de utilizarepydoc con docstrings de texto plano, sin ningún tipo demarcadoespecial.

“““Moduloparaejemplificarelusodeepydoc.”””

classPersona:

“““Miclasedeejemplo.”””

def__init__(self,nombre):

“““InicializadordelaclasePersona.”””

self.nombre=nombre

self.mostrar_nombre()

defmostrar_nombre(self):

“““Imprimeelnombredelapersona”””

print“Estaeslapersona%s”%self.nombre

classEmpleado(Persona):“““SubclasedePersona.”””pass

if__name__==“__main__”:raul=Persona(“Raul”)El formato de salida por defecto de epydoc es HTML. Por lo tanto para

generarladocumentaciónenformadedocumentosHTMLbastaríaescribiralgo

Page 165: Python para todos repasa aspectos esenciales de

así:epydocejemplo.pyobienepydoc --html ejemplo.py Para generar un archivo PDF, utilizando LaTeX, se

utilizaría el flag --pdf: epydoc --pdf ejemplo.py Si LaTeX no está instalado o

epydocnoencuentraelejecutablenoseráposiblegenerarelPDF.

Tambiénpodemos indicar el nombre del proyecto y laURLmediante lasopciones --name y --url: epydoc --name Ejemplo --url http://mundogeek.netejemplo.pyEinclusoañadirdiagramasmostrandolaclasebaseysubclases(--graph classtree), las llamadas entre funciones y métodos (--graphcallgraph), clases y subclases usando notación UML (--graph uml-

classtree)otodosellos(--graphall).epydoc --graph all ejemplo.py Para generar el grafo de llamadas, no obstante, es

necesario generar un archivo con la información necesaria utilizando el módulo

profileoelmódulohotshoteindicarelarchivoresultanteutilizandoelflag--

pstat: epydoc --graph all --pstat profile.out ejemplo.py Veamos ahora algunas

funcionalidadesbásicasdemarcadoenreStructuredText.

Paraponeruntextoenitálicaserodeaeltextoconasteriscos:*itálica*->itálicaParaponerloennegrita,seutilizandosasteriscos:**negrita**->negritaPara mostrar el texto como monoespacio, por ejemplo para mostrar códigoinline,seutiliza“.

“monoespacio”->monoespacioSinecesitamosutilizarcualquieradeestoscaracteres

especiales,sepuedenescaparutilizandolabarrainvertida.

\* es un carácter especial -> * es un carácter especial Los títulos se crean

añadiendo una línea de caracteres no alfanuméricos por debajo del texto, o por

encima y por debajo del texto. Para crear un subtitulo basta utilizar una nueva

combinación.

Título

======

Subtitulo

---------

TítuloSubtitulo

Paracrearunalistanoordenadaseempiezacadalíneaconelcarácter‘*’,‘-’o‘+’:

*Python*C*Java

Python

Page 166: Python para todos repasa aspectos esenciales de

CJava

Paracrearunalistanumeradaseempiezalalíneaconelnúmeroseguidodeun punto, o bien con el símbolo ‘#’ para que se introduzca el númeroautomáticamente.

1.Python

2.C

3.Java

1. Python2. C3. Java

Paradescribirpropiedadesdeloselementosqueestamosdocumentandoseutilizanloscamposofields.EnreStructuredTextloscamposcomienzancon‘:’,le sigue el nombredel campoyopcionalmente sus argumentos, y se cierra denuevocon‘:’,paraterminarconelcuerpodelcampo.

EstossonalgunosdeloscamposquesoportaEpydoc:

Funcionesymétodos:paramp:Unparámetro Describeelparámetrop.:typep:str Especificaeltipoesperadoparaelparámetrop.:return:Truesisoniguales

Valorderetorno.

:rtype:str Tipodelvalorderetorno.:keywordp:Unparámetro

Descripcióndelparámetroconvalorpordefectoynombrep.

:raisee:Sielparámetroescero

Describelascircunstanciasparalasqueselanzalaexcepcióne.

Variables:ivarv:Unavariable Descripcióndelainstanciav.:cvarv:Unavariable Descripcióndelavariableestáticadeclasev.:varv:Unavariable Descripcióndelavariablevdelmódulo.:typev:str Tipodelavariablev.

Page 167: Python para todos repasa aspectos esenciales de

Notas:note:Unanota Unanotasobreelobjeto.:attention:Importante Unanotaimportantesobreelobjeto.:bug:Nofuncionaparaelvalor0 Descripcióndeunerrorenelobjeto.:warning:Cuidadoconelvalor0 Unaadvertenciaacercadeunobjeto.:see:Ver‘Pythonparatodos’ Paraindicarinformaciónrelacionada.

Estado:version:1.0 Versiónactualdelobjeto.:change:Versióninicial Listadodecambios.:todo:Internacionalización Uncambioplaneadoparaelobjeto.:status:Versiónestable Estadodelobjeto.

Autoría:author:RaulGonzalez Autoroautoresdelobjeto.:organization:Mundogeek Organizaciónquecreóomantieneelobjeto.:license:GPL Licenciadelobjeto.:contact:zootropoengmail Informacióndecontactodelautor.

Para que Epydoc sepa que utilizamos reStructuredText es necesarioindicarlomedianteunavariable__docformat__enelcódigo,obienmediantelaopción--docformatdelíneadecomandos.Lasopcionesposiblessonepytext,plaintext,restructuredtextojavadoc.

Veamosunejemploconcampos:“““Moduloparaejemplificarelusode*epydoc*.

:author:RaulGonzalez:version:0.1”””

__docformat__=“restructuredtext”

classPersona:“““Modelaunapersona.”””def__init__(self,nombre,edad):

“““Inicializadordelaclase`Persona`.:paramnombre:Nombredelapersona.

Page 168: Python para todos repasa aspectos esenciales de

:paramedad:Edaddelapersona”””self.nombre=nombreself.edad=edadself.mostrar_nombre()

defmostrar_nombre(self):“““Imprimeelnombredelapersona”””print“Estaeslapersona%s”%self.nombre

classEmpleado(Persona):“““Subclasede`Persona`correspondientealaspersonasquetrabajanparalaorganizacion.:todo:Escribirimplementacion.”””

passif__name__==“__main__”:

juan=Persona(“Juan”,26)reStructuredText tambiénsoportaunsegundo tipodecamposenelqueel

cuerpodel campoesuna lista.Deesta formapodemos,por ejemplo,describirtodoslosparámetrosdeunafunciónométodoconunsolocampo:Parameters:,enlugardeconuncampo:param:paracadaparámetro.

classPersona:

“““Modelaunapersona.”””

def__init__(self,nombre,edad):

“““Inicializadordelaclase`Persona`.

:Parameters:

-`nombre`:Nombredelapersona.

-`edad`:Edaddelapersona.

”””

self.nombre=nombreself.edad=edad

self.mostrar_nombre()

Otros campos que admiten listas son :Exceptions: para indicar variasexcepciones(:except:),:Variables:paracomentarvariasvariables(:var:)o:Ivariables:paracomentarvariasinstancias(:ivar:).

Page 169: Python para todos repasa aspectos esenciales de

PRUEBASParaasegurarenlamedidadeloposibleelcorrectofuncionamientoylacalidaddel software se suelen utilizar distintos tipos de pruebas, comopueden ser laspruebasunitarias,laspruebasdeintegración,olaspruebasderegresión.Alolargodeestecapítulonoscentraremosenlaspruebasunitarias,mediantelasquesecompruebaelcorrectofuncionamientodelasunidadeslógicasenlasquesedivideelprograma,sintenerencuentalainterrelaciónconotrasunidades.La solución más extendida para las pruebas unitarias en el mundo Python esunittest, a menudo combinado con doctest para pruebas más sencillas.AmbosmódulosestánincluidosenlalibreríaestándardePython.

Page 170: Python para todos repasa aspectos esenciales de

DoctestComoesdesuponerporelnombredelmódulo,doctestpermitecombinar laspruebas con la documentación. Esta idea de utilizar las pruebas unitarias paraprobarelcódigoy tambiénamododedocumentaciónpermiterealizarpruebasdeformamuysencilla,propiciaelquelaspruebassemantenganactualizadas,ysirve a modo de ejemplo de uso del código y como ayuda para entender supropósito.Cuando doctest encuentra una línea en la documentación que comienza con‘>>>’ se asume que lo que le sigue es código Python a ejecutar, y que larespuestaesperadaseencuentraenlalíneaolíneassiguientes,sin>>>.Eltextodelapruebaterminacuandoseencuentraunalíneaenblanco,ocuandosellegaalfinaldelacadenadedocumentación.Tomemos como ejemplo la siguiente función, que devuelve una lista con loscuadradosdetodoslosnúmerosquecomponenlalistapasadacomoparámetro:

defcuadrados(lista):

“““Calculaelcuadradodelosnumerosdeunalista”””

Page 171: Python para todos repasa aspectos esenciales de

return[n**2forninlista]

Podríamoscrearunapruebacomolasiguiente,enlaquecomprobamosqueelresultadoalpasarlalista[0,1,2,3]eselqueesperábamos:

defcuadrados(lista):“““Calculaelcuadradodelosnumerosdeunalista>>>l=[0,1,2,3]>>>cuadrados(l)[0,1,4,9]”””

return[n**2forninlista]Loquehacemosenesteejemploesindicaradoctestquecreeunlistalcon

valor[0,1,2,3], que llame a continuación a la funcióncuadrados con lcomoargumento,yquecompruebequeelresultadodevueltoseaiguala[0,1,4,9].

Paraejecutarlaspruebasseutilizalafuncióntestmoddelmódulo,alaqueselepuedepasaropcionalmenteelnombredeunmóduloaevaluar(parámetroname).Enelcasodequenoseindiqueningúnargumento,comoenestecaso,seevalúaelmóduloactual:

defcuadrados(lista):“““Calculaelcuadradodelosnumerosdeunalista>>>l=[0,1,2,3]>>>cuadrados(l)[0,1,4,9]”””

return[n**2forninlista]

def_test():importdoctestdoctest.testmod()

if__name__==“__main__”:_test()En el caso de que el código no pase alguna de las pruebas que hemos

definido, doctest mostrará el resultado obtenido y el resultado esperado. Encasocontrario,sitodoescorrecto,nosemostraráningúnmensaje,amenosqueañadamos la opción -v al llamar al script o el parámetro verbose=True a lafunción testmod, en cuyo caso se mostrarán todas las pruebas ejecutadas,independientementedesiseejecutaronconéxito.

Esteseríaelaspectodelasalidadedoctestutilizandoelparámetro-v:Trying:

l=[0,1,2,3]

Page 172: Python para todos repasa aspectos esenciales de

ExpectingnothingokTrying:

cuadrados(l)Expecting:[0,1,4,9]

ok2itemshadnotests:__main____main__._test1itemspassedalltests:2testsin__main__.cuadrados2testsin3items.2passedand0failed.Testpassed.Ahoravamos a introducir un error en el códigode la funciónparaver el

aspecto de un mensaje de error de doctest. Supongamos, por ejemplo, quehubiéramos escrito un operador de multiplicación (‘*’) en lugar de uno deexponenciación(‘**’):

defcuadrados(lista):“““Calculaelcuadradodelosnumerosdeunalista>>>l=[0,1,2,3]>>>cuadrados(l)[0,1,4,9]“““

return[n*2forninlista]

def_test():importdoctestdoctest.testmod()

if__name__==“__main__”:_test()Obtendríamosalgoparecidoaesto:****************************************File“ejemplo.py”,line5,in__main__.cuadradosFailedexample:

cuadrados(l)Expected:[0,1,4,9]

Got:[0,2,4,6]

****************************************1 items had failures: 1 of 2 in __main__.cuadrados ***Test Failed*** 1

failures.Comovemos,elmensajenosindicaquehafalladolapruebadelalínea5,

Page 173: Python para todos repasa aspectos esenciales de

al llamar a cuadrados(l), cuyo resultado debería ser [0, 1, 4, 9], y sinembargoobtuvimos[0,2,4,6].

Veamosporúltimocómoutilizar sentenciasanidadasparahacer cosasunpoco más complicadas con doctest. En el ejemplo siguiente nuestra funcióncalculael cuadradodeunúniconúmeropasadocomoparámetro,ydiseñamosunapruebaquecompruebequeelresultadoeseladecuadoparavariasllamadascondistintosvalores.Lassentenciasanidadascomienzancon“...”enlugarde“>>>”:

defcuadrado(num):“““Calculaelcuadradodeunnumero.

>>>l=[0,1,2,3]>>>forninl:...cuadrado(n)[0,1,4,9]“““

returnnum**2

def_test():importdoctestdoctest.testmod()

if__name__==“__main__”:_test()

Page 174: Python para todos repasa aspectos esenciales de

unittest/PyUnitunittest,tambiénllamadoPyUnit,formapartedeunafamiliadeherramientasconocidacolectivamentecomoxUnit,unconjuntodeframeworksbasadosenelsoftwareSUnitparaSmalltalk, creadoporKentBeck,unode lospadresde laeXtremeProgramming.Otrosejemplosdeherramientasqueformanpartedeestafamilia son JUnit para Java, creada por el propio Kent Beck junto a ErichGamma,oNUnit,para.NET.Elusodeunittest esmuysencillo.Paracadagrupodepruebas tenemosquecrear una clase que herede de unittest.TestCase, y añadir una serie demétodos que comiencen con test, que serán cada una de las pruebas quequeremosejecutardentrodeesabateríadepruebas.Paraejecutar laspruebas,basta llamara la funciónmain()delmódulo,con loqueseejecutarán todos losmétodoscuyonombrecomiencecon test,enordenalfanumérico.Alejecutarcadaunadelaspruebaselresultadopuedeser:

Page 175: Python para todos repasa aspectos esenciales de

OK:Lapruebahapasadoconéxito.FAIL: La prueba no ha pasado con éxito. Se lanza una excepciónAssertionErrorparaindicarlo.ERROR: Al ejecutar la prueba se lanzó una excepción distinta deAssertionError.

Enelsiguienteejemplo,dadoqueelmétodoquemodelanuestrapruebanolanzaningunaexcepción,lapruebapasaríaconéxito.

importunittest

classEjemploPruebas(unittest.TestCase):

deftest(self):

pass

if__name__==“__main__”:unittest.main()Enesteotro,sinembargo,fallaría:importunittest

classEjemploPruebas(unittest.TestCase):deftest(self):

raiseAssertionError()

if__name__==“__main__”:unittest.main()Nadanosimpideutilizarcláusulasifparaevaluarlascondicionesquenos

interesen y lanzar una excepción de tipo AssertionError cuando no sea así,pero la claseTestCase cuenta con variosmétodos que nos pueden facilitar latareaderealizarcomprobacionessencillas.Sonlossiguientes:

assertAlmostEqual(first,second,places=7,msg=None):Compruebaque los objetos pasados como parámetros sean iguales hasta el séptimodecimal(oelnúmerodedecimalesindicadoporplaces).assertEqual(first, second, msg=None): Comprueba que los objetospasadoscomoparámetrosseaniguales.assertFalse(expr,msg=None):Compruebaquelaexpresiónseafalsa.assertNotAlmostEqual(first, second, places=7, msg=None):Compruebaquelosobjetospasadoscomoparámetrosnoseanigualeshastaelséptimodecimal(ohastaelnúmerodedecimalesindicadoporplaces).assertNotEqual(first,second,msg=None):Compruebaquelosobjetospasadoscomoparámetrosnoseaniguales.

Page 176: Python para todos repasa aspectos esenciales de

assertRaises(excClass,callableObj,*args,**kwargs):CompruebaquealllamaralobjetocallableObjconlosparámetrosdefinidospor*argsy**kwargsselanzaunaexcepcióndetipoexcClass.assertTrue(expr,msg=None):Compruebaquelaexpresiónseacierta.assert_(expr,msg=None):Compruebaquelaexpresiónseacierta.fail(msg=None):Fallainmediatamente.failIf(expr,msg=None):Fallasilaexpresiónescierta.failIfAlmostEqual(first,second,places=7,msg=None):Falla si losobjetospasadoscomoparámetros son igualeshastael séptimodecimal (ohastaelnúmerodedecimalesindicadoporplaces).failIfEqual(first, second, msg=None): Falla si los objetos pasadoscomoparámetrossoniguales.failUnless(expr,msg=None):Fallaamenosquelaexpresiónseacierta.failUnlessAlmostEqual(first,second,places=7,msg=None):Fallaamenos que los objetos pasados como parámetros sean iguales hasta elséptimodecimal(ohastaelnúmerodedecimalesindicadoporplaces).failUnlessEqual(first, second, msg=None): Falla a menos que losobjetospasadoscomoparámetrosseaniguales.failUnlessRaises(excClass,callableObj,*args,**kwargs):Fallaamenos que al llamar al objetocallableObj con los parámetros definidospor*argsy**kwargsselanceunaexcepcióndetipoexcClass.

Comovemostodoslosmétodoscuentanconunparámetroopcionalmsgconunmensajeamostrarcuandodichacomprobaciónfalle.

Retomemos nuestra pequeña función para calcular el cuadrado de unnúmero. Para probar el funcionamiento de la función podríamos hacer, porejemplo,algoasí:

importunittest

defcuadrado(num):“““Calculaelcuadradodeunnumero.”””

returnnum**2

classEjemploPruebas(unittest.TestCase):deftest(self):

l=[0,1,2,3]r=[cuadrado(n)forninl]self.assertEqual(r,[0,1,4,9])

Page 177: Python para todos repasa aspectos esenciales de

if__name__==“__main__”:unittest.main()

PreparacióndelcontextoEnocasionesesnecesarioprepararelentornoenelquequeremosqueseejecutenlaspruebas.Porejemplo,puedesernecesariointroducirunosvalorespordefectoenunabasededatos,crearunaconexiónconunamáquina,crearalgúnarchivo,etc.EstoesloqueseconoceenelmundodexUnitcomotestfixture.

La clase TestCase proporciona un par de métodos que podemossobreescribirparaconstruirydesconstruirelentornoyqueseejecutanantesydespués de las pruebas definidas en esa clase. Estos métodos son setUp() ytearDown().

classEjemploFixture(unittest.TestCase):

defsetUp(self):

print“Preparandocontexto”

self.lista=[0,1,2,3]

deftest(self):

print“Ejecutandoprueba”

r=[cuadrado(n)forninself.lista]

self.assertEqual(r,[0,1,4,9])

deftearDown(self):print“Desconstruyendocontexto”delself.lista

Page 178: Python para todos repasa aspectos esenciales de

DISTRIBUIRAPLICACIONESPYTHON

Una vez terminemos con el desarrollo de nuestra nueva aplicación esconvenienteempaquetarladeformaqueseasencilloparalosusuariosinstalarla,yparanosotrosdistribuirla.EnPythonexistendosmódulosprincipalesparaestecometido:distutils,queespartedelalibreríaestándaryeraelmétodomásutilizadohastahacepoco,ysetuptools, que extiende la funcionalidad de distutils y es cada vez máspopular.En este capítulo veremos el funcionamiento de ambas herramientas, yterminaremosexplicandocómocrearejecutables.exeparaWindowsapartirdenuestroprogramaenPython.

Page 179: Python para todos repasa aspectos esenciales de

distutilsTodo programa distribuido con distutils contiene un script llamado porconvención setup.py, que se encarga de instalar la aplicación llamando a lafunciónsetupdedistutils.core.Estafuncióntienemontonesdeargumentos,quecontrolan,entreotrascosas,cómoinstalarlaaplicación.Destinadosadescribirlaaplicacióntenemoslossiguientesargumentos:

name:Elnombredelpaquete.version:Elnúmerodeversión.description:Unalíneadescribiendoelpaquete.long_description:Descripcióncompletadelpaquete.author:Nombredelautordelaaplicación.author_email:Correoelectrónicodelautor.maintainer:Nombre de la persona encargada demantener el paquete, sidifieredelautor.

Page 180: Python para todos repasa aspectos esenciales de

maintainer_email: Correo de la persona encargada de mantener elpaquete,sidifieredelautor.url:Webdelaaplicación.download_url:Urldelaquedescargarlaaplicación.license:Licenciadelaaplicación

Tambiéntenemosargumentosquecontrolanlosarchivosydirectoriosquedebeninstalarse,comosonpackages,py_modules,scriptsyext_modules.Elparámetroscripts,queesunalistadecadenas,indicaelnombredelmóduloomódulosprincipales,esdecir,losqueejecutaelusuario.Sinuestraaplicaciónconsistiera, por ejemplo, en un solo script ejemplo.py, el código de setup.pypodríatenerunaspectosimilaralsiguiente:fromdistutils.coreimportsetup

setup(name=”Aplicaciondeejemplo”,version=”0.1”,description=”Ejemplo del funcionamiento de distutils”, author=”RaulGonzalez”,author_email=”zootropoengmail”,url=”http://mundogeek.net/tutorial-python/”,license=”GPL”,scripts=[“ejemplo.py”]

)Si hemos escritootrosmódulospara ser utilizadospor el script principal,

estos se indicanmediante el parámetropy_modules.Por ejemplo, supongamosque la aplicación consiste en un script principal ejemplo.py, y un módulo deapoyoapoyo.py:

fromdistutils.coreimportsetup

setup(name=”Aplicaciondeejemplo”,version=”0.1”,description=”Ejemplo del funcionamiento de distutils”, author=”Raul

Gonzalez”,author_email=”zootropoengmail”,url=”http://mundogeek.net/tutorial-python/”,license=”GPL”,scripts=[“ejemplo.py”],py_modules=[“apoyo”])Para instalarpaquetesPython(directoriosquecontienenvariosmódulosy

unarchivo__init__.py)usaríamoselparámetropackages.Siademásdelmóduloejemplo.pyquisiéramosinstalarlospaquetesguiybbdd,porejemplo,haríamosalgoasí:

Page 181: Python para todos repasa aspectos esenciales de

fromdistutils.coreimportsetup

setup(name=”Aplicaciondeejemplo”,version=”0.1”,description=”Ejemplo del funcionamiento de distutils”, author=”Raul

Gonzalez”,author_email=”zootropoengmail”,url=”http://mundogeek.net/tutorial-python/”,license=”GPL”,scripts=[“ejemplo.py”],packages=[“gui”,“bbdd”])ext_modules, por último, sirve para incluir extensiones que utilice el

programa,enC,C++,Fortran,…Veamosahoracómoseutilizaríaelarchivosetup.pyunavezcreado.Alejecutarelcomandopython setup.py install los módulos y paquetes especificados por py_modules y

packages se instalan en el directorio Lib de Python. Los programas indicados en

scripts,secopianaldirectorioScriptsdePython.

Una vez hemos comprobado que la aplicación se instala correctamente,procedemos a crear archivos mediante los que distribuir la aplicación a losusuarios.Paracreararchivosconelcódigofuenteseutilizalaopciónsdistdesetup.py,quecreapordefectounarchivotar.gzenUnixyunzipenWindows.

python setup.py sdist Sin embargo se puede utilizar --formats para especificar el

formatooformatosquequeramosgenerar

bztar .tar.bz2gztar .tar.gztar .tarzip .zipztar .tar.Z

Paracrearunarchivotar.bz2,untar.gzyunzip,porejemplo,seutilizaríalasiguienteorden:pythonsetup.pysdist--formats=bztar,gztar,zipParagenerarunarchivo de distribución binaria, se usa la opciónbdist: python setup.py bdistLosformatosquesoportabdistsonlossiguientes:

rpm RPMgztar .tar.gz

Page 182: Python para todos repasa aspectos esenciales de

bztar .tar.bz2ztar .tar.Ztar .tarwininst InstaladorWindowszip .zip

Para crear un archivo rpm y un instalador de Windows, por ejemplo,escribiríamos:pythonsetup.pybdist --formats=wininst,rpmTambiénesposiblecrear otros tipos de archivos de distribución utilizando scripts que extiendendistutils, como es el caso de los paquetes deb mediante el script stdeb(http://stdeb.python-hosting.com/)

Page 183: Python para todos repasa aspectos esenciales de

setuptoolssetuptools extiende distutils añadiendo una serie de funcionalidades muyinteresantes: introduce un nuevo formato de archivo para distribución deaplicacionesPython llamadoegg, se encargadebuscar todos lospaquetesquedebeninstalarseyañadirlasposiblesdependencias,permiteinstalarpaquetesdePyPIconunsolocomando,etc.Además, como setuptools se basa en distutils, un script de instalación básicoutilizando setuptools esprácticamente igual a su equivalente condistutils.Tansólocambiaríalasentenciadeimportación.

fromsetuptoolsimportsetup

setup(name=”Aplicaciondeejemplo”,

version=”0.1”,

description=”Ejemplo del funcionamiento de distutils”, author=”Raul Gonzalez”,

author_email=”zootropoengmail”,

url=”http://mundogeek.net/tutorial-python/”,license=”GPL”,

scripts=[“ejemplo.py”],

)

Page 184: Python para todos repasa aspectos esenciales de

ElúnicoinconvenientequepodríamosencontraralusodesetuptoolsesquenoestáincluidopordefectoenPython2.5,aunqueesprobablequeestocambieen próximas versiones debido a su gran uso. Pero los desarrolladores desetuptools han pensado en todo, e incluso esto no debería suponer ningúnproblema,yaqueconunmínimoesfuerzopornuestrapartepodemoshacerquesetuptoolssedescarguee instaleautomáticamenteen lamáquinadelusuariosieste no se encuentra ya en el sistema.Basta distribuir con nuestro paquete unpequeñomóduloextraez_setup.pyquevieneincluidopordefectoconsetuptools(http://peak.telecommunity.com/dist/ez_setup.py) y llamar a la funciónuse_setuptoolsdelmóduloaliniciodesetup.py:

fromez_setupimportuse_setuptoolsuse_setuptools()

fromsetuptoolsimportsetupsetup(name=”Aplicaciondeejemplo”,version=”0.1”,description=”Ejemplo del funcionamiento de distutils”, author=”Raul

Gonzalez”,author_email=”zootropoengmail”,url=”http://mundogeek.net/tutorial-python/”,license=”GPL”,scripts=[“ejemplo.py”],)Veamosahoraconmásdetenimientoalgunosde loscambiosynovedades

queintroducesetuptools.

IntegraciónconPyPIAlestilodeCPANenPerlsetuptoolspermiteinstalardeformafácilysencillalospaquetespertenecientesaPyPI,elÍndicedePaquetesPython(http://pypi.python.org/pypi),asícomosubirnuestrospropiospaquetes.

PyPIcuentaenelmomentodeescribirestaslíneascon4782paquetes,porlo que poder instalar los paquetes de este repositorio con un simple comandosuponeunaayudamuyatenerencuenta.

Instalar un paquete de PyPI es tan sencillo como pasar al comandoeasy_installelnombredelpaqueteainstalar

easy_installdocutils

Searchingfordocutils

Readinghttp://pypi.python.org/simple/docutils/

Readinghttp://docutils.sourceforge.net/

Bestmatch:docutils0.5

Downloadinghttp://prdownloads.sourceforge.net/docutils/

docutils-0.5.tar.gz?download

Processingdocutils-0.5.tar.gz

Page 185: Python para todos repasa aspectos esenciales de

Running docutils-0.5/setup.py -q bdist_egg --dist-dir /tmp/easy_install-

wUAyUZ/docutils-0.5/egg-dist-tmp-kWkkkv “optparse” module already present; ignoring

extras/optparse.py.

“textwrap”modulealreadypresent;ignoringextras/textwrap.py.

zip_safeflagnotset;analyzingarchivecontents…

docutils.writers.newlatex2e.__init__:modulereferences__file__

docutils.writers.pep_html.__init__:modulereferences__file__

docutils.writers.html4css1.__init__:modulereferences__file__

docutils.writers.s5_html.__init__:modulereferences__file__

docutils.parsers.rst.directives.misc:modulereferences__file__

Adding docutils 0.5 to easy-install.pth file Installing rst2pseudoxml.py script to

/usr/binInstallingrst2html.pyscriptto/usr/binInstallingrst2latex.pyscriptto

/usr/bin Installing rst2s5.py script to /usr/bin Installing rst2newlatex.py script

to /usr/bin Installing rstpep2html.py script to /usr/bin Installing rst2xml.py

scriptto/usr/binInstalled/usr/lib/python2.5/site-packages/docutils-0.5-py2.5.egg

Processingdependenciesfordocutils

Finishedprocessingdependenciesfordocutils

PodersubirnuestrospaquetesaPyPIrequieredeunprocesounpocomáslaborioso. Primero registramos los detalles de nuestra aplicación en PyPImediantelaopciónregisterdelscriptsetup.py,elcualnospreguntarápornuestronombre de usuario, contraseña y correo electrónico si no tenemos cuenta enPyPI,onombredeusuarioycontraseñasinosregistramosanteriormente:

pythonsetup.pyregisterrunningregisterrunningegg_infocreating Aplicacion_de_ejemplo.egg-info writing

Aplicacion_de_ejemplo.egg-info/PKG-INFOwriting top-level names to Aplicacion_de_ejemplo.egg-info/top_level.txt

writing dependency_links to Aplicacion_de_ejemplo.egg-info/dependency_links.txt writing manifest file ‘Aplicacion_de_ejemplo.egg-info/SOURCES.txt’

readingmanifestfile‘Aplicacion_de_ejemplo.egg-info/SOURCES.txt’writingmanifestfile‘Aplicacion_de_ejemplo.egg-info/SOURCES.txt’Weneedtoknowwhoyouare,sopleasechooseeither:1.useyourexisting

login,2.registerasanewuser,3.havetheservergenerateanewpasswordforyou(andemailittoyou),or

4.quitYourselection[default1]:1Username:zootropoPassword:Serverresponse(200):OKIcanstoreyourPyPIloginsofuturesubmissionswillbefaster.(theloginwillbestoredin/home/zootropo/.pypirc)Saveyourlogin(y/N)?

y

Page 186: Python para todos repasa aspectos esenciales de

Para crear y subir una distribución con el código fuente de nuestraaplicación se utiliza la opción sdist upload: python setup.py sdist uploadTambiénpodríamoscrearysubirunegg(unformatodearchivoparadistribuiraplicaciones Python que veremos en la próxima sección) utilizando la opciónbdist_eggupload:pythonsetup.pybdist_egguploadOcombinarlostrespasosen un solo comando: python setup.py register sdist bdist_egg uploadUna vezsubido el paquete cualquier persona podría instalarlo en su sistema utilizandoeasy_install, de la misma forma que cualquier otro paquete de PyPI:easy_installmi-paquete

EggsLoseggs(huevoeninglés)sonarchivosdeextensión.eggmediantelosque

distribuir aplicaciones en Python. Serían algo así como el equivalente a losarchivos .jar del mundo Java. Son multiplataforma, permiten manejardependencias,ypermiteninstalardistintasversionesdelmismopaquete.

La formamás sencillade instalar aplicacionesdistribuidas comoarchivoseggesmedianteelcomandoeasy_install,elcualcomentamosbrevementeenelpuntoanterioralhablarsobresuusoparainstalarpaquetesdePyPI.Parainstalarunarchivoeggnotenemosmásquepasarleelnombredelarchivoalcomandoeasy_install:easy_installmi-aplicacion.eggobienpodemospasarlelaURLdelaque descargar el egg: easy_install http://mundogeek.net/mi-aplicacion.eggParaconstruir nuestros propios eggs podemos utilizar el comando bdist_egg desetup.py, de forma similar a lamanera en que construíamos paquetes RPM oinstaladores para Windows con distutils: python setup.py bdist_egg OtroscambiosdestacablesUnode loscambiosmás interesanteses la incorporacióndeunnuevoargumentopara la funciónsetup llamadoinstall_requires, queconsiste en una cadena o lista de cadenas que indica los paquetes de los quedependelaaplicación.Sinuestraaplicaciónnecesitaratenerinstaladoelpaqueteapoyo para poder ejecutarse, por ejemplo, escribiríamos lo siguiente:install_requires=[“apoyo”]

Ydeestaforma,easy_installseencargaríadebuscareinstalarelpaquetesifuera necesario, bien en PyPI, o en cualquier otro repositorio indicado por elparámetrodependency_links.

Además podemos especificar que se necesita una versión concreta delpaquete requerido,queseamayoromenorqueunaciertaversión,oquenosetrate de una versión determinada utilizando operadores relacionales (==,!=, <,<=,>,>=):install_requires=[“apoyo>=1.0<2.0”]

También existen argumentos similares para declarar paquetes que deben

Page 187: Python para todos repasa aspectos esenciales de

instalarse para poder ejecutar el script de instalación (setup_requires), parapoderejecutarlasposiblespruebasincluidasconelpaquete(tests_require)ypara conseguir funcionalidades adicionales (extras_require, que consiste enestecasoenundiccionario).

setuptoolsincluyetambiénatajosútiles,comolafunciónfind_packages()quenosevitatenerquelistartodosycadaunodelospaquetesqueutilizanuestroscriptenelparámetropackages,comoeraelcasodedistutils:

fromez_setupimportuse_setuptools

use_setuptools()

fromsetuptoolsimportsetup,find_packagessetup(name=”Aplicaciondeejemplo”,

version=”0.1”,

description=”Ejemplodelfuncionamientodedistutils”,author=”RaulGonzalez”,

author_email=”zootropoengmail”,

url=”http://mundogeek.net/tutorial-python/”,license=”GPL”,

scripts=[“ejemplo.py”],

packages=find_packages()

)

Page 188: Python para todos repasa aspectos esenciales de

Crearejecutables.exeTanto en Mac OS como en la mayor parte de las distribuciones Linux elintérpretedePythonestáinstaladopordefecto,porloquelosusuariosdeestossistemas no tienen mayor complicación a la hora de instalar y ejecutaraplicacionesescritasenPython.En el caso de Windows, esto no es así, por lo que sería interesante que losusuarios de este sistema operativo no tuvieran que instalar el intérprete dePython. También sería interesante que nuestro programa consistiera en unarchivo.exeenlugardeunoovariosarchivos.py,parasimplificarlascosas.Todoestolopodemoslogrargraciasapy2exe,unaextensiónparadistutilsque,como su nombre indica, permite crear ejecutables para Windows a partir decódigoPython,yquepermiteejecutarestasaplicacionessinnecesidaddetenerinstaladoelintérpretedePythonenelsistema.Py2exefuncionaexaminandonuestrocódigofuenteenbuscadelosmódulosypaquetes que utilizamos, compilándolos y construyendo un nuevo archivo que

Page 189: Python para todos repasa aspectos esenciales de

incluyeestosarchivosyunpequeñointérpretedePythonintegrado.Para probar el funcionamiento de py2exe creemos un pequeño programaejemplo.py

print“Soyun.exe”

yelarchivosetup.pycorrespondiente.Loscambiosquetenemosquerealizarasetup.py son sencillos: importar py2exe, y utilizar los argumentos console ywindows para indicar elnombredel scripto scriptsquequeramosconvertir enejecutablesdeconsolaoejecutablesdeinterfazgráfica,respectivamente.

fromdistutils.coreimportsetupimportpy2exe

setup(name=”Aplicaciondeejemplo”,

version=”0.1”,

description=”Ejemplodelfuncionamientodedistutils”,author=”RaulGonzalez”,

author_email=”zootropo en gmail”, url=”http://mundogeek.net/tutorial-python/”,

license=”GPL”,

scripts=[“ejemplo.py”],

console=[“ejemplo.py”]

)Paracrearelejecutable,utilizamosunanuevaopcióndelíneadecomandos

para setup.pydisponible tras importar elmóduloy llamada, cómono,py2exe:python setup.pypy2exeConestopy2exegeneraráundirectoriobuild, con laslibrerías compiladas, y un directorio dist, con los archivos que conformannuestraaplicación.

Entre losarchivosquepodemosencontrarendist tendremosunoovariosejecutables con el mismo nombre que los scripts indicados en console ywindows, un archivo python*.dll, que es el intérprete de Python, y un archivolibrary.zip,quecontienevariosarchivospycquesonlosmódulosqueutilizalaaplicacióncompilados.

Siqueremosreducirelnúmerodearchivosadistribuir,podemosutilizarlaopción--bundledepy2exeparaañadiralibrary.ziplasdllylospyd(--bundle2)olasdll,lospydyelintérprete(--bundle1).

pythonsetup.pypy2exe--bundle1

obienpodemosañadirunnuevoargumentooptionsalafunciónsetupqueindiqueelvalorautilizar(opciónbundle_files),deformaquenotengamosqueañadirelflag--bundlecadavezqueusemoselcomandopy2exe:

fromdistutils.coreimportsetupimportpy2exe

setup(name=”Aplicaciondeejemplo”,version=”0.1”,description=”Ejemplo del funcionamiento de distutils”, author=”Raul

Page 190: Python para todos repasa aspectos esenciales de

Gonzalez”,author_email=”zootropo en gmail”, url=”http://mundogeek.net/tutorial-

python/”,license=”GPL”,scripts=[“ejemplo.py”],console=[“ejemplo.py”],options={“py2exe”:{“bundle_files”:1}})Por último podemos incluso prescindir de library.zip e incrustarlo en el

ejecutableutilizandoelargumentozipfile=Nonefromdistutils.coreimportsetupimportpy2exe

setup(name=”Aplicaciondeejemplo”,

version=”0.1”,

description=”Ejemplodelfuncionamientodedistutils”,author=”RaulGonzalez”,

author_email=”zootropo en gmail”, url=”http://mundogeek.net/tutorial-python/”,

license=”GPL”,

scripts=[“ejemplo.py”],

console=[“ejemplo.py”],

options={“py2exe”:{“bundle_files”:1}},zipfile=None

)

Page 191: Python para todos repasa aspectos esenciales de

Índiceanalítico

Símbolos__call____cmp____del____doc____init____len____main____name____new____str__

Page 192: Python para todos repasa aspectos esenciales de

A

archivosatributos

Page 193: Python para todos repasa aspectos esenciales de

B

basesdedatosboolbreak

Page 194: Python para todos repasa aspectos esenciales de

C

cadenas,métodoscandadosclasesclasesdenuevoestiloclassclosecolamultihilocolecciones

diccionarioslistastuplas

comentarioscompilecomprensióndelistascondiciones,sincronizacióncontinuecookiescountcPickle

Page 195: Python para todos repasa aspectos esenciales de

D

dbapidecoradoresdefdiccionario,métodosdistutilsdocstringdocstringsdoctestdocutils

Page 196: Python para todos repasa aspectos esenciales de

E

eggselifelseencapsulaciónenvepydoceventosexcepcionesexcept

Page 197: Python para todos repasa aspectos esenciales de

F

Falseficherosfilefilterfinallyfindallfloatfor...inforkfrom...importfuertementetipadofuncionesfuncionesdeordensuperiorfuncioneslambda

Page 198: Python para todos repasa aspectos esenciales de

G

generadores

Page 199: Python para todos repasa aspectos esenciales de

GIL

GlobalInterpreterLock

Page 200: Python para todos repasa aspectos esenciales de

H

hashbanghelpherenciaherenciamúltiplehilos

Page 201: Python para todos repasa aspectos esenciales de

I

ifimportinputint10.VéaseaquíenterosiPython

Page 202: Python para todos repasa aspectos esenciales de

J

Jython

Page 203: Python para todos repasa aspectos esenciales de

K

Komodo

Page 204: Python para todos repasa aspectos esenciales de

L

lambdalenguajecompiladolenguajedescriptlenguajeinterpretadolenguajesemiinterpretadolistas,métodoslocks

Page 205: Python para todos repasa aspectos esenciales de

M

mapmarshalmarshallingmatchmétodosmodulemódulosmutex

Page 206: Python para todos repasa aspectos esenciales de

N

namemanglingNone

Page 207: Python para todos repasa aspectos esenciales de

O

objetosopenoperacionesrelacionalesoperadoresaniveldebitoperadoresaritméticosoperadoreslógicosorientaciónaobjetos

Page 208: Python para todos repasa aspectos esenciales de

P

paquetesparámetros,funcionesparámetrosporlíneadecomandoparámetros,valorespordefectoparticionadopasoporreferenciapasoporvalorpatrones(expresionesregulares)picklepolimorfismoprintprocesosprogramaciónfuncionalprogramaciónorientadaaobjetospropiedadespruebaspy2exePyDEVpydocPyPIPyPyPython

definicióninstalaciónventajas

Page 209: Python para todos repasa aspectos esenciales de

PYTHONPATH

R

raiseraw,cadenaraw_inputreadreadlinereadlinesreducereStructuredTextreturn

Page 210: Python para todos repasa aspectos esenciales de

S

searchseekselfsemáforosserializaciónsetuptoolssharpbangshebangshelvesincronizaciónslicingsocketssplitsubsubclasesuperclasesys.argv

Page 211: Python para todos repasa aspectos esenciales de

T

telltestfixtureteststhreadingthreadstipadodinámicotipadofuertetiposbásicos

booleanoscadenasnúmeros

complejosenterosreales

Truetry

Page 212: Python para todos repasa aspectos esenciales de

U

unittestupperurlliburllib2

Page 213: Python para todos repasa aspectos esenciales de

V

valoresinmutablesvaloresmutables

Page 214: Python para todos repasa aspectos esenciales de

W

whileWingIDEwritewritelines

Page 215: Python para todos repasa aspectos esenciales de

Y

yield

Page 216: Python para todos repasa aspectos esenciales de

RaúlGonzálezDuqueesun Ingeniero Informáticoaficionadoa losgadgets, laprogramación, Internet, la ciencia ficción, la tecnología, y todo lo relacionadoconelmundogeek.NacidoenToledo, lleva toda lavidaviviendoenMadrid,desdedondesededicaadesarrollaraplicaciones.

Page 217: Python para todos repasa aspectos esenciales de

TableofContentsPythonparatodosIntroducción

¿QuéesPython?¿PorquéPython?InstalacióndePythonHerramientasbásicas

MiprimerprogramaenPythonTiposbásicos

NúmerosCadenasBooleanos

ColeccionesListasTuplasDiccionarios

ControldeflujoSentenciascondicionalesBucles

FuncionesOrientaciónaobjetos

ClasesyobjetosHerenciaHerenciamúltiplePolimorfismoEncapsulaciónClasesde“nuevo-estilo”Métodosespeciales

RevisitandoobjetosDiccionariosCadenasListas

ProgramaciónfuncionalFuncionesdeordensuperiorIteracionesdeordensuperiorsobrelistasFuncioneslambda

Page 218: Python para todos repasa aspectos esenciales de

ComprensióndelistasGeneradoresDecoradores

ExcepcionesMódulosypaquetes

MódulosPaquetes

Entrada/salidayficherosEntradaestándarParámetrosdelíneadecomandoSalidaestándarArchivos

ExpresionesregularesPatronesUsandoelmódulore

SocketsInteractuarconwebsThreads

¿Quésonlosprocesosylosthreads?ElGILThreadsenPythonSincronizaciónDatosglobalesindependientesCompartirinformación

SerializacióndeobjetosBasesdedatos

DBAPIOtrasopciones

DocumentaciónDocstringsPydocEpydocyreStructuredText

PruebasDoctestunittest/PyUnit

DistribuiraplicacionesPythondistutilssetuptoolsCrearejecutables.exe

Page 219: Python para todos repasa aspectos esenciales de

ÍndiceanalíticoAutor