23 de gener 2008

About Python

Aquests dies estic ficat enmig d'un projecte que vaig decidir fer amb Python. I a aquestes alçades m'ha picat per fer-ne un balanç, doncs això, aquest post és un pros i contres del Python:

Primer exposaré els punts a favor i després els punts en contra.
En primer lloc, és rapidíssim fer qualsevol mena de programa tonto, no calen ni capçaleres ni res (algun import, si és que s'ha d'importar alguna biblioteca o s'han de cridar algunes funcions que no tenim ganes d'implementar):


1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 import sys, string
4 print "hello world"


Si guardem aquestes línies com un fitxer "hello_world.py", li donem permissos d'execusió "chmod u+x hello_world.py" veurem el nostre "hola món" (in english, of course).
Tot i ser un llenguatge que no s'hagi de compilar, és a dir, del nostre codi no generarem un arxiu binari, sinó que l'executar directament l'interpret de Python (el mateix funcionament que Perl, PHP, Ruby on Rails i demés), va prou ràpid. Ens estalviem doncs, el temps de compilació (clar, que a la llarga acaba convertint-se en un punt negatiu [llegir els punts negatius :P]).
Un altre punt positiu se l'enduen les variables, que no s'han de definir (són atipades: no tenen tipus), tot i que es diferencia el que és un enter, un string, un float... no cal declarar les variables, aquestes ja agafaran el tipus del valor que se li assigni.


1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 import sys, string
4 missatge = "hello world"
5 numero = 4096
6 for i in range(numero):
7 print missatge


Si algun professor ens castiga a la pissarra i ens demana que copiem 2^12 vegades una frase, ens podem estalviar una tarda sencera si li escribim aquestes 7 línies de codi.
També són bons els noms curts i clars de les funcions dels mòduls bàsics com a Perl. Certament, és un llenguatge que s'assembla moltíssim al Perl, però amb la diferència que el Perl queda tot una guarrada i aquest és més ordenat. Ah! i no he dit que és un llenguatge que està orientat a objectes, però realment hi pots programar sudant mil de les classes i demés. Tot i que sense punters explícits a vegades has de fer alguna guarrada.

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #aquest fitxer el guardem com joc.py
4 import sys, string
5
6 class videojoc:
7 consola=""
8 joc = ""
9 def __init__ (self, consola_nova, joc_nou):
10 self.consola = consola_nova
11 self.joc = joc_nou
12 def jugar(self):
13 print "POWER ON"
14 print "press A to play"
15 def parar_de_jugar(self):
16 print "bye bye"
17 print "POWER OFF"
18 def canviar_de_joc(self, joc_nou):
19 if self.joc != "":
20 print "treient joc"
21 self.joc = joc_nou
22 print "joc canviat"
23 def treure_joc(self):
24 self.joc = ""
25 print "joc tret"

Això és la implementació d'una classe ben senzilla, com veieu, no hi ha n punts i comes (;), ni claus ({), això sí els ":" després de la descripció de la funció sí que són necessaris i que tot estigui ben segmentat per espais o tabuladors. Això sí, és emprenyador el haver de passar com a paràmetre "self", per indicar que estem en una classe: això és així per després accedir a les variables de la classe, com es veu en l'exemple ("self.joc").
Aquesta classe d'exemple la podríem importar des d'un altre fitxer python:

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 import sys, string
4 import joc
5
6 juga = joc.videojoc("Wii","Red Steel")
7 juga.jugar()
8 juga.canviar_de_joc("Wii Sports")
9 juga.jugar()
10 juga.parar_de_jugar()

veiem que l'import importa el nom del fitxer i no la classe, que està a dins del fitxer. I que òbviament, abans de fer res, tenim que cridar la constructora de la classe (__init__).
Després d'executar aquest últim codi, veurem que el python ha creat el fitxer joc.pyc, un fitxer binari que conté informació de les classes que hi ha a joc.py. Però clar, no sempre és necessari crear classes i punyetes, i el fitxer joc, podria ser aquest:

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #aquest fitxer l'anomenarem joc_funcions.py
4 import sys, string
5
6 def inicia(consola_nova, joc_nou):
7 consola = consola_nova
8 joc = joc_nou
9 #retorna una tupla
10 return (consola, joc)
11 def jugar(consola, joc):
12 print "POWER ON"
13 print "Jugant al "+joc+" de "+consola
14 def parar_de_jugar():
15 print "bye bye"
16 print "POWER OFF"
17 def canviar_de_joc(joc_vell, joc_nou):
18 if joc_vell != "":
19 print "treient joc"
20 joc = joc_nou
21 print "joc canviat"
22 return joc
23 def treure_joc(joc_tret):
24 joc = ""
25 print joc_vell+" tret"
26 return joc

Així ens estalviem els self i el fitxer que es crea amb extensió pyc per a les classe. Però tenim un inconvenient, i és que al no tenir punters no podem guardar l'estat de les dades que es van actualitzant i clar, sempre s'han d'anar passant (i rebent) com a paràmetre (com a resultat) des de l'executable:

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 import sys, string
4 import joc_funcions
5
6 estat = joc_funcions.inicia("Wii","Red Steel")
7 consola = estat[0]
8 joc = estat[1]
9 joc_funcions.jugar(joc, estat[1])
10 joc = joc_funcions.canviar_de_joc(joc, "Wii Sports")
11 joc_funcions.parar_de_jugar()

Si no es pot disposar de punters és millor tenir classes, però tot i així, el no disposar de punters fa que la manera de pensar del programador no tingui en compte el funcionament de la màquina, cosa que implica, a la llarga, fer programes ineficients. Però bé, l'objectiu de les classes és aconseguir un nivell d'abstracció i no estar tant pendent de com funciona el sistema: conclusió aprèn a fer servir els punter i a manegar les classes :P [Personalment em quedo amb els punters, ja que amb les classes, al final es monten unes paranoies totalment inútils, però clar, què et diran ells?]
Però potser el puntàs més enorme de Python, és lo poc que has d'escriure per fer moltes coses, i la gran quantitat de biblioteques que t'ajuden (que no et fan les coses com a Java), l'exemple més clar és la connexió amb una base de dades, on amb una línia ja et connectes i amb dues més ja has executat la instrucció SQL. En canvi amb C++ necessites un mínim de 8 línies per fer alguna cosa amb una base de dades SQL (jo faig servir MySQL <- i ara que hi penso aquest punt ja el vaig comentar en un altre post... aix que em faig vell i repeteixo les coses...):

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import sys, string
5 import MySQLdb
6
7 llista = []
8 conn = MySQLdb.connect (host="10.0.0.11",user="neioo",passwd="neioo",db="videojocs")
9 cursor = conn.cursor()
10 cursor.execute ("SELECT nom FROM videojocs WHERE consola=\'Wii\'")
11 while (1):
12 row = cursor.fetchone()
13 if row == None:
14 break
15 if row[0] != None:
16 llista.append(row[0])
17 #retorna una llista ordenada de tots els videojocs de la Wii que estigui a la base de dades "videojocs"
18 llista = sorted(llista)
19 #imprimeix tota la llista
20 for joc in llista:
21 print joc

Aquest és un exemple d'accés a una base de dades, realment xupat si ho comparem amb el mètode d'accés de C o de C++. Important, que si la query a la base de dades fós una actualització (DELETE, UPDATE o INSERT) hauríem de fer "conn.commit()" per fer la actualització, si no, serà com si no haguessim fet res. En el codi, també es pot veure un recorregut per les llistes.
A nivell de sintaxi, no calen els clàssics punts i coma finals d'instrucció ni les claus "{" i "}" per delimitar les funcions i controls de fluxe (for, if...). Això fa que a l'hora d'escriure el codi un l'hagi d'escriure amb la segmentació idònia, cosa que fa que quedi ordenat.
Com a punts negatius dir: No té punters, ja ho sé, per a molts això és un puntàs enorme positiu, però mira, sense punters un està més limitat i per suplir la falta de punters has de fer virgaries amb les classes i les seves instàncies... Apart, com que no es compila el codi, a l'hora de corretgir els errors típics de compilació és un autèntic mal son, doncs s'ha de fer en temps d'execució, cosa que vol dir executar tots els trossos de codi possible (anar provant totes les possibilitats) i anar corretgint els errors a mesura que es van produïnt. Molts d'aquests errors són els típics errors que t'avisa el copilador: "aquesta variable no se li ha assignat cap valor", "aquesta funció es crida amb un paràmetre incorrecte", i coses típiques dels compiladors, aquest és segurament el primer motiu que faria que un projecte no es fés amb Python.
A més, per comentar es fa igual que els shellscripts, i.e. en una linia, tot el que hi hagi darrere del símbol "#" estarà comentat, cosa que si vols comentar n línies has d'escriure n #'s i clar, quan un està en fase de proves és feixuc anar comentant les m línies que fan no sé què una a una (fins i tot amb el VIM).
En general però, és un llenguatge amb el que s'hi treballa molt bé, jo us diria que és el llenguatge de programació per a fer els programets tontos, però és que Python es fa servir fins i tot en tractament d'imatges 3D en temps real! i els senyors de Google també els hi sembla agradar. Un consell, abans de començar a picar codi, feu una estructura ben feta, que si no, és un conyàs, sobretot a l'hora de verificar que tot funciona bé.[<-aquest onsell es pot aplicar a qualsevol llenguatge].
Per tant, la meva llista de llenguatges a tenir en compte vindria a quedar amb: C, Python i shellscripts. Òbviament dependrà de què és el que volem fer i com sempre, s'ha d'estar a la guait de les altres alternatives, a vegades ens podem trobar alguna sorpresa.
Com lo promès és deute: la pàgina oficial de Pythonaquí el tutorial de Python i au, una entrevista tonta a l'autor de Python
PS: Jooo Neioo tot està en anglès (<-a practicar!)