Novedades de Python 2.5

Autor

A.M. Kuchling

Este artículo explica las nuevas características de Python 2.5. La versión final de Python 2.5 está prevista para agosto de 2006; PEP 356 describe el cronograma de lanzamiento planificado.

Los cambios en Python 2.5 son una interesante mezcla de mejoras en el lenguaje y en las bibliotecas. Las mejoras en las bibliotecas serán más importantes para la comunidad de usuarios de Python, creo, debido a que se han añadido varios paquetes bastante útiles. Los nuevos módulos incluyen ElementTree para el procesamiento de XML (xml.etree), el módulo de base de datos SQLite (sqlite), y el módulo ctypes para llamar a funciones escritas en lenguaje C.

Los cambios en el lenguaje son de mediana importancia. Se han añadido algunas características nuevas y agradables, pero la mayoría de ellas no son características que vaya a utilizar todos los días. Las expresiones condicionales fueron finalmente añadidas al lenguaje usando una nueva sintaxis; ver sección PEP 308: Expresiones condicionales. La nueva sentencia “with” facilitará la escritura de código de limpieza (sección PEP 343: La declaración «con). Ahora se pueden pasar valores a los generadores (sección PEP 342: Nuevas funciones del generador). Las importaciones son ahora visibles como absolutas o relativas (sección PEP 328: Importaciones absolutas y relativas). Se han mejorado algunos casos de manejo de excepciones (sección PEP 341: Try/except/finally unificados). Todas estas mejoras merecen la pena, pero son mejoras de una u otra característica específica del lenguaje; ninguna de ellas es una modificación amplia de la semántica de Python.

Además de las adiciones al lenguaje y a la biblioteca, se han realizado otras mejoras y correcciones de errores en todo el árbol de código fuente. Una búsqueda en los registros de cambios del SVN revela que se aplicaron 353 parches y se corrigieron 458 errores entre Python 2.4 y 2.5. (Es probable que ambas cifras estén subestimadas)

Este artículo no pretende ser una especificación completa de las nuevas características; en su lugar, los cambios se introducen brevemente utilizando ejemplos útiles. Para obtener todos los detalles, siempre debes consultar la documentación de Python 2.5 en https://docs.python.org. Si quieres entender la implementación completa y los fundamentos del diseño, consulta el PEP de una nueva característica en particular.

Son bienvenidos los comentarios, las sugerencias y los informes de errores para este documento; por favor, envíelos por correo electrónico al autor o abra un error en el rastreador de errores de Python.

PEP 308: Expresiones condicionales

Durante mucho tiempo, la gente ha solicitado una forma de escribir expresiones condicionales, que son expresiones que devuelven el valor A o el valor B dependiendo de si un valor booleano es verdadero o falso. Una expresión condicional le permite escribir una única sentencia de asignación que tiene el mismo efecto que la siguiente:

if condition:
    x = true_value
else:
    x = false_value

Ha habido interminables y tediosas discusiones sobre la sintaxis tanto en python-dev como en comp.lang.python. Incluso se llevó a cabo una votación en la que se descubrió que la mayoría de los votantes querían expresiones condicionales de alguna forma, pero no había ninguna sintaxis que fuera preferida por una clara mayoría. Los candidatos incluían cond ? true_v : false_v, if cond then true_v else false_v, y otras 16 variaciones.

Guido van Rossum eligió finalmente una sintaxis sorprendente:

x = true_value if condition else false_value

La evaluación sigue siendo perezosa como en las expresiones booleanas existentes, por lo que el orden de evaluación salta un poco. La expresión condición del medio se evalúa primero, y la expresión valor_verdadero se evalúa sólo si la condición es verdadera. Del mismo modo, la expresión valor_falso sólo se evalúa cuando la condición es falsa.

Esta sintaxis puede parecer extraña y retrógrada; ¿por qué la condición va en el medio de la expresión, y no en la parte delantera como en c ? x : y de C? La decisión se comprobó aplicando la nueva sintaxis a los módulos de la biblioteca estándar y viendo cómo se leía el código resultante. En muchos casos en los que se utiliza una expresión condicional, un valor parece ser el «caso común» y otro valor es un «caso excepcional», utilizado sólo en las raras ocasiones en las que no se cumple la condición. La sintaxis condicional hace que este patrón sea un poco más obvio:

contents = ((doc + '\n') if doc else '')

Leo la afirmación anterior en el sentido de que «aquí se asigna a contents un valor de doc+'\n'; a veces doc está vacío, en cuyo caso especial se devuelve una cadena vacía» Dudo que use expresiones condicionales muy a menudo donde no hay un caso común y no común claro.

Hubo alguna discusión sobre si el lenguaje debería requerir rodear las expresiones condicionales con paréntesis. Se tomó la decisión de no requerir paréntesis en la gramática del lenguaje Python, pero como una cuestión de estilo creo que siempre deberías usarlos. Considere estas dos declaraciones:

# First version -- no parens
level = 1 if logging else 0

# Second version -- with parens
level = (1 if logging else 0)

En la primera versión, creo que el ojo de un lector podría agrupar la sentencia en “nivel = 1”, “si registro”, “si no 0”, y pensar que la condición decide si se realiza la asignación a nivel. La segunda versión se lee mejor, en mi opinión, porque deja claro que la asignación se realiza siempre y que se está eligiendo entre dos valores.

Otra razón para incluir los paréntesis: algunas combinaciones extrañas de comprensiones de listas y lambdas podrían parecer expresiones condicionales incorrectas. Véase PEP 308 para algunos ejemplos. Si pone paréntesis alrededor de sus expresiones condicionales, no se encontrará con este caso.

Ver también

PEP 308 - Expresiones condicionales

PEP escrito por Guido van Rossum y Raymond D. Hettinger; implementado por Thomas Wouters.

PEP 309: Aplicación parcial de funciones

El módulo functools está destinado a contener herramientas para la programación de estilo funcional.

Una herramienta útil de este módulo es la función partial(). Para los programas escritos en un estilo funcional, a veces querrá construir variantes de funciones existentes que tengan algunos de los parámetros rellenados. Considere una función Python f(a, b, c); podría crear una nueva función g(b, c) que fuera equivalente a f(1, b, c). Esto se llama «aplicación parcial de funciones».

parcial() toma los argumentos (function, arg1, arg2, ... kwarg1=valor1, kwarg2=valor2). El objeto resultante es invocable, por lo que puedes llamarlo para invocar la función con los argumentos rellenados.

He aquí un pequeño pero realista ejemplo:

import functools

def log (message, subsystem):
    "Write the contents of 'message' to the specified subsystem."
    print '%s: %s' % (subsystem, message)
    ...

server_log = functools.partial(log, subsystem='server')
server_log('Unable to open socket')

Aquí hay otro ejemplo, de un programa que utiliza PyGTK. Aquí se está construyendo dinámicamente un menú emergente sensible al contexto. El callback proporcionado para la opción de menú es una versión parcialmente aplicada del método open_item(), donde se ha proporcionado el primer argumento

...
class Application:
    def open_item(self, path):
       ...
    def init (self):
        open_func = functools.partial(self.open_item, item_path)
        popup_menu.append( ("Open", open_func, 1) )

Otra función del módulo functools es la función update_wrapper(wrapper, wrapped) que le ayuda a escribir decoradores con un buen comportamiento. update_wrapper() copia el nombre, el módulo y el atributo docstring a una función wrapper para que las trazas dentro de la función envuelta sean más fáciles de entender. Por ejemplo, puedes escribir:

def my_decorator(f):
    def wrapper(*args, **kwds):
        print 'Calling decorated function'
        return f(*args, **kwds)
    functools.update_wrapper(wrapper, f)
    return wrapper

wraps() es un decorador que se puede utilizar dentro de sus propios decoradores para copiar la información de la función envuelta. Una versión alternativa del ejemplo anterior sería:

def my_decorator(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        print 'Calling decorated function'
        return f(*args, **kwds)
    return wrapper

Ver también

PEP 309 - Aplicación parcial de funciones

PEP propuesto y escrito por Peter Harris; implementado por Hye-Shik Chang y Nick Coghlan, con adaptaciones de Raymond Hettinger.

PEP 314: Metadatos para paquetes de software Python v1.1

Se ha añadido a Distutils un sencillo soporte de dependencias. La función setup() ahora tiene parámetros de palabras clave requires, provides y obsoletes. Cuando se construye una distribución de origen utilizando el comando sdist, la información de las dependencias se registrará en el archivo PKG-INFO.

Otro nuevo parámetro de palabra clave es download_url, que debe establecerse como una URL para el código fuente del paquete. Esto significa que ahora es posible buscar una entrada en el índice de paquetes, determinar las dependencias de un paquete y descargar los paquetes necesarios.

VERSION = '1.0'
setup(name='PyPackage',
      version=VERSION,
      requires=['numarray', 'zlib (>=1.1.4)'],
      obsoletes=['OldPackage']
      download_url=('http://www.example.com/pypackage/dist/pkg-%s.tar.gz'
                    % VERSION),
     )

Otra nueva mejora en el índice de paquetes de Python en https://pypi.org es el almacenamiento de archivos fuente y binarios de un paquete. El nuevo comando upload de Distutils subirá un paquete al repositorio.

Antes de poder subir un paquete, debes ser capaz de construir una distribución usando el comando sdist de Distutils. Una vez que funcione, puedes ejecutar python setup.py upload para añadir tu paquete al archivo PyPI. Opcionalmente puedes firmar el paquete con GPG suministrando las opciones --sign y --identity.

La carga de paquetes fue implementada por Martin von Löwis y Richard Jones.

Ver también

PEP 314 - Metadatos para paquetes de software Python v1.1

PEP propuesto y redactado por A.M. Kuchling, Richard Jones y Fred Drake; aplicado por Richard Jones y Fred Drake.

PEP 328: Importaciones absolutas y relativas

La parte más sencilla de PEP 328 se implementó en Python 2.4: los paréntesis podían utilizarse ahora para encerrar los nombres importados de un módulo utilizando la sentencia from ... import ..., facilitando la importación de muchos nombres diferentes.

La parte más complicada se ha implementado en Python 2.5: la importación de un módulo puede especificarse para utilizar importaciones absolutas o relativas al paquete. El plan es hacer que las importaciones absolutas sean el valor por defecto en futuras versiones de Python.

Digamos que tienes un directorio de paquetes como este:

pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py

Esto define un paquete llamado pkg que contiene los submódulos pkg.main y pkg.string.

Considera el código del módulo main.py. ¿Qué ocurre si ejecuta la sentencia importar cadena? En Python 2.4 y anteriores, primero buscará en el directorio del paquete para realizar una importación relativa, encuentra pkg/string.py, importa el contenido de ese archivo como el módulo pkg.string, y ese módulo se vincula al nombre string en el espacio de nombres del módulo pkg.main.

Eso está bien si pkg.string era lo que querías. ¿Pero qué pasa si quieres el módulo estándar de Python string? No hay una forma limpia de ignorar pkg.string y buscar el módulo estándar; generalmente tienes que mirar el contenido de sys.modules, lo cual es ligeramente sucio. El paquete py.std de Holger Krekel proporciona una forma más ordenada de realizar importaciones desde la biblioteca estándar, import py; py.std.string.join(), pero ese paquete no está disponible en todas las instalaciones de Python.

La lectura de código que depende de importaciones relativas también es menos clara, porque un lector puede confundirse sobre qué módulo, cadena o cadena.pkg, se pretende utilizar. Los usuarios de Python aprendieron pronto a no duplicar los nombres de los módulos de la biblioteca estándar en los nombres de los submódulos de sus paquetes, pero no puedes protegerte de que el nombre de tu submódulo se utilice para un nuevo módulo añadido en una futura versión de Python.

En Python 2.5, puedes cambiar el comportamiento de import a importaciones absolutas usando una directiva from __future__ import absolute_import. Este comportamiento de importación absoluta será el predeterminado en una versión futura (probablemente Python 2.7). Una vez que las importaciones absolutas sean el valor por defecto, import string siempre encontrará la versión de la biblioteca estándar. Se sugiere que los usuarios comiencen a usar importaciones absolutas tanto como sea posible, así que es preferible comenzar a escribir de pkg import string en su código.

Las importaciones relativas siguen siendo posibles añadiendo un punto inicial al nombre del módulo cuando se utiliza la forma from ... import:

# Import names from pkg.string
from .string import name1, name2
# Import pkg.string
from . import string

Esto importa el módulo string relativo al paquete actual, así que en pkg.main esto importará nombre1 y nombre2 de pkg.string. Los puntos iniciales adicionales realizan la importación relativa empezando por el padre del paquete actual. Por ejemplo, el código en el módulo A.B.C puede hacer:

from . import D                 # Imports A.B.D
from .. import E                # Imports A.E
from ..F import G               # Imports A.F.G

Los puntos suspensivos no pueden usarse con la forma importar nombre de modelo de la sentencia import, sólo con la forma de ... import.

Ver también

PEP 328 - Importaciones: Multilínea y Absoluto/Relativo

PEP escrito por Aahz; implementado por Thomas Wouters.

https://pylib.readthedocs.io/

La biblioteca py de Holger Krekel, que contiene el paquete py.std.

PEP 338: Ejecutando Módulos como Scripts

El conmutador -m añadido en Python 2.4 para ejecutar un módulo como un script ganó algunas habilidades más. En lugar de estar implementado en código C dentro del intérprete de Python, el interruptor ahora utiliza una implementación en un nuevo módulo, runpy.

El módulo runpy implementa un mecanismo de importación más sofisticado de forma que ahora es posible ejecutar módulos en un paquete como pychecker.checker. El módulo también soporta mecanismos de importación alternativos como el módulo zipimport. Esto significa que puede añadir la ruta de un archivo .zip a sys.path y luego utilizar el modificador -m para ejecutar el código del archivo.

Ver también

PEP 338 - Ejecución de módulos como scripts

PEP escrito e implementado por Nick Coghlan.

PEP 341: Try/except/finally unificados

Hasta la versión 2.5 de Python, la sentencia try tenía dos variantes. Podías usar un bloque finally para asegurarte de que el código se ejecutaba siempre, o uno o más bloques except para capturar excepciones específicas. No podías combinar ambos bloques except y un bloque finally, porque generar el bytecode correcto para la versión combinada era complicado y no estaba claro cuál debía ser la semántica de la sentencia combinada.

Guido van Rossum pasó algún tiempo trabajando con Java, que sí soporta el equivalente de combinar bloques except y un bloque finally, y esto aclaró lo que debería significar la declaración. En Python 2.5, ahora se puede escribir:

try:
    block-1 ...
except Exception1:
    handler-1 ...
except Exception2:
    handler-2 ...
else:
    else-block
finally:
    final-block

Se ejecuta el código del bloque-1. Si el código lanza una excepción, se comprueban los distintos bloques except: si la excepción es de clase Exception1, se ejecuta handler-1; en caso contrario, si es de clase Exception2, se ejecuta handler-2, y así sucesivamente. Si no se produce ninguna excepción, se ejecuta el bloque else.

No importa lo que haya sucedido previamente, el bloque final se ejecuta una vez que el bloque de código se ha completado y se han manejado las excepciones planteadas. Incluso si hay un error en un manejador de excepciones o en el bloque else y se lanza una nueva excepción, el código del bloque final se sigue ejecutando.

Ver también

PEP 341 - Unificar try-except y try-finally

PEP escrito por Georg Brandl; implementación por Thomas Lee.

PEP 342: Nuevas funciones del generador

Python 2.5 añade una forma sencilla de pasar valores a un generador. Tal y como se introdujo en Python 2.3, los generadores sólo producen salida; una vez que se invoca el código de un generador para crear un iterador, no hay forma de pasar ninguna información nueva a la función cuando se reanuda su ejecución. A veces, la capacidad de pasar alguna información sería útil. Las soluciones más ingeniosas para esto incluyen hacer que el código del generador mire a una variable global y luego cambie el valor de la variable global, o pasar algún objeto mutable que los llamadores luego modifiquen.

Para refrescar la memoria de los generadores básicos, he aquí un ejemplo sencillo:

def counter (maximum):
    i = 0
    while i < maximum:
        yield i
        i += 1

Cuando se llama a contador(10), el resultado es un iterador que devuelve los valores de 0 a 9. Al encontrar la sentencia yield, el iterador devuelve el valor proporcionado y suspende la ejecución de la función, preservando las variables locales. La ejecución se reanuda en la siguiente llamada al método next() del iterador, retomando después de la sentencia yield.

En Python 2.3, yield era una declaración; no devolvía ningún valor. En 2.5, yield es ahora una expresión, que devuelve un valor que se puede asignar a una variable o que se puede operar de otra manera:

val = (yield i)

Te recomiendo que siempre pongas paréntesis alrededor de una expresión yield cuando estés haciendo algo con el valor devuelto, como en el ejemplo anterior. Los paréntesis no siempre son necesarios, pero es más fácil añadirlos siempre en lugar de tener que recordar cuándo son necesarios.

(PEP 342 explica las reglas exactas, que consisten en que una expresión yielddebe ir siempre entre paréntesis, excepto cuando ocurre en la expresión de nivel superior en el lado derecho de una asignación. Esto significa que puedes escribir val = yield i pero tienes que usar paréntesis cuando hay una operación, como en val = (yield i) + 12)

Los valores se envían a un generador llamando a su método send(value). El código del generador se reanuda y la expresión yield devuelve el valor especificado. Si se llama al método regular next(), la expresión yield devuelve None.

Aquí está el ejemplo anterior, modificado para permitir cambiar el valor del contador interno.

def counter (maximum):
    i = 0
    while i < maximum:
        val = (yield i)
        # If value provided, change counter
        if val is not None:
            i = val
        else:
            i += 1

Y aquí hay un ejemplo de cambio de contador:

>>> it = counter(10)
>>> print it.next()
0
>>> print it.next()
1
>>> print it.send(8)
8
>>> print it.next()
9
>>> print it.next()
Traceback (most recent call last):
  File "t.py", line 15, in ?
    print it.next()
StopIteration

yield normalmente devolverá None, por lo que siempre debes comprobar este caso. No utilices su valor en las expresiones sin más, a menos que estés seguro de que el método send() será el único utilizado para reanudar tu función generadora.

Además de send(), hay otros dos nuevos métodos en los generadores:

  • throw(type, value=None, traceback=None) se utiliza para lanzar una excepción dentro del generador; la excepción es lanzada por la expresión yield donde la ejecución del generador se pausa.

  • close() lanza una nueva excepción GeneratorExit dentro del generador para terminar la iteración. Al recibir esta excepción, el código del generador debe lanzar GeneratorExit o StopIteration. Capturar la excepción GeneratorExit y devolver un valor es ilegal y provocará un RuntimeError; si la función lanza alguna otra excepción, esa excepción se propaga a quien la llama. close() también será llamado por el recolector de basura de Python cuando el generador sea recolectado.

    Si necesitas ejecutar código de limpieza cuando se produce un GeneratorExit, te sugiero que utilices un conjunto try: ... finally: en lugar de atrapar GeneratorExit.

El efecto acumulativo de estos cambios es que los generadores pasan de ser productores unidireccionales de información a ser tanto productores como consumidores.

Los generadores también se convierten en corutinas, una forma más generalizada de subrutinas. Las subrutinas se introducen en un punto y se salen en otro (la parte superior de la función, y una declaración return), pero las coroutines pueden introducirse, salirse y reanudarse en muchos puntos diferentes (las declaraciones yield). Tendremos que descubrir patrones para usar coroutines de forma efectiva en Python.

La adición del método close() tiene un efecto secundario que no es obvio. close() es llamado cuando un generador es recogido por la basura, lo que significa que el código del generador tiene una última oportunidad de ejecutarse antes de que el generador sea destruido. Esta última oportunidad significa que ahora se puede garantizar que las sentencias intentar...finalmente en los generadores funcionen; la cláusula finally ahora siempre tendrá una oportunidad de ejecutarse. Por lo tanto, se ha eliminado la restricción sintáctica que impedía mezclar sentencias yield con un conjunto try...finally. Esto parece una trivialidad menor del lenguaje, pero el uso de generadores y try...finally es realmente necesario para implementar la sentencia with descrita por PEP 343. Veré esta nueva sentencia en la siguiente sección.

Otro efecto aún más esotérico de este cambio: antes, el atributo gi_frame de un generador era siempre un objeto frame. Ahora es posible que gi_frame sea None una vez que el generador se ha agotado.

Ver también

PEP 342 - Coroutines mediante generadores mejorados

PEP escrito por Guido van Rossum y Phillip J. Eby; implementado por Phillip J. Eby. Incluye ejemplos de algunos usos más sofisticados de los generadores como coroutines.

Versiones anteriores de estas características fueron propuestas en PEP 288 por Raymond Hettinger y PEP 325 por Samuele Pedroni.

https://en.wikipedia.org/wiki/Coroutine

La entrada de Wikipedia para las coroutines.

https://web.archive.org/web/20160321211320/http://www.sidhe.org/~dan/blog/archives/000178.html

Una explicación de las coroutines desde el punto de vista de Perl, escrita por Dan Sugalski.

PEP 343: La declaración «con

La sentencia “with” aclara el código que antes utilizaba bloques try...finally” para asegurar que se ejecuta el código de limpieza. En esta sección, hablaré de la sentencia tal y como se utiliza habitualmente. En la siguiente sección, examinaré los detalles de la implementación y mostraré cómo escribir objetos para usar con esta sentencia.

La declaración “with” es una nueva estructura de flujo de control cuya estructura básica es:

with expression [as variable]:
    with-block

La expresión se evalúa y debe dar como resultado un objeto que soporte el protocolo de gestión de contextos (es decir, que tenga los métodos __enter__() y __exit__()).

El __enter__() del objeto es llamado antes de que se ejecute with-block y por lo tanto puede ejecutar código de configuración. También puede devolver un valor ligado al nombre variable, si se da. (Observe cuidadosamente que a variable no se le asigna el resultado de la expresión)

Una vez finalizada la ejecución del with-block, se llama al método __exit__() del objeto, incluso si el bloque lanzó una excepción, y por lo tanto puede ejecutar código de limpieza.

Para habilitar la declaración en Python 2.5, debe añadir la siguiente directiva a su módulo:

from __future__ import with_statement

La declaración siempre estará habilitada en Python 2.6.

Algunos objetos estándar de Python soportan ahora el protocolo de gestión de contextos y pueden utilizarse con la sentencia “with””. Los objetos de archivo son un ejemplo:

with open('/etc/passwd', 'r') as f:
    for line in f:
        print line
        ... more processing code ...

Después de que esta sentencia se haya ejecutado, el objeto archivo en f se habrá cerrado automáticamente, incluso si el bucle for lanzó una excepción a mitad del bloque.

Nota

En este caso, f es el mismo objeto creado por open(), porque file.__enter__() devuelve self.

Los bloqueos y las variables de condición del módulo threading también soportan la sentencia “with”:

lock = threading.Lock()
with lock:
    # Critical section of code
    ...

El bloqueo se adquiere antes de que se ejecute el bloque y siempre se libera una vez que el bloque se ha completado.

La nueva función localcontext() del módulo decimal facilita el guardado y la restauración del contexto decimal actual, que encapsula las características de precisión y redondeo deseadas para los cálculos:

from decimal import Decimal, Context, localcontext

# Displays with default precision of 28 digits
v = Decimal('578')
print v.sqrt()

with localcontext(Context(prec=16)):
    # All code in this block uses a precision of 16 digits.
    # The original context is restored on exiting the block.
    print v.sqrt()

Redacción de Gestores de Contexto

Bajo el capó, la sentencia “with” es bastante complicada. La mayoría de la gente sólo utilizará “with” en compañía de objetos existentes y no necesita conocer estos detalles, así que puedes saltarte el resto de esta sección si quieres. Los autores de nuevos objetos necesitarán entender los detalles de la implementación subyacente y deberían seguir leyendo.

Una explicación de alto nivel del protocolo de gestión del contexto es:

  • La expresión se evalúa y debe dar como resultado un objeto llamado «gestor de contexto». El gestor de contexto debe tener métodos __enter__() y __exit__().

  • Se llama al método __enter__() del gestor de contexto. El valor devuelto se asigna a VAR. Si no está presente la cláusula 'as VAR', el valor simplemente se descarta.

  • Se ejecuta el código en BLOQUE.

  • Si BLOCK lanza una excepción, se llama a __exit__(type, value, traceback) con los detalles de la excepción, los mismos valores devueltos por sys.exc_info(). El valor de retorno del método controla si la excepción se vuelve a lanzar: cualquier valor falso vuelve a lanzar la excepción, y True resultará en suprimirla. Sólo en raras ocasiones querrá suprimir la excepción, porque si lo hace el autor del código que contiene la declaración “with” nunca se dará cuenta de que algo ha ido mal.

  • Si BLOCK no lanzó una excepción, el método __exit__() sigue siendo llamado, pero type, value, y traceback son todos None.

Pensemos en un ejemplo. No presentaré un código detallado, sino que sólo esbozaré los métodos necesarios para una base de datos que soporte transacciones.

(Para quienes no estén familiarizados con la terminología de las bases de datos: un conjunto de cambios en la base de datos se agrupa en una transacción. Las transacciones pueden ser confirmadas, lo que significa que todos los cambios se escriben en la base de datos, o revertidas, lo que significa que todos los cambios se descartan y la base de datos no se modifica. Consulte cualquier libro de texto sobre bases de datos para obtener más información)

Supongamos que hay un objeto que representa una conexión a la base de datos. Nuestro objetivo será permitir que el usuario escriba código como este:

db_connection = DatabaseConnection()
with db_connection as cursor:
    cursor.execute('insert into ...')
    cursor.execute('delete from ...')
    # ... more operations ...

La transacción debe ser confirmada si el código en el bloque se ejecuta sin problemas o revertida si hay una excepción. Aquí está la interfaz básica para DatabaseConnection que voy a asumir:

class DatabaseConnection:
    # Database interface
    def cursor (self):
        "Returns a cursor object and starts a new transaction"
    def commit (self):
        "Commits current transaction"
    def rollback (self):
        "Rolls back current transaction"

El método __enter__() es bastante sencillo, ya que sólo hay que iniciar una nueva transacción. Para esta aplicación el objeto cursor resultante sería un resultado útil, por lo que el método lo devolverá. El usuario puede entonces añadir as cursor a su sentencia “with” para ligar el cursor a un nombre de variable.

class DatabaseConnection:
    ...
    def __enter__ (self):
        # Code to start a new transaction
        cursor = self.cursor()
        return cursor

El método __exit__() es el más complicado porque es donde hay que hacer la mayor parte del trabajo. El método tiene que comprobar si se produjo una excepción. Si no hubo ninguna excepción, la transacción es confirmada. La transacción es revertida si hubo una excepción.

En el código de abajo, la ejecución simplemente caerá al final de la función, devolviendo el valor por defecto de None. None es falso, por lo que la excepción se volverá a lanzar automáticamente. Si lo desea, puede ser más explícito y añadir una declaración return en el lugar marcado.

class DatabaseConnection:
    ...
    def __exit__ (self, type, value, tb):
        if tb is None:
            # No exception, so commit
            self.commit()
        else:
            # Exception occurred, so rollback.
            self.rollback()
            # return False

El módulo contextlib

El nuevo módulo contextlib proporciona algunas funciones y un decorador que son útiles para escribir objetos para usar con la sentencia “with”.

El decorador se llama contextmanager(), y permite escribir una única función generadora en lugar de definir una nueva clase. El generador debe producir exactamente un valor. El código hasta la palabra clave yield se ejecutará como el método __enter__(), y el valor producido será el valor de retorno del método que se vinculará a la variable en la cláusula with de la sentencia as, si existe. El código después de yield se ejecutará en el método __exit__(). Cualquier excepción lanzada en el bloque será lanzada por la sentencia yield.

Nuestro ejemplo de base de datos de la sección anterior podría escribirse utilizando este decorador como:

from contextlib import contextmanager

@contextmanager
def db_transaction (connection):
    cursor = connection.cursor()
    try:
        yield cursor
    except:
        connection.rollback()
        raise
    else:
        connection.commit()

db = DatabaseConnection()
with db_transaction(db) as cursor:
    ...

El módulo contextlib también tiene una función anidada(mgr1, mgr2, ...) que combina varios gestores de contexto para que no sea necesario escribir sentencias “with” anidadas. En este ejemplo, la única sentencia “with` inicia una transacción de base de datos y adquiere un bloqueo de hilo:

lock = threading.Lock()
with nested (db_transaction(db), lock) as (cursor, locked):
    ...

Por último, la función closing(object) devuelve el objeto para que pueda ser vinculado a una variable, y llama a object.close al final del bloque.

import urllib, sys
from contextlib import closing

with closing(urllib.urlopen('http://www.yahoo.com')) as f:
    for line in f:
        sys.stdout.write(line)

Ver también

PEP 343 - La declaración «con»

PEP escrito por Guido van Rossum y Nick Coghlan; implementado por Mike Bland, Guido van Rossum y Neal Norwitz. El PEP muestra el código generado para una sentencia “with”, que puede ser útil para aprender cómo funciona la sentencia.

La documentación del módulo contextlib.

PEP 352: Las excepciones como clases de nuevo estilo

Las clases de excepción ahora pueden ser clases de nuevo estilo, no sólo clases clásicas, y la clase incorporada Exception y todas las excepciones incorporadas estándar (NameError, ValueError, etc.) son ahora clases de nuevo estilo.

La jerarquía de herencia de las excepciones se ha reordenado un poco. En 2.5, las relaciones de herencia son:

BaseException       # New in Python 2.5
|- KeyboardInterrupt
|- SystemExit
|- Exception
   |- (all other current built-in exceptions)

Esta reorganización se hizo porque la gente a menudo quiere atrapar todas las excepciones que indican errores del programa. KeyboardInterrupt y SystemExit no son errores, sin embargo, y por lo general representan una acción explícita como el usuario pulsando Control-C o el código llamando a sys.exit(). Una simple except: atrapará todas las excepciones, por lo que comúnmente se necesita listar KeyboardInterrupt y SystemExit para volver a lanzarlas. El patrón habitual es:

try:
    ...
except (KeyboardInterrupt, SystemExit):
    raise
except:
    # Log error...
    # Continue running program...

En Python 2.5, ahora puedes escribir except Exception para conseguir el mismo resultado, capturando todas las excepciones que suelen indicar errores pero dejando KeyboardInterrupt y SystemExit en paz. Como en versiones anteriores, un except: desnudo sigue capturando todas las excepciones.

El objetivo de Python 3.0 es requerir que cualquier clase lanzada como excepción derive de BaseException o de algún descendiente de BaseException, y las futuras versiones de la serie Python 2.x pueden empezar a imponer esta restricción. Por lo tanto, sugiero que empieces a hacer que todas tus clases de excepción deriven de Exception ahora. Se ha sugerido que la forma desnuda except: sea eliminada en Python 3.0, pero Guido van Rossum no ha decidido si hacerlo o no.

El lanzamiento de cadenas como excepciones, como en la declaración raise "Error occurred", está obsoleto en Python 2.5 y provocará una advertencia. El objetivo es poder eliminar la función de excepción de cadena en algunas versiones.

Ver también

PEP 352 - Superclase necesaria para las excepciones

PEP escrito por Brett Cannon y Guido van Rossum; implementado por Brett Cannon.

PEP 353: Uso de ssize_t como tipo de índice

Un cambio de gran alcance en la API C de Python, que usa una nueva definición de tipo Py_ssize_t en lugar de int, permitirá que el intérprete maneje más datos en plataformas de 64 bits. Este cambio no afecta la capacidad de Python en plataformas de 32 bits.

Varias piezas del intérprete de Python usaban el tipo int de C para almacenar tamaños o conteos; por ejemplo, la cantidad de elementos en una lista o tupla se almacenaron en un int. Los compiladores de C para la mayoría de las plataformas de 64 bits aún definen int como un tipo de 32 bits, lo que significa que las listas solo pueden contener hasta 2**31 - 1 = 2147483647 elementos. (En realidad, hay algunos modelos de programación diferentes que los compiladores de C de 64 bits pueden usar; consulte https://unix.org/version2/whatsnew/lp64_wp.html para ver una discusión, pero el modelo más comúnmente disponible deja :c: expr:int como 32 bits).

Un límite de 2147483647 elementos no importa realmente en una plataforma de 32 bits porque te quedarás sin memoria antes de alcanzar el límite de longitud. Cada elemento de la lista requiere espacio para un puntero, que es de 4 bytes, más espacio para un PyObject que representa el elemento. 2147483647*4 ya son más bytes de los que puede contener un espacio de direcciones de 32 bits.

Sin embargo, es posible abordar esa cantidad de memoria en una plataforma de 64 bits. Los punteros para una lista de ese tamaño solo requerirían 16 GiB de espacio, por lo que no es irrazonable que los programadores de Python puedan construir listas tan grandes. Por lo tanto, el intérprete de Python tuvo que cambiarse para usar algún tipo diferente a int, y este será un tipo de 64 bits en plataformas de 64 bits. El cambio provocará incompatibilidades en las máquinas de 64 bits, por lo que se consideró que valía la pena hacer la transición ahora, mientras que la cantidad de usuarios de 64 bits aún es relativamente pequeña. (En 5 o 10 años, es posible que todo esté en máquinas de 64 bits y la transición sería más dolorosa entonces).

Este cambio afecta en mayor medida a los autores de módulos de extensión de C. Las cadenas de Python y los tipos contenedores como las listas y las tuplas utilizan ahora Py_ssize_t para almacenar su tamaño. Funciones como PyList_Size() ahora devuelven Py_ssize_t. Por lo tanto, el código de los módulos de extensión puede necesitar cambiar algunas variables a Py_ssize_t.

Las funciones PyArg_ParseTuple() y Py_BuildValue() tienen un nuevo código de conversión, n, para Py_ssize_t. s# y t# de PyArg_ParseTuple() aún generan int de forma predeterminada, pero puede definir la macro PY_SSIZE_T_CLEAN antes de incluir Python.h para que devuelvan Py_ssize_t.

PEP 353 tiene una sección sobre directrices de conversión que los autores de extensiones deberían leer para aprender a soportar plataformas de 64 bits.

Ver también

PEP 353 - Uso de ssize_t como tipo de índice

PEP escrito y aplicado por Martin von Löwis.

PEP 357: El método “__index__”

Los desarrolladores de NumPy tenían un problema que sólo podía resolverse añadiendo un nuevo método especial, __index__(). Cuando se utiliza la notación de trozos, como en [start:stop:step], los valores de los índices start, stop y step deben ser todos enteros o enteros largos. NumPy define una variedad de tipos de enteros especializados que corresponden a enteros sin signo y con signo de 8, 16, 32 y 64 bits, pero no había forma de señalar que estos tipos pudieran usarse como índices de trozos.

El rebanado no puede utilizar el método __int__() existente porque ese método también se utiliza para implementar la coerción a enteros. Si el rebanado utilizara __int__(), los números de punto flotante también se convertirían en índices de rebanada legales y eso es claramente un comportamiento indeseable.

En su lugar, se ha añadido un nuevo método especial llamado __index__(). No toma argumentos y devuelve un entero que da el índice de corte a utilizar. Por ejemplo:

class C:
    def __index__ (self):
        return self.value

El valor devuelto debe ser un entero de Python o un entero largo. El intérprete comprobará que el tipo devuelto es correcto, y lanza un TypeError si no se cumple este requisito.

Se ha añadido la correspondiente ranura nb_index a la estructura PyNumberMethods de nivel C para que las extensiones C puedan implementar este protocolo. El código de la extensión puede utilizar PyNumber_Index(obj) para llamar a la función __index__() y obtener su resultado.

Ver también

PEP 357 - Permitir el uso de cualquier objeto para rebanar

PEP escrito e implementado por Travis Oliphant.

Otros cambios lingüísticos

Estos son todos los cambios que Python 2.5 introduce en el núcleo del lenguaje Python.

  • El tipo dict tiene un nuevo gancho para permitir que las subclases proporcionen un valor por defecto cuando una clave no está contenida en el diccionario. Cuando no se encuentre una clave, se llamará al método missing__(key) del diccionario. Este hook se utiliza para implementar la nueva clase defaultdict en el módulo collections. El siguiente ejemplo define un diccionario que devuelve cero para cualquier clave que falte:

    class zerodict (dict):
        def __missing__ (self, key):
            return 0
    
    d = zerodict({1:1, 2:2})
    print d[1], d[2]   # Prints 1, 2
    print d[3], d[4]   # Prints 0, 0
    
  • Tanto las cadenas de 8 bits como las de Unicode tienen nuevos métodos partition(sep) y rpartition(sep) que simplifican un caso de uso común.

    El método find(S) se utiliza a menudo para obtener un índice que luego se utiliza para cortar la cadena y obtener las piezas que están antes y después del separador. El método partition(sep) condensa este patrón en una sola llamada al método que devuelve una tripleta que contiene la subcadena antes del separador, el propio separador y la subcadena después del separador. Si no se encuentra el separador, el primer elemento de la tupla es la cadena completa y los otros dos elementos están vacíos. rpartition(sep) también devuelve una tupla de 3 elementos, pero empieza a buscar desde el final de la cadena; la r significa «al revés».

    Algunos ejemplos:

    >>> ('http://www.python.org').partition('://')
    ('http', '://', 'www.python.org')
    >>> ('file:/usr/share/doc/index.html').partition('://')
    ('file:/usr/share/doc/index.html', '', '')
    >>> (u'Subject: a quick question').partition(':')
    (u'Subject', u':', u' a quick question')
    >>> 'www.python.org'.rpartition('.')
    ('www.python', '.', 'org')
    >>> 'www.python.org'.rpartition(':')
    ('', '', 'www.python.org')
    

    (Implementado por Fredrik Lundh tras una sugerencia de Raymond Hettinger)

  • Los métodos startswith() y endswith() de los tipos de cadena aceptan ahora tuplas de cadenas para su comprobación.

    def is_image_file (filename):
        return filename.endswith(('.gif', '.jpg', '.tiff'))
    

    (Implementado por Georg Brandl tras una sugerencia de Tom Lynn)

  • Las funciones incorporadas min() y max() han ganado un parámetro de palabra clave key análogo al argumento key de sort(). Este parámetro proporciona una función que toma un único argumento y es llamada para cada valor de la lista; min()/max() devolverá el elemento con el valor de retorno más pequeño/más grande de esta función. Por ejemplo, para encontrar la cadena más larga de una lista, puede hacer:

    L = ['medium', 'longest', 'short']
    # Prints 'longest'
    print max(L, key=len)
    # Prints 'short', because lexicographically 'short' has the largest value
    print max(L)
    

    (Contribución de Steven Bethard y Raymond Hettinger)

  • Dos nuevas funciones incorporadas, any() y all(), evalúan si un iterador contiene algún valor verdadero o falso. any() devuelve True si cualquier valor devuelto por el iterador es verdadero; en caso contrario devolverá False. all() devuelve True sólo si todos los valores devueltos por el iterador se evalúan como verdaderos. (Sugerido por Guido van Rossum, e implementado por Raymond Hettinger)

  • El resultado del método __hash__() de una clase puede ser ahora un entero largo o un entero normal. Si se devuelve un entero largo, se toma el hash de ese valor. En versiones anteriores se requería que el valor del hash fuera un entero regular, pero en 2.5 el built-in id() se cambió para devolver siempre números no negativos, y los usuarios parecen utilizar a menudo id(self) en los métodos __hash__() (aunque esto se desaconseja).

  • ASCII es ahora la codificación por defecto para los módulos. Ahora es un error de sintaxis si un módulo contiene literales de cadena con caracteres de 8 bits pero no tiene una declaración de codificación. En Python 2.4 esto provocaba una advertencia, no un error de sintaxis. Vea en PEP 263 cómo declarar la codificación de un módulo; por ejemplo, puede añadir una línea como ésta cerca de la parte superior del fichero fuente:

    # -*- coding: latin1 -*-
    
  • Una nueva advertencia, UnicodeWarning, se activa cuando se intenta comparar una cadena Unicode y una cadena de 8 bits que no se puede convertir a Unicode utilizando la codificación ASCII por defecto. El resultado de la comparación es falso:

    >>> chr(128) == unichr(128)   # Can't convert chr(128) to Unicode
    __main__:1: UnicodeWarning: Unicode equal comparison failed
      to convert both arguments to Unicode - interpreting them
      as being unequal
    False
    >>> chr(127) == unichr(127)   # chr(127) can be converted
    True
    

    Anteriormente, esto lanzaba una excepción UnicodeDecodeError, pero en 2.5 esto podía dar lugar a problemas desconcertantes al acceder a un diccionario. Si se buscaba unichr(128) y se utilizaba chr(128) como clave, se producía una excepción UnicodeDecodeError. Otros cambios en la versión 2.5 hicieron que esta excepción se lanzara en lugar de ser suprimida por el código de dictobject.c que implementa los diccionarios.

    Lanzar una excepción para tal comparación es estrictamente correcto, pero el cambio podría haber roto el código, así que en su lugar se introdujo UnicodeWarning.

    (Implementado por Marc-André Lemburg.)

  • Un error que a veces cometen los programadores de Python es olvidarse de incluir un módulo __init__.py en el directorio de un paquete. Depurar este error puede ser confuso, y normalmente requiere ejecutar Python con el modificador -v para registrar todas las rutas buscadas. En Python 2.5, una nueva advertencia ImportWarning se activa cuando una importación habría recogido un directorio como paquete pero no se encontró ningún __init__.py. Esta advertencia se ignora silenciosamente por defecto; proporcione la opción -Wd cuando ejecute el ejecutable de Python para mostrar el mensaje de advertencia. (Implementado por Thomas Wouters)</-W>

  • La lista de clases base en una definición de clase ahora puede estar vacía. Como ejemplo, esto es ahora legal:

    class C():
        pass
    

    (Implementado por Brett Cannon.)

Cambios en el intérprete interactivo

En el intérprete interactivo, quit y exit han sido durante mucho tiempo cadenas para que los nuevos usuarios obtengan un mensaje algo útil cuando intenten salir:

>>> quit
'Use Ctrl-D (i.e. EOF) to exit.'

En Python 2.5, quit y exit son ahora objetos que siguen produciendo representaciones de cadena de sí mismos, pero también son invocables. Los novatos que prueben quit() o exit() ahora saldrán del intérprete como se espera. (Implementado por Georg Brandl.)

El ejecutable de Python ahora acepta las opciones largas estándar --help y --version; en Windows, también acepta la opción /? para mostrar un mensaje de ayuda. (Implementado por Georg Brandl)

Optimizaciones

Varias de las optimizaciones se desarrollaron en el sprint NeedForSpeed, un evento celebrado en Reikiavik, Islandia, del 21 al 28 de mayo de 2006. El sprint se centró en las mejoras de velocidad de la implementación de CPython y fue financiado por EWT LLC con el apoyo local de CCP Games. Las optimizaciones añadidas en este sprint están especialmente marcadas en la siguiente lista.

  • Cuando se introdujeron en Python 2.4, los tipos incorporados set y frozenset se construyeron sobre el tipo diccionario de Python. En 2.5 la estructura de datos interna se ha personalizado para implementar conjuntos, y como resultado los conjuntos utilizarán un tercio menos de memoria y son algo más rápidos. (Implementado por Raymond Hettinger)

  • Se ha mejorado la velocidad de algunas operaciones Unicode, como la búsqueda de subcadenas, la división de cadenas y la codificación y decodificación de mapas de caracteres. (Las mejoras en la búsqueda de subcadenas y la división fueron añadidas por Fredrik Lundh y Andrew Dalke en el sprint NeedForSpeed. Los mapas de caracteres fueron mejorados por Walter Dörwald y Martin von Löwis)

  • La función long(str, base) es ahora más rápida en cadenas de dígitos largos porque se calculan menos resultados intermedios. El máximo es para cadenas de alrededor de 800-1000 dígitos, donde la función es 6 veces más rápida. (Aportado por Alan McIntyre y comprometido en el sprint NeedForSpeed)

  • Ahora es ilegal mezclar la iteración sobre un fichero con for line in file y llamar a los métodos read()/readline()/readlines() del objeto fichero. La iteración utiliza un buffer interno y los métodos read*() no utilizan ese buffer. En su lugar, devolverán los datos que siguen al buffer, haciendo que los datos aparezcan desordenados. Mezclar la iteración y estos métodos provocará ahora un ValueError del método read*(). (Implementado por Thomas Wouters)

  • El módulo struct ahora compila cadenas de formato de estructura en una representación interna y almacena en caché esta representación, lo que supone una mejora del 20% s. (Contribuido por Bob Ippolito en el sprint NeedForSpeed)

  • El módulo re obtuvo un 1 o 2% s de velocidad al cambiar a las funciones asignadoras de Python en lugar de las malloc() y free() del sistema. (Contribuido por Jack Diederich en el sprint NeedForSpeed)

  • El optimizador de la mirilla del generador de código realiza ahora un simple plegado de constantes en las expresiones. Si escribes algo como a = 2+3, el generador de código hará la aritmética y producirá el código correspondiente a a = 5. (Propuesto e implementado por Raymond Hettinger)

  • Las llamadas a funciones son ahora más rápidas porque los objetos de código guardan ahora el último fotograma terminado (un «fotograma zombi») en un campo interno del objeto de código, reutilizándolo la próxima vez que se invoque el objeto de código. (Parche original de Michael Hudson, modificado por Armin Rigo y Richard Jones; confirmado en el sprint NeedForSpeed) Los objetos marco son también ligeramente más pequeños, lo que puede mejorar la localidad de la caché y reducir un poco el uso de la memoria. (Contribución de Neal Norwitz)

  • Las excepciones incorporadas en Python son ahora clases de nuevo estilo, un cambio que acelera considerablemente la instanciación. El manejo de excepciones en Python 2.5 es, por tanto, un 30% f más rápido que en 2.4. (Contribución de Richard Jones, Georg Brandl y Sean Reifschneider en el sprint NeedForSpeed)

  • La importación ahora almacena en caché las rutas intentadas, registrando si existen o no para que el intérprete haga menos llamadas a open() y stat() al iniciar. (Contribución de Martin von Löwis y Georg Brandl)

Módulos nuevos, mejorados y eliminados

La biblioteca estándar ha recibido muchas mejoras y correcciones de errores en Python 2.5. Aquí hay una lista parcial de los cambios más notables, ordenados alfabéticamente por el nombre del módulo. Consulte el archivo Misc/NEWS en el árbol de fuentes para obtener una lista más completa de los cambios, o busque en los registros de SVN para obtener todos los detalles.

  • El módulo audioop soporta ahora la codificación a-LAW, y se ha mejorado el código para la codificación u-LAW. (Contribución de Lars Immisch)

  • El módulo codecs ha ganado soporte para códecs incrementales. La función codec.lookup() devuelve ahora una instancia de CodecInfo en lugar de una tupla. Las instancias de CodecInfo se comportan como una cuádruple tupla para preservar la compatibilidad con versiones anteriores, pero también tienen los atributos encode, decode, incrementalencoder, incrementaldecoder, streamwriter y streamreader. Los códecs incrementales pueden recibir la entrada y producir la salida en varios trozos; la salida es la misma que si la entrada completa fuera alimentada por el códec no incremental. Consulte la documentación del módulo codecs para más detalles. (Diseñado e implementado por Walter Dörwald)

  • El módulo collections ha ganado un nuevo tipo, defaultdict, que subclasifica el tipo estándar dict. El nuevo tipo se comporta principalmente como un diccionario pero construye un valor por defecto cuando una clave no está presente, añadiéndolo automáticamente al diccionario para el valor de la clave solicitada.

    El primer argumento del constructor de defaultdict es una función de fábrica que se llama cada vez que se solicita una clave pero no se encuentra. Esta función de fábrica no recibe argumentos, por lo que puede utilizar constructores de tipo incorporado como list() o int(). Por ejemplo, puedes hacer un índice de palabras basado en su letra inicial así:

    words = """Nel mezzo del cammin di nostra vita
    mi ritrovai per una selva oscura
    che la diritta via era smarrita""".lower().split()
    
    index = defaultdict(list)
    
    for w in words:
        init_letter = w[0]
        index[init_letter].append(w)
    

    Al imprimir index se obtiene la siguiente salida:

    defaultdict(<type 'list'>, {'c': ['cammin', 'che'], 'e': ['era'],
            'd': ['del', 'di', 'diritta'], 'm': ['mezzo', 'mi'],
            'l': ['la'], 'o': ['oscura'], 'n': ['nel', 'nostra'],
            'p': ['per'], 's': ['selva', 'smarrita'],
            'r': ['ritrovai'], 'u': ['una'], 'v': ['vita', 'via']}
    

    (Contribución de Guido van Rossum.)

  • El tipo de cola doble deque suministrado por el módulo collections tiene ahora un método remove(value) que elimina la primera aparición de value en la cola, lanzando ValueError si no se encuentra el valor. (Contribución de Raymond Hettinger)

  • Nuevo módulo: El módulo contextlib contiene funciones de ayuda para usar con la nueva sentencia “with”. Consulte la sección El módulo contextlib para obtener más información sobre este módulo.

  • Nuevo módulo: El módulo cProfile es una implementación en C del módulo existente profile que tiene una sobrecarga mucho menor. La interfaz del módulo es la misma que la de profile: se ejecuta cProfile.run('main()') para perfilar una función, se pueden guardar los datos del perfil en un archivo, etc. Todavía no se sabe si el perfilador Hotshot, que también está escrito en C pero no coincide con la interfaz del módulo profile, seguirá manteniéndose en futuras versiones de Python. (Contribución de Armin Rigo.)

    Además, el módulo pstats para analizar los datos medidos por el perfilador ahora soporta dirigir la salida a cualquier objeto archivo suministrando un argumento stream al constructor Stats. (Contribución de Skip Montanaro)

  • El módulo csv, que analiza archivos en formato de valores separados por comas, recibió varias mejoras y varias correcciones de errores. Ahora puede establecer el tamaño máximo en bytes de un campo llamando a la función csv.field_size_limit(new_limit); omitir el argumento new_limit devolverá el límite establecido actualmente. La clase reader ahora tiene un atributo line_num que cuenta la cantidad de líneas físicas leídas de la fuente; los registros pueden abarcar varias líneas físicas, por lo que line_num no es lo mismo que el número de registros leídos.

    El analizador CSV es ahora más estricto con los campos entrecomillados de varias líneas. Anteriormente, si una línea terminaba dentro de un campo entre comillas sin un carácter de nueva línea final, se insertaba una nueva línea en el campo devuelto. Este comportamiento causaba problemas cuando se leían archivos que contenían caracteres de retorno de carro dentro de los campos, por lo que se cambió el código para devolver el campo sin insertar nuevas líneas. Como consecuencia, si las nuevas líneas incrustadas dentro de los campos son importantes, la entrada debe dividirse en líneas de manera que se conserven los caracteres de nueva línea.

    (Contribución de Skip Montanaro y Andrew McNamara)

  • La clase datetime del módulo datetime tiene ahora un método strptime(string, format) para analizar cadenas de fechas, aportado por Josh Spoerri. Utiliza los mismos caracteres de formato que time.strptime() y time.strftime():

    from datetime import datetime
    
    ts = datetime.strptime('10:13:15 2006-03-07',
                           '%H:%M:%S %Y-%m-%d')
    
  • El método SequenceMatcher.get_matching_blocks() del módulo difflib garantiza ahora la devolución de una lista mínima de bloques que describen subsecuencias coincidentes. Anteriormente, el algoritmo rompía ocasionalmente un bloque de elementos coincidentes en dos entradas de la lista. (Mejora realizada por Tim Peters)

  • El módulo doctest ha ganado una opción SKIP que impide que un ejemplo se ejecute en absoluto. Esto está pensado para los fragmentos de código que son ejemplos de uso destinados al lector y que no son realmente casos de prueba.

    Se ha añadido un parámetro encoding a la función testfile() y a la clase DocFileSuite para especificar la codificación del archivo. Esto facilita el uso de caracteres no ASCII en las pruebas contenidas en un docstring. (Contribución de Bjorn Tillenius)

  • El paquete email ha sido actualizado a la versión 4.0. (Contribución de Barry Warsaw.)

  • El módulo fileinput se ha hecho más flexible. Ahora se soportan los nombres de archivo Unicode, y se ha añadido un parámetro mode que por defecto es "r" a la función input() para permitir la apertura de archivos en modo binario o universal newlines. Otro nuevo parámetro, openhook, permite utilizar una función distinta de open() para abrir los ficheros de entrada. Una vez que se itera sobre el conjunto de archivos, el nuevo fileno() del objeto FileInput devuelve el descriptor de archivo del archivo actualmente abierto. (Contribuido por Georg Brandl.)

  • En el módulo gc, la nueva función get_count() devuelve una 3-tupla que contiene los recuentos de recolección actuales para las tres generaciones de GC. Se trata de información contable para el recolector de basura; cuando estos recuentos alcanzan un umbral especificado, se realiza un barrido de recolección de basura. La función gc.collect() existente ahora toma un argumento opcional generación de 0, 1 o 2 para especificar qué generación recoger. (Contribución de Barry Warsaw)

  • Las funciones nsmallest() y nlargest() del módulo heapq soportan ahora un parámetro de palabra clave key similar al proporcionado por las funciones min()/max() y los métodos sort(). Por ejemplo:

    >>> import heapq
    >>> L = ["short", 'medium', 'longest', 'longer still']
    >>> heapq.nsmallest(2, L)  # Return two lowest elements, lexicographically
    ['longer still', 'longest']
    >>> heapq.nsmallest(2, L, key=len)   # Return two shortest elements
    ['short', 'medium']
    

    (Contribución de Raymond Hettinger.)

  • La función itertools.islice() ahora acepta None para los argumentos de inicio y paso. Esto la hace más compatible con los atributos de los objetos slice, por lo que ahora se puede escribir lo siguiente:

    s = slice(5)     # Create slice object
    itertools.islice(iterable, s.start, s.stop, s.step)
    

    (Contribución de Raymond Hettinger.)

  • Se ha modificado la función format() del módulo locale y se han añadido dos nuevas funciones, format_string() y currency().

    El parámetro val de la función format() podía ser antes una cadena siempre que no apareciera más de un especificador %char; ahora el parámetro debe ser exactamente un especificador %char sin texto alrededor. También se ha añadido un parámetro opcional monetario que, si es Verdadero, utilizará las reglas de la configuración regional para formatear la moneda al colocar un separador entre grupos de tres dígitos.

    Para formatear cadenas con múltiples especificadores %char, utilice la nueva función format_string() que funciona como format() pero que también permite mezclar especificadores %char con texto arbitrario.

    También se ha añadido una nueva función currency() que formatea un número de acuerdo con la configuración local actual.

    (Contribución de Georg Brandl.)

  • El módulo mailbox ha sido reestructurado de forma masiva para añadir la capacidad de modificar los buzones además de leerlos. Un nuevo conjunto de clases que incluyen mbox, MH, y Maildir se utilizan para leer buzones, y tienen un método add(message) para añadir mensajes, remove(key) para eliminar mensajes, y lock()/unlock() para bloquear/desbloquear el buzón. El siguiente ejemplo convierte un buzón con formato maildir en uno con formato mbox:

    import mailbox
    
    # 'factory=None' uses email.Message.Message as the class representing
    # individual messages.
    src = mailbox.Maildir('maildir', factory=None)
    dest = mailbox.mbox('/tmp/mbox')
    
    for msg in src:
        dest.add(msg)
    

    (Contribución de Gregory K. Johnson. La financiación fue proporcionada por el Summer of Code 2005 de Google)

  • Nuevo módulo: el módulo msilib permite crear archivos .msi de Microsoft Installer y archivos CAB. También se incluye soporte para la lectura de la base de datos .msi. (Contribución de Martin von Löwis)

  • El módulo nis soporta ahora el acceso a dominios distintos del dominio por defecto del sistema proporcionando un argumento dominio a las funciones nis.match() y nis.maps(). (Contribución de Ben Bell)

  • Las funciones operator del módulo itemgetter() y attrgetter() ahora soportan múltiples campos. Una llamada como operator.attrgetter('a', 'b') devolverá una función que recupera los atributos a y b. La combinación de esta nueva función con el parámetro key del método sort() permite ordenar fácilmente las listas utilizando varios campos. (Contribución de Raymond Hettinger)

  • El módulo optparse se ha actualizado a la versión 1.5.1 de la biblioteca Optik. La clase OptionParser obtuvo un atributo epilog, una cadena que se imprimirá después del mensaje de ayuda, y un método destroy() para romper los ciclos de referencia creados por el objeto. (Contribuido por Greg Ward.)

  • El módulo os ha sufrido varios cambios. La variable stat_float_times ahora está predeterminada a true, lo que significa que os.stat() ahora devolverá los valores de tiempo como flotantes. (Esto no significa necesariamente que os.stat() devolverá tiempos con una precisión de fracciones de segundo; no todos los sistemas soportan dicha precisión)

    Se han añadido las constantes os.SEEK_SET, os.SEEK_CUR y os.SEEK_END, que son los parámetros de la función os.lseek(). Dos nuevas constantes para el bloqueo son os.O_SHLOCK y os.O_EXLOCK.

    Se han añadido dos nuevas funciones, wait3() y wait4(). Son similares a la función waitpid() que espera la salida de un proceso hijo y devuelve una tupla con el ID del proceso y su estado de salida, pero wait3() y wait4() devuelven información adicional. wait3() no toma un ID de proceso como entrada, por lo que espera a que cualquier proceso hijo salga y devuelve una tupla de id de proceso, estado de salida, uso de recursos tal y como se devuelve desde la función resource.getrusage(). wait4(pid) toma un ID de proceso. (Contribuido por Chad J. Schroeder.)

    En FreeBSD, la función os.stat() devuelve ahora tiempos con resolución de nanosegundos, y el objeto devuelto tiene ahora st_gen y st_birthtime. El atributo st_flags también está disponible, si la plataforma lo soporta. (Contribución de Antti Louko y Diego Pettenò)

  • El depurador de Python proporcionado por el módulo pdb puede ahora almacenar listas de comandos a ejecutar cuando se alcanza un punto de ruptura y se detiene la ejecución. Una vez creado el punto de interrupción nº 1, introduzca comandos 1 e introduzca una serie de comandos a ejecutar, terminando la lista con end. La lista de comandos puede incluir comandos que reanuden la ejecución, como continue o next. (Contribución de Grégoire Dooms.)

  • Los módulos pickle y cPickle ya no aceptan un valor de retorno de None del método __reduce__(); el método debe devolver una tupla de argumentos. La capacidad de devolver None fue obsoleta en Python 2.4, así que esto completa la eliminación de la función.

  • El módulo pkgutil, que contiene varias funciones de utilidad para encontrar paquetes, fue mejorado para soportar los ganchos de importación de PEP 302 y ahora también funciona para paquetes almacenados en archivos con formato ZIP. (Contribución de Phillip J. Eby)

  • El conjunto de pruebas pybench de Marc-André Lemburg se incluye ahora en el directorio Tools/pybench. El conjunto de pruebas pybench es una mejora del programa pystone.py de uso común, ya que pybench proporciona una medición más detallada de la velocidad del intérprete. Calcula el tiempo de determinadas operaciones como las llamadas a funciones, el corte de tuplas, las búsquedas de métodos y las operaciones numéricas, en lugar de realizar muchas operaciones diferentes y reducir el resultado a un único número como hace pystone.py.

  • El módulo pyexpat utiliza ahora la versión 2.0 del analizador sintáctico Expat. (Contribución de Trent Mick)

  • La clase Queue proporcionada por el módulo Queue ha ganado dos nuevos métodos. join() bloquea hasta que todos los elementos de la cola han sido recuperados y todo el trabajo de procesamiento de los elementos ha sido completado. Los hilos de trabajo llaman al otro método nuevo, task_done(), para indicar que el procesamiento de un elemento ha finalizado. (Contribución de Raymond Hettinger)

  • Los antiguos módulos regex y regsub, obsoletos desde Python 2.0, han sido finalmente eliminados. Otros módulos eliminados: statcache, tzparse, whrandom.

  • También se ha eliminado el directorio lib-old, que incluye módulos antiguos como dircmp y ni. lib-old no estaba en el directorio por defecto sys.path, así que a menos que tus programas añadan explícitamente el directorio a sys.path, esta eliminación no debería afectar a tu código.

  • El módulo rlcompleter ya no depende de la importación del módulo readline y, por lo tanto, ahora funciona en plataformas no Unix. (Parche de Robert Kiendl.)

  • Las clases SimpleXMLRPCServer y DocXMLRPCServer tienen ahora un atributo rpc_paths que restringe las operaciones XML-RPC a un conjunto limitado de rutas URL; por defecto sólo se permiten '/' y '/RPC2'. Establecer rpc_paths como None o una tupla vacía desactiva esta comprobación de rutas.

  • El módulo socket ahora soporta sockets AF_NETLINK en Linux, gracias a un parche de Philippe Biondi. Los sockets Netlink son un mecanismo específico de Linux para las comunicaciones entre un proceso en el espacio del usuario y el código del kernel; hay un artículo introductorio sobre ellos en https://www.linuxjournal.com/article/7356. En el código Python, las direcciones de netlink se representan como una tupla de 2 enteros, (pid, group_mask).

    Dos nuevos métodos en objetos socket, recv_into(buffer) y recvrom_into(buffer), almacenan los datos recibidos en un objeto que soporta el protocolo de buffer en lugar de devolver los datos como una cadena. Esto significa que puedes poner los datos directamente en un array o en un archivo mapeado en memoria.

    Los objetos Socket también han ganado métodos de acceso getfamily(), gettype() y getproto() para recuperar los valores de familia, tipo y protocolo del socket.

  • Nuevo módulo: el módulo spwd proporciona funciones para acceder a la base de datos de contraseñas en la sombra en sistemas que soportan contraseñas en la sombra.

  • El módulo struct es ahora más rápido porque compila cadenas de formato en objetos Struct con métodos pack() y unpack(). Esto es similar a cómo el módulo re permite crear objetos de expresión regular compilados. Puede seguir utilizando las funciones pack() y unpack() a nivel de módulo; éstas crearán objetos Struct y los almacenarán en caché. O puede utilizar directamente las instancias de Struct:

    s = struct.Struct('ih3s')
    
    data = s.pack(1972, 187, 'abc')
    year, number, name = s.unpack(data)
    

    También puedes empaquetar y desempaquetar datos hacia y desde objetos buffer directamente usando los métodos pack_into(buffer, offset, v1, v2, ...) y unpack_from(buffer, offset). Esto te permite almacenar datos directamente en un array o en un archivo mapeado en memoria.

    (Struct objects fueron implementados por Bob Ippolito en el sprint NeedForSpeed. El soporte para los objetos buffer fue añadido por Martin Blais, también en el sprint NeedForSpeed)

  • Los desarrolladores de Python cambiaron de CVS a Subversion durante el proceso de desarrollo de la versión 2.5. La información sobre la versión exacta de construcción está disponible como la variable sys.subversion, una 3-tupla de (nombre del intérprete, nombre de la rama, rango de revisión). Por ejemplo, en el momento de escribir esto, mi copia de 2.5 informaba de ('CPython', 'trunk', '45313:45315').

    Esta información también está disponible para las extensiones de C a través de la función Py_GetBuildInfo() que devuelve una cadena de información de compilación como esta "trunk:45355:45356M, Apr 13 2006, 07:42:19". (Contribuido por Barry Warsaw.)

  • Otra nueva función, sys._current_frames(), devuelve los marcos de pila actuales para todos los hilos en ejecución como un diccionario que asigna los identificadores de los hilos al marco de pila superior actualmente activo en ese hilo en el momento en que se llama a la función. (Contribuido por Tim Peters.)

  • La clase TarFile del módulo tarfile tiene ahora un método extractall() que extrae todos los miembros del archivo en el directorio de trabajo actual. También es posible establecer un directorio diferente como destino de la extracción, y desempaquetar sólo un subconjunto de los miembros del archivo.

    La compresión utilizada para un archivo tar abierto en modo stream puede ahora ser autodetectada utilizando el modo 'r|*'. (Contribución de Lars Gustäbel)

  • El módulo threading permite ahora establecer el tamaño de la pila utilizado cuando se crean nuevos hilos. La función stack_size([*size*]) devuelve el tamaño de pila actualmente configurado, y suministrando el parámetro opcional size establece un nuevo valor. No todas las plataformas soportan el cambio del tamaño de la pila, pero Windows, POSIX threading y OS/2 lo hacen. (Contribución de Andrew MacIntyre)

  • El módulo unicodedata ha sido actualizado para utilizar la versión 4.1.0 de la base de datos de caracteres Unicode. La versión 3.2.0 es requerida por algunas especificaciones, por lo que sigue estando disponible como unicodedata.ucd_3_2_0.

  • Nuevo módulo: el módulo uuid genera identificadores únicos universales (UUID) de acuerdo con RFC 4122. El RFC define varias versiones diferentes de UUID que se generan a partir de una cadena inicial, de propiedades del sistema o de forma puramente aleatoria. Este módulo contiene una clase UUID y funciones llamadas uuid1(), uuid3(), uuid4(), y uuid5() para generar diferentes versiones de UUID. (Los UUID de la versión 2 no se especifican en RFC 4122 y no están soportados por este módulo)

    >>> import uuid
    >>> # make a UUID based on the host ID and current time
    >>> uuid.uuid1()
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
    
    >>> # make a UUID using an MD5 hash of a namespace UUID and a name
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
    
    >>> # make a random UUID
    >>> uuid.uuid4()
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
    
    >>> # make a UUID using a SHA-1 hash of a namespace UUID and a name
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
    

    (Contribución de Ka-Ping Yee.)

  • Los tipos weakref del módulo WeakKeyDictionary y WeakValueDictionary han obtenido nuevos métodos para iterar sobre las referencias débiles contenidas en el diccionario. Se han añadido los métodos iterkeyrefs() y keyrefs() a WeakKeyDictionary, y itervaluerefs() y valuerefs() a WeakValueDictionary. (Contribución de Fred L. Drake, Jr.)

  • El módulo webbrowser ha recibido una serie de mejoras. Ahora se puede utilizar como un script con python -m webbrowser, tomando una URL como argumento; hay una serie de interruptores para controlar el comportamiento (-n para una nueva ventana del navegador, -t para una nueva pestaña). Se han añadido nuevas funciones a nivel de módulo, open_new() y open_new_tab(), para soportar esto. La función open() del módulo soporta una característica adicional, un parámetro autoraise que señala si se debe levantar la ventana abierta cuando sea posible. Se añadieron varios navegadores adicionales a la lista de soportados, como Firefox, Opera, Konqueror y elinks. (Contribución de Oleg Broytmann y Georg Brandl)

  • El módulo xmlrpclib ahora soporta la devolución de objetos datetime para el tipo de fecha XML-RPC. Proporcione use_datetime=True a la función loads() o a la clase Unmarshaller para activar esta característica. (Contribución de Skip Montanaro)

  • El módulo zipfile ahora soporta la versión ZIP64 del formato, lo que significa que un archivo .zip ahora puede ser mayor de 4 GiB y puede contener archivos individuales mayores de 4 GiB. (Contribución de Ronald Oussoren)

  • Los objetos zlib y Decompress del módulo zlib soportan ahora un método copy() que realiza una copia del estado interno del objeto y devuelve un nuevo objeto Compress o Decompress. (Contribución de Chris AtLee)

El paquete ctypes

El paquete ctypes, escrito por Thomas Heller, se ha añadido a la biblioteca estándar. ctypes permite llamar a funciones arbitrarias en bibliotecas compartidas o DLL. Los usuarios veteranos recordarán el módulo dl, que proporciona funciones para cargar bibliotecas compartidas y llamar a las funciones que contienen. El paquete ctypes es mucho más sofisticado.

Para cargar una biblioteca compartida o DLL, debes crear una instancia de la clase CDLL y proporcionar el nombre o la ruta de la biblioteca compartida o DLL. Una vez hecho esto, puedes llamar a funciones arbitrarias accediendo a ellas como atributos del objeto CDLL.

import ctypes

libc = ctypes.CDLL('libc.so.6')
result = libc.printf("Line of output\n")

Se proporcionan constructores de tipo para los distintos tipos de C: c_int(), c_float(), c_double(), c_char_p() (equivalente a char* ), etcétera. A diferencia de los tipos de Python, las versiones C son todas mutables; puede asignar a su atributo value para cambiar el valor envuelto. Los enteros y las cadenas de Python se convertirán automáticamente a los tipos C correspondientes, pero para otros tipos debe llamar al constructor de tipo correcto. (Y me refiero a debe; hacerlo mal a menudo resultará en que el intérprete falle con una falla de segmentación).

No debería usar c_char_p() con una cadena de Python cuando la función C vaya a modificar el área de memoria, porque se supone que las cadenas de Python son inmutables; romper esta regla causará errores desconcertantes. Cuando necesite un área de memoria modificable, utilice create_string_buffer():

s = "this is a string"
buf = ctypes.create_string_buffer(s)
libc.strfry(buf)

Se supone que las funciones en C devuelven números enteros, pero se puede establecer el atributo restype del objeto de la función para cambiar esto:

>>> libc.atof('2.71828')
-1783957616
>>> libc.atof.restype = ctypes.c_double
>>> libc.atof('2.71828')
2.71828

ctypes también proporciona un contenedor para la API C de Python como objeto ctypes.pythonapi. Este objeto not libera el bloqueo del intérprete global antes de llamar a una función, porque el bloqueo debe mantenerse cuando se llama al código del intérprete. Hay un constructor de tipo py_object() que creará un puntero PyObject*. Un uso simple:

import ctypes

d = {}
ctypes.pythonapi.PyObject_SetItem(ctypes.py_object(d),
          ctypes.py_object("abc"),  ctypes.py_object(1))
# d is now {'abc', 1}.

No olvides usar py_object(); si se omite acabas con un fallo de segmentación.

ctypes existe desde hace tiempo, pero la gente sigue escribiendo y distribuyendo módulos de extensión codificados a mano porque no se puede confiar en que ctypes esté presente. Quizás los desarrolladores empiecen a escribir envoltorios de Python sobre una biblioteca a la que se accede a través de ctypes en lugar de módulos de extensión, ahora que ctypes está incluido en el núcleo de Python.

Ver también

https://web.archive.org/web/20180410025338/http://starship.python.net/crew/theller/ctypes/

La página web pre-stdlib ctypes, con un tutorial, referencia y preguntas frecuentes.

La documentación del módulo ctypes.

El paquete ElementTree

Un subconjunto de la biblioteca ElementTree de Fredrik Lundh para el procesamiento de XML se ha añadido a la biblioteca estándar como xml.etree. Los módulos disponibles son ElementTree, ElementPath y ElementInclude de ElementTree 1.2.6. También se incluye el módulo acelerador cElementTree.

El resto de esta sección proporcionará una breve descripción general del uso de ElementTree. La documentación completa de ElementTree está disponible en https://web.archive.org/web/20201124024954/http://effbot.org/zone/element-index.htm.

ElementTree representa un documento XML como un árbol de nodos de elementos. El contenido de texto del documento se almacena como los atributos text y tail de (Esta es una de las principales diferencias entre ElementTree y el Modelo de Objetos del Documento; en el DOM hay muchos tipos diferentes de nodo, incluyendo TextNode)

La función de análisis más utilizada es parse(), que toma una cadena (se supone que contiene un nombre de archivo) o un objeto similar a un archivo y devuelve una instancia de ElementTree:

from xml.etree import ElementTree as ET

tree = ET.parse('ex-1.xml')

feed = urllib.urlopen(
          'http://planet.python.org/rss10.xml')
tree = ET.parse(feed)

Una vez que tengas una instancia de ElementTree, puedes llamar a su método getroot() para obtener el nodo raíz de Element.

También hay una función XML() que toma un literal de cadena y devuelve un nodo Element (no un ElementTree). Esta función proporciona una forma ordenada de incorporar fragmentos XML, acercándose a la comodidad de un literal XML:

svg = ET.XML("""<svg width="10px" version="1.0">
             </svg>""")
svg.set('height', '320px')
svg.append(elem1)

Cada elemento XML admite algunos métodos de acceso tipo diccionario y otros tipo lista. Las operaciones tipo diccionario se utilizan para acceder a los valores de los atributos, y las operaciones tipo lista se utilizan para acceder a los nodos hijos.

Operación

Resultado

elem[n]

Devuelve el elemento hijo enésimo.

elem[m:n]

Devuelve la lista de m’s a n’s elementos hijos.

len(elem)

Devuelve el número de elementos hijos.

lista(elem)

Devuelve la lista de elementos hijos.

elem.append(elem2)

Añade elemento2 como hijo.

elem.insert(index, elem2)

Inserta elemento2 en el lugar especificado.

del elem[n]

Elimina el elemento hijo enésimo.

elem.keys()

Devuelve la lista de nombres de atributos.

elem.get(name)

Devuelve el valor del atributo nombre.

elem.set(nombre, valor)

Establece el nuevo valor del atributo nombre.

elem.attrib

Recupera el diccionario que contiene los atributos.

del elem.attrib[name]

Borra el atributo nombre.

Los comentarios y las instrucciones de procesamiento también se representan como nodos Element. Para comprobar si un nodo es un comentario o unas instrucciones de procesamiento:

if elem.tag is ET.Comment:
    ...
elif elem.tag is ET.ProcessingInstruction:
    ...

Para generar una salida XML, debes llamar al método ElementTree.write(). Al igual que parse(), puede tomar una cadena o un objeto tipo archivo:

# Encoding is US-ASCII
tree.write('output.xml')

# Encoding is UTF-8
f = open('output.xml', 'w')
tree.write(f, encoding='utf-8')

(Atención: la codificación por defecto utilizada para la salida es ASCII. Para el trabajo general de XML, donde el nombre de un elemento puede contener caracteres Unicode arbitrarios, ASCII no es una codificación muy útil porque lanzará una excepción si el nombre de un elemento contiene cualquier carácter con valores superiores a 127. Por lo tanto, es mejor especificar una codificación diferente, como UTF-8, que puede manejar cualquier carácter Unicode)

Esta sección es sólo una descripción parcial de las interfaces de ElementTree. Por favor, lee la documentación oficial del paquete para más detalles.

El paquete hashlib

Se ha añadido un nuevo módulo hashlib, escrito por Gregory P. Smith, para sustituir a los módulos md5 y sha. hashlib añade soporte para hashes seguros adicionales (SHA-224, SHA-256, SHA-384 y SHA-512). Cuando está disponible, el módulo utiliza OpenSSL para implementaciones rápidas de algoritmos optimizados para la plataforma.

Los antiguos módulos md5 y sha siguen existiendo como envoltorios de hashlib para preservar la compatibilidad hacia atrás. La interfaz del nuevo módulo es muy parecida a la de los módulos antiguos, pero no es idéntica. La diferencia más significativa es que las funciones constructoras para crear nuevos objetos hashing tienen un nombre diferente

# Old versions
h = md5.md5()
h = md5.new()

# New version
h = hashlib.md5()

# Old versions
h = sha.sha()
h = sha.new()

# New version
h = hashlib.sha1()

# Hash that weren't previously available
h = hashlib.sha224()
h = hashlib.sha256()
h = hashlib.sha384()
h = hashlib.sha512()

# Alternative form
h = hashlib.new('md5')          # Provide algorithm as a string

Una vez que se ha creado un objeto hash, sus métodos son los mismos que antes: actualizar(cadena) convierte la cadena especificada en el estado de resumen actual, digest() y hexdigest() devuelven el valor de resumen como una cadena binaria o una cadena de dígitos hexadecimales, y copiar() devuelve un nuevo objeto hash con el mismo estado de resumen.

Ver también

La documentación del módulo hashlib.

El paquete sqlite3

El módulo pysqlite (https://www.pysqlite.org), un envoltorio para la base de datos incrustada de SQLite, se agregó a la biblioteca estándar con el nombre de paquete sqlite3.

SQLite es una biblioteca en C que proporciona una base de datos ligera basada en disco que no requiere un proceso de servidor independiente y permite acceder a la base de datos utilizando una variante no estándar del lenguaje de consulta SQL. Algunas aplicaciones pueden utilizar SQLite para el almacenamiento interno de datos. También es posible crear un prototipo de una aplicación utilizando SQLite y luego portar el código a una base de datos más grande como PostgreSQL u Oracle.

pysqlite fue escrito por Gerhard Häring y proporciona una interfaz SQL que cumple con la especificación DB-API 2.0 descrita por PEP 249.

Si estás compilando el código fuente de Python tú mismo, ten en cuenta que el árbol de código fuente no incluye el código de SQLite, sólo el módulo envolvente. Necesitarás tener las librerías y cabeceras de SQLite instaladas antes de compilar Python, y el proceso de construcción compilará el módulo cuando las cabeceras necesarias estén disponibles.

Para utilizar el módulo, primero hay que crear un objeto Connection que represente la base de datos. Aquí los datos se almacenarán en el archivo /tmp/example:

conn = sqlite3.connect('/tmp/example')

También puede suministrar el nombre especial :memory: para crear una base de datos en la RAM.

Una vez que tengas una Connection, puedes crear un objeto Cursor y llamar a su método execute() para realizar comandos SQL:

c = conn.cursor()

# Create table
c.execute('''create table stocks
(date text, trans text, symbol text,
 qty real, price real)''')

# Insert a row of data
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")

Normalmente tus operaciones SQL necesitarán usar valores de variables de Python. No deberías montar tu consulta usando las operaciones de cadena de Python porque hacerlo es inseguro; hace que tu programa sea vulnerable a un ataque de inyección SQL.

En su lugar, utilice la sustitución de parámetros de la DB-API. Ponga ? como marcador de posición donde quiera usar un valor, y luego proporcione una tupla de valores como segundo argumento al método execute() del cursor. (Otros módulos de base de datos pueden utilizar un marcador de posición diferente, como %s o :1) Por ejemplo:

# Never do this -- insecure!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)

# Do this instead
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)

# Larger example
for t in (('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
          ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00),
          ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
         ):
    c.execute('insert into stocks values (?,?,?,?,?)', t)

Para recuperar datos después de ejecutar una sentencia SELECT, puede tratar el cursor como un iterador, llamar al método fetchone() del cursor para recuperar una sola fila que coincida, o llamar a fetchall() para obtener una lista de las filas que coincidan.

Este ejemplo utiliza la forma del iterador:

>>> c = conn.cursor()
>>> c.execute('select * from stocks order by price')
>>> for row in c:
...    print row
...
(u'2006-01-05', u'BUY', u'RHAT', 100, 35.140000000000001)
(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0)
(u'2006-04-06', u'SELL', u'IBM', 500, 53.0)
(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0)
>>>

Para más información sobre el dialecto SQL soportado por SQLite, consulte https://www.sqlite.org.

Ver también

https://www.pysqlite.org

La página web de pysqlite.

https://www.sqlite.org

La página web de SQLite; la documentación describe la sintaxis y los tipos de datos disponibles para el dialecto SQL soportado.

La documentación del módulo sqlite3.

PEP 249 - Especificación de la API de la base de datos 2.0

PEP escrito por Marc-André Lemburg.

El paquete wsgiref

La Interfaz de Pasarela del Servidor Web (WSGI) v1.0 define una interfaz estándar entre los servidores web y las aplicaciones web de Python y se describe en PEP 333. El paquete wsgiref es una implementación de referencia de la especificación WSGI.

El paquete incluye un servidor HTTP básico que ejecutará una aplicación WSGI; este servidor es útil para la depuración pero no está pensado para su uso en producción. La configuración de un servidor sólo requiere unas pocas líneas de código:

from wsgiref import simple_server

wsgi_app = ...

host = ''
port = 8000
httpd = simple_server.make_server(host, port, wsgi_app)
httpd.serve_forever()

Ver también

https://web.archive.org/web/20160331090247/http://wsgi.readthedocs.org/en/latest/

Un sitio web central para los recursos relacionados con WSGI.

PEP 333 - Interfaz del servidor web Python v1.0

PEP escrito por Phillip J. Eby.

Cambios en la API de construcción y C

Los cambios en el proceso de construcción de Python y en la API de C incluyen:

  • El árbol de fuentes de Python fue convertido de CVS a Subversion, en un complejo procedimiento de migración que fue supervisado y llevado a cabo de forma impecable por Martin von Löwis. El procedimiento se desarrolló como PEP 347.

  • Coverity, una empresa que comercializa una herramienta de análisis de código fuente llamada Prevent, proporcionó los resultados de su examen del código fuente de Python. El análisis encontró alrededor de 60 errores que fueron rápidamente corregidos. Muchos de los errores eran problemas de recuento, que a menudo se producen en el código de gestión de errores. Consulte las estadísticas en https://scan.coverity.com.

  • El mayor cambio en la API de C provino de PEP 353, que modifica el intérprete para usar una definición de tipo Py_ssize_t en lugar de int. Consulte la sección anterior PEP 353: Uso de ssize_t como tipo de índice para obtener una explicación de este cambio.

  • El diseño del compilador de código de bytes ha cambiado mucho, ya no genera código de bytes recorriendo el árbol de análisis sintáctico. En su lugar, el árbol de análisis se convierte en un árbol de sintaxis abstracta (o AST), y es el árbol de sintaxis abstracta el que se recorre para producir el código de bytes.

    Es posible que el código Python obtenga objetos AST utilizando el built-in compile() y especificando _ast.PyCF_ONLY_AST como valor del parámetro flags:

    from _ast import PyCF_ONLY_AST
    ast = compile("""a=0
    for i in range(10):
        a += i
    """, "<string>", 'exec', PyCF_ONLY_AST)
    
    assignment = ast.body[0]
    for_loop = ast.body[1]
    

    Todavía no se ha escrito ninguna documentación oficial para el código AST, pero PEP 339 discute el diseño. Para empezar a conocer el código, lea la definición de los distintos nodos AST en Parser/Python.asdl. Un script de Python lee este archivo y genera un conjunto de definiciones de estructuras C en Include/Python-ast.h. Las funciones PyParser_ASTFromString() y PyParser_ASTFromFile(), definidas en Include/pythonrun.h, toman el código fuente de Python como entrada y devuelven la raíz de un AST que representa el contenido. Este AST puede convertirse en un objeto de código mediante PyAST_Compile(). Para más información, lea el código fuente, y luego haga preguntas en python-dev.

    El código de la AST fue desarrollado bajo la dirección de Jeremy Hylton, e implementado por (en orden alfabético) Brett Cannon, Nick Coghlan, Grant Edwards, John Ehresman, Kurt Kaiser, Neal Norwitz, Tim Peters, Armin Rigo y Neil Schemenauer, además de los participantes en varios sprints de la AST en conferencias como la PyCon.

  • Se aplicó el parche de Evan Jones a obmalloc, descrito por primera vez en una charla en la PyCon DC 2005. Python 2.4 asignaba objetos pequeños en arenas de 256K, pero nunca liberaba arenas. Con este parche, Python liberará arenas cuando estén vacías. El efecto neto es que en algunas plataformas, cuando se asignan muchos objetos, el uso de la memoria de Python puede realmente caer cuando se borran y la memoria puede ser devuelta al sistema operativo. (Implementado por Evan Jones, y reelaborado por Tim Peters)

    Tenga en cuenta que este cambio significa que los módulos de extensión deben ser más cuidadosos al asignar memoria. La API de Python tiene muchas funciones diferentes para asignar memoria que se agrupan en familias. Por ejemplo, PyMem_Malloc(), PyMem_Realloc(), y PyMem_Free() son una familia que asigna memoria en bruto, mientras que PyObject_Malloc(), PyObject_Realloc(), y PyObject_Free() son otra familia que se supone que se utiliza para crear objetos de Python.

    Anteriormente estas diferentes familias se reducían a las funciones malloc() y free() de la plataforma. Esto significaba que no importaba si te equivocabas y asignabas memoria con la función PyMem() pero la liberabas con la función PyObject(). Con los cambios de la versión 2.5 en obmalloc, estas familias hacen ahora cosas diferentes y los desajustes probablemente darán lugar a un fallo de seguridad. Deberías probar cuidadosamente tus módulos de extensión C con Python 2.5.

  • Los tipos de conjuntos incorporados tienen ahora una API oficial en C. Llame a PySet_New() y PyFrozenSet_New() para crear un nuevo conjunto, PySet_Add() y PySet_Discard() para añadir y eliminar elementos, y PySet_Contains() y PySet_Size() para examinar el estado del conjunto. (Contribución de Raymond Hettinger)

  • El código C puede ahora obtener información sobre la revisión exacta del intérprete de Python llamando a la función Py_GetBuildInfo() que devuelve una cadena de información de compilación como esta "trunk:45355:45356M, Apr 13 2006, 07:42:19". (Contribuido por Barry Warsaw.)

  • Se pueden utilizar dos nuevas macros para indicar las funciones C que son locales al fichero actual, de modo que se pueda utilizar una convención de llamada más rápida. Py_LOCAL(type) declara que la función devuelve un valor del tipo especificado y utiliza un calificador de llamada rápida. Py_LOCAL_INLINE(type) hace lo mismo y también solicita que la función sea inline. Si PY_LOCAL_AGGRESSIVE() se define antes de que se incluya python.h, se habilita un conjunto de optimizaciones más agresivas para el módulo; debería comparar los resultados para averiguar si estas optimizaciones realmente hacen el código más rápido. (Contribuido por Fredrik Lundh en el sprint NeedForSpeed)

  • PyErr_NewException(name, base, dict) ahora puede aceptar una tupla de clases base como su argumento base. (Contribuido por Georg Brandl.)

  • La función PyErr_Warn() para emitir avisos está ahora obsoleta en favor de PyErr_WarnEx(category, message, stacklevel) que permite especificar el número de marcos de pila que separan esta función y la que la llama. Un stacklevel de 1 es la función que llama a PyErr_WarnEx(), 2 es la función que está por encima, y así sucesivamente. (Añadido por Neal Norwitz.)

  • El intérprete de CPython sigue estando escrito en C, pero el código ahora puede ser compilado con un compilador de C++ sin errores. (Implementado por Anthony Baxter, Martin von Löwis, Skip Montanaro)

  • Se ha eliminado la función PyRange_New(). Nunca se documentó, nunca se utilizó en el código del núcleo, y tenía una comprobación de errores peligrosamente laxa. En el improbable caso de que sus extensiones la utilizaran, puede sustituirla por algo como lo siguiente:

    range = PyObject_CallFunction((PyObject*) &PyRange_Type, "lll",
                                  start, stop, step);
    

Cambios específicos en los puertos

  • MacOS X (10.3 y superior): la carga dinámica de módulos utiliza ahora la función dlopen() en lugar de funciones específicas de MacOS.

  • MacOS X: se ha añadido una opción --enable-universalsdk al script configure que compila el intérprete como un binario universal capaz de funcionar tanto en procesadores PowerPC como Intel. (Contribución de Ronald Oussoren; bpo-2573.)

  • Windows: .dll ya no se admite como extensión de nombre de archivo para los módulos de extensión. .pyd es ahora la única extensión de nombre de archivo que se buscará.

Adaptación a Python 2.5

Esta sección enumera los cambios descritos anteriormente que pueden requerir cambios en su código:

  • ASCII es ahora la codificación por defecto para los módulos. Ahora es un error de sintaxis si un módulo contiene literales de cadena con caracteres de 8 bits pero no tiene una declaración de codificación. En Python 2.4 esto provocaba una advertencia, no un error de sintaxis.

  • Anteriormente, el atributo gi_frame de un generador era siempre un objeto frame. Debido a los cambios de PEP 342 descritos en la sección PEP 342: Nuevas funciones del generador, ahora es posible que gi_frame sea None.

  • Una nueva advertencia, UnicodeWarning, se lanza cuando se intenta comparar una cadena Unicode y una cadena de 8 bits que no puede ser convertida a Unicode utilizando la codificación ASCII por defecto. Anteriormente estas comparaciones lanzaban una excepción UnicodeDecodeError.

  • Biblioteca: el módulo csv es ahora más estricto con los campos citados en varias líneas. Si sus archivos contienen nuevas líneas incrustadas dentro de los campos, la entrada debe dividirse en líneas de manera que se conserven los caracteres de nueva línea.

  • Biblioteca: la función format() del módulo locale aceptaba antes cualquier cadena siempre que no apareciera más de un especificador %char. En Python 2.5, el argumento debe ser exactamente un especificador %char sin texto alrededor.

  • Biblioteca: Los módulos pickle y cPickle ya no aceptan un valor de retorno de None del método __reduce__(); el método debe devolver una tupla de argumentos. Los módulos tampoco aceptan ya el parámetro obsoleto de la palabra clave bin.

  • Biblioteca: Las clases SimpleXMLRPCServer y DocXMLRPCServer tienen ahora un atributo rpc_paths que restringe las operaciones XML-RPC a un conjunto limitado de rutas URL; por defecto sólo se permiten '/' y '/RPC2'. Establecer rpc_paths como None o una tupla vacía desactiva esta comprobación de rutas.

  • API de C: muchas funciones ahora usan Py_ssize_t en lugar de int para permitir el procesamiento de más datos en máquinas de 64 bits. Es posible que el código de extensión deba realizar el mismo cambio para evitar advertencias y admitir máquinas de 64 bits. Consulte la sección anterior PEP 353: Uso de ssize_t como tipo de índice para obtener una explicación de este cambio.

  • API C: Los cambios en obmalloc significan que debe tener cuidado de no mezclar el uso de las familias de funciones PyMem_* y PyObject_*. La memoria asignada con la función *_Malloc de una familia, debe ser liberada con la función *_Free de la familia correspondiente.

Agradecimientos

El autor desea agradecer a las siguientes personas sus sugerencias, correcciones y ayuda en varios borradores de este artículo: Georg Brandl, Nick Coghlan, Phillip J. Eby, Lars Gustäbel, Raymond Hettinger, Ralf W. Grosse-Kunstleve, Kent Johnson, Iain Lowe, Martin von Löwis, Fredrik Lundh, Andrew McNamara, Skip Montanaro, Gustavo Niemeyer, Paul Prescod, James Pryor, Mike Rovner, Scott Weikart, Barry Warsaw, Thomas Wouters.