Preguntas frecuentes sobre bibliotecas y extensiones
****************************************************


Cuestiones generales sobre bibliotecas
======================================


¿Cómo encuentro un módulo o aplicación para ejecutar la tarea X?
----------------------------------------------------------------

Vea la referencia de bibliotecas para comprobar si existe un módulo
relevante en la biblioteca estándar. (Eventualmente aprenderá lo que
hay en la biblioteca estándar y será capaz de saltarse este paso.)

Para paquetes de terceros, busque Python Package Index o pruebe Google
u otro motor de búsqueda web. La búsqueda de "Python" más una palabra
clave o dos para su tema de interés generalmente encontrará algo útil.


¿Dónde está el fichero fuente *math.py* (*socket.py*, *regex.py*, etc.)?
------------------------------------------------------------------------

Si no puede encontrar un fichero fuente para un módulo, puede ser un
módulo incorporado o cargado dinámicamente implementado en C, C++ u
otro lenguaje compilado. En este caso puede no disponer del fichero
fuente o puede ser algo como "mathmodule.c", en algún lugar de un
directorio fuente C (fuera del Python *Path*).

Hay (al menos) tres tipos de módulos en Python:

1. módulos escritos en Python (.py);

2. módulos escritos en C y cargados dinámicamente (*.dll, .pyd, .so,
   .sl*, etc.);

3. módulos escritos en C y enlazados con el intérprete; para obtener
   una lista de estos, escriba:

      import sys
      print(sys.builtin_module_names)


¿Cómo hago ejecutable un script Python en Unix?
-----------------------------------------------

Necesita hacer dos cosas: el modo del fichero del script debe ser
ejecutable y la primera línea debe comenzar con "#!" seguido de la
ruta al intérprete de Python.

Lo primero se hace ejecutando "chmod +x scriptfile" o bien "chmod 755
scriptfile".

Lo segundo se puede hacer de distintas maneras. La manera más directa
es escribir

   #!/usr/local/bin/python

en la primera línea de su fichero, usando la ruta donde está instalado
el intérprete de Python en su plataforma.

Si quiere que el script sea independiente de donde se ubique el
intérprete de Python, puede usar el programa **env**. Casi todas las
variantes de Unix soportan lo siguiente, asumiendo que el intérprete
de Python está en un directorio del "PATH" de usuario:

   #!/usr/bin/env python

*No* haga esto para scripts CGI. La variable "PATH" para scripts CGI
es mínima, así que necesita usar la ruta real absoluta al intérprete.

Ocasionalmente, un entorno de usuario está tan lleno que el programa
**/usr/bin/env** falla; o bien no existe el programa env. En ese caso,
puede intentar el siguiente truco (gracias a Alex Rezinsky):

   #! /bin/sh
   """:"
   exec python $0 ${1+"$@"}
   """

Una pequeña desventaja es que esto define el *__doc__* del script. Sin
embargo, puede arreglarlo añadiendo

   __doc__ = """...Whatever..."""


¿Hay un paquete curses/termcap para Python?
-------------------------------------------

Para variantes Unix: La distribución estándar de Python viene con un
módulo curses en el subdirectorio Modules, aunque no está compilado
por defecto. (Nótese que esto no está disponible en la distribución
Windows — no hay módulo curses para Windows.)

El módulo "curses" soporta características básicas de cursores así
como muchas funciones adicionales de ncurses y cursores SYSV como
color, soporte para conjuntos de caracteres alternativos, pads, y
soporte para ratón. Esto significa que el módulo no es compatible con
sistemas operativos que sólo tienen cursores BSD, pero no parece que
ningún sistema operativo actualmente mantenido caiga dentro de esta
categoría.


¿Hay un equivalente en Python al onexit() de C?
-----------------------------------------------

El módulo "atexit" proporciona una función de registro que es similar
a "onexit()" de C.


¿Por qué no funcionan mis manejadores de señales?
-------------------------------------------------

El problema más común es que el manejador de señales esté declarado
con la lista incorrecta de argumentos. Se llama como

   handler(signum, frame)

así que debería declararse con dos argumentos:

   def handler(signum, frame):
       ...


Tareas comunes
==============


¿Cómo pruebo un programa o un componente Python?
------------------------------------------------

Python viene con dos *frameworks* de *testing*. El módulo "doctest"
encuentra ejemplos en los docstrings para un módulo y los ejecuta,
comparando la salida con la salida esperada especificada en la cadena
de documentación.

El módulo "unittest" es un *framework* de *testing* más agradable y
modelado sobre los *frameworks* de *testing* de Java y Smalltalk.

Para hacer más fácil el *testing*, debería usar un buen diseño modular
en su programa. Su programa debería tener casi toda la funcionalidad
encapsulada en funciones o en métodos de clases — y esto algunas veces
tiene el efecto sorprendente y encantador de que su programa funcione
más rápido (porque los accesos a las variables locales son más rápidas
que los accesos a las variables globales). Además el programa debería
evitar depender de la mutación de variables globales, ya que esto
dificulta mucho más hacer el *testing*.

La "lógica global principal" de su programa puede ser tan simple como

   if __name__ == "__main__":
       main_logic()

al final del módulo principal de su programa.

Una vez que su programa esté organizado en una colección manejable de
funciones y comportamientos de clases, usted debería escribir
funciones de comprobación que ejerciten los comportamientos. Se puede
asociar un conjunto de pruebas a cada módulo. Esto suena a mucho
trabajo, pero gracias a que Python es tan conciso y flexible, se hace
sorprendentemente fácil. Puede codificar de manera mucho más agradable
y divertida escribiendo funciones de comprobación en paralelo con el
"código de producción", ya que esto facilita encontrar antes errores e
incluso fallos de diseño.

Los "módulos de soporte" que no tienen la intención de estar en el
módulo principal de un programa pueden incluir un auto *test* del
módulo.

   if __name__ == "__main__":
       self_test()

Incluso los programas que interactúan con interfaces externas
complejas se pueden comprobar cuando las interfaces externas no están
disponibles usando interfaces "simuladas" implementadas en Python.


¿Cómo creo documentación a partir de los docstrings?
----------------------------------------------------

The "pydoc" module can create HTML from the doc strings in your Python
source code.  An alternative for creating API documentation purely
from docstrings is epydoc.  Sphinx can also include docstring content.


¿Cómo consigo presionar una única tecla cada vez?
-------------------------------------------------

Para variantes Unix hay varias soluciones. Lo más directo es hacerlo
usando cursores, pero curses es un módulo bastante amplio para
aprenderlo.


Hilos
=====


¿Cómo programo usando hilos?
----------------------------

Asegúrese de usar el módulo "threading" y no el módulo "_thread". El
módulo "threading" construye abstracciones convenientes sobre las
primitivas de bajo nivel proporcionadas por el módulo "_thread".


Ninguno de mis hilos parece funcionar: ¿por qué?
------------------------------------------------

Tan pronto como el hilo principal termine, se matan todos los hilos.
Su hilo principal está corriendo demasiado rápido, sin dar tiempo a
los hilos para hacer algún trabajo.

Una solución sencilla es añadir un *sleep* al final del programa que
sea suficientemente largo para que todos los hilos terminen:

   import threading, time

   def thread_task(name, n):
       for i in range(n):
           print(name, i)

   for i in range(10):
       T = threading.Thread(target=thread_task, args=(str(i), i))
       T.start()

   time.sleep(10)  # <---------------------------!

Por ahora (en muchas plataformas) los hilos no corren en paralelo,
sino que parece que corren secuencialmente, ¡uno a la vez! La razón es
que el planificador de hilos del sistema operativo no inicia un nuevo
hilo hasta que el hilo anterior está bloqueado.

Una solución sencilla es añadir un pequeño *sleep* al comienzo de la
función run:

   def thread_task(name, n):
       time.sleep(0.001)  # <--------------------!
       for i in range(n):
           print(name, i)

   for i in range(10):
       T = threading.Thread(target=thread_task, args=(str(i), i))
       T.start()

   time.sleep(10)

En vez de intentar adivinar un valor de retardo adecuado para
"time.sleep()", es mejor usar algún tipo de mecanismo de semáforo. Una
idea es usar el módulo "queue" para crear un objeto cola, permitiendo
que cada hilo añada un *token* a la cola cuando termine, y permitiendo
al hilo principal leer tantos tokens de la cola como hilos haya.


¿Cómo puedo dividir trabajo entre un grupo de hilos?
----------------------------------------------------

La manera más fácil es usar el nuevo módulo "concurrent.futures",
especialmente el módulo "ThreadPoolExecutor".

O, si quiere tener un control más preciso sobre el algoritmo de
despacho, puede escribir su propia lógica manualmente. Use el módulo
"queue" para crear una cola que contenga una lista de trabajos. La
clase "Queue" mantiene una lista de objetos y tiene un método
".put(obj)" que añade elementos a la cola y un método ".get()" que los
retorna. Esta clase se encargará de los bloqueos necesarios para
asegurar que cada trabajo se reparte exactamente una vez.

Aquí hay un ejemplo trivial:

   import threading, queue, time

   # The worker thread gets jobs off the queue.  When the queue is empty, it
   # assumes there will be no more work and exits.
   # (Realistically workers will run until terminated.)
   def worker():
       print('Running worker')
       time.sleep(0.1)
       while True:
           try:
               arg = q.get(block=False)
           except queue.Empty:
               print('Worker', threading.current_thread(), end=' ')
               print('queue empty')
               break
           else:
               print('Worker', threading.current_thread(), end=' ')
               print('running with argument', arg)
               time.sleep(0.5)

   # Create queue
   q = queue.Queue()

   # Start a pool of 5 workers
   for i in range(5):
       t = threading.Thread(target=worker, name='worker %i' % (i+1))
       t.start()

   # Begin adding work to the queue
   for i in range(50):
       q.put(i)

   # Give threads time to run
   print('Main thread sleeping')
   time.sleep(5)

Cuando se ejecute, esto producirá la siguiente salida:

   Running worker
   Running worker
   Running worker
   Running worker
   Running worker
   Main thread sleeping
   Worker <Thread(worker 1, started 130283832797456)> running with argument 0
   Worker <Thread(worker 2, started 130283824404752)> running with argument 1
   Worker <Thread(worker 3, started 130283816012048)> running with argument 2
   Worker <Thread(worker 4, started 130283807619344)> running with argument 3
   Worker <Thread(worker 5, started 130283799226640)> running with argument 4
   Worker <Thread(worker 1, started 130283832797456)> running with argument 5
   ...

Consulte la documentación del módulo para más detalles; la clase
"Queue" proporciona una interfaz llena de características.


¿Qué tipos de mutación de valores globales son *thread-safe*?
-------------------------------------------------------------

Un *global interpreter lock* (GIL) se usa internamente para asegurar
que sólo un hilo corre a la vez en la VM de Python. En general, Python
ofrece cambiar entre hilos sólo en instrucciones bytecode; la
frecuencia con la que cambia se puede fijar vía
"sys.setswitchinterval()". Cada instrucción bytecode y por lo tanto,
toda la implementación de código C alcanzada por cada instrucción, es
atómica desde el punto de vista de un programa Python.

En teoría, esto significa que un informe exacto requiere de un
conocimiento exacto de la implementación en bytecode de la PVM. En la
práctica, esto significa que las operaciones entre variables
compartidas de tipos de datos *built-in* (enteros, listas,
diccionarios, etc.) que "parecen atómicas" realmente lo son.

Por ejemplo, las siguientes operaciones son todas atómicas (L, L1, L2
son listas, D, D1, D2 son diccionarios, *x, y* son objetos, *i, j* son
enteros):

   L.append(x)
   L1.extend(L2)
   x = L[i]
   x = L.pop()
   L1[i:j] = L2
   L.sort()
   x = y
   x.field = y
   D[x] = y
   D1.update(D2)
   D.keys()

Estas no lo son:

   i = i+1
   L.append(L[-1])
   L[i] = L[j]
   D[x] = D[x] + 1

Las operaciones que reemplazan otros objetos pueden invocar el método
"__del__()" de esos otros objetos cuando su número de referencias
alcance cero, y eso puede afectar a otras cosas. Esto es especialmente
cierto para las actualizaciones en masa de diccionarios y listas.
Cuando se esté en duda, ¡use un mutex!


¿Podemos deshacernos del *Global Interpreter Lock*?
---------------------------------------------------

El *global interpreter lock* (GIL) se percibe a menudo como un
obstáculo en el despliegue de Python sobre máquinas servidoras finales
de múltiples procesadores, porque un programa Python multihilo
efectivamente sólo usa una CPU, debido a la exigencia de que (casi)
todo el código Python sólo puede correr mientras el GIL esté activado.

En los días de Python 1.5, Greg Stein de hecho implementó un conjunto
amplio de parches (los parches "libres de hilo") que eliminaba el GIL
y lo reemplazaba con un bloqueo de grano fino. Adam Olsen hizo
recientemente un experimento similar con su proyecto python-
safethread. Desafortunadamente, ambos experimentos mostraron una aguda
caída en el rendimiento (al menos del 30% o más baja), debido a la
cantidad de bloqueos de grano fino necesarios para compensar la
eliminación del GIL.

¡Esto no significa que no pueda hacer buen uso de Python en máquinas
de múltiples CPU! Usted sólo tiene que ser creativo a la hora de
dividir el trabajo entre múltiples *procesos* en vez de entre
múltiples *hilos*. La clase "ProcessPoolExecutor" del nuevo módulo
"concurrent.futures" proporciona una manera sencilla de hacer esto; el
módulo "multiprocessing" proporciona una API de bajo nivel en caso de
que se quiera tener un mayor control sobre el despacho de las tareas.

El uso sensato de extensiones C también ayudará; si usa una extensión
C para ejecutar una tarea que consume mucho tiempo, la extensión puede
liberar al GIL mientras el hilo de ejecución esté en el código C y
permite a otros hilos hacer trabajo. Algunos módulos de la biblioteca
estándar tales como "zlib" y "hashlib" ya lo hacen.

Se ha sugerido que el GIL debería ser un bloqueo por estado de
intérprete, en vez de realmente global; luego los intérpretes no
serían capaces de compartir objetos. Desafortunadamente, esto tampoco
es probable que ocurra. Sería una tremenda cantidad de trabajo, porque
muchas implementaciones de objetos actualmente tienen un estado
global. Por ejemplo, los enteros pequeños y las cadenas pequeñas están
*cacheadas*; estas *caches* se tendrían que mover al estado del
intérprete. Otros tipos de objetos tienen su propia lista libre; estas
listas libres se tendrían que mover al estado del intérprete. Y así
sucesivamente.

Y dudo de si se puede hacer en tiempo finito, porque el mismo problema
existe para extensiones de terceros. Es probable que las extensiones
de terceros se escriban más rápido de lo que se puedan convertir para
almacenar todo su estado global en el estado del intérprete.

Y finalmente, una vez que tenga múltiples intérpretes sin compartir
ningún estado, ¿qué habrá ganado sobre correr cada intérprete en un
proceso separado?


Entrada y Salida
================


¿Cómo borro un fichero? (Y otras preguntas sobre ficheros...)
-------------------------------------------------------------

Use "os.remove(filename)" o "os.unlink(filename)"; para la
documentación, vea el módulo "os". Las dos funciones son idénticas;
"unlink()" es simplemente el nombre de la llamada al sistema UNIX para
esta función.

Para borrar un directorio, use "os.rmdir()"; use "os.mkdir()" para
crear uno. "os.makedirs(path)" creará cualquier directorio intermedio
que no exista en "path". "os.removedirs(path)" borrará los directorios
intermedios siempre y cuando estén vacíos; si quiere borrar un árbol
de directorios completo y sus contenidos, use "shutil.rmtree()".

Para renombrar un fichero, use "os.rename(old_path, new_path)".

Para truncar un fichero, ábralo usando "f = open(filename, "rb+")", y
use "f.truncate(offset)"; el desplazamiento toma por defecto la
posición actual de búsqueda. También existe "os.ftruncate(fd, offset)"
para ficheros abiertos con "os.open()",  donde *fd* es el descriptor
del fichero (un entero pequeño).

El módulo "shutil" también contiene distintas funciones para trabajar
con ficheros incluyendo "copyfile()", "copytree()" y "rmtree()".


¿Cómo copio un fichero?
-----------------------

The "shutil" module contains a "copyfile()" function. Note that on
Windows NTFS volumes, it does not copy alternate data streams nor
resource forks on macOS HFS+ volumes, though both are now rarely used.
It also doesn't copy file permissions and metadata, though using
"shutil.copy2()" instead will preserve most (though not all) of it.


¿Cómo leo (o escribo) datos binarios?
-------------------------------------

Para leer o escribir formatos binarios de datos complejos, es mejor
usar el módulo "struct". Esto le permite tomar una cadena de texto que
contiene datos binarios (normalmente números) y convertirla a objetos
de Python; y viceversa.

Por ejemplo, el siguiente código lee de un fichero dos enteros de
2-bytes y uno de 4-bytes en formato *big-endian*:

   import struct

   with open(filename, "rb") as f:
       s = f.read(8)
       x, y, z = struct.unpack(">hhl", s)

El '>' en la cadena de formato fuerza los datos a *big-endian*; la
letra 'h' lee un "entero corto" (2 bytes), y 'l' lee un "entero largo"
(4 bytes) desde la cadena de texto.

Para datos que son más regulares (por ejemplo una lista homogénea de
enteros o flotantes), puede también usar el módulo "array".

Nota:

  Para leer y escribir datos binarios, es obligatorio abrir el fichero
  en modo binario (aquí, pasando ""rb"" a "open()"). Si, en cambio,
  usa ""r"" (por defecto), el fichero se abrirá en modo texto y
  "f.read()" retornará objetos "str" en vez de objetos "bytes".


No consigo usar os.read() en un *pipe* creado con os.popen(); ¿por qué?
-----------------------------------------------------------------------

"os.read()" es una función de bajo nivel que recibe un descriptor de
fichero, un entero pequeño representando el fichero abierto.
"os.popen()" crea un objeto fichero de alto nivel, el mismo tipo que
retorna la función *built-in* "open()". Así, para leer *n* bytes de un
*pipe* *p* creado con "os.popen()", necesita usar "p.read(n)".


¿Cómo accedo al puerto serial (RS232)?
--------------------------------------

For Win32, OSX, Linux, BSD, Jython, IronPython:

   https://pypi.org/project/pyserial/

Para Unix, vea una publicación Usenet de Mitch Chapman:

   https://groups.google.com/groups?selm=34A04430.CF9@ohioee.com


¿Por qué al cerrar sys.stdout (stdin, stderr) realmente no se cierran?
----------------------------------------------------------------------

Los *objetos de tipo fichero* en Python son una capa de abstracción de
alto nivel sobre los descriptores de ficheros de bajo nivel de C.

Para la mayoría de objetos de tipo fichero que cree en Python vía la
función *built-in* "open()", "f.close()" marca el objeto de tipo
fichero Python como ya cerrado desde el punto de vista de Python, y
también ordena el cierre del descriptor de fichero subyacente en C.
Esto además ocurre automáticamente en el destructor de "f", cuando "f"
se convierte en basura.

Pero *stdin*, *stdout* y *stderr* se tratan de manera especial en
Python, debido a un estatus especial que también tienen en C.
Ejecutando "sys.stdout.close()" marca el objeto fichero de nivel
Python para ser cerrado, pero *no* cierra el descriptor de fichero
asociado en C.

Para cerrar el descriptor de fichero subyacente en C para uno de estos
tres casos, debería primero asegurarse de que eso es realmente lo que
quiere hacer (por ejemplo, puede confundir módulos de extensión
intentado hacer *I/O*). Si es así, use "os.close()":

   os.close(stdin.fileno())
   os.close(stdout.fileno())
   os.close(stderr.fileno())

O puede usar las constantes numéricas 0, 1 y 2, respectivamente.


Programación de Redes/Internet
==============================


¿Qué herramientas de Python existen para WWW?
---------------------------------------------

Vea los capítulos titulados Protocolos y soporte de Internet y Manejo
de Datos de Internet en el manual de referencia de bibliotecas. Python
tiene muchos módulos que le ayudarán a construir sistemas web del lado
del servidor y del lado del cliente.

Paul Boddie mantiene un resumen de los *frameworks* disponibles en
https://wiki.python.org/moin/WebProgramming.

Cameron Laird maintains a useful set of pages about Python web
technologies at https://web.archive.org/web/20210224183619/http://pha
seit.net/claird/comp.lang.python/web_python.


¿Cómo puedo imitar un envío de formulario CGI (*METHOD=POST*)?
--------------------------------------------------------------

Me gustaría recuperar páginas web que son resultado del envío de un
formulario. ¿Existe algún código que me permita hacer esto fácilmente?

Sí. Aquí hay un ejemplo sencillo que usa "urllib.request":

   #!/usr/local/bin/python

   import urllib.request

   # build the query string
   qs = "First=Josephine&MI=Q&Last=Public"

   # connect and send the server a path
   req = urllib.request.urlopen('http://www.some-server.out-there'
                                '/cgi-bin/some-cgi-script', data=qs)
   with req:
       msg, hdrs = req.read(), req.info()

Nótese que para operaciones POST de tipo *percent-encoded*, las
cadenas de consulta tienen que estar entrecomilladas usando
"urllib.parse.urlencode()". Por ejemplo, para enviar "name=Guy Steele,
Jr.":

   >>> import urllib.parse
   >>> urllib.parse.urlencode({'name': 'Guy Steele, Jr.'})
   'name=Guy+Steele%2C+Jr.'

Ver también:

  HOWTO - Cómo obtener recursos de Internet con el paquete urllib para
  ejemplos más detallados.


¿Qué modulo debería usar para generación de HTML?
-------------------------------------------------

Puede encontrar una colección de enlaces útiles en la página wiki de
programación web.


¿Cómo envío correo desde un script Python?
------------------------------------------

Use el módulo  "smtplib" de la biblioteca estándar.

Aquí hay un remitente simple interactivo que lo usa. Este método
trabajará en cualquier máquina que soporte un *listener SMTP*.

   import sys, smtplib

   fromaddr = input("From: ")
   toaddrs  = input("To: ").split(',')
   print("Enter message, end with ^D:")
   msg = ''
   while True:
       line = sys.stdin.readline()
       if not line:
           break
       msg += line

   # The actual mail send
   server = smtplib.SMTP('localhost')
   server.sendmail(fromaddr, toaddrs, msg)
   server.quit()

Una alternativa sólo para UNIX es usar *sendmail*. La ubicación del
programa *sendmail* varía entre sistemas; algunas veces está en
"/usr/lib/sendmail", otras veces en "/usr/sbin/sendmail". El manual de
*sendmail* le ayudará. Aquí hay un ejemplo de código:

   import os

   SENDMAIL = "/usr/sbin/sendmail"  # sendmail location
   p = os.popen("%s -t -i" % SENDMAIL, "w")
   p.write("To: receiver@example.com\n")
   p.write("Subject: test\n")
   p.write("\n")  # blank line separating headers from body
   p.write("Some text\n")
   p.write("some more text\n")
   sts = p.close()
   if sts != 0:
       print("Sendmail exit status", sts)


¿Cómo evito el bloqueo en el método *connect()* de un *socket*?
---------------------------------------------------------------

El módulo "select" es mayoritariamente usado para ayudar con
entrada/salida de sockets.

Para evitar que la conexión TCP se bloquee, puede configurar el socket
en modo sin bloqueo. Luego, cuando hagas el "socket.connect()", te
conectarás inmediatamente (poco probable) u obtendrás una excepción
que contiene el número de error como ".errno". "errno.EINPROGRESS"
indica que la conexión está en curso, pero aún no ha terminado. Los
diferentes sistemas operativos devolverán valores diferentes, por lo
que tendrá que verificar lo que se devuelve en su sistema.

Puede utilizar el método "socket.connect_ex()" para evitar crear una
excepción. Simplemente retornará el valor de errno. Para sondear,
puede llamar a "socket.connect_ex()" nuevamente más tarde -- "0" o
"errno.EISCONN" indican que está conectado -- o puede pasar este
socket a "select.select()" para comprobar si se puede escribir.

Nota:

  El módulo "asyncio" proporciona una biblioteca asíncrona concurrente
  y de un solo subproceso de propósito general, que se puede utilizar
  para escribir código de red sin bloqueo. La biblioteca de terceros
  Twisted es una alternativa popular y rica en funciones.


Bases de datos
==============


¿Hay paquetes para interfaces a bases de datos en Python?
---------------------------------------------------------

Sí.

Interfaces a *hashes* basados en disco tales como "DBM" y "GDBM" están
también incluidas en Python estándar. También hay un módulo "sqlite3",
que proporciona una base de datos relacional ligera basada en disco.

Está disponible el soporte para la mayoría de bases de datos
relacionales. Vea la página wiki de Programación de Bases de datos
para más detalles.


¿Cómo implementar objetos persistentes en Python?
-------------------------------------------------

El módulo de biblioteca "pickle" soluciona esto de una forma muy
general (aunque todavía no puede almacenar cosas como ficheros
abiertos, sockets o ventanas), y el módulo de biblioteca "shelve" usa
*pickle* y *(g)dbm* para crear mapeos persistentes que contienen
objetos arbitrarios Python.


Matemáticas y Numérica
======================


¿Cómo genero números aleatorios en Python?
------------------------------------------

El módulo estándar "random" implementa un generador de números
aleatorios. El uso es simple:

   import random
   random.random()

Esto retorna un número flotante aleatorio en el rango [0, 1).

Hay también muchos otros generadores especializados en este módulo,
tales como:

* "randrange(a, b)" selecciona un entero en el rango [a, b).

* "uniform(a, b)" selecciona un número flotante en el rango [a, b).

* "normalvariate(mean, sdev)" muestrea una distribución normal
  (*Gausiana*).

Algunas funciones de alto nivel operan directamente sobre secuencias,
tales como:

* "choice(S)" selecciona un elemento aleatorio de una secuencia dada.

* "shuffle(L)" reorganiza una lista in-situ, es decir, la permuta
  aleatoriamente.

También hay una clase "Random" que usted puede instanciar para crear
múltiples generadores independientes de valores aleatorios.
