Ordre a la llista!
Escrit per Aaloy a 23 de September , 2007 a les 7:18 p.m.
Una de les accions més repetitives que sovint feim quan passam cap a la capa de presentació és la d'ordenar els elements que volem que es presentin. Potser algú dirà que els elements ja poden venir ordenats de la consulta a la base de dades, però què passa si en lloc d'atacar a una base de dades directament obtenim el que s'ha de mostrar d'un servei web? o ja hem fet un tractament de les dades i ara les volem ordenar per un altra camp. Poder fer ordenacions de manera senzilla i ràpida ens soluciona molts maldecaps.
Anem a veure com Python ens permet fer ordenacions de llistes de pràcticament qualsevol cosa. Python fa servir el mètode sort per a ordenar una llista. L'exemple més senzill seria l'ordenació d'una llista d'enters
$ llista = [2,4,5,6,7,6,7] $ llista.sort() $ llista [2, 4, 5, 6, 6, 7, 7]
Sí, és tan senzill com pareix, i fins i tot podem fer
$ llista.reverse() $ llista [7, 7, 6, 6, 5, 4, 2]
Però clar, una llista a Python pot contenir qualsevol cosa, no sols sencers, anem a veure què passa si passam una llista de parells (tuples)
$ llista = [(1,5),(1,2),(2,2),(3,5),(4,8),(1,9)] $ llista.sort() $ llista [(1, 2), (1, 5), (1, 9), (2, 2), (3, 5), (4, 8)]
Suposem però que jo el que vull és que s'ordeni pel segon element de la tupla, aquí si un prové d'altres llenguatges de programació ja se pot esperar tenir que escriure un bon munt de codi, però no en Python, l'ordenació es fa per una clau i podem definir quina és aquesta clau passant-li al mètode sort una funció construida de manera que prengui un sol element i ens retorni la clau a comparar.
Per fer el que volem farem servir el mòdul operator, i dins aquest la funció itemgetter, aquesta funció ens retorna una altra funció que aplicada damunt una llista o tupla ens donarà l'element especificat que haguem definit, així per exemple
$ segon=itemgetter(1) $ segon(llista) (2, 2) $ llista [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)] $ segon(llista) (2, 2) $ segon((1,5)) 5
Farem servir aquesta funció per a obtenir la clau per la qual volem ordenar la nostra llista, així
$ llista.sort(key=segon) $ llista [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]
Pensem en les implicacions que té això quan volem omplir un select d'html, encara que la llista ens hagi arribada ordenada per codi, podem fàcilment canviar l'ordenació al texte sols amb aquesta instrucció. Un altra paràmetre que ens serà de molta utilitat a l'hora de fer ordenacions és el cmp, aquest ens permet passar una funció que donats dos arguments haurà de retornar un nombre positiu per indicar que el primer és major que el segon, zero per indicar que els elements són igual o negatiu per indicar que el segon és major que el primer.
Per exemple, suposem que el que volem fer és ordenar la nostra llista segons el que sumen els seus components.
$ t=llista[:] #Farem primer una còpia de la llista original
$ def ordena(x,y):
p1 = x[0]+x[1]
p2 = y[0]+y[1]
return p1-p2
$ t.sort(cmp=ordena)
$ t
[(1, 2), (2, 2), (1, 5), (3, 5), (1, 9), (4, 8)]
$ llista
[(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]
O també poden fer un codi més florit i escriure
$ t = llista[:] $ t [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)] $ t.sort(lambda x,y: x[0]+x[1]-y[0]-y[1]) $ t [(1, 2), (2, 2), (1, 5), (3, 5), (1, 9), (4, 8)]
Si algú ha tingut la paciència d'arribar fins aquí, un momentet, que ara ve el més interessant. Què passa quan en lloc de llistes de nombres tenim llistes d'objectes? Doncs res, podem fer servir el paràmetre cmp o el paràmetre key segons ens vagi millor per fer l'ordenació. Anem a veure tres maneres de fer el mateix. Primer definirem la nostra llista d'objectes
class Persona:
def __init__(self, nom, edat):
self.nom = nom
self.edat = edat
def __cmp__(self, altri):
return cmp(self.edat,altri.edat)
Aquí el que he defint és una funció cmp dins la classe, que és la que faríem servir per defecte a l'hora d'ordenar una llista d'objectes d'aquest tipus, així:
$ agenda = [Persona('Benjamí', 31), Persona('Pau', 22),
Persona('Juan',34), Persona('Ricardo',38),
Persona('Guillem',28),
Persona('Bernat',58)]
$ agenda.sort()
$ for amic in agenda:
$ print "%25s \t %i" % (amic.nom, amic.edat)
Pau 22
Guillem 28
Benjamí 31
Juan 34
Ricardo 38
Bernat 58
Ara suposem però que volem ordenar la llista per nom. Una opció seria refer el mètode cmp, però tenim altres opcions. La primera és encriure una nova funció de comparació:
$ def compara_nom(amic1, amic2): $ return cmp(amic1.nom,amic2.nom) $ agenda.sort(compara_nom) $ for amic in agenda: $ print "%25s \t %i" % (amic.nom, amic.edat)
Benjamí 31
Bernat 58
Guillem 28
Juan 34
Pau 22
Ricardo 38
O bé, si ens agrada més l'opció lambda
$ agenda.sort(lambda amic1, amic2: cmp(amic1.nom,amic2.nom))
Però encara tenim una altra maner, deixant que Python faci la feina per nosaltres, hem d'indicar la clau d'ordenació i fer que les eines de comparació del llenguatge facin la seva via. El problema però està en com dir-li quina clau fer servir, això s'aconsegueix amb attrgetter de la llibreria operator.
$ agenda.sort(key=attrgetter('nom'))
$ for amic in agenda:
$ print "%25s \t %i" % (amic.nom, amic.edat)
Fixau-vos el senzill que seria poder fer una ordenació per qualsevol camp de la classe.
Referències:
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python
Cap a una nova arquitectura de desenvolupament
Escrit per Aaloy a 15 de September , 2007 a les 11:46 a.m.
En el negoci on-line cada cop és més important adaptar-se als canvis més ràpid, posar nous serveis a l'abast dels clients i fer-ho per ahir. Fins ara havíem fet servir dues aproximacions diferents:
- aplicacions fetes en Python i Django, per les parts més dinàmiques i mensy crítiques del negoci
- aplicacions desenvolupades anb Java/J2EE de contenidor fi (Tomcat) per les parts més serioses del negoci.
Llevat de la conya de que Java deixa més tranquils a consultors i auditors, he de dir que la tecnologia té moltes coses bones, la qualitat del programari obert és molt bona, i bastiments com XFire (ara baix l'ala del projecte Apache), Spring o Hibernate fan la vida del programador molt més senzilla, encara que la corba d'aprenentatge sigui gran. La tecnologia està té un gran nombre d'eines i els IDE de desenvolupament com Eclipse o Netbeans són vertaderes meravelles.
El problema fonamental que té fer-ho tot en Java és que és força lent fer el desplegament de les aplicacions, així com fer petits canvis en la lògica de negoci o la capa de presentació. Fer un canvi que afecti a la part del model implica sovint tenir que recarregar l'aplicació a Tomcat, maleir quan a la sessió de depuració veus que no t'ha refrescat les classes, reiniciar el contenidor, esperar fins a un minut o dos que recarregui tot i començar la depuració.
La posada en producció també es veu afectada per com fa les coses la tecnologia, la velocitat i l'estabilitat que dona Java i el Tomcat s'aconsegueixen fent que les aplicacions es despleguin al contenidor, que la capa de presentació es compili en temps d'execució. La qual cosa vol dir, que un desplegament típic de les aplicacions pot dur un mínim d'uns 15 minuts entre baixar el servidor, posar-hi l'aplicació, pujar el servidor i fer que aquest compili els jsp. Baixar el servidor no vol dir aturar-ho, sinó llevar-ho de l'accés públic, encara que sovint aquest llevar-ho de l'accés públic també implica l'aturada.
Davant això tenim aplicacions fetes amb Django i Python, on provar un canvi no duu més que uns pocs segons, el servidor de desenvolupament respon de manera immediata als canvis fets en el codi. Posar una aplicació a l'entorn de proves normalment implica actualitzar el repositori de subversion al tag que s'hagi determinat com estable i fer un reload de l'Apache, tot plegat menys de 15 segons. Passar-ho a producció normalment és igual de senzill, moltes vegades ni tan sols és necessari establir un procediment d'aturada del servei, ja que l'actualització de les plantilles no implica aturada i un reload de l'Apache no arriba al segon en els mega servidors de producció.
Hem d'aconseguir anar cap a una arquitectura d'aplicacions i de desenvolupament que aconsegueixi unificar el millor dels dos mons: la facilitat de desenvolupar i testejar aplicacions sense capa de presentació que té Java i la potència i facilitat de fer canvis a la capa de presentació de Python i Django.
En altres apunts ja he comentat cap a on volia anar, fer els serveis en Java, que se n'encarregaran d'accedir a les bases de dades i fer tota la fontaneria necessària i fer tota la capa de presentació web en un llenguatge dinàmic, en el nostre cas Python amb el bastiment Django, que sigui un consumidor dels serveis web.
Amb això podem no tant sols escalar les aplicacions, sinó també escalar l'equip de desenvolupament, ja que podem tenir equips fent feina a cada una de les capes de l'aplicació sense que hi hagi pràcticament interferències una vegada s'han definits els serveis.
Donat que els serveis no tenen capa de presentació i per tant no hi ha compilacions de JSP per exemple, resulta que el temps necessari per desplegar-los és molt petit comparat amb de l'aplicació sencera. El testeig es relativament senzill, bé amb tests d'unitat direcatament en Java o amb eines com SoapUI.
Ens queda doncs lligar la capa de serveis (arquitectura SOA que queda millor), amb la capa de presentació. Consumir serveis web Soap complexes amb Python fins ara no era senzill, l'espacificació Soap és tan complexe que llevat de el propi Java i .net (a la seva manera), són capaços de convertir el wsdl publicat a classes manejables pel programador. Però això està canviant i ho està fent molt ràpid, el projecte ZSI ha madurat molt els darrers temps i a les darreres proves ha demostrat que és capaç de consumir els serveis web fets amb XFire sense problemes. També hi ha que dir que els serveis ja s'han pensat de tal manera que siguin fàcils de mapejar, evintat fer us de característiques sols suportades sols per Java, però això no crec que sigui una mancança sinó una inversió de futur, augmentar la complexitat implica augmentar també temps de depuració i tenir que lluitar amb incompatibilitats entre versions.
Els prototips realitzats fins al moment són molt encoratjadors, els temps de resposta de tot plegat és excel·lent, sense fer optimitzacions tenim temps de 0.6s des de la capa de presentació feta amb Python fins a la capa de base de dades a la que s'hi ha accedit mitjançant un servei web fet amb Java i XFire.
Encara que hi ha una regla que diu que quan es fa un estudi per veure la viabilitat d'un projecte aquest estudi sempre dóna que és viable, per ara tot pareix demostrar que el camí pel que estam anant és correcte i que per projectes amb molts programadors és molt productiu, ja que a més de separar l'aplicació en capes, estam separant en capes el propi desenvolupament.
Queden encara força aspectes a estudiar, però que no són tant d'arquitectura d'aplicacions com de metodologia de desenvolupament i de desplegament de les aplicacions, de manera que s'acabin optimitzant tant els mètodes de desenvolupament, el mètodes de desplegament com la comunicació entre els membres del projecte. L'objectiu és poder respondre ràpid a les necessitats del negoci i que la tecnologia no ens condicioni de manera negativa el temps de resposta, mantenint al mateix temps l'estabilitat i l'escalabilitat de les aplicacions.
Hi som molt aprop....!
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL)
Creant objectes a la manera de Python.
Escrit per Aaloy a 09 de September , 2007 a les 10:33 p.m.
- El patró MVC (Model view controller) de sobres conegut per la gent que es dedica al desenvolupament web fonamentalment.
- El patró MVP (Model view presenter) , que intenta fer que la part d'interacció sigui més testejable y que Flower ha considerat que s'havia de xapar en dos.
- El patró Presentació Model, que independitza la capa de presentació de la vista, en un intent de separar el que és la part de comportament i estat de la vista en un model que és part de la presentació però que no es específic d'una implementació d'interfície concreta.
class Agenda:
... def __init__(self, nom, llinatge, telefon, amic=True):
... self.nom = nom
... self.llinatge = llinatge
... self.telefon = telefon
... self.amic = amic
...
La manera habitual de crear un objecte de tipus Agenda seria per exemple
amic = Agenda('toni','aloy','971xxxxxxx')
Suposem ara que tenim la informació dins una llista o una tupla, bastant habitual si per exemple hem importat les dades d'un arxiu de text o des de una base de dades, aleshores podem tenir la informació com
un_amic =('Pau','Rul·lan','971xxxxxxx')
La creació de l'objecte és molt ràpida d'escriure
amic2 = Agenda(*un_amic)
amic2.nom
'Pau'
És a dir, s'han substituït els paràmetres de construcció de l'objecte pels valors de la llista. Aquesta substitució és posicional, és a dir, el primer valor correspon al primer paràmetre, el segon al segon, etc. La sintaxi és conseqüent amb la manera d'anomenar llistes de paràmetres en la construcció de funcions, per exemple:
def prova (x, *y):
... print x
... for item in y:
... print item
...
prova(2,3,4,5,6,7)
2
3
4
5
6
7
prova (2,7,10)
2
7
10
Però clar, si això funciona d'aquesta manera i estam parlant de Python i haurà una manera obvia de fer el mateix si en lloc d'una llista tenim un diccionari, és a dir, ara tenim:
un_amic ={'nom':'Benjamí','llinatge':'Villoslada','telefon':'971xxxxxxx'}
Les claus del diccionari coincideixen amb els noms dels paràmetres, i hauríem de poder fer
amic3 = Agenda(**un_amic)
Això és Python, i per tant
amic3.nom
'Benjam\xc3\xad'
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python
Llegir codi
Escrit per Aaloy a 09 de September , 2007 a les 1:36 p.m.
Aquests darrers dies estic llegint el llibre wxPython in Action de Robin Dunn i Noel Rappin. El llibre és un tutorial de com escriure aplicacions fent servir la llibreria wxPython i com fer servir cada component (widget) que la llibreria inclou.
En el que és la explicació de cada component i els exemples hi ha una gran quantitat de llistats de codi font i comentaris damunt aquests llistats. Això m'ha fet recordar el capítol en que Glass tracta la importància de poder llegir codi. Diu, i estic completament d'acord, que a programar no se n'aprèn sols coneixent la sintaxi del llenguatge de programació, sinó també escrivint programes i sobretot llegint codi que ha escrit altra gent, i que aquesta capacitat de llegir codi s'hauria de cultivar més a les universitats i escoles tècniques.
Sense aquesta capacitat de llegir codi d'altres també ens trobam que llegir tutorials com el de wxPython es fa pràcticament impossible, si no som capaços de llegir el codi, interpretar mentalment que fa i imaginar-nos la sortida, no ens queda més remei que picar el codi i executar-ho per aprendre, la qual cosa fa que l'avanç en el domini de la llibreria sigui molt més lent.
Ser capaç de llegir el codi d'un altre ens permet aprendre noves tècniques que potser no estan explicades en el llibre, normalment perquè no és el seu objectiu, i ens permet la lectura a llocs allunyats de l'ordinador: al sofà, a la fresca a la terrassa,...
El programari lliure ens permet llegir codi que ha fet altre gent, veure com funciona, aprendre noves tècniques o veure el que s'ha fet malament o maneres de millorar-ho. Aquesta capacitat és fonamental a l'hora d'aprendre el funcionament d'una nova llibreria, de fer inspeccions de codi abans de posar en test un programa, o a l'hora de depurar o modificar codi que ha fet una altra persona.
Les èpoques del programador solitari que ho feia tot han ja queden lluny. El més normal actualment és que els programes és desenvolupin en equip i la gent acostumada a llegir codi ho té molt més fàcil per a adaptar-se a la feina en equip.
Si una persona sols ha fet feina fent servir programari tancat no haurà tingut l'oportunitat d'aprendre el que significa poder veure codi de tercers i per tant la seva evolució com a programador serà menor que aquells que estan acostumats, bé per necessitat o bé per convicció, a llegir el codi font d'altres persones.
Com vaig sentir a dir a Ricardo Gali a una conferència de Bulma, el codi és una font en sí mateixa per emmagatzemar i transmetre coneixement.En els cas dels programadors això també es tradueix en possibilitat d'aprenentatge i amb minimitzar el nombre d'errors i tasques de depuració.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Llibres i revistes Gestió de projectes
L’akismet, que filtra massa
Escrit per Aaloy a 04 de September , 2007 a les 9:31 p.m.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL)
Facts and Fallacies on Sofware Engineering
Escrit per Aaloy a 04 de September , 2007 a les 6:15 p.m.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Informàtica Llibres i revistes
Intrussisme professional a la informàtica
Escrit per Aaloy a 03 de September , 2007 a les 7:26 p.m.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Informàtica
