Professional Documents
Culture Documents
1 web2py.exe -S welcome
Sobre Apple OS X, ingresa el siguiente comando en una ventana de terminal (suponiendo que
estás en la misma carpeta que web2py.app):
1 ./web2py.app/Contents/MacOS/web2py -S welcome
En una máquina con Linux u otro Unix, probablemente ya tengas instalado Python. Si es así, en
el prompt de la shell escribe:
Si no tienes Python 2.5 (o las posteriores 2.x) pre-instalado, tendrás que descargarlo e instalarlo
antes de correr web2py.
La opción -S welcome de línea de comandos ordena a web2py que ejecute la shell interactiva
como si los comandos se ejecutaran en un controlador para la aplicación welcome, la aplicación
de andamiaje de web2py. Esto pone a tu disposición casi todas las clases, objetos y funciones
de web2py. Esta es la única diferencia entre la línea de comando interactiva de web2py y la
línea de comando normal de Python.
La interfaz administrativa además provee de una shell basada en web para cada aplicación.
Puedes acceder a la de la aplicación "welcome" en:
1 http://127.0.0.1:8000/admin/shell/index/welcome
Puedes seguir todos los ejemplos en este capítulo utilizando una shell normal o la shell para
web.
help, dir
El lenguaje Python provee de dos comandos para obtener documentación sobre objetos
definidos en el scope actual, tanto los incorporados como los definidos por el usuario.
Podemos pedir ayuda ( help ) acerca de un objeto, por ejemplo "1":
1 >>> help(1)
4 class int(object)
5 | int(x[, base]) -> integer
6 |
| __abs__(...)
...
y, como "1" es un entero, obtenemos una descripción de la clase int y de todos sus métodos.
Aquí la salida fue truncada porque es realmente larga y detallada.
En forma similar, podemos obtener una lista de métodos del objeto "1" con el comando dir :
1 >>> dir(1)
Tipos
Python es un lenguaje de tipado dinámico, o sea que las variables no tienen un tipo y por lo
tanto no deben ser declaradas. Los valores, sin embargo, tienen tipo. Puedes consultar a una
variable el tipo de valor que contiene:
1 >>> a = 3
4 >>> a = 3.14
6 <type 'float'>
9 <type 'str'>
Python además incluye, como características nativas, estructuras de datos como listas y
diccionarios.
str
Python soporta el uso de dos diversos tipo de cadenas: ASCII y Unicode. Las cadenas ASCII
se delimitan por '...', "..." o por '...' o """...""". Las comillas triples delimitan cadenas multilínea.
Las cadenas Unicode comienzan con un u seguido por la cadena conteniendo caracteres
Unicode. Una cadena Unicode puede convertirse en una cadena ASCII seleccionando un una
codificación por ejemplo:
1 >>> a = 'esta es una cadena ASCII'
3 >>> a = b.encode('utf8')
Al ejecutar estos tres comandos, la a resultante es una cadena ASCII que almacena caracteres
codificados con UTF8. Por diseño, web2py utiliza cadenas codificadas con UTF8 internamente.
Además es posible utilizar variables en cadenas de distintas formas:
2 el número es 3
4 el número es 3
6 el número es 3
3 3 3
4 hola 'hola'
Para las clases definidas por el usuario, str y repr pueden definirse/redefinirse utilizando los
operadores especiales __str__ y __repr__ . Estos se describirán básicamente más adelante;
para mayor información, consulta la documentación oficial de Python [pydocs]. repr siempre tiene
un valor por defecto.
Otra característica importante de una cadena de Python es que, como una lista, es un
objeto iterable
1 >>> for i in 'hola':
2 print i
3 h
4 o
5 l
6 a
list
Los métodos principales de una lista de Python son append, insert, y delete:
1 >>> a = [1, 2, 3]
3 <type 'list'>
4 >>> a.append(8)
5 >>> a.insert(2, 7)
7 >>> print a
8 [2, 7, 3, 8]
10 4
2 [2, 7, 3]
4 [7, 3, 8]
6 [3, 8]
y concatenar:
1 >>> a = [2, 3]
2 >>> b = [5, 6]
3 >>> print a + b
4 [2, 3, 5, 6]
1 >>> a = [1, 2, 3]
2 >>> for i in a:
3 print i
4 1
5 2
6 3
Los elementos de una lista no tienen que ser del mismo tipo; pueden ser de cualquier tipo de
objeto de Python.
Hay una situación muy común en la que se puede usar una lista por comprensión o list
comprehension . Consideremos el siguiente código:
1 >>> a = [1,2,3,4,5]
2 >>> b = []
3 >>> for x in a:
4 if x % 2 == 0:
5 b.append(x * 3)
6 >>> b
7 [6, 12]
Este código claramente procesa una lista de ítems, separa y modifica un subconjunto de la lista
ingresada y crea una nueva lista resultante, y este código puede ser enteramente reemplazado
por la siguiente lista por comprensión:
1 >>> a = [1,2,3,4,5]
2 >>> b = [x * 3 for x in a if x % 2 == 0]
3 >>> b
4 [6, 12]
tuple
Una tupla es como una lista, pero su tamaño y elementos son inmutables, mientras que en una
lista son mutables. Si un elemento de una tupla es un objeto, los atributos del objeto son
mutables. Una tupla está delimitada por paréntesis.
1 >>> a = (1, 2, 3)
1 >>> a = [1, 2, 3]
2 >>> a[1] = 5
3 >>> print a
4 [1, 5, 3]
1 >>> a = (1, 2, 3)
3 2
4 >>> a[1] = 5
Una tupla, como en la lista, es un objeto iterable. Nótese que una tupla que consista de un
elemento debe incluir una coma al final, como se muestra abajo:
1 >>> a = (1)
3 <type 'int'>
4 >>> a = (1,)
6 <type 'tuple'>
Las tuplas son realmente útiles para ordenar objetos en grupos eficientemente por su
inmutabilidad, y los paréntesis son a veces opcionales:
1 >>> a = 2, 3, 'hola'
2 >>> x, y, z = a
3 >>> print x
4 2
5 >>> print z
6 hola
dict
Un dict (diccionario) de Python es una tabla hash que asocia ( map ) un objeto-clave a un
objeto-valor. Por ejemplo:
1 >>> a = {'k':'v', 'k2':3}
2 >>> a['k']
3 v
4 >>> a['k2']
5 3
6 >>> a.has_key('k')
7 True
8 >>> a.has_key('v')
9 False
Las claves pueden ser de cualquier tipo apto para tabla hash (int, string, o cualquier objeto cuya
clase implemente el método __hash__ ). Los valores pueden ser de cualquier tipo. Las claves y
valores diferentes en el mismo diccionario no tienen que ser de un único tipo. Si las claves son
caracteres alfanuméricos, el diccionario también se puede declarar con una sintaxis alternativa:
1 >>> a = dict(k='v', h2=3)
2 >>> a['k']
3 v
4 >>> print a
5 {'k':'v', 'h2':3}
3 ['k', 'k2']
5 ['v', 3]
El método items produce una lista de tuplas, cada una conteniendo una clave y su valor
asociado.
1 >>> a = [1, 2, 3]
3 >>> print a
4 [1, 3]
7 >>> print a
8 {'k':'v'}
Internamente, Python utiliza el operador hash para convertir objetos en enteros, y usa ese
entero para determinar dónde almacenar el valor.
1 >>> hash("hola mundo")
2 -1500746465
Acerca del espaciado
Python usa espaciado/sangría para delimitar bloques de código. Un bloque de código comienza
con una línea que finaliza con dos puntos, y continúa para todas las líneas que tengan igual o
mayor espaciado que la próxima línea. Por ejemplo:
1 >>> i = 0
3 >>> print i
4 >>> i = i + 1
5 >>>
6 0
7 1
8 2
Es común el uso de cuatro espacios para cada nivel de espaciado o indentation. Es una buena
práctica no combinar la tabulación con el espacio, porque puede resultar (invisiblemente)
confuso.
for...in
En Python, puedes recorrer objetos iterables en un bucle
2 >>> for i in a:
3 print i
4 0
5 1
6 hola
7 python
Un atajo usual es xrange , que genera un rango iterable sin almacenar la lista entera de
elementos.
1 >>> for i in xrange(0, 4):
2 print i
3 0
4 1
5 2
6 3
Otro comando de utilidad es enumerate , que realiza un conteo mientras avanza el bucle:
1 >>> a = [0, 1, 'hola', 'python']
3 print i, j
4 0 0
5 1 1
6 2 hola
7 3 python
También hay un keyword range(a, b, c) que devuelve una lista de enteros comenzando con
el valor a y con un incremento de c , y que finaliza con el último valor menor a b . Por
defecto, a es 0 y c es 1. xrange es similar es similar pero en realidad no genera una lista, sólo
un iterator para la lista; que es más apropiado para crear estos bucles.
Se puede salir de un bucle utilizando break
1 >>> for i in [1, 2, 3]:
2 print i
3 break
4 1
Puedes saltar a la próxima iteración del bucle sin ejecutar todo el bloque de código
con continue
1 >>> for i in [1, 2, 3]:
2 print i
3 continue
4 print 'test'
5 1
6 2
7 3
while
El bucle while en Python opera básicamente como lo hace en otros lenguajes de
programación, iterando una cantidad indefinida de veces y comprobando una condición antes
de cada iteración. Si la condición es False , el bucle finaliza.
1 >>> i = 0
3 i = i + 1
4 >>> print i
5 10
if...elif...else
El uso de condicional en Python es intuitivo:
1 >>> for i in range(3):
2 >>> if i == 0:
4 >>> elif i == 1:
6 >>> else:
8 cero
9 uno
10 otro
"elif" significa "else if". Tanto elif como else son partes opcionales. Puede haber más de
una elif pero sólo una declaración else . Se pueden crear condicionales complicados
utilizando los operadores not , and y or .
1 >>> for i in range(3):
try...except...else...finally
Python puede lanzar (throw) - perdón, generar - excepciones (Exception):
1 >>> try:
2 >>> a = 1 / 0
5 >>> else:
7 >>> finally:
10 listo
7 error sintáctico
3 +-- SystemExit
4 +-- KeyboardInterrupt
5 +-- Exception
6 +-- GeneratorExit
7 +-- StopIteration
8 +-- StandardError
9 | +-- ArithmeticError
10 | | +-- FloatingPointError
11 | | +-- OverflowError
12 | | +-- ZeroDivisionError
13 | +-- AssertionError
14 | +-- AttributeError
15 | +-- EnvironmentError
16 | | +-- IOError
17 | | +-- OSError
20 | +-- EOFError
21 | +-- ImportError
22 | +-- LookupError
23 | | +-- IndexError
24 | | +-- KeyError
25 | +-- MemoryError
26 | +-- NameError
27 | | +-- UnboundLocalError
28 | +-- ReferenceError
29 | +-- RuntimeError
30 | | +-- NotImplementedError
31 | +-- SyntaxError
32 | | +-- IndentationError
33 | | +-- TabError
34 | +-- SystemError
35 | +-- TypeError
36 | +-- ValueError
37 | | +-- UnicodeError
38 | | +-- UnicodeDecodeError
39 | | +-- UnicodeEncodeError
40 | | +-- UnicodeTranslateError
41 +-- Warning
42 +-- DeprecationWarning
43 +-- PendingDeprecationWarning
44 +-- RuntimeWarning
45 +-- SyntaxWarning
46 +-- UserWarning
47 +-- FutureWarning
48 +-- ImportWarning
49 +-- UnicodeWarning
Para una descripción detallada de cada una, consulta la documentación oficial de Python.
web2py expone sólo una nueva excepción, llamada HTTP . Cuando es generada, hace que el
programa devuelva una página de error HTTP (para más sobre este tema consulta el Capítulo
4).
Cualquier objeto puede ser utilizado para generar una excepción, pero es buena práctica
generar excepciones con objetos que extienden una de las clases de excepción incorporadas.
def...return
Las funciones se declaran utilizando def . Aquí se muestra una función de Python típica:
1 >>> def f(a, b):
2 return a + b
4 6
No hay necesidad (o forma) de especificar los tipos de los argumentos ni el tipo o tipos
devueltos. En este ejemplo, se define una función f para que tome dos argumentos.
Las funciones son la primer característica sintáctica descripta en este capítulo para introducir el
concepto de "scope" (alcance/ámbito), o "namespace" (espacio de nombres). En el ejemplo de
arriba, los identificadores ( identifier ) a y b son indefinidos fuera del scope de la función f :
1 >>> def f(a):
2 return a + 1
4 2
5 >>> print a
8 print a
Los identificadores definidos por fuera del scope de una función son accesibles dentro de la
función; nótese cómo el identificador a es manejado en el siguiente código:
1 >>> a = 1
3 return a + b
5 2
6 >>> a = 2
8 3
9 >>> a = 1 # redefine a
12 return a + b
14 4
16 1
Si se modifica a , las siguientes llamadas a la función usarán el nuevo valor del a global porque
la definición de la función enlaza la ubicación de almacenamiento del identificador a , no el valor
de a mismo al momento de la declaración de la función; sin embargo, si se asigna a a dentro
de la función g , la a global no es afectada porque la nueva a local protege el valor global. La
referencia del scope externo puede ser utilizada en la creación de "cierres" (closures):
1 >>> def f(x):
2 def g(y):
3 return x * y
4 return g
9 10
11 15
13 20
La función f crea nuevas funciones; y nótese que el scope del nombre g es enteramente
interno a f . Los cierres son extremadamente poderosos.
Los argumentos de función pueden tener valores por defecto, y pueden devolver múltiples
resultados:
2 return a + b, a - b
3 >>> x, y = f(5)
4 >>> print x
5 7
6 >>> print y
7 3
Los argumentos de las funciones pueden pasarse explícitamente por nombre, y esto significa
que el orden de los argumentos especificados en la llamada puede ser diferente del orden de
los argumentos con los que la función fue definida:
2 return a + b, a - b
4 >>> print x
5 7
6 >>> print y
7 -3
2 return a, b
4 >>> print x
5 (3, 'hola')
6 >>> print y
7 {'c':4, 'test':'mundo'}
Aquí los argumentos no pasados por nombre (3, 'hola') se almacenan en la tupla a , y los
argumentos pasados por nombre ( c y test ) se almacenan en el diccionario b .
En el caso opuesto, puede pasarse una lista o tupla a una función que requiera una conjunto
ordenado de argumentos para que los "abra" (unpack):
3 >>> c = (1, 2)
5 3
2 return a + b
5 3
lambda
lambda presenta una forma de declarar en forma fácil y abreviada funciones sin nombre:
1 >>> a = lambda b: b + 2
3 5
La expresión " lambda [a]:[b]" se lee exactamente como "una función con argumentos [a] que
devuelve [b]". La expresión lambda es anónima, pero la función adquiere un nombre al ser
asignada a un identificador a . Las reglas de espacios de nombres para def también son
igualmente válidas para lambda , y de hecho el código de arriba, con respecto a a es idéntico
al de la declaración de la función utilizando def :
1 >>> def a(b):
2 return b + 2
4 5
La única ventaja de lambda es la brevedad; sin embargo, la brevedad puede ser muy
conveniente en ciertas ocasiones. Consideremos una función llamada map que aplica una
función a todos los ítems en una lista, creando una lista nueva:
1 >>> a = [1, 7, 2, 5, 4, 8]
2 >>> map(lambda x: x + 2, a)
3 [3, 9, 4, 7, 6, 10]
3 >>> g(2)
4 5
Hay muchas situaciones donde es útil condimentar, pero una de ellas es especialmente a
propósito en web2py: el manejo del caché. Supongamos que tenemos una función pesada que
comprueba si un argumento es número primo:
1 def esprimo(numero):
3 if (numero % p) == 0:
4 return False
5 return True
La primera vez que se llame, llamará a su vez a la función f() , almacenará la salida en un
diccionario en memoria (digamos "d"), y lo devolverá de manera que el valor es:
1 valor = d['clave']=f()
La segunda vez que se llame, si la clave está en el diccionario y no es más antigua del número
de segundos especificados (60), devolverá el valor correspondiente sin volver a ejecutar la
llamada a la función.
1 valor = d['clave']
¿Cómo podemos almacenar en el caché la salida de la función esprimo para cualquier valor de
entrada? De esta forma:
1 >>> numero = 7
2 >>> segundos = 60
4 True
6 True
La salida es siempre la misma, pero la primera vez que se llama a cache.ram , se llama
a esprimo ; la segunda vez, no.
Las funciones de Python, creadas tanto con def como con lambda permiten refactorizar
funciones existentes en términos de un conjunto distinto de
argumentos. cache.ram y cache.disk son funciones para manejo de caché de web2py.
class
Como Python es un lenguaje de tipado dinámico, las clases y objetos pueden resultar extrañas.
De hecho no necesitas definir las variables incluidas (atributos) al declarar una clase, y distintas
instancias de la misma clase pueden tener distintos atributos. Los atributos (attribute) se asocian
generalmente con la instancia, no la clase (excepto cuando se declaran como atributos de clase
o "class attributes", que vienen a ser las "static member variables" de C++/Java).
Aquí se muestra un ejemplo:
3 >>> miinstancia.mivariable = 3
5 3
Nótese que pass es un comando que no "hace" nada. En este caso se utiliza para definir una
clase MiClase que no contiene nada. MiClase() llama al constructor de la clase (en este caso
el constructor por defecto) y devuelve un objeto, una instancia de la clase. El (object) en la
definición de la clase indica que nuestra clase extiende la clase incorporada object . Esto no es
obligatorio, pero se considera una buena práctica.
He aquí una clase más complicada:
4 >>> self.x = a
5 >>> self.y = b
10 9
Las funciones declaradas adentro de la clase son métodos. Algunos métodos tienen nombres
especiales reservados. Por ejemplo, __init__ es el constructor. Todas las variables son
variables locales del método exceptuando las variables declaradas fuera de los métodos. Por
ejemplo, z es una "variable de clase", que equivale a una "static member variable" de C++ que
almacena el mismo valor para toda instancia de la clase.
Hay que tener en cuenta que __init__ toma 3 argumentos y add toma uno, y sin embargo los
llamamos con dos y ningún argumento respectivamente. El primer argumento representa, por
convención, el nombre local utilizado dentro del método para referirse a el objeto actual, pero
podríamos haber utilizado cualquier otro. self cumple el mismo rol que *this en C++
o this en Java, pero self no es una palabra reservada.
Esta sintaxis es necesaria para evitar ambigüedad cuando se declaran clases anidadas, como
una clase que es local a un método dentro de otra clase.
__len__
__getitem__
__setitem__
Se pueden usar, por ejemplo, para crear un objeto contenedor que se comporta como una lista:
6 >>> b = MiLista(3, 4, 5)
8 4
9 >>> b.a[1] = 7
11 [3, 7, 5]
Entre otros operadores especiales están __getattr__ y __setattr__ , que definen los atributos
get y set para la clase, y __sum__ y __sub__ , que hacen sobrecarga de operadores aritméticos.
Para el uso de estos operadores se pueden consultar textos más avanzados en este tema. Ya
mencionamos anteriormente los operadores especiales __str__ y __repr__ .
Entrada/salida de archivos
En Python puedes abrir y escribir en un archivo con:
3 >>> archivo.close()
3 hola mundo
Como alternativa, puedes leer en modo binario con "rb", escribir en modo binario con "wb", y
abrir el archivo en modo incremental (append) con "a", utilizando la notación estándar de C.
El comando de lectura read toma un argumento opcional, que es el número de byte. Puedes
además saltar a cualquier ubicación en el archivo usando seek .
Puedes recuperar lo escrito en el archivo con read
1 >>> print archivo.seek(5)
1 >>> archivo.close()
exec , eval
A diferencia de Java, Python es realmente un lenguaje interpretado. Esto significa que tiene la
habilidad de ejecutar comandos de Python almacenados en cadenas. Por ejemplo:
2 >>> exec(a)
3 'hola mundo'
¿Qué ha ocurrido? La función exec le dice al intérprete que se llame a sí mismo y ejecute le
contenido de la cadena pasada como argumento. También es posible ejecutar el contenido de
una cadena en el contexto definido por los símbolos de un diccionario:
1 >>> a = "print b"
2 >>> c = dict(b=3)
4 3
Aquí el intérprete, cuando ejecuta la cadena a , ve los símbolos definidos en c ( b en el
ejemplo), pero no ve a c o a . Esto no es equivalente a un entorno restringido, porque exec no
impone límites a lo que el código interior pueda hacer; sólo define el conjunto de variables
visibles en el código.
Una función relacionada es eval , que hace algo muy parecido a exec , pero espera que el
argumento pasado evalúe a un valor dado, y devuelve ese valor.
1 >>> a = "3*4"
2 >>> b = eval(a)
3 >>> print b
4 12
import
El verdadero poder de Python está en sus librerías de módulos. Ellos proveen un gran y
consistente conjunto de Interfaces de Programación de Aplicaciones (API) para muchas
librerías del sistema (a menudo en un modo independiente del sistema operativo).
Por ejemplo, si necesitamos utilizar un número aleatorio, podemos hacer:
3 5
1 >>> import os
2 >>> os.chdir('..')
3 >>> os.unlink('archivo_a_borrar')
3 >>> print a
4 ruta/sub_ruta
2 >>> sys.path.append('ruta/a/mis/módulos')
Cuando corremos web2py, Python permanece residente en memoria, y se configura un
único sys.path , aunque puede haber varios hilos respondiendo a las solicitudes HTTP. Para
evitar la pérdida de espacio en memoria (leak), es mejor comprobar que una ruta ya está
presente antes de añadirla:
1 >>> ruta = 'ruta/a/mis/módulos'
3 sys.path.append(ruta)
datetime
El uso del módulo datetime es más fácil de describir por algunos ejemplos:
1 >>> import datetime
3 2008-07-04 14:03:90
5 2008-07-04
De vez en cuando puedes necesitar una referencia cronológica para los datos (timestamp)
según el tiempo de UTC en lugar de usar la hora local. En ese caso puedes usar la siguiente
función:
3 2008-07-04 14:03:90
El módulo datetime contiene varias clases: date (fecha), datetime (fecha y hora), time (hora) y
timedelta. La diferencia entre dos objetos date o dos datetime o dos time es un timedelta:
3 >>> c = b - a
5 1
En web2py, date y datetime se usan para almacenar los tipos de datos SQL correspondientes
cuando se pasan desde o a la base de datos.
time
El módulo time difiere de date o datetime porque representa el tiempo en segundos desde el
epoch (comenzando desde 1970)
1 >>> import time
2 >>> t = time.time()
3 1215138737.571
y ahora:
2 >>> b = cPickle.dumps(a)
3 >>> c = cPickle.loads(b)