Novedades de Python 2.4 Release 1.02

A. M. Kuchling 17 de abril de 2005 Python Software Foundation Dirección: [email protected]

Índice 1. PEP 218: Objetos conjunto internos

2

2. PEP 237: Unificación de enteros largos y enteros

3

3. PEP 289: Expresiones generadoras

3

4. PEP 292: Sustituciones de cadena simplificadas

4

5. PEP 318: Decoradores para funciones y métodos

4

6. PEP 322: Iteración inversa

7

7. PEP 324: Nuevo módulo de subprocesos

7

8. PEP 327: Tipo de dato Decimal 8.1. ¿Por qué se necesita Decimal? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2. El tipo Decimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3. El tipo Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

8 8 9 11

9. PEP 328: Importaciones multilínea

12

10. PEP 331: Conversiones de flotantes/cadenas independientes de regionalización

12

11. Otros cambios del lenguaje 11.1. Optimizaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13 15

12. Módulos nuevos, mejorados y abandonados 12.1. cookielib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2. doctest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16 20 21

13. Cambio en el proceso de compilación y el API de C 13.1. Cambios específicos de las plataformas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22 23

14. Migrar a Python 2.4

23

15. Agradecimientos

24

16. Sobre la traducción

24

Este artículo comenta las nuevas características de Python 2.4, liberado el 30 de noviembre de 2004. Python 2.4 es una versión moderada. No introduce tantos cambios como la radical Python 2.2, pero tiene más novedades que la conservadora Python 2.3. Las características más significativas son los decoradores de funciones y las expresiones generadoras; la mayoría del resto de los cambios afectan a la biblioteca estándar. Según los registros de cambios del CVS, hubo 481 parches y 502 correcciones entre Python 2.3 y Python 2.4. Seguramente, tanto una cifra como otra se queden cortas. Este artículo no intenta proporcionar una especificación completa de todas y cada una de las nuevas características, sino dar una breve presentación de cada característica. Para obtener todos los detalles, se debería consultar la documentación de Python 2.4, como la Referencia de las bibliotecas de Python y el Manual de referencia de Python. A menudo se encontrarán referencias a la PEP para obtener detalles de una característica concreta o de la implentación y la lógica del diseño.

1.

PEP 218: Objetos conjunto internos

Python 2.3 introdujo el módulo sets. Las implementaciones en C de los tipos de datos conjunto se han incorporado en Python como dos tipos de dato internos nuevos, set(iterable) y frozenset(iterable). Proporcionan operaciones de alta velocidad para verificación de pertenencia, para eliminar duplicados de las secuencias y para operaciones matemáticas como uniones, intersecciones, diferencias y diferencias simétricas. >>> a = set(’abracadabra’) >>> ’z’ in a False >>> a set([’a’, ’r’, ’b’, ’c’, ’d’]) >>> ’’.join(a) ’arbcd’

# crea un conjunto a partir de una cadena # verificación rápida de pertenencia # distintas letras de a # volver a formar una cadena

>>> b = set(’alacazam’) >>> a - b set([’r’, ’d’, ’b’]) >>> a | b set([’a’, ’c’, ’r’, ’d’, ’b’, ’m’, ’z’, >>> a & b set([’a’, ’c’]) >>> a ^ b set([’r’, ’d’, ’b’, ’m’, ’z’, ’l’])

# formar un segundo conjunto # letras de a que no están en b

>>> a.add(’z’) >>> a.update(’wxy’) >>> a set([’a’, ’c’, ’b’, ’d’, ’r’, ’w’, ’y’, >>> a.remove(’x’) >>> a set([’a’, ’c’, ’b’, ’d’, ’r’, ’w’, ’y’,

# añadir elemento # añadir varios elementos

# letras de a o b ’l’]) # letras de a y b # letras de a, de b, pero no de ambas

’x’, ’z’]) # extracción de un elemento ’z’])

El tipo frozenset es una versión inmutable de set. Al ser inmutable y tener un “hash” fijo, se puede utilizar como clave de un diccionario o como miembro de otro conjunto. El módulo sets permanece en la biblioteca estándar y puede resultar útil si se desea heredar de las clases Set o ImmutableSet. No hay planes en la actualidad de declarar anticuado el módulo. MÃas ˛ informaciøsn en: PEP 218, “Adición de un tipo objeto interno” Propuesta original de Greg Wilson, implementación final de Raymond Hettinger.

2

1

PEP 218: Objetos conjunto internos

2.

PEP 237: Unificación de enteros largos y enteros

El dilatado proceso de transición de esta PEP, iniciado en Python 2.2, da un nuevo paso en Python 2.4. En la 2.3, ciertas operaciones de enteros se habrían comportado de manera diferente después de que la unificación int/long lanzase advertencias FutureWarning y hubieran devuelto valores limitados a 32 o 64 bits (dependiendo de la plataforma). En la 2.4, estas expresiones ya no lanzan advertencias y en su lugar producen un resultado diferente, normalmente un entero largo. Las expresiones problemáticas son principalmente los desplazamientos de bits a la izquierda y las constantes grandes hexadecimales y octales. Por ejemplo, 2 >> ’%(pag)i: %(tit)s’ % {’pag’:2, ’tit’: ’El alcalde de Zalamea’} ’2: El alcalde de Zalamea’

Al escribir la cadena-plantilla, es común olvidar la ‘i’ o la ‘s’ tras el cierre del paréntesis. Esto no supone un problema si la plantilla está en un módulo de Python, porque se ejecuta el código, se obtiene un “Unsupported format character” ValueError y se arregla. Sin embargo, en una aplicación como Mailman, en la que las plantillas y sus traducciones son modificadas por usuarios desconocedores del lenguaje Python. La sintaxis de las cadenas de formato es compleja de explicar a tales usuarios y, si comenten un error, es difícil proporcionarles ayuda. La PEP 292 añade una clase Template al módulo string que utiliza ‘$’ para marcar las sustituciones: >>> >>> >>> ’2:

import string t = string.Template(’$pag: $tit’) t.substitute({’pag’:2, ’tit’: ’El alcalde de Zalamea’}) El alcalde de Zalamea’

Si falta una clave del diccionario, el método substitute lanzará un KeyError. También hay un método safe_substitute que deja sin tocar las claves que faltan: >>> t = string.Template(’$pag: $tit’) >>> t.safe_substitute({’pag’:3}) ’3: $tit’

MÃas ˛ informaciøsn en: PEP 292, “Sustituciones de cadena simplificadas” Escrita e implementada por Barry Warsaw.

5.

PEP 318: Decoradores para funciones y métodos

Python 2.2 extendió el modelo de objetos, añadiendo los métodos estáticos y métodos de clase, pero no extendió la sintaxis para proporcionar ningún modo nuevo de definir los métodos estáticos o de clase. Había que escribir la sentencia def del modo habitual y pasar el método resultante a una función staticmethod() o classmethod() para envolver la función como método del nuevo tipo. El código tendría este aspecto:

4

5

PEP 318: Decoradores para funciones y métodos

class C: def met (cls): ... met = classmethod(met)

# Reasignar el método de clase envolvente

Si el método era largo, era fácil no ver u olvidar la llamada a classmethod() tras el cuerpo de la función. Siempre hubo la intención de añadir sintaxis para hacer más legible este tipo de definiciones, pero no estaba claro en el momento de la liberación de la 2.2 cuál era la mejor sintaxis. A día de hoy, aún no se ha encontrado la mejor sintaxis, pero los usuarios demandan un acceso más sencillo a estas características. Se ha añadido una nueva sintaxis para responder a esta demanda. La nueva característica se denomina “decoratores de función”. El nombre parte de la idea de que classmethod, staticmethod y similares almacenan información adicional sobre el objeto función, decoran las funciones con más detalles. La notación se toma prestada de Java; utiliza el carácter ‘@’ como marcador. Con la nueva sintaxis, el ejemplo anterior se escribiría: class C: @classmethod def met (cls): ...

@classmethod es una abreviatura de la asignación meth=classmethod(meth). En general, esta construcción: @A @B @C def f (): ...

es equivalente al siguiente código pre-decoradores: def f(): ... f = A(B(C(f)))

Los decoradores deben estar en las líneas inmediatamente anteriores a la definición de la función, un decorador por línea, así que @A def f(): ... no vale. Además, sólo se puede decorar definiciones de funciones, al nivel del módulo o dentro de una clase; no es posible decorar definiciones de clase. Un decorador es simplemente una función que toma como argumento la función a decorar y devuelve la misma función o un objeto nuevo. El resultado de llamar a un decorador no ha de ser invocable (aunque típicamente lo es), a menos que se aplique de forma anidada. Es fácil escribir decoradores. El siguiente ejemplo se limita a asignar un valor a un atributo del objeto función:

5

>>> def deco(func): ... func.atr = ’decorada’ ... return func ... >>> @deco ... def f(): pass ... >>> f >>> f.atr ’decorada’ >>>

En un ejemplo algo más realista, el siguiente decorador verifica que el argumento suministrado es un entero: def exige_int (func): def envoltorio (arg): assert isinstance(arg, int) return func(arg) return envoltorio @exige_int def p1 (arg): print arg @exige_int def p2(arg): print arg*2

Hay un ejemplo en PEP 318 que contiene una versión más elaborada de esta idea, que permite especificar el tipo de entrada y verificar el valor de salida. Las funciones decoradoras pueden tomar argumentos. Si se proporcionan argumentos, se llama a la función decoradora sólo con esos argumentos y debe devolver una función, según se ha descrito. En otras palabras, @A @B @C(args) se transforma en: def f(): ... _deco = C(args) f = A(B(_deco(f)))

Comprender esto puede retorcer un poco las neuronas, pero no es tan difícil. Un cambio ligero relativo a esto permite modificar el atributo func_name de las funciones. Este atributo se utiliza para presentar los nombres de las funciones en los volcados de pila de los mensajes de error, por lo que los decoradores deben cambiar el nombre de cualquier función construida y devuelta. MÃas ˛ informaciøsn en: PEP 318, “Decoradores para funciones, métodos y clases” Escrita por Kevin D. Smith, Jim Jewett y Skip Montanaro. Varias personas escribieron parches para implementar los decoradores de funciones, pero el que fue realmente aceptado fue el #979728, de Mark Russell. http://www.python.org/moin/PythonDecoratorLibrary

Esta página wiki contiene varios ejemplos de decoradores.

6

5

PEP 318: Decoradores para funciones y métodos

6.

PEP 322: Iteración inversa

Hay una función nueva, reversed(seq), que toma una secuencia y devuelve un iterador que recorre los elementos de la secuencia en orden inverso. >>> for i in reversed(xrange(1,4)): ... print i ... 3 2 1

Comparada con el rebanado extendido, como range(1,4)[::-1], reversed() es más fácil de leer, se ejecuta más rápido y usa bastante menos memoria. Hay que destacar que reversed() sólo acepta secuencias, no cualquier iterador. Si se desea invertir un iterador, hay que convertirlo primero en lista con list(). >>> entrada = open(’/etc/passwd’, ’r’) >>> for linea in reversed(list(entrada)): ... print linea ... root:*:0:0:System Administrator:/var/root:/bin/tcsh ...

MÃas ˛ informaciøsn en: PEP 322, “Iteración inversa” Escrita e implementada por Raymond Hettinger.

7.

PEP 324: Nuevo módulo de subprocesos

La bilioteca estándar proporciona diversos modos de ejecutar un subproceso, ofreciendo diferentes posibilidades y diferentes niveles de complejidad. os.system(command) es fácil de usar, pero es lenta (ejecuta un nuevo proceso del intérprete de órdenes, que ejecuta la orden) y potencialmente peligrosa (hay que tener cuidado de neutralizar todos los metacaracteres del intérprete). El módulo popen2 contiene clases para capturar la salida estándar y el flujo de errores estándar del subproceso, pero la nomenclatura resulta confusa. El módulo subprocess aclara todo esto, proporcionando una interfaz que ofrece todas las posibilidades que se puedan necesitar. En lugar de la colección de clases de popen2, subprocess contiene una sola clase denominada Popen, cuyo constructor permite diversos parámetros por nombre. class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0):

args suele ser una secuencia de cadenas que supondrán los argumentos del programa ejecutado como subproceso (si el argumento shell es verdadero, args puede ser una cadena que se le pasará al intérprete de órdenes para que lo interprete, igual que hace os.system()). stdin, stdout y stderr especifican cuáles serán los flujos de entrada, salida y errores del subproceso. Se puede proporcionar un objeto fichero o un descriptor de fichero, o se puede usar la constante subprocess.PIPE para crear una tubería entre el subproceso y el padre. El constructor dispone de útiles opciones: close_fds solicita que todos los descriptores de fichero estén cerrados antes de ejecutar el subproceso. 7

cwd especifica el directorio de trabajo en el que se ejecutará el subproceso (el valor por omisión es el del padre). env es un diccionario que especifica las variables de entorno. preexec_fn es una función a la que se llama antes de arrancar el hijo. universal_newlines abre la entrada y salida del hijo utilizando la característica de salto de línea universal de Python. Una vez creada la instancia de Popen, se puede llamar a su método wait() para detenerlo hasta que el subproceso haya terminado, poll() para verificar si ha terminado sin parar, o communicate(data) para enviar la cadena data a la entrada estándar del subproceso. communicate(data) lee a su vez cualquier dato que el subproceso haya enviado a su salida estándar de flujo de errores, devolviendo una tupla (stdout_data, stderr_data). call() es un atajo que traspasa sus argumentos al constructor de Popen, espera a que termine la orden y devuelve el código de estado resultante del subproceso. Puede servir como análogo más seguro de os.system(): sts = subprocess.call([’dpkg’, ’-i’, ’/tmp/new-package.deb’]) if sts == 0: # Éxito ... else: # dpkg ha devuelto un error ...

Se invoca la orden sin uso del intérprete de órdenes. Si realmente sí que se desea usar el intérprete, se puede añadir shell=True como argumento con nombre y proporcionar una cadena en lugar de una secuencia: sts = subprocess.call(’dpkg -i /tmp/new-package.deb’, shell=True)

La PEP toma varios ejemplos de código del intérprete de línea de órdenes y de Python y muestra cómo se traduciría a código de Python que utilice subprocess. Se recomienda encarecidamente leer esta sección de la PEP. MÃas ˛ informaciøsn en: PEP 324, “subprocess - Nuevo módulo de subprocesos” Escrita e implementada por Peter Åstrand, asistido por Fredrik Lundh y otros.

8.

PEP 327: Tipo de dato Decimal

Python simpre ha tenido números de coma flotante, basados en el tipo de C double subyacente, como tipo de dato. No obstante, aunque la mayoría de los lenguajes de programación proporcionan un tipo de coma flotante, mucha gente (incluidos programadores) ignoran que los números de coma flotante no representan ciertas fracciones decimales exactamente. El nuevo tipo Decimal puede representar estas fracciones exactamente, hasta un límite de precisión especificado por el usuario

8.1.

¿Por qué se necesita Decimal?

Las limitaciones surgen de la representación utilizada para los números de coma flotante. Los números de coma flotante se componen de: El signo, que es positivo o negativo. La mantisa, que es un número binario de un solo dígito seguido por una parte fraccional. Por ejemplo, 1,01 en notación de base 2 es 1 + 0/2 + 1/4 o 1,25 en notación decimal. 8

8

PEP 327: Tipo de dato Decimal

El exponente, que indica dónde está la coma decimal en el número representado. Por ejemplo, el número 1,25 tiene signo positivo, una mantisa de 1,01 (en binario) y un exponente de 0 (no hay que desplazar la coma). El número 5 tiene el mismo signo y mantisa, pero el exponente es 2, porque hay que multiplicar la mantisa por 4 (2 a la 2); 1,25 x 4 vale 5. Los sistemas modernos suelen proporcionar servicios de coma flotante conforme a la norma IEEE 754. El tipo de C double se suele implementar como un número de 64 bits del IEEE 754, que utiliza 52 bits de espacio para la mantisa. Esto significa que los números sólo se pueden especificar hasta 54 bits de precisión. Si se intenta representar números periódicos, la lista de cifras se recorta a los 52 bits. Sin embargo, la mayoría de los programas exigen que la salida sea en base 10, y muchas fracciones comunes en base 10 son periódicas en base 2. Por ejemplo, 1,1 decimal es en binario 1.0001100110011 ...; .1 = 1/16 + 1/32 + 1/256 más un número infinito de términos adicionales. El IEEE 754 tiene que recortar este número periódico tras 52 dígitos, por lo que la representación es ligeramente imprecisa. A veces se aprecia esta inexactitud cuando se presenta el número: >>> 1.1 1.1000000000000001

La inexactitud no es siempre visible al presentar el número porque la conversión de coma flotante a decimal es la proporcionada por la biblioteca de C, y la mayoría de bibliotecas de C intentan producir una salida sensible. Aunque no se presente, sin embargo, la inexactitud está ahí, y las siguientes operaciones pueden magnificar el error. Hay muchas aplicaciones en las que esto es indiferente. Si estoy pintando puntos en la pantalla, la diferencia entre 1,1 y 1,1000000000000001 es demasiado pequeña para resultar visible. Los informes limitan la salida a menudo a cierto número de decimales, por lo que al redondear a dos, tres o hasta ocho decimales el error nunca se manifiesta. Sin embargo, en las aplicaciones en las que esto es importante, es muy laborioso implementar rutinas aritméticas a medida. Y por eso se creó el tipo Decimal.

8.2.

El tipo Decimal

Se ha añadido un nuevo módulo, decimal, a la biblioteca estándar de Python. Contiene dos clases, Decimal y Context. Las instancias de Decimal representan números; las instancias de Context se usan para agrupar diversas propiedades, tales como la precisión y el modo de redondeo predeterminado. Las instancias de Decimal son inmutables, como los enteros y números de coma decimal de Python; una vez creados, es imposible cambiar el valor que representa una instancia. Las instancias de Decimal se pueden crear a partir de enteros o de cadenas: >>> import decimal >>> decimal.Decimal(1972) Decimal("1972") >>> decimal.Decimal("1.1") Decimal("1.1")

También se puede proporcionar tuplas que contengan el signo, la mantisa como tupla de dígitos decimales, y el exponente: >>> decimal.Decimal((1, (1, 4, 7, 5), -2)) Decimal("-14.75")

Nota de advertencia: el bit de signo es Booleano, por lo que 0 significa positivo y 1 significa negativo.

8.2

El tipo Decimal

9

La conversión a partir de números de coma flotante supone un problema: ¿se debería convertir el número de coma flotante que representa 1,1 en el número decimal 1,1 o 1,1 más las inexactitudes asociadas? La decisión tomada fue inhibirse y dejar fuera de la API este tipo de conversiones. Lo que hay que hacer es convertir el número de coma flotante en cadena con la precisión deseada y pasar la cadena al constructor de Decimal: >>> f = 1.1 >>> decimal.Decimal(str(f)) Decimal("1.1") >>> decimal.Decimal(’%.12f’ % f) Decimal("1.100000000000")

Una vez se tienen instancias de Decimal, es posible realizar las operaciones matemáticas comunes sobre ellas, con una limitación: la exponenciación exige que el exponente sea entero: >>> a = decimal.Decimal(’35.72’) >>> b = decimal.Decimal(’1.73’) >>> a+b Decimal("37.45") >>> a-b Decimal("33.99") >>> a*b Decimal("61.7956") >>> a/b Decimal("20.64739884393063583815028902") >>> a ** 2 Decimal("1275.9184") >>> a**b Traceback (most recent call last): ... decimal.InvalidOperation: x ** (non-integer)

Se puede combinar instancias de Decimal con enteros, pero no con números de coma flotante: >>> a + 4 Decimal("39.72") >>> a + 4.5 Traceback (most recent call last): ... TypeError: You can interact Decimal only with int, long or Decimal data types. >>>

Es posible usar los números Decimal con los módulos math y cmath, pero hay que saber que serán convertidos de inmediato a números de coma flotante antes de realizar la operación, causando una posible pérdida de precisión y exactidud. Además, el resultado obtenido será un número de coma flotante y no un Decimal. >>> import math, cmath >>> d = decimal.Decimal(’123456789012.345’) >>> math.sqrt(d) 351364.18288201344 >>> cmath.sqrt(-d) 351364.18288201344j

Las instancias de Decimal tienen un método sqrt() que devuelve un Decimal, pero si se necesita otras cosas, tales como funciones trigonométricas, se tendrán que implementar. >>> d.sqrt() Decimal("351364.1828820134592177245001")

10

8

PEP 327: Tipo de dato Decimal

8.3.

El tipo Context

Las instancias de la clase Context encapsulan propiedades de las operaciones decimales: prec es la precisión, el número de decimales. rounding especifica el modo de redondeo. El módulo decimal dispone de constantes para las diferentes opciones: ROUND_DOWN (hacia cero), ROUND_CEILING (hacia arriba), ROUND_HALF_EVEN (al más cercano), entre otros. traps es un diccionario que especifica qué ocurre cuando se encuentran ciertas condiciones de error: se lanza una excepción o se devuelve un valor. Algunos ejemplos de condiciones de error son la división por cero, la pérdida de precisión y el desbordamiento. Hay un contexto predeterminado local del hilo de ejecución disponible al llamar a getcontext(); es posible cambiar las propiedades de este contexto para alterar la precisión, el redondeo o captura de errores por omisión. El siguiente ejemplo muestra el efecto de cambiar la precisión del contexto predeterminado. >>> decimal.getcontext().prec 28 >>> decimal.Decimal(1) / decimal.Decimal(7) Decimal("0.1428571428571428571428571429") >>> decimal.getcontext().prec = 9 >>> decimal.Decimal(1) / decimal.Decimal(7) Decimal("0.142857143")

Se puede seleccionar la acción predeterminada para las condiciones de error, el módulo puede devolver un valor especial, como infinito o un no-número, o lanzar excepciones: >>> decimal.Decimal(1) / decimal.Decimal(0) Traceback (most recent call last): ... decimal.DivisionByZero: x / 0 >>> decimal.getcontext().traps[decimal.DivisionByZero] = False >>> decimal.Decimal(1) / decimal.Decimal(0) Decimal("Infinity") >>>

La instancia de Context también cuenta con métodos para dar formato a números, como to_eng_string() y to_sci_string(). Si quieres más información, consulta la documentación del módulo decimal, que incluye una guía rápida y una referencia. MÃas ˛ informaciøsn en: PEP 327, “Tipo de dato Decimal” Escrita por Facundo Batista, implementada por Facundo Batista, Eric Price, Raymond Hettinger, Aahz y Tim Peters. http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html

Una visión más detallada de la representación IEEE-754. http://www.lahey.com/float.htm

Este artículo usa código Fortran para ilustrar muchos de los problemas que las inexactitudes de coma flotante puede causar. http://www2.hursley.ibm.com/decimal/

Una descripción de la representación basada en decimal. Se propone esta representación como estándar y se defiende el nuevo tipo Decimal de Python. Gran parte de este material fue escrito por Mike Cowlishaw, autor del diseño del lenguaje Rexx. 8.3

El tipo Context

11

9.

PEP 328: Importaciones multilínea

Un cambio pequeño del lenguaje es un truquillo dirigido a facilitar la importación de multitud de nombre de un módulo. En una sentencia from module import names, names es una secuencia de nombres separados por comas. Si la secuencia es muy larga, se puede indicar varias importaciones del mismo módulo o utilizar barras invertidas para neutralizar el salto de línea de este modo: from SimpleXMLRPCServer import SimpleXMLRPCServer,\ SimpleXMLRPCRequestHandler,\ CGIXMLRPCRequestHandler,\ resolve_dotted_attribute

El cambio sintáctico de Python 2.4 se limita a permitir poner los nombres entre paréntesis. Python ignora los saltos de línea dentro de una expresión entre paréntesis, por lo que ya no es necesario poner las barras invertidas from SimpleXMLRPCServer import (SimpleXMLRPCServer, SimpleXMLRPCRequestHandler, CGIXMLRPCRequestHandler, resolve_dotted_attribute)

Esta PEP también propone que todas las sentencias import sean importaciones absolutas, marcando con un carácter ‘.’ una importación relativa. Esta parte de la PEP aún no está implementada, por lo que tendrá que esperar a Python 2.5 u otra versión posterior. MÃas ˛ informaciøsn en: PEP 328, “Importaciones: Multilínea y absolutas/relativas” Escrita por Aahz. Las importaciones multilínea fueron implementadas por Dima Dorfman.

10.

PEP 331: Conversiones de flotantes/cadenas independientes de regionalización

El módulo locale permite al software en Python elegir diversas conversiones y convenciones de presentación adaptadas a las caraterísticas de un país o lengua. Sin embargo, el módulo tenía cuidado de no cambiar la regionalización de números porque hay varias funciones de la implementación de Python que exigen que la regionalización permanezca con un valor de ’C’. A menudo ocurría esto porque el código utilizaba la función atof() de la biblioteca de C. Al no establecer el valor de la regionalización para los números, se causaban problemas a las extensiones que utilizaban bibliotecas de C de terceros, sin embargo, porque ellas utilizaban el valor regionalizado correcto. El ejemplo más llamativo era GTK+, cuyos controles de la interfaz de usuario no presentaban los números en la regionalización activa. La solución descrita en la PEP es añadir tres nuevas funciones al API de Python que realizan conversiones ASCII, independientes de la regionalización: PyOS_ascii_strtod(str, ptr) y PyOS_ascii_atof(str, ptr) convierten una cadena a un double de C. PyOS_ascii_formatd(buffer, buf_len, format, d) convierte un double a una cadena ASCII. el código de estas funciones se tomó de la biblioteca GLib (http://developer.gnome.org/arch/gtk/glib.html), cuyos desarrolladores dieron una nueva licencia y donaron amablemente las funciones relevantes a la Python Software Foundation. El módulo locale puede cambiar la regionalización de los números, permitiendo que las extensiones como GTK+ produzcan resultados correctos. MÃas ˛ informaciøsn en: 12

10

PEP 331: Conversiones de flotantes/cadenas independientes de regionalización

PEP 331, “Conversiones de flotantes/cadenas independientes de regionalización” Escrita por Christian R. Reis e implementada por Gustavo Carneiro.

11.

Otros cambios del lenguaje

He aquí todos los cambios del núcleo de Python en su versión 2.4. Se añadieron los decoradores de funciones y métodos (PEP 318). Se añadieron los tipos internos set y frozenset (PEP 218). Otra función interna nueva es reversed(seq) (PEP 322). Se añadieron las expresiones generadoras (PEP 289). Ciertas expresiones numéricas ya no devuelven valores restringidos a 32 o 64 bits (PEP 237). Es posible encerrar entre paréntesis la lista de nombres de una sentencia from module import names (PEP 328). El método dict.update() ya acepta las mismas combinaciones de argumentos que el constructor de dict. Esto incluye cualquier correspondencia, cualquier iterable de parejas clave/valor y argumentos por clave (contribución de Raymond Hettinger). Los métodos de cadena ljust(), rjust() y center() ahora toman un argumento opcional para especificar un carácter de relleno diferente de un espacio (contribución de Raymond Hettinger). Las cadenas estrenan un método rsplit() que funciona como el método split() pero trocea partiendo del final de la cadena (contribución de Raymond Hettinger). >>> ’www.python.org’.split(’.’, 1) [’www’, ’python.org’] ’www.python.org’.rsplit(’.’, 1) [’www.python’, ’org’]

Se añadieron tres parámetros por nombre cmp, key y reverse al método sort() de las listas. Estos parámetros simplifican algunos usos comunes de sort(). Todos estos parámetros son opcionales. En el caso del parámetro cmp, el valor debe ser una función de comparación que tome dos parámetros y devuelva -1, 0 o +1 dependiendo del resultado de comparar los parámetros. Esta función es el criterio que se utilizará para ordenar la lista. Antes, éste era el único parámetro que se podía proporcionar a sort(). key (clave) debe ser una función de un solo parámetro que tome un elemento de la lista y devuelva una clave de comparación para el elemento. Esta lista se ordena entonces usando las claves de comparación. El siguiente ejemplo ordena una lista sin tener en cuenta las mayúsculas y las minúsculas: >>> L = [’A’, ’b’, ’c’, ’D’] >>> L.sort() # Ordenación, mayúsculas primero >>> L [’A’, ’D’, ’b’, ’c’] >>> # Uso del parámetro ’key’ para ordenar la lista >>> L.sort(key=lambda x: x.lower()) >>> L [’A’, ’b’, ’c’, ’D’] >>> # A la antigua >>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower())) >>> L [’A’, ’b’, ’c’, ’D’]

Este último ejemplo, que usa el parámetro cmp, es el antiguo método de realizar una ordenación sin tener en cuenta mayúsculas. Funciona, pero es más lento que utilizar un parámetro key. Al usar key se llama al 13

método lower() una vez por elemento de la lista, mientras que si se usa cmp, se llamará dos veces por comparación. En resumen, al usar key ahorra llamadas al método lower(). En el caso de las funciones de clave y comparación simples, suele poderse evitar una expresión lambda utilizando un método sin enlazar en su lugar. Por ejemplo, la ordenación anterior tiene una mejor escritura de este modo: >>> L.sort(key=str.lower) >>> L [’A’, ’b’, ’c’, ’D’]

Por último, el parámetro reverse toma un valor booleano. Si el valor es verdadero, la lista se ordenará en orden inverso. En lugar de L.sort() ; L.reverse(), ahora se puede escribir L.sort(reverse=True). Ahora se garantiza que los resultados de la ordenación son estables. Esto significa que los elementos con claves de ordenación iguales se devolverán en el mismo orden de entrada. Por ejemplo, se puede ordenar una lista por nombre y luego por edad. El resultado estará ordenado edad, y dentro de la misma edad ordenado por nombre. (Todos los cambios de sort() contribución de Raymond Hettinger.) Hay una nueva función interna sorted(iterable) que funciona como el método list.sort() que modifica la propia lista, pero que es utilizable en expresiones. Las diferencias son: • la entrada puede ser cualquier iterable; • se genera una copia nueva ordenada, dejando la original intacta; y • la expresión devuelve la nueva copia ordenada >>> L = [9,7,8,3,2,4,1,6,5] >>> [10+i for i in sorted(L)] # utilizable en una lista autodefinida [11, 12, 13, 14, 15, 16, 17, 18, 19] >>> L # No se modifica el original [9,7,8,3,2,4,1,6,5] >>> sorted(’Monty Python’) # cualquier iterable puede ser una entrada [’ ’, ’M’, ’P’, ’h’, ’n’, ’n’, ’o’, ’o’, ’t’, ’t’, ’y’, ’y’] >>> # Enumerar el contenido de un dict ordenado por el valor de sus claves >>> mapa_colores = dict(rojo=1, azul=2, verde=3, negro=4, amarillo=5) >>> for k, v in sorted(mapa_colores.iteritems()): ... print k, v ... negro 4 azul 2 verde 3 rojo 1 amarillo 5

(Contribución de Raymond Hettinger.) Las operaciones con enteros ya no lanzarán OverflowWarning. La advertencia OverflowWarning desaparecerá en Python 2.5. Aparece un nuevo indicador para el intérprete, -m, que toma un nombre, busca el módulo correspondiente en sys.path y ejecuta el módulo como guion. Por ejemplo, se puede ejecutar el perfilador de Python con python -m profile. (Contribución de Nick Coghlan.) Las funciones eval(expr, globals, locals), execfile(filename, globals, locals) y la sentencia exec ya aceptan cualquier tipo correspondencia en el parámetro locals. Antes sólo aceptaban diccionarios propiamente dichos. (Contribución de Raymond Hettinger.)

14

11

Otros cambios del lenguaje

Las funciones internas zip() e itertools.izip() ahora devuelven una lista vacía si se les llama sin argumentos. Antes lanzaban una excepción TypeError. Esto las hace más adecuadas para usarlas con listas de argumentos de longitud variable: >>> def transponer(matriz): ... return zip(*matriz) ... >>> transponer([(1,2,3), (4,5,6)]) [(1, 4), (2, 5), (3, 6)] >>> transponer([]) []

(Contribución de Raymond Hettinger.) Si se encuentra un fallo al importar un módulo, ya no se queda un módulo iniciado a medias en sys.modules. El objeto módulo incompleto estropeaba nuevas importaciones del mismo módulo, llevando a confusión. (Arreglo de Tim Peters.) Ahora None es una constante; el código que asigne un valor nuevo al nombre ‘None’ es ahora un error de sintaxis. (Contribución de Raymond Hettinger.)

11.1.

Optimizaciones

Se han optimizado los bucles internos para hacer cortes de listas y tuplas, y ahora se ejecutan cerca de un terció más rápido. También se han optimizado los bucles internos de los diccionarios, consiguiéndose mejoras de rendimiento en keys(), values(), items(), iterkeys(), itervalues() y iteritems(). (Contribución de Raymond Hettinger.) Se ha optimizado la maquinaria de crecer y menguar las listas en cuanto a velocidad y ocupación. Añadir y tomar elementos del extremo de las listas es más rápido gracias a caminos de código más eficientes y al uso reducido de la función de sistema realloc() subyacente. También se han beneficiado de esto las listas autodefinidas. Se ha optimizado list.extend(); ya no convierte sus argumentos a una lista temporal antes de extender la lista base. (Contribución de Raymond Hettinger.) list(), tuple(), map(), filter() y zip() ahora son varias veces más rápidas con argumentos no secuenciales que proporcionan un método __len__(). (Contribución de Raymond Hettinger.) Los métodos list.__getitem__(), dict.__getitem__() y dict.__contains__() ahora se implementan como objetos method_descriptor en lugar de objetos wrapper_descriptor. Esta forma de acceso duplica su rendimiento y los hace más adecuados para la programación funcional: ‘map(midict.__getitem__, listaclaves)’. (Contribución de Raymond Hettinger.) Se ha añadido un nuevo “opcode”, LIST_APPEND, que simplifica el “bytecode” generado para las listas autodefinidas y aumenta su velocidad en 1/3. (Contribución de Raymond Hettinger.) El microoptimizador de “bytecode” se ha mejorado para producir “bytecode” más breve y más rápido; además, el código resultante es más legible. (Mejorado por Raymond Hettinger.) Las concatenaciones de cadenas de la forma s = s + "bla" y s += "bla" se realizan de una manera más eficaz en ciertas condiciones. Esta optimización aún no estará presente en otras implementaciones, como en Jython, por lo que no conviene fiarse de esto; aún se recomienda el uso del método join() de las cadenas cuando se desee empalmar una gran cantidad de cadenas. (Contribución de Armin Rigo.) El resultado neto de las optimizaciones es que Python 2.4 ejecuta el banco de pruebas pystone alrededor de 5 % más rápido que 2.3 y 35 % más rápido que Python 2.2 (pystone no es un banco de pruebas especialmente bueno, pero es el más utilizado para medir el rendimiento de Python. Las aplicaciones concretas pueden beneficiarse en mayor o menor grado de Python 2.4).

11.1

Optimizaciones

15

12.

Módulos nuevos, mejorados y abandonados

Como es habitual, la biblioteca estándar de Python sufrió mejoras y corrección de errores. He aquí una lista, incompleta, de los cambios más notables, por orden alfabético del nombre del módulo afectado. En el fichero ‘Misc/NEWS’ del árbol de las fuentes una lista más exhaustiva de los cambios y en los registros de CVS están todos los detalles. En el módulo asyncore, la función loop() ahora tiene un parámetro count que permite realizar un número limitado de pasadas por el bucle de muestreo. El valor predeterminado sigue siendo un bucle infinito. El módulo base64 dispone de soporte RFC 3548 más completo para codificación y descodificación Base64, Base32 y Base16, incluyendo cambios de mayúsculas/minúsculas y alfabetos alternativos opcionales. (Contribución de Barry Warsaw.) El módulo bisect cuenta ahora con una implementación en C que mejora su rendimiento. (Contribución de Dmitry Vasiliev.) Se integraron en la versión 2.4 las colecciones CJKCodecs de codecs del Este asiático, mantenidas por Hye-Shik Chang. Las nuevas codificaciones son: • Chino (PRC): gb2312, gbk, gb18030, big5hkscs, hz • Chino (ROC): big5, cp950 • Japonés: cp932, euc-jis-2004, euc-jp, euc-jisx0213, iso-2022-jp, iso-2022-jp-1, iso-2022-jp-2, iso2022-jp-3, iso-2022-jp-ext, iso-2022-jp-2004, shift-jis, shift-jisx0213, shift-jis-2004 • Coreano: cp949, euc-kr, johab, iso-2022-kr Se han añadido algunas codificaciones nuevas: HP Roman8, ISO_8859-11, ISO_8859-16, PCTP-154 y TIS620. Los codecs de UTF-8 y UTF-16 gestionan mejor la recepción parcial de datos. Antes, la clase StreamReader intentaba leer más datos, imposibilitando reanudar la descodificación del flujo de datos. Ahora el método read() devolverá tantos datos como pueda y las siguientes llamadas reaunudarán la descodificación donde se quedaron las anteriores. (Implementada por Walter Dörwald.) Hay un nuevo módulo collections que contiene diversos tipos de datos colección especializados. Por el momento, sólo contiene un tipo, deque, una cola de dos extremos que da soporte a añadir y quitar elementos eficientemente de cualquiera de los extremos: >>> from collections import deque >>> d = deque(’ghi’) # genera una nueva deque con tres elementos >>> d.append(’j’) # añade un nuevo elemento por la derecha >>> d.appendleft(’f’) # añade uno por la izquierda >>> d # muestra el contenido de la deque deque([’f’, ’g’, ’h’, ’i’, ’j’]) >>> d.pop() # obtiene y elimina el elemento de la derecha ’j’ >>> d.popleft() # obtiene y elimina el elemento de la derecha ’f’ >>> list(d) # muestra la deque convertida en lista [’g’, ’h’, ’i’] >>> ’h’ in d # buscar en la deque True

Varios módulos, como Queue y threading, ahora aprovechan collections.deque para mejorar su rendimiento. (Contribución de Raymond Hettinger.) Se han mejorado las clases de ConfigParser. El método read() ahora devuelve una lista de los ficheros que se analizaron con éxito y el método set() lanza TypeError si recibe un argumento value que no sea una cadena (Contribución de John Belmonte y David Goodger.)

16

12

Módulos nuevos, mejorados y abandonados

El módulo curses ahora ofrece la extensión de ncurses use_default_colors(). En plataformas cuyo terminal disponga de transparencia, esto posibilita utilizar un fondo transparente. (Contribución de Jörg Lehmann.) El módulo difflib ahora incluye una clase HtmlDiff que genera una tabla HTML que muestra una comparación de dos versiones de un texto. (Contribución de Dan Gass.) Se ha actualizado el paquete email a la versión 3.0, abandonando ciertas APIs obsoletas y el soporte de versiones de Python anteriores a la 2.3. La versión 3.0 utiliza un nuevo analizador incremental para los mensajes MIME, disponible en el módulo email.FeedParser. El nuevo analizador no exige leer el mensaje entero en memoria y no lanza excepciones si el mensaje no está bien formado, sino que registra los posibles problemas en el atributo defect del mensaje. (Desarrolado por Anthony Baxter, Barry Warsaw, Thomas Wouters, entre otros.) Se ha convertido el módulo heapq a C. Al acelerarse en un factor de diez, se ha hecho aceptable su uso con volúmenes de carga elevados. Además, el módulo cuenta con dos nuevas funciones, nlargest() y nsmallest(), que usan montículos para encontrar los N mayores o menores valores de un juego de datos sin tener que ordenar el conjunto completo. (Contribuición de Raymond Hettinger.) El módulo httplib ahora contiene constantes para los códigos de estado definidos en diversos RFC relativos a HTTP. Las constantes tienen nombres del estilo de OK, CREATED, CONTINUE o MOVED_PERMANENTLY. Se puede obtener la lista completa usando pydoc. (Contribución de Andrew Eland.) El módulo imaplib ahora soporta la orden de IMAP THREAD (contribución de Yves Dionne) y cuenta con los nuevos métodos deleteacl() y myrights() (contribución de Arnaud Mazin). El módulo itertools mejora con una función groupby(iterable[, func ]). iterable es algún valor sobre el que se puede iterar para obtener un flujo de elementos y el parámetro opcional func es una función que toma un elemento y devuelve un valor clave; si se omite, la clave es el propio elemento. groupby() agrupa los elementos en subsecuencias que contienen valores iguales de clave y devuelve una serie de duplas que contienen la clave y un iterador de la subsecuencia. Intentaremos aclarar esto con un ejemplo. La función key simplemente devuelve si el número es par o impar, para que el resultado de groupby() sea filas consecutivas de números impares o pares. >>> import itertools >>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14] >>> for key_val, it in itertools.groupby(L, lambda x: x % 2): ... print key_val, list(it) ... 0 [2, 4, 6] 1 [7] 0 [8] 1 [9, 11] 0 [12, 14] >>>

A menudo, groupby() se aplica sobre una entrada ordenada. La lógica de groupby() se parece a la de el filtro de U NIX uniq, lo que hace que sea de mucha ayuda para eliminar, contar o identificar duplicados:

17

>>> palabra = ’abracadabra’ >>> letras = sorted(palabra) # Saca una lista ordenada de sus letras >>> letras [’a’, ’a’, ’a’, ’a’, ’a’, ’b’, ’b’, ’c’, ’d’, ’r’, ’r’] >>> for k, g in itertools.groupby(letras): ... print k, list(g) ... a [’a’, ’a’, ’a’, ’a’, ’a’] b [’b’, ’b’] c [’c’] d [’d’] r [’r’, ’r’] >>> # Lista de letras sin repetir >>> [k for k, g in groupby(letras)] [’a’, ’b’, ’c’, ’d’, ’r’] >>> # Contar apariciones de una letra >>> [(k, len(list(g))) for k, g in groupby(letras)] [(’a’, 5), (’b’, 2), (’c’, 1), (’d’, 1), (’r’, 2)]

(Contribución de Hye-Shik Chang.) itertools también cuenta con una nueva función tee(iterator, N) que devuelve N iteradores independientes, réplica de iterator. Si se omite N se devuelven dos copias. >>> L = [1,2,3] >>> i1, i2 = itertools.tee(L) >>> i1,i2 (, ) >>> list(i1) # Recorre el primer iterador hasta agotarlo [1, 2, 3] >>> list(i2) # Recorre el segundo iterador hasta agotarlo [1, 2, 3] >

Hay que destacar que tee() debe mantener copias de los valores devueltos por el iterador y, en el peor de los casos, puede que tenga que mantener copia de todos. Se ha de evaluar detenidamente si uno de los iteradores va a adelantar mucho al último en un flujo de entrada largo. Si la separación se hace muy grande, puede convenir usar list() mejor. Cuando los iteradores se mantienen casi parejos, el uso de tee() es óptimo. Las posibles aplicaciones incluyen marcado de texto, ventanas de señal o iteradores con acceso a elementos futuros. (Contribución de Raymond Hettinger.) Se han añadido varias funciones al módulo locale, como bind_textdomain_codeset() para especificar una codificación particular y una familia de funciones l*gettext() que devuelven los mensajes en la codificación elegida. (Contribución de Gustavo Niemeyer.) Se han añadido argumentos con nombre a la función basicConfig del paquete logging para simplificar la configuración del registro. El comportamiento predeterminado es registrar los mensajes al flujo de error estándar, pero se pueden especificar varios argumentos con nombre para registrar sobre un fichero particular, cambiar el formato de registro o establecer el nivel de registro. Por ejemplo: import logging logging.basicConfig(filename=’/var/log/aplicacion.log’, level=0, # Registrar todos los mensajes format=’%(levelname):%(process):%(thread):%(message)’)

Otras mejoras del paquete logging son el método de servicio log(level, msg), además de una clase TimedRotatingFileHandler que rota sus ficheros de registro a un intervalo dado. El módulo ya contaba con RotatingFileHandler, que rotaba los registros al alcanzar un tamaño dado. Las dos clases se derivan de una clase nueva BaseRotatingHandler que se puede utilizar para implementar otros gestores de rotación. (Cambios implementados por Vinay Sajip.) 18

12

Módulos nuevos, mejorados y abandonados

El módulo marshal ahora comparte las cadenas internadas al desempaquetar una estructura de datos. Esto puede suponer una reducción en el tamaño de ciertas cadenas estibadas (pickled), pero el principal efecto es el de reducir significativamente el tamaño de los archivos ‘.pyc’. (Contribución de Martin von Loewis.) En el módulo nntplib, la clase NNTP se mejora con los métodos description() y descriptions() para obtener las descripciones de un solo grupo o varios, respectivamente. (Contribución de Jürgen A. Erhard.) Se ha añadido dos nuevas funciones al módulo operator, attrgetter(attr) y itemgetter(index). Las dos devuelven objetos invocables que toman un solo argumento y devuelven el atributo o elemento correspondiente; esto las hace idóneas para extraer datos al usar map() o sorted(). Por ejemplo: >>> L = [(’c’, 2), (’d’, 1), (’a’, 4), (’b’, 3)] >>> map(operator.itemgetter(0), L) [’c’, ’d’, ’a’, ’b’] >>> map(operator.itemgetter(1), L) [2, 1, 4, 3] >>> sorted(L, key=operator.itemgetter(1)) # Ordena la lista por el segundo elemento [(’d’, 1), (’c’, 2), (’b’, 3), (’a’, 4)]

(Contribución de Raymond Hettinger.) El módulo optparse ha sufrido diversas mejoras. El módulo ahora pasa sus mensajes por gettext.gettext(), posibilitando internacionalizar la ayuda y los mensajes de error de Optik. Los mensajes de ayuda de las opciones ahora pueden incluir la cadena ’%default’, que será sustituida por el valor predeterminado de la opción (contribución de Greg Ward). El plan a largo plazo es declarar obsoleto el módulo rfc822 en una versión futura de Python, en favor del paquete email. Con esto como objetivo, se ha cambiado la función email.Utils.formatdate() para que sea un reemplazo adecuado de rfc822.formatdate(). Es deseable que el código que se escriba de ahora en adelante tenga esto presente. (Cambio implementado por Anthony Baxter.) Se ha añadido una función nueva, urandom(n), al módulo os, que devuelve una cadena de n bytes de datos aleatorios. Esta función proporciona un acceso dependiente de la plataforma a fuentes de aleatoriedad, como ‘/dev/urandom’ en Linux o la CryptoAPI de Windows. (Contribución de Trevor Perrin.) Otra función nueva: os.path.lexists(path) devuelve verdadero si existe el fichero especificado por path, sea o no un enlace simbólico. Esto difiere de la función existente os.path.exists(path), que devuelve falso si path es un enlace simbólico que apunta a un destino inexistente. (Contribución de Beni Cherniavsky.) Se añadió una nueva función getsid() al módulo posix subyacente al módulo os. (Contribución de J. Raynor.) El módulo poplib ahora da soporte a POP sobre SSL. (Contribución de Héctor Urtubia.) El módulo profile ahora puede perfilar funciones de extensión en C. (Contribución de Nick Bastin.) El módulo random ahora cuenta con un nuevo método getrandbits(N) que devuelve un entero largo de N bits de longitud. El método existente randrange() ahora usa getrandbits() donde ha lugar, haciendo más eficaz la generación de números aleatorios arbitrariamente grandes. (Contribución de Raymond Hettinger.) Se ha extendido el lenguaje de expresiones regulares aceptado por el módulo re con expresiones condicionales simples, escritas como d(?(group)A|B)c. group es un ID de grupo numérico o un nombre de grupo definido antes con d(?P...)c dentro de la expresión. Si coincide el grupo especificado, se comprobará la expresión regular A contra la cadena; si no, se utilizará el patrón B en su lugar. (Contribución de Gustavo Niemeyer.) El módulo re deja de ser recursivo, gracias a un trabajo titánico de Gustavo Niemeyer. En un motor de expresiones regulares recursivo, ciertos patrones causan que se ocupe una gran cantidad de la pila de C, por lo que era posible desbordarla. Por ejemplo, a comparar una cadena de 30000 caracteres ‘a’ contra la 19

expresión d(a|b)+c, se consumía un marco de pila por carácter. Python 2.3 intentaba verificar el desbordamiento y lanzar una excepción RuntimeError, pero ciertos patrones desafortunados podrían saltarse la comprobación y causar un fallo de segmentación en Python. El motor de expresiones regulares de Python puede comprobar este tipo de patrones sin problemas. El módulo signal ahora realiza comprobaciones de errores más estrictas sobre los parámetros de la función signal.signal(). Por ejemplo, no se puede establecer un gestor de la señal SIGKILL; las versiones anteriores de Python aceptaban esto silenciosamente, pero la 2.4 hará saltar una excepción RuntimeError. Se han añadido dos nuevas funciones al módulo socket. socketpair() devuelve un par de zócalos conectados y getservbyport(port) busca el nombre de servicio para un número de puerto dado. (Contribución de Dave Cole y Barry Warsaw.) La función sys.exitfunc() se ha abandonado. El código deberá adaptarse a usar el módulo existente atexit, que gestiona correctamente múltiples funciones de salida. Al final, sys.exitfunc() se convertirá simplemente en una interfaz estrictamente interna, accesible sólo desde el módulo atexit. El módulo tarfile ahora genera ficheros tar de formato GNU de manera predeterminada. (Contribución de Lars Gustaebel.) El módulo threading ahora cuenta con un sistema elegantemente simple de proporcionar datos locales al hilo. El módulo contiene una clase local cuyos valores de atributo son locales al hilo. import threading data = threading.local() data.number = 42 data.url = (’www.python.org’, 80)

Otros hilos pueden asignar y recuperar sus propios valores a los atributos number y url. Se puede derivar local para inicializar atributos o añadir métodos. (Contribución de Jim Fulton.) El módulo timeit ahora desactiva automáticamente la recolección periódica de basura durante el bucle de temporización. Estos cambios hacen más comparables medidas consecutivas. (Contribución de Raymond Hettinger.) El módulo weakref ahora da soporte a una variedad ampliada de objetos, incluyendo funciones de Python, instancias de clases, conjuntos, conjuntos congelados, deques, matrices, ficheros, zócalos y objetos patrón de expresiones regulares. (Contribución de Raymond Hettinger.) El módulo xmlrpclib ahora dispone de una extensión multillamada para transmitir múltiples llamadas XML-RPC en una sola operación HTTP. (Contribución de Brian Quinlan.) Se han retirado los módulos mpz, rotor y xreadlines.

12.1.

cookielib

La biblioteca cookielib permite la gestión en el lado del cliente de cookies (galletas) HTTP, a imagen del módulo Cookie de gestión de cookies del lado del servidor. Las cookies se guardan en tarros de cookies; la biblioteca almacena transparentemente las cookies ofrecidas por el servidor web al conectarse al servidor. Como en los navegadores normales, hay un objeto de política que controla si se aceptan o no las cookies. Para guardar las cookies entre sesiones, se proporcionan dos implementaciones de tarros de cookies: Una almacena las cookies en el formato Netscape, para que las aplicaciones puedan utilizar los ficheros de cookies de Mozilla o Lynx, y otra que almacena las cookies en el mismo formato que la biblioteca de Perl libwww. Se ha cambiado el módulo urllib2 para interactuar con cookielib: HTTPCookieProcessor gestiona un tarro de cookies que se utiliza al acceder a URLs. (Contribución de John J. Lee.)

20

12

Módulos nuevos, mejorados y abandonados

12.2.

doctest

El módulo doctest sufrió una considerable refactorización gracias a Edward Loper y Tim Peters. Las pruebas pueden ser tan sencillas como ejecutar doctest.testmod(), pero las refactorizaciones permiten adaptar el funcionamiento del módulo de diversas maneras. La nueva clase DocTestFinder extrae las pruebas de las cadenas de documentación de un objeto dado: def f (x, y): """>>> f(2,2) 4 >>> f(3,2) 6 """ return x*y buscador = doctest.DocTestFinder() # Obtener la lista de instancias de DocTest pruebas = buscador.find(f)

Entonces, la nueva clase DocTestRunner ejecuta las pruebas individuales y puede producir un resumen de los resultados: ejecutor = doctest.DocTestRunner() for t in tests: tried, failed = ejecutor.run(t) ejecutor.summarize(verbose=1)

El ejemplo produce la siguiente salida: 1 items passed all tests: 2 tests in f 2 tests in 1 items. 2 passed and 0 failed. Test passed.

DocTestRunner usa una instancia de la clase OutputChecker para comparar la salida esperada con la salida real. Esta clase admite diferentes indicadores que personalizan su comportamiento; los usuarios ambiciosos también pueden escribir una subclase de OutputChecker completamente nueva. El comprobador de salida predefinido ofrece características muy útiles. Por ejemplo, con el indicador de opción doctest.ELLIPSIS, los puntos suspensivos (‘...’) de la entrada pueden coincidir con cualquier subcadena, facilitando acomodar salidas que varían ligeramente: def o (n): """>>> o(1) >>> """

Hay otra cadena, ‘’, que coincide con una línea en blanco:

12.2

doctest

21

def p (n): """>>> p(1) >>> """

Otra posibilidad nueva es la de producir una presentación tipo diff de la salida especificando los indicadores de opción doctest.REPORT_UDIFF (unificados), doctest.REPORT_CDIFF (de contexto) o doctest.REPORT_NDIFF (tipo delta). Por ejemplo: def g (n): """>>> g(4) bajel pirata que llaman >>>""" L = ’bajel pirata que llaman por su bravura el temido’.split() for palabra in L[:n]: print palabra

Al ejecutar esto especificando doctest.REPORT_UDIFF, se obtiene el siguiente resultado: ********************************************************************** File ‘‘t.py’’, line 15, in g Failed example: g(4) Differences (unified diff with -expected +actual): @@ -2,3 +2,3 @@ pirata que -laman +llaman **********************************************************************

13.

Cambio en el proceso de compilación y el API de C

Los cambios del proceso de compilación y el API de C incluyen: Se han añadido tres nuevas macros de servicio para valores de retorno comunes desde las funciones de extensión: Py_RETURN_NONE, Py_RETURN_TRUE y Py_RETURN_FALSE. (Contribución de Brett Cannon.) Otra macro nueva, Py_CLEAR(obj), decrementa la cuenta de referencias de obj y asigna a obj el puntero a nulo. (Contribución de Jim Fulton.) Una nueva función, PyTuple_Pack(N, obj1, obj2, ..., objN), construye tuplas a partir de una lista de argumentos de logitud variable de objetos Python. (Contribución de Raymond Hettinger.) Una nueva función, PyDict_Contains(d, k), implementa búsquedas en diccionarios rápidas sin enmascarar las excepciones ocurridas durante el proceso de la búsqueda. (Contribución de Raymond Hettinger.) La macro Py_IS_NAN(X) devuelve 1 si su argumento float o double X es un NaN (no-número). (Contribución de Tim Peters.)

22

13

Cambio en el proceso de compilación y el API de C

El código en C puede evitar bloqueos innecesarios utilizando la nueva función PyEval_ThreadsInitialized() que indica si se han realizado operaciones de multihilo. Si esta función devuelve falso, no se necesita hacer operaciones de bloqueo. (Contribución de Nick Coghlan.) La nueva función PyArg_VaParseTupleAndKeywords() es la misma que PyArg_ParseTupleAndKeywords() pero toma una va_list en lugar de un número de argumentos. (Contribución de Greg Chapman.) Un nuevo indicador, METH_COEXISTS, permite que una función definida con ranuras coexista con una PyCFunction homónima, Esto puede recortar a la mitad el tiempo de acceso de un método como set.__contains__(). (Contribución de Raymond Hettinger.) Python se puede compilar con perfilado adicional para el propio intérprete, para ayudar a los desarrolladores del núcleo de Python. Si se da la opción -—enable-profiling al guion configure estará permitido perfilar el intérprete con gprof, y si se da la opción -—with-tsc se permitirá el perfilado usando el registro del Pentium Time-Stamp-Counter. Hay que tener en cuenta que la opción -—with-tsc tiene un nombre algo confuso, porque la capacidad de perfilado también se aplica a la plataforma PowerPC, aunque esta arquitectura no denomina al registro correspondiente “TSC”. (Contribución de Jeremy Hylton.) Se ha renombrado el tipo tracebackobject a PyTracebackObject.

13.1.

Cambios específicos de las plataformas

La versión de Windows se puede compilar sobre MSVC++ 7.1 además de sobre la versión 6. (Contribución de Martin von Loewis.)

14.

Migrar a Python 2.4

Esta sección enumera los cambios anteriores que pueden exigir cambios al código: Los desplazamientos a la izquierda y las constantes hexadecimales/octales demasiado grandes ya no lanzan FutureWarning y devuelven un valor limitado a 32 o 64 bits; devolverán un entero largo. Las operaciones de enteros ya no lanzarán OverflowWarning. La advertencia OverflowWarning desaparecerá en Python 2.5. La función interna zip() y itertools.izip() ahora devuelven una lista vacía en lugar de lanzar una excepción TypeError si se les llama sin argumentos. dircache.listdir() Ahora traspasa las excepciones al llamante en lugar de devolver listas vacías. Antes, LexicalHandler.startDTD() recibía los IDs del sistema público y privado en orden incorrecto. Esto ha sido corregido; hay que corregir las aplicaciones que esperaban el comportamiento erróneo anterior. fcntl.ioctl ahora avisa si se omite el argumento mutate y es relevante. El módulo tarfile ahora genera ficheros tar de formato GNU de manera predeterminada. Si se encuentra un fallo al importar un módulo, ya no queda un módulo inicializado a medias en sys.modules. None ahora es una constante; el código que le asigne un valor a ‘None’ ahora es un error de sintaxis. La función signals.signal() ahora lanza una excepción RuntimeError para ciertos valores ilegales de entrada; antes estos errores pasaban silenciosamente. Por ejemplo, ya no es posible establecer un manejador de la señal SIGKILL.

13.1

Cambios específicos de las plataformas

23

15.

Agradecimientos

El autor agradece a las siguientes personas por ofrecer sugerencias, correcciones y asistencia con los diversos borradores de este artículo: Koray Can, Hye-Shik Chang, Michael Dyck, Raymond Hettinger, Brian Hurt, Hamish Lawson, Fredrik Lundh, Sean Reifschneider.

16.

Sobre la traducción

Esta traducción al castellano fue realizada por Marcos Sánchez Provencio ([email protected]), con correcciones de Sonia Rubio Hernando.

24

16

Sobre la traducción