-
SOLO PROGRAMADORES
Introduccin
En este primer artculo nos dedicaremos a intro-ducir la sintaxis
de Python y a iniciarnos en laprogramacin orientada a objetos a
travs dePython. En un segundo artculo hablaremos delas facilidades
provistas por Python para la pro-gramacin de interfaces grficas. En
la terceraentrega explicaremos las bondades de Pythonpara la
programacin de aplicaciones web conacceso a bases de datos.
Finalmente, concluire-mos este curso de Python en una cuarta
entregacon la descripcin de su primo hermano Jython.Python, el otro
lenguaje de programacin libreque empieza con 'P' y que no es ni
Perl ni PHP,fue creado por Guido van Rossum
(http://www-.python.org/~guido/) en 1991. Dio este nombreal
lenguaje inspirado por el popular grupo cmi-co britnico Monty
Python. Guido cre Pythondurante unas vacaciones de navidad en las
que(al parecer) se estaba aburriendo. Hola Mundo en PythonComo con
cualquier otro lenguaje de programa-cin, comencemos el aprendizaje
de Python conel ms simple de los ejemplos:
print "Hola Mundo" # "Hola Mundo"
En este primer extracto de cdigo ya podemosobservar la
simplicidad de Python. Probable-mente este es el ejemplo del
programa "HolaMundo" ms sencillo que jams has visto. Lasentencia
print imprime una cadena de caracte-res a consola. Las cadenas de
caracteres enPython se pueden denotar bien entre comillasdobles o
comillas simples, por ejemplo 'Holamundo'. Ntese que los
comentarios de lnea seindican con el smbolo #, mientras que los
blo-ques de cdigo pueden comentarse entre '"' y '"'.
Caractersticas de Python
Tras ver el primer extracto de cdigo en Python,enumeremos sus
principales caractersticas:z Sintaxis elegante, minimalista y
densa: En
Python todo aquello innecesario no hay queescribirlo (;, {, },
\n). Adems como veremospocas lneas de cdigo revierten en
muchafuncionalidad.
z Moderno: Soporta objetos y estructuras dedatos de alto nivel
tales como cadenas decaracteres (strings), listas,
diccionarios.
z Multi-paradigma: En vez de forzar a los pro-gramadores a
adoptar un paradigma de pro-gramacin nico, Python permite el uso
deprogramacin orientada a objetos, programa-cin estructurada o
procedural e incluso pro-gramacin funcional.
z Organizado y extendible: Dispone de mltiplesformas de
organizar cdigo tales como funcio-nes, clases, mdulos, y paquetes.
Si hay reasque son lentas se pueden reemplazar por plu-gins en C o
C++, siguiendo la API para exten-der o empotrar Python en una
aplicacin.
z Interpretado: No es necesario declarar cons-tantes y variables
antes de utilizarlas y norequiere paso de compilacin/linkaje. La
pri-mera vez que se ejecuta un script de Pythonse compila y genera
bytecode que es luegointerpretado. Python es dinmico,
encuentraerrores de uso de tipos de datos en tiempo deejecucin y
usa un recolector de basura parala gestin de memoria.
z Multiplataforma: Python genera cdigointeroperable, que se
puede ejecutar en ml-tiples plataformas (ms an que Java).Adems, es
posible embeber Python dentrode una JVM, como veremos en la
cuartaentrega de esta serie.
20
MIDDLEWARE
Pensando en Python (I):3 en raya en modo textoPensando en Python
(I):3 en raya en modo texto
En la serie de artculos que aqucomenzamos describiremos
ellenguaje de programacin Python.Para ilustrar sus
virtudesdesarrollaremos un juego de tres enraya, que segn
transcurra esta serieir hacindose cada vez mssofisticado. Pasar de
ser un simplejuego con interfaz en modo texto, atener una interfaz
grfica, y de ste aser una aplicacin web que accede auna base de
datos.
DIEGO LZ. DE IPIA GZ. DE ARTAZA (Profesor del Departa-mento de
Ingeniera del Software de la Facultad deIngeniera (ESIDE) de la
Universidad de Deusto)
python_Middleware.qxd 26/01/1998 6:38 Pgina 20
-
SOLO PROGRAMADORES
z Open source: Razn por la cual la librera demdulos de Python
(http://docs.python-.org/lib/lib.html) contiene un sinfn de
mdulosde utilidad y sigue creciendo continuamente.
z De propsito general: Toda aplicacin progra-mable con C# o Java
tambin puede ser pro-gramada con Python.
Peculiaridades sintcticasPython presenta unas diferencias
sintcticasnotables con respecto a otros lenguajes de pro-gramacin.
Usa tabulacin (o espaciado) paramostrar una estructura de bloques.
Se tabulauna vez para indicar el comienzo de bloque y sedes-tabula
para indicar el final del bloque.Adems, Python no usa el smbolo ';'
para indi-car el final de una sentencia sino simplementeun retorno
de carro. El cuadro "C/Java vs.Python" compara un extracto de cdigo
enC/Java con otro de cdigo en Python. Obsrveseque las
peculiaridades sintcticas de Pythontraen consigo una reduccin de
los caracteresutilizados y lneas de cdigo. Adems, comoefecto
lateral, estas peculiaridades sintcticasobligan a diferentes
programadores a escribir elcdigo del mismo modo. No hace falta
definirmanuales de referencia de programacin, paraasegurarte que
todos los programadores queintervienen en un proyecto utilizan las
mismasconvenciones. Como nota positiva, comentarque la mayora de
las palabras claves utilizadaspor Python coinciden con las usadas
en C o Java.Dominios de aplicacin de PythonTodo ingeniero de
software, como buen artesano,debera dominar varios lenguajes de
programa-cin. Es inviable concebir que con un slo lengua-je de
programacin podemos llevar a cabo todotipo de desarrollos. Hay
aplicaciones o parte deellas que se adecuarn ms a las
caractersticasde un lenguaje de programacin que otro. En
esteapartado vamos a resaltar las situaciones en lascuales
deberamos considerar el uso de Python yen cuales otras lo deberamos
desdear.Python, al ser un lenguaje de scripting e inter-pretado no
es adecuado para la programacin debajo nivel o de sistemas. Por
ejemplo, la progra-macin de drivers y kernels, dado que Python
alser de demasiado alto nivel, no tiene controldirecto sobre
memoria y otras reas de bajonivel. Tampoco es adecuado para
aplicaciones
que requieren una alta capa-cidad de computo, tal es elcaso de
sistemas de procesa-miento de imgenes. Paraeste tipo de
aplicaciones el"viejo" C o C++ nunca podrser superado.Python es
ideal, sin embargo,como lenguaje "pegamento"para combinar varios
compo-nentes juntos, para llevar acabo prototipos de sistemas, para
la elaboracinde aplicaciones cliente web o con interfaz grfi-ca, el
desarrollo de sistemas distribuidos o laprogramacin de tareas
cientficas, en las quehay que simular y prototipar
rpidamente.Python ha sido utilizado para desarrollar muchosgrandes
proyectos de software como el servidorde aplicaciones Zope, el
sistema de comparticinde ficheros Mnet o parte de la
implementacinde Google. Actualmente, Python es uno de lostres
lenguajes de programacin que se usan enla framework de desarrollo
de servidores de apli-caciones libres LAMP (Linux Apache MySQL
yPython, Perl o PHP).
Programando en Python
Una vez conocidas las caractersticas de Pythones momento de
empezar a usarlo. Para ellohabremos de descargar una versin del
mismo(actualmente 2.3.4) de la seccin Download delportal de Python
(http://www.python.org), mos-trado en la figura 1 (tambin puede
obtenersedel CD-ROM que acompaa la revista). La insta-lacin para
Windows es tan sencilla como hacerdoble clic en el ejecutable
descargado. ParaLinux, podremos usar los rpms disponibles
enhttp://www.python.org/2.3.3/rpms.html. El co-mando que te
permitir su instalacin ser algosimilar a:rpm -iv
python2.3-2.3.4-pydotorg.i386.rpm
Modos de programacin Python se puede usar de dos modos
diferentes:interactivamente o en modo script. Para arrancarPython
en modo interactivo todo lo que se nece-sita es ejecutar en una
consola de comandos(cmd en Windows o xterm en Linux) el intrpre-te
de Python, esto es, el ejecutable python. Unavez arrancado el
intrprete podrs introducircualquier sentencia en Python. La figura
2 mues-
21
MIDDLEWAREPensando en Python (I): 3 en raya en modo texto
C/Java vs Python
Cdigo en C/Java
if (x) {if (y) {
f1();}f2();
}
Cdigo en Python
if x:if y:
f1() f2()
Figura 1. Pgina principal de www.python.org.
Figura 2. Python en modo interactivo.
python_Middleware.qxd 26/01/1998 6:38 Pgina 21
-
SOLO PROGRAMADORES
tra dos sesiones interactivas de Python. En la pri-mera se ha
codificado el ejemplo "Hola Mundo"mostrado con anterioridad. Para
salir del intr-prete se ha pulsado Ctrl-Z. Para realizar lo mismoen
UNIX deberamos haber pulsado Ctrl-D.Alternativamente, se podran
haber usado lasdos sentencias mostradas en la segunda
sesininteractiva de la figura 2. La primera importa elmdulo sys (ms
detalles luego) y la segundaejecuta el mtodo exit() de ese mdulo,
que haceque el hilo de ejecucin del programa finalice.Para utilizar
Python en modo script, se guardanlas sentencias del programa en un
fichero yluego se ejecuta el mismo escribiendo python. Por ejemplo,
en UNIXpodramos hacer lo siguiente para crear el fiche-ro
holamundo.py y luego ejecutarlo:$ cat > holamundo.py
#!/usr/bin/env python
print "Hello World"
Ctrl^D
$ python holamundo.py
Hello World
Ntese que la sentencia:#!/usr/bin/env python
se usara en entornos UNIX para indicar al siste-ma que el
intrprete Python se debera utilizarpara ejecutar un fichero que
tenga atributos deejecucin. En Windows es ignorada.Sentencias y
bloquesPara realizar un programa til es necesario agru-par grupos
de sentencias en unidades lgicas obloques. Recuerda que en Python
las sentenciasse delimitan por el salto de lnea y los bloques
seindican por tabulacin que sigue a una senten-cia acabada en ':'.
Por ejemplo, el cdigo del lis-tado 1 contiene la comparacin de una
variablecon un valor que imprime diferentes mensajessegn el
resultado de su evaluacin. La ejecucin del programa del listado 1
median-te el comando:python bloque.py
generara la siguiente salida:Quin eres?
No eres Diego!
IdentificadoresLos identificadores sirven para nombrar
varia-bles, funciones y mdulos. Deben empezar conun carcter no
numrico y contener letras,nmeros y '_'. Python es sensible al uso
demaysculas y minsculas en identificadores. Lassiguientes son
palabras reservadas y no se pue-den utilizar como identificadores:
and, elif, glo-bal, or, assert, else, if, len, pass, break,
except,import, print, class, exec, in, raise, continue,finally, is,
return, def, for, lambda, try, del, from,not, while. Existen unos
cuantos identificadoresespeciales con prefijo '__' para variables y
fun-ciones que corresponden a smbolos implcita-mente definidos:z
__name__: nombre de funcinz __doc__: documentacin sobre una funcinz
__init__(): constructor de una claseVariables y tipos de datosPara
declarar una variable en Python solamentees necesario darle un
nombre y asignarle unvalor. La variable es del tipo del valor
asignado.Por defecto las variables son locales y
accesiblessolamente dentro del bloque de cdigo dondehan sido
declaradas, para acceder a variablesglobales, es necesario preceder
el nombre de lavariable con el identificador global. Si no sequiere
asignar ningn valor a una variable, se lepuede asignar el valor
None, equivalente a nullen Java.Numricos. Python define los
siguientes tiposnumricos: integer, long integer, floating-point,y
complex. Sobre los valores numricos se pue-den aplicar los mismos
operadores que en Java oC++, esto es, +, -, *, / y % (resto). Su
uso se ilus-tra en los siguientes comandos escritos en
modointeractivo:>>> x = 4
>>> int (x) # convierte x a entero4
>>> long(x) # convirtelo a long4L
>>> float(x) # a float4.0
>>> complex (4, .2) (4+0.2j)
Strings. Python soporta las cadenas de caracte-res que son
delimitadas por un par de ' o ". Dosstrings juntos separados por un
espacio se unen,y los separados por comas aparecen separadospor un
espacio:>>> print "Hola" "Iigo" # imprime HolaIigo
>>> print "Hola", "Iigo" # imprime Hola Iigo
Se utilizan los mismos cdigos de escape que enC y Java. Por
ejemplo, para imprimir una nueva
22
MIDDLEWARE
LISTADO 1 Nuestro primer bloque# bloque.pyname = "Diego1" #
asignacin de valor a variable if name == "Diego":
print "Aupa Diego" else:
print "Quin eres?" print "No eres Diego!"
python_Middleware.qxd 26/01/1998 6:38 Pgina 22
-
SOLO PROGRAMADORES
lnea utilizaramos print '\n'. Las cadenas decaracteres cuyos
caracteres especiales no quere-mos que sean interpretados se
indican con elprefijo 'r' de raw.Las cadenas de caracteres son
objetos en Pythona los cuales se les pueden aplicar algunas de
lasfunciones predefinidas por Python, como len,que devuelve el
nmero de elementos en unasecuencia o los mtodos que define tales
comoupper para convertir a maysculas y find paraencontrar
sub-cadenas en una cadena, entreotros muchos. Para ms informacin
tanto sobrela clase String como cualquier otra clase omdulo de
Python es recomendable revisar ladocumentacin de la librera estndar
de Python(http://docs.python.org/lib/lib.html), cuya tablade
contenidos se muestra en la figura 3. A con-tinuacin mostramos
algunas sentencias quehacen uso de strings:>>> len('La
vida es mucho mejor con Python.')>>> 34
>>> 'La vida es mucho mejor con Python.'.upper() 'LA
VIDA ES MUCHO MEJOR CON PYTHON'
>>> "La vida es mucho mejor con
Python".find("Python")27
>>> "La vida es mucho mejor con Python".find('Perl')
-1
>>> 'La vida es mucho mejor con
Python'.replace('Python', 'Jython') 'La vida es mucho mejor con
Jython'
El carcter '%' representa al operador de forma-teo de cadenas,
que se usa de una manera muysimilar a los formateadores en C para
la senten-cia printf, tales como d para decimal, f para floato, x
para hexadecimal:>>> provincia = 'lava'
>>> "La capital de %s es %s" %
(provincia,"Vitoria-Gasteiz")'La capital de lava es
Vitoria-Gasteiz'
Booleanos. Las constantes booleanas definidaspor Python son True
y False. El resultado de unacondicin siempre devuelve uno de esos
dosvalores.Listas. Una lista representa una secuencia din-mica que
puede crecer, y est indexada por unentero que comienza con el valor
0. Python defi-ne el operador ':' u operador de rodajas que
per-mite indicar dando el ndice inicial y final frag-mentos del
string a recuperar. Una lista es unaclase definida por Python y por
tanto tienemtodos para aadir (add) o insertar (insert)valores. Para
borrar un elemento se utiliza la
funcin predefinida del:>>> meses = ["Enero", "Febrero"]
>>> print meses[0] Enero
>>> meses.append("Marzo") >>> print
meses[1:2]['Febrero']>>> del meses[0]>>>
meses
['Febrero', 'Marzo']
Tuplas. Las tuplas son como laslistas, pero no se pueden
modifi-car. Son convenientes cuandoqueremos devolver varios
valorescomo resultado de invocar a unafuncin. Se definen con el
opera-dor (, por ejemplo, (1,2).Diccionarios. Los diccionarios son
arrays asocia-tivos o mapas, indexados por una clave en vez deun
ndice numrico. La clave puede ser cualquierobjeto Python, aunque
normalmente es unatupla. Como se trata de una clase define unaserie
de mtodos que podemos invocar talescomo has_key. El operador in se
utiliza paracomprobar si un elemento forma parte de
unasecuencia:>>> mydict = {"altura" : "media",
"habilidad": "intermedia"} >>> print mydict
{'altura': 'media', 'habilidad': 'intermedia'} >>>
print mydict["habilidad"] intermedia
>>>if mydict.has_key('altura'):>>> print 'Nodo
encontrado'
Nodo encontrado
>>> if 'altura' in mydict:
>>> print 'Nodo encontrado'
Nodo encontrado
Control de flujoCondicionales. La sentencia if se utiliza para
ladefinicin de condiciones y puede ir seguida devarias partes elif
y una else. En Python los opera-dores boleanos definidos son: or,
and y not. Losoperadores relacionales definidos son ==, >, <
y =.q = 4
h = 5
d = 3
if q < h:
print "primer test pasado"
elif d
-
SOLO PROGRAMADORES
else:
print "tercer test pasado"
>>> python condicional.py
primer test pasado
Bucles. Para la definicin de bucles podemosusar el operador for
o while. for se utiliza princi-palmente para iterar sobre los
miembros de unasecuencia: listas, tuplas o diccionarios. for se
uti-liza a menudo con la funcin predefinida range,que crea una
secuencia descrita por ([start,] end[,step]), donde los campos
start y step son opcio-nales. start es 0 y step es 1 por
defecto:>>> for x in range(1,5):>>> print x
>>> 1 2 3 4
La sentencia while es otra sentencia de repeti-cin. Se utiliza
para ejecutar un bloque de cdi-go hasta que una condicin sea falsa.
La senten-cia break se utiliza a menudo dentro de un buclewhile y
sirve para salir del bucle:>>> reply = 'repite'
>>> while reply == 'repite':
... print 'Hola'
... reply = raw_input('Introduce "repite" para hacerlo de nuevo:
')...
Hola
Introduce "repite" para hacerlo de nuevo:
adis
>>>
FuncionesUna funcin se declara usando la palabra clavedef,
seguida del nombre de la funcin y entreparntesis una lista de
argumentos. Los argu-mentos si corresponden a tipos numricos,
bole-anos o strings se pasan por valor y si correspon-den a
secuencias por referencia. A una funcinse le pueden asignar
parmetros por defecto,preasignado un valor a cada parmetro de
unafuncin. Por ejemplo:def myfunc(a,b=2):
sum = a + b
return sum
print myfunc(2) # devuelve el valor 4
A una funcin se le puede pasar un nmerovariable de argumentos
(argumento con prefijo*) y argumentos basados en palabras clave
nopredefinidas (argumento con prefijo **):def testArgLists_1(*args,
**kwargs):
print 'args:', args
print 'kwargs:', kwargs
testArgLists_1('aaa', 'bbb', arg1='ccc', arg2='ddd')
que visualizara:args: ('aaa', 'bbb') kwargs: {'arg1': 'ccc',
'arg2': 'ddd'}
ClasesLas clases en Python son creadas usando la sen-tencia
class. Una clase contiene una coleccin demtodos. Cada mtodo
contiene como primerparmetro (self) que hace referencia a la
instan-cia de la clase, es equivalente al this de C++ oJava. Python
soporta mltiple herencia de clases.Existe un soporte limitado para
variables priva-das, usando una tcnica llamada name mangling.Todo
identificador de la forma __spam es tex-tualmente reemplazado por
_classname__spam.Sin embargo, el identificador todava podra
seraccedido por cdigo que usa la instancia de laclase mediante
_classname__spam. El listado 2muestra un simple ejemplo de
herencia.ExcepcionesCada vez que un error ocurre se lanza
unaexcepcin, visualizndose un extracto de la piladel sistema. La
ejecucin de la ltima sentenciadel ejemplo anterior
producira:Traceback (most recent call last):
File "clasesherencia.py", line 28, in ?
print obj2.__upper
AttributeError: Special instance has no
attribute '__upper'
Para capturar una excepcin se usa except ypara lanzar una
excepcin se usa raise. Sepueden crear excepciones personalizadas
cre-
24
MIDDLEWARE
LISTADO 2 Un simple ejemplo de herencia# clasesherencia.pyclass
Basic:
def __init__(self, name): self.__name = name
def show(self): print 'Basic -- name: %s' % self.__name
class Special(Basic): # entre parntesis la clase basedef
__init__(self, name, edible):
Basic.__init__(self, name) self.__upper =
name.upper()self.__edible = edible
def show(self): Basic.show(self) print 'Special -- upper name:
%s.' % self.__upper, if self.__edible:
print "It's edible." else:
print "It's not edible." def edible(self):
return self.__edible
obj1 = Basic('Manzana')obj1.show() print '=' * 30 obj2 =
Special('Naranja', 1) obj2.show()print obj2._Basic__nameprint
obj2.__upper # lanzar una excepcin
python_Middleware.qxd 26/01/1998 6:39 Pgina 24
-
SOLO PROGRAMADORES
ando una nueva clase que derive de laclase RuntimeError definida
por Python.El siguiente fragmento ilustra el uso deexcepciones:#
excepcion.py
try:
fh=open("new.txt", "r")except IOError, e:
print e
$ python excepcion.py
[Errno 2] No such file or directory: 'new.txt'
Mdulos y paquetesLas libreras de mtodos y clases seagrupan en
Python en mdulos. Unmdulo es una coleccin de mtodos oclases en un
fichero que acaba en .py.El nombre del fichero determina elnombre
del mdulo en la mayora delos casos. Para usar un mdulo se usa
lasentencia:import
que hace que un mdulo y su conteni-do sean disponibles para su
uso.Alternativamente se puede usar lasentencia:from import
Por ejemplo, un mdulo se podra definircomo:# modulo.py
def one(a): print "in one"
def two (c): print "in two"
Este modulo se usara como sigue. Ntesela diferencia que existe
entre el uso de laclusula import y la from:>>> import
modulo
>>> modulo.one(2)in one
>>> from modulo import *
>>> one(2)in one
>>>
Un conjunto de mdulos puede agru-parse como una unidad
representadapor un paquete. En la siguiente entregaveremos un
ejemplo de creacin y usode paquetes.
Desarrollando tu primera aplicacin
Para poner en prctica la sintaxis del len-guaje Python vamos a
desarrollar una sim-ple aplicacin de tres en raya. Aparte
depermitirnos jugar contra la mquina, estejuego requiere que el
jugador se autentifi-que antes de jugar y adems guarda esta-dsticas
en memoria sobre las partidasganadas, perdidas o empatadas por
cadajugador. Por el momento la mquina usa unalgoritmo sencillsimo
para la eleccin de lacasilla a tachar por la mquina, la elige
demanera aleatoria. En prximas entregas deesta serie discutiremos
algoritmos mejoresbasados en inteligencia artificial. El listado3
muestra la clase RegistroJugadores quees utilizada para mantener
las estadsticasde las partidas de los jugadores.El constructor de
RegistroJugadores definedos atributos privados de tipo
diccionarioque guardan los jugadores registrados(self.__jugadores)
y las estadsticas de laspartidas (self.__estadisticas). Se carga
unslo jugador con nombre de usuario "solop"y contrasea "solop", e
inicializamos lasestadsticas para el jugador 'solop', con la
lista [0,0,0] que indica que el usuario no haganado, ni
empatado, ni perdido ningnjuego todava. La clase
RegistroJugadoresdefine el mtodo registarJugador que per-mita
registrar los detalles de login de unnuevo jugador. Si ya existe un
usuario conel nombre de usuario pasado, se lanza unaexcepcin y si
no se crea una nueva entra-da en el atributo self.__jugadores. El
mto-do login permite la autenticacin de unusuario, y en caso de
proveerse un nombrede usuario o clave errneas se lanza unaexcepcin.
Por su parte, los mtodosregistrarVictoria, registrarEmpate
yregistrarPerdida sirven para modificar elatributo
self.__estadisticas con los resulta-dos de las partidas de cada
jugador.Finalmente el mtodo getEstadisticasdevuelve una lista con
los resultados obte-nidos por un jugador.La clase JuegoTresEnRaya
(vase la figura 4),que define la lgica principal de la aplicacin,no
se ha incluido en estas pginas por razonesde espacio, sin embargo
el cdigo de dichaclase puede encontrarse en el CD-ROM.
Elconstructor de esta clase recibe como parme-tros una referencia
al registro de jugadores, elnombre de usuario y la clave del
jugador que
25
MIDDLEWAREPensando en Python (I): 3 en raya en modo texto
LISTADO 3 La clase RegistroJugadores# imports para toda la
aplicacinimport osimport sysimport randomfrom types import *
class RegistroJugadores:def __init__(self):
self.__jugadores = {'solop':'solop'}self.__estadisticas =
{'solop':[0, 0, 0]} # jugador -> [ganados, empa
tados, perdidos]
def registrarJugador(self, jugador, clave):if len(trim(jugador))
== 0 or len(trim(clave)) == 0:
raise "Los campos jugador y clave no pueden estar vacios"if
self.__jugadores.has_key(jugador):
raise "Jugador " + jugador + " ya ha sido
registrado!"self.__jugadores[jugador] =
claveself.__estadisticas[jugador] = [0, 0, 0]
def login(self, jugador, clave):if not
self.__jugadores.has_key(jugador):
raise "Jugador " + jugador + " no registrado!"
if not self.__jugadores[jugador] == clave:raise "Clave de
jugador " + jugador + " es invalida"
return True
def registrarVictoria(self,
userName):self.__estadisticas[userName][0] += 1
def registrarEmpate(self,
userName):self.__estadisticas[userName][1] += 1
def registrarPerdida(self,
userName):self.__estadisticas[userName][2] += 1
def getEstadisticas(self, userName):return
self.__estadisticas[userName]
python_Middleware.qxd 26/01/1998 6:40 Pgina 25
-
SOLO PROGRAMADORES
quiere competircon la mquina.El constructor enprimer lugarguarda
la referen-cia al registro enla variable privadaself.__registro
yvalida que losdatos de autenti-ficacin del juga-
dor son correctos.A continuacin,
declara las constantes self.__combiGanadorascon las
combinaciones ganadoras del juego,self.__marcaJugador con el
carcter 'o' queindica la marca de un jugador yself.__marcaMaquina
con el valor 'x' quedenota las casillas marcadas por la
mquina.Finalmente, el constructor declara las
variablesself.__userName donde memoriza el identifi-cador del
jugador, self.__casillasMarcadasdonde cuenta cuntas casillas estn
marcadashasta el momento y el array bidimensionalself.__casillero
que recoge los valores marca-dos en cada casilla, inicialmente
ninguno. Estaclase tambin declara los siguientes mtodosde ayuda
privados: __elegirMarcaMaquina,__verTablero y __hayGanador. El
mtodo
__elegirMarcaMaquina hace uso del mdulorandom para elegir de
manera aleatoria una delas casillas no marcadas. El
mdulo__verTablero visualiza en modo texto el table-ro. Finalmente,
el mtodo __hayGanadordetermina si alguna de las
combinacionesganadoras ha sido alcanzada.La clase JuegoTresEnRaya
slo define elmtodo pblico jugar() que define toda lalgica del juego
de tres en raya entre unusuario y la mquina. Asume que el
usuariosiempre comienza. La partida no concluyehasta que se ha
encontrado una combina-cin ganadora o se han tachado las
nuevecasillas del tablero. Mientras el usuario nointroduce los
datos de una casilla correcta-mente el mtodo itera sobre un bucle.
Pararecoger la entrada del usuario se utiliza lafuncin
raw_string(). Ademsdado que se pretende que la entrada tengael
formato (x, y), se evala si los datosintroducidos corresponden a
una tupla,mediante la funcin eval que convierte unstring al tipo de
datos representado.Adems se valida si el valor
interpretadocorresponde a una tupla haciendo uso delmtodo type del
mdulo types y del opera-dor is que permite la comparacin entre
unvalor y su tipo: if not type(casillaCoords) isTupleType. Adems en
cada iteracin secomprueba que el valor de la celda intro-
ducida est dentro del rango de valo-res validos y adems no haya
sido yamarcado. Despus de que el usuariointroduzca una casilla
vlida se evalasi ha ganado invocando el mtodo__hayGanador. Si es as
se registra lavictoria del usuario
invocandoself.__registro.registrarVictoria-(self.__userName). Si
todava no sehan marcado las nueve casillas deltablero se pasa el
turno a la mquina,eligindose la casilla a marcarmediante la llamada
al mtodo priva-do __elegirMarcaMaquina. A conti-nuacin, se
comprueba si tras marcarla ltima casilla la mquina ha ganado
la partida y si es as seregistra que el usuariola ha perdido.
Cuandolas casillas marcadas
sean nueve y no hahabido ningn ganadorse registrar el hecho
deque el juego ha acabadoen empate.El listado 4 muestra elbloque de
entrada delprograma. Todo bloqueque comience con if__name__ ==
'__ma-
in__':, es equivalente a un bloque main enC o Java. El bloque
main, en primer lugar,obtiene una referencia al registro. En
futu-ras entregas recuperaremos ese registrobien de un fichero o de
una base de datos.Por el momento, esto se consigue invocan-do al
constructor de RegistroJugadores quemantiene un diccionario en
memoria conlos jugadores registrados y otro con lasestadsticas de
juego de los mismos. Ensegundo lugar, el bloque main crea una
ins-tancia de la clase JuegoTresEnRaya, pasan-do como referencia el
registro obtenido y elnombre y contrasea del jugador. Estos
dosltimos valores son recuperados a partir delos parmetros pasados
en la invocacindel programa, mediante la sentenciasys.argv[x],
donde x indica el orden delparmetro, apuntando el ndice 0 al
nom-bre del script. A continuacin, se permiteque el usuario inicie
una partida llamandoal mtodo jugar() de la instancia
deJuegoTresEnRaya. Al finalizar esta partidase pregunta al usuario
si quiere seguirjugando y se repite este proceso hasta queel
usuario no responda s. Finalmente,antes de terminar el programa se
muestranlas estadsticas de resultados de los enfren-tamientos entre
la mquina y el usuarioindicado. La figura 5 muestra una sesindel
juego de tres en raya.
Conclusines
Este artculo ha mostrado la sintaxis dellenguaje Python y ha
ilustrado su uso a tra-vs de la elaboracin de un simple juego
detres en raya. A travs de la elaboracin deeste pequeo programa
hemos podidocomprobar la simplicidad de Python y suscapacidades
para construir de manera rpi-da cualquier tarea de programacin
quetengamos en mente. En la siguiente entre-ga de esta serie
veremos cmo proporcio-nar una interfaz grfica a este juego ycmo
mantener el registro de jugadores ysus estadsticas en varios
ficheros.
26
MIDDLEWARE
Figura 4. La clase JuegoTresEnRaya
Figura 5. Ejecucin del juego tres en raya.
LISTADO 4 El bloque mainif __name__ == '__main__':
registro = RegistroJugadores()juego = JuegoTresEnRaya(registro,
sys.argv[1], sys.argv[2])juego.jugar()while True:
s = raw_input("Quieres jugar otra vez? (s) o (n): ")if
s.strip().lower() == 's':
juego = JuegoTresEnRaya(registro, 'solop',
'solop')juego.jugar()
else:print 'Gracias por jugar al tres en raya!'print
'Estadsticas de juego de solop: victorias (' +
str(registro.getEstadisticas('solop')[0]) +\
') - empates (' + str(registro.getEstadisticas('solop')[1]) +
\') - derrotas (' + str(registro.getEstadisticas('solop')[2]) +
')'
break
python_Middleware.qxd 26/01/1998 6:40 Pgina 26