Qué hay de nuevo en Python 2.4
******************************

Autor:
   A.M. Kuchling

Este artículo explica las nuevas funcionalidades en Python 2.4.1
lanzadas el 30 de marzo de 2005.

Python 2.4 es un lanzamiento de término medio. Esto significa que no
se han introducido grandes cambios como en la versión 2.2 de Python
pero si son más significativas que la versión 2.3. Lo más relevante de
estas nuevas funcionalidades son los decoradores y generadores de
expresiones, la mayor parte del resto de los cambios son a la librería
estándar.

De acuerdo al registro de cambios CVS , han sido aplicados 481 parches
y 502 bugs han sido corregidos entre las versiones 2.3 y 2.4 de
Python. Es posible que ambas cifras no concuerden con la realidad,
podrían estar subestimadas.

Este artículo no pretende proveer una especificación completa y
detallada de cada funcionalidad nueva, en vez de esto, se provee una
breve descripción de las nuevas características. Para obtener más
información se debe consultar la documentación oficial de Python 2.4,
tal como la librería de referencia de Python y el manual de referencia
de Python. Otra fuente de información es PEP (guía de estilo-mejoras
de python) para buscar información sobre la implementación y
fundamentación del diseño.


PEP 218: Objetos conjunto integrados
====================================

Python 2.3 introdujo el módulo "sets" , implementaciones del lenguaje
C de tipos de datos han sido agregados al core de Python como dos
nuevos tipos integrados. "set (iterable)" y "frozenset (iterable)" .
Ellos proveen operaciones de alto rendimiento para pruebas de
pertenencia, eliminar datos duplicados de una secuencia y operaciones
matemáticas como: uniones, intersecciones, diferencias y diferencias
simétricas.

   >>> a = set('abracadabra') # formar un conjunto a partir de una cadena
   >>> 'z' en a # prueba rápida de pertenencia
   Falso
   >>> a # letras únicas en a
   set(['a', 'r', 'b', 'c', 'd'])
   >>> ''.join(a) # convertir de nuevo a una cadena
   'arbcd'

   >>> b = set('alacazam') # formar un segundo conjunto
   >>> a - b # letras en a pero no en b
   set(['r', 'd', 'b'])
   >>> a | b # letras en a o b
   set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
   >>> a & b # letras en a y b
   set(['a', 'c'])
   >>> a ^ b # letras en a o b pero no en ambos
   set(['r', 'd', 'b', 'm', 'z', 'l'])

   >>> a.add('z') # agrega un nuevo elemento
   >>> a.update('wxy') # agrega varios elementos nuevos
   >>> a
   set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z'])
   >>> a.remove('x') # saca un elemento
   >>> a
   set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z'])

La función de conjuntos integrados "frozenset()" es una versión
inmutable de "set()". Como es inmutable y hashable (su valor no
cambia), se puede usar como una llave de diccionario o como parte de
otro set.

El módulo set "sets" se encuentra en la librería estándar y puede ser
útil si se desea usar una subclase de "Set" o "ImmutableSet" No
existen planes de deprecación del módulo.

Ver también:

  **PEP 218** - Agregando tipo de objeto integrado set
     Originalmente propuesto por Greg Wilson e implementado finalmente
     por Raymond Hettinger.


PEP 237: Unificando enteros largos y enteros
============================================

El prolongado proceso de transición para este PEP que comenzó en
Python 2.2 ha dado un paso más adelante en Python 2.4. En la versión
2.3 ciertas operaciones de enteros podían comportarse diferente
después de lanzar la unificación del tipo de dato int-long entregando
alertas "FutureWarning" y retornando valores limitados a 32 o 64 bits
dependiendo de su plataforma. En la versión 2.4 estas expresiones ya
no producen alertas y en vez de eso entrega un resultado diferente que
suele ser un entero largo.

Las expresiones problemáticas son principalmente desplazamientos a la
izquierda y constantes largas de hexadecimales y octales. Por ejemplo,
"2 << 32"  entrega una alerta en la versión 2.3 y evalúa 0 en
plataformas 32-bit. Ahora en Python 2.4 la expresión retorna la
respuesta correcta, 8589934592.

Ver también:

  **PEP 237** - Unificando enteros largos y enteros
     PEP original escrito por Moshe Zadka y GvR.  Los cambios a la
     versión 2.4 fueron implementados por Kalle Svensson.


PEP 289: Expresiones generadoras
================================

La función de iterador introducida en Python 2.2 y el módulo
"itertools" facilitan la escritura de programas que recorren grandes
conjuntos de datos sin tener todo el conjunto de datos en la memoria
al mismo tiempo. Las listas de comprensión no encajan muy bien en esta
imagen porque producen un objeto de lista de Python que contiene todos
los elementos. Esto inevitablemente lleva todos los objetos a la
memoria, lo que puede ser un problema si su conjunto de datos es muy
grande. Al tratar de escribir un programa de estilo funcional, sería
natural escribir algo como:

   links = [enlace para enlace en get_all_links() si no es link.followed]
   para enlace en enlaces:
   ...

en vez de

   para el enlace en get_all_links():
   si link.followed:
   continúa
   ...

La primera forma es mas concisa y quizás mas legible pero en caso de
trabajar con un gran número largo de objetos podría ser necesario el
escribir una segunda línea para evitar tener los objetos enlazados en
memoria al mismo tiempo.

Las expresiones generadoras trabajan de forma similar a las listas por
comprensión pero no materializan la lista completa, en vez de eso se
crea un generador que retornará los elementos uno a uno. El siguiente
ejemplo podría ser escrito como:

   links = (enlace para enlace en get_all_links() si no se sigue el enlace)
   para enlace en enlaces:
   ...

Los generadores de expresiones siempre tienen que ser escritos dentro
de paréntesis como en el ejemplo descrito arriba. Los paréntesis
señalan una llamada a la función que también se puede contar, entonces
si se necesita crear un iterador que inmediatamente pasara a una
función se podría escribir:

   imprimir suma(obj.count para obj en list_all_objects())

Las expresiones generadoras difieren de las listas de comprensión por
pequeñas diferencias. La mas notable es que la variable del loop
(*obj* en el ejemplo de arriba) no es accesible fuera de la expresión
generadora. Las listas de comprensión dejan la variable asignada a su
último valor, en versiones futuras de Python esto será cambiado en lo
que respecta a hacer que las listas de comprensión coincidan con las
expresiones de los generadores.

Ver también:

  **PEP 289** - Expresiones generadoras
     Propuesto por Raymond Hettinger e implementada por Jiwon Seo con
     los primeros esfuerzos dirigidos por Hye-Shik Chang.


PEP 292: Sustituciones simples de cadenas de caracteres
=======================================================

Algunas nuevas clases en la librería estándar proveen un mecanismo
alternativo para sustituir variables dentro de cadenas de caracteres,
este estilo de sustituciones puede ser mejor por aplicaciones donde
usuarios sin experiencia necesitan editar plantillas.

La manera usual de sustituir variables por el nombre es con el
operador "%" :

   >>> '%(page)i: %(title)s' % {'page':2, 'title': 'Lo mejor de los tiempos'}
   '2: Lo mejor de los tiempos'

Cuando se escriben plantillas con cadenas de caracteres puede ser muy
fácil olvidar el uso de "i" or "s" después de cerrar paréntesis. Esto
no es un problema grande si se está dentro de un módulo de Python pues
al correr el código se lanza el siguiente mensaje de error
"Unsupported format character" "ValueError" y el problema se resuelve.
Sin embargo, tengamos en cuenta una aplicación como Mailman donde una
plantilla de caracteres o traducciones son editadas por usuarios que
no están familiarizados con Python. La sintaxis de como formatear las
cadenas de caracteres es complicada de explicar para ciertos usuarios
y si ellos cometen un error es una dificultad el entregar
retroalimentación y ayuda.

PEP 292 agrega una clase "Template" al módulo "string" al módulo que
usa "$" para indicar una sustitución:

   >>> import string
   >>> t = string.Template('$page: $title')
   >>> t.substitute({'page':2, 'title': 'Lo mejor de los tiempos'})
   '2: Lo mejor de los tiempos'

Si una llave falta en el diccionario, el método "substitute()" lanzará
una "KeyError". También el método "safe_substitute()" que ignora las
llaves faltantes:

   >>> t = string.Template('$página: $título')
   >>> t.safe_substitute({'página':3})
   '3: $título'

Ver también:

  **PEP 292** - Sustituciones simples de cadenas de caracteres
     Escrito e implementado por Barry Warsaw.


PEP 318: Decoradores para funciones y métodos
=============================================

Python 2.2 extendió el modelo de objeto de Python añadiendo métodos
estáticos y métodos de clase pero no se extendió la sintaxis de Python
para proveer alguna nueva forma de definir métodos estáticos o de
clase. En vez de eso se tenía que escribir la palabra clave "def" de
manera usual y pasar el método resultante a la "staticmethod()" o a la
"classmethod()" que podía agrupar la función como método de un nuevo
tipo. El código podría verse como esto:

   clase C:
   def meth (cls):
   ...

   meth = classmethod(meth) # Volver a vincular el nombre al método de clase encapsulado

Si el método era muy largo, era muy probable el perder o olvidar la
invocación "classmethod()" dentro del cuerpo de la función.

La intención era siempre agregar alguna sintaxis que hicieran las
definiciones mas entendibles pero al tiempo del lanzamiento de la
versión 2.2 una buena sintaxis no era clara. Al día de hoy una buena
sintaxis aun no es clara pero los usuarios están preguntando por
formas más fáciles de acceder a las características, entonces una
nueva funcionalidad sintáctica ha sido añadida para satisfacer esta
necesidad.

La nueva característica es llamada decoradores de funciones. El nombre
proviene de la idea de que "classmethod()", "staticmethod()" son
amigos y guardan información adicional en un objeto de una función.
ellos están decorando funciones con mas detalles.

La notación proviene de Java y usa el "'@'" símbolo arroba como un
indicador. Usando la nueva sintaxis el ejemplo descrito arriba podría
ser escrito de la siguiente forma:

   clase C:

   @classmethod
   def meth (cls):
   ...

El "@classmethod"  es un atajo para "meth=classmethod(meth)". De forma
general si se tiene lo siguiente:

   @A
   @B
   @C
   def f():
   ...

Es el equivalente para el siguiente código de pre decorador:

   definición f(): ...
   f = A(B(C(f)))

Los decoradores deben agregarse en una línea antes de la definición de
la función, un decorador por línea y no puede estar en la misma línea
donde se usa la palabra def para comenzar una función, por ejemplo "@A
def f(): ..." es incorrecto. Solo se puede decorar una definición de
función tanto al nivel de módulo o dentro de una clase pero no puedes
decorar definiciones de clase.

Un decorador es simplemente una función que toma la función a ser
decorada como un argumento y retorna tanto la misma función o un nuevo
objeto. El valor de retorno del decorador no necesita ser llamado
(como típicamente se cree) si no que los decoradores podrán ser
aplicados al resultado. Es fácil escribir sus propios decoradores. El
siguiente ejemplo agrega un atributo a la función objetiva:

   >>> def deco(func):
   ... func.attr = 'decorado'
   ... return func
   ...
   >>> @deco
   ... def f(): pass
   ...
   >>> f
   <función f en 0x402ef0d4>
   >>> f.attr
   'decorado'
   >>>

Como un ejemplo un poco mas realista, el siguiente decorador revisa si
el argumento entregado es un entero:

   def require_int (función):
   def contenedor (arg):
   assert isinstance(arg, int)
   return func(arg)

   return contenedor

   @require_int
   def p1 (arg):
   print arg

   @require_int
   def p2(arg):
   print arg*2

Un ejemplo en **PEP 318**  contiene una versión mas elegante de esta
idea donde deja que usted elija específicamente el tipo y revisa el
tipo de retorno.

Los decoradores de funciones pueden tomar argumentos. Si los
argumentos son provistos, el decorador de la función es llamado con
solo esos argumentos y retorna un nuevo decorador de función, esta
función debe tomar una función sola y retorna una función como
previamente se ha descrito. En otras palabras "@A @B @C(args)"
comienza:

   def f(): ...
   _deco = C(argumentos)
   f = A(B(_deco(f)))

Conseguir que esto resulte correcto puede ser un acertijo pero tampoco
es muy dificultoso.

Un pequeño cambio relacionado hace que el atributo "func_name" de las
funciones sea escribible. Este atributo se utiliza para mostrar los
nombres de las funciones en los seguimientos, por lo que los
decoradores deben cambiar el nombre de cualquier función nueva que se
construya y devuelva.

Ver también:

  **PEP 318** Decoradores para funciones, métodos y clases
     Escrito por Kevin D.Smith, Jim Jewett y Skip Montanaro. Varias
     personas escribieron parches sobre la implementación de los
     decoradores de funciones, pero el único que fue chequeado fue
     #979728 por Mark Russell.

  https://wiki.python.org/moin/PythonDecoratorLibrary
     Esta pagina de wiki contiene múltiples ejemplos de decoradores.


PEP 322: Iteración inversa
==========================

Una nueva función de conjuntos integrados, "reversed(seq)" toma una
secuencia y retorna un iterador que recorre los elementos de la
secuencia en orden inverso.:

   >>> para i en reversed(xrange(1,4)):
   ... imprimir i
   ...
   3
   2
   1

Comparado con el uso tradicional de la segmentación tal como
"range(1,4)[::-1]" la  función "reversed()" es fácil de leer,  se
ejecuta mas rápido y usa sustancialmente menos memoria.

Señalar que la función "reversed()" solo acepta secuencias, no
iteradores arbitrarios. Si se quiere revertir un iterador, primero se
debe convertir a una lista usando la función "list()".:

   >>> input = open('/etc/passwd', 'r')
   >>> for line in reversed(list(input)):
   ... print line
   ...
   root:*:0:0:Administrador del sistema:/var/root:/bin/tcsh
   ...

Ver también:

  **PEP 322** - Iteración inversa
     Escrita e implementada por Raymond Hettinger.


PEP 324: Nuevo módulo de subproceso
===================================

La biblioteca estándar proporciona varias formas de ejecutar un
subproceso, ofreciendo distintas funciones y distintos niveles de
complejidad. "os.system(command)" es fácil de usar, pero lento
(ejecuta un proceso de shell que ejecuta el comando) y peligroso (hay
que tener cuidado con el escape de los metacaracteres del shell). El
módulo "popen2" ofrece clases que pueden capturar la salida estándar y
el error estándar del subproceso, pero la nomenclatura es confusa. El
módulo "subprocess" soluciona este problema, proporcionando una
interfaz unificada que ofrece todas las funciones que se pueden
necesitar.

En vez de "popen2" que es una colección de clases el "subprocess"
contiene una sola clase llamada "subprocess.Popen" cuyo constructor
soporta un número de diferentes argumentos de palabra clave:

   clase Popen(args, bufsize=0, ejecutable=Ninguno,
   stdin=Ninguno, stdout=Ninguno, stderr=Ninguno,
   preexec_fn=Ninguno, close_fds=False, shell=False,
   cwd=Ninguno, env=Ninguno, universal_newlines=False,
   startupinfo=Ninguno, creationflags=0):

*args* es comúnmente una secuencia de cadenas de caracteres que podrán
ser los argumentos del programa ejecutado como un subproceso. (Si el
argumento *shell* es verdadero, *args* puede ser una cadena de
caracteres que serán pasados directamente a la shell para su
interpretación, tal como "os.system()" lo hace.)

*stdin*, *stdout*, y *stderr* especifican que flujos de entrada,
salida y error serán utilizados. Se puede proceder un objeto de
archivo o un archivo de descripción o se puede usar la constante
"subprocess.PIPE" para crear un enlace entre el subproceso y el
proceso principal.

El constructor tiene un número de opciones útiles:

* *close_fds* requiere que todos los descriptores de archivos sean
  cerrados antes de correr el subproceso.

* *cwd*  especifica el directorio operativo donde el subproceso será
  ejecutado (por defecto, cualquiera que sea el directorio principal)

* *env*  es un diccionario donde se especifican las variables de
  entorno.

* *preexec_fn* es una función que es llamada antes de que el proceso
  hijo sea llamado.

* *universal_newlines* abre el flujo de entrada y salida del hijo
  usando la característica de Python *universal newlines* .

Una vez que se ha creado la instancia de la "Popen"  se puede llamar
al método "wait()" para poner en pausa hasta que el subproceso ha
terminado, el método "poll()" comprueba si se ha salido sin pausar o
el uso de "communicate(data)" envía la cadena de caracteres *data* a
la entrada estándar del subproceso. Y el uso de "communicate(data)"
que lee cualquier dato que el subproceso ha enviado a la salida
estándar, retornando una tupla "(stdout_data, stderr_data)".

"call()" es un atajo que pasa estos argumentos a lo largo del
constructor de la clase "Popen", espera por el comando para completar
la secuencia y retorna el código de estatus del subproceso. Esto puede
servir como un análogo mas seguro de "os.system()":

   sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb'])
   if sts == 0:
   # Éxito
   ...
   else:
   # dpkg devolvió un error
   ...

El comando es invocado sin el uso del interprete de comandos. Si se
desea usar el intérprete se puede agregar "shell=True" como un
argumento de palabra clave y proveer una cadena de caracteres en vez
de una secuencia:

   sts = subproceso.call('dpkg -i /tmp/nuevo-paquete.deb', shell=True)

La guía de estilo de Python toma varios ejemplos de línea de comandos
y código python y muestra como estos son traducidos en el código
python "subprocess". Leer esta sección de la guía de estilo es
altamente recomendado.

Ver también:

  **PEP 324** - subprocess - Nuevo módulo de procesos
     Escrito e implementado por Peter Åstrand, con asistencia de
     Frederik Lundh y otros.


PEP 327: Tipo de dato decimal
=============================

Python siempre ha soportado números de punto flotante (FP), basados
​​en el tipo subyacente C double, como un tipo de datos. Sin embargo,
aunque la mayoría de los lenguajes de programación proporcionan un
tipo de punto flotante, muchas personas (incluso los programadores) no
saben que los números de punto flotante no representan ciertas
fracciones decimales con precisión. El nuevo tipo "Decimal" puede
representar estas fracciones con precisión, hasta un límite de
precisión especificado por el usuario.


¿Por qué se necesita Decimal?
-----------------------------

Las limitaciones surgen de la representación usada para los números de
punto flotante. Los números de punto flotante están hechos de tres
componentes:

* El signo, el cual es positivo o negativo.

* El significando o mantisa el cual es el un dígito binario seguido de
  su parte fraccional. Por ejemplo, "1.01" en notación base 2 es "1 +
  0/2 + 1/4" o 1.25 en notación decimal.

* El exponente, que indica dónde se encuentra el punto decimal en el
  número representado.

Por ejemplo, el número 1.25 tiene un signo positivo, una mantisa de
valor 1.01 (en binario) y un exponente de 0 (el punto decimal no
necesita ser desplazado. El números 5 tiene el mismo signo y
significando pero, el exponente es 2 porque el significando es
multiplicado por 4 (2 elevado a la potencia del exponente 2), 1.25 * 4
es igual a 5.

Los sistemas modernos generalmente brindan soporte de coma flotante
que se ajusta a un estándar llamado IEEE 754. El tipo double de C
generalmente se implementa como un número IEEE 754 de 64 bits, que usa
52 bits de espacio para la mantisa. Esto significa que los números
solo se pueden especificar con 52 bits de precisión. Si está tratando
de representar números cuya expansión se repite sin cesar, la
expansión se corta después de 52 bits. Desafortunadamente, la mayoría
del software necesita producir resultados en base 10, y las fracciones
comunes en base 10 a menudo son decimales repetidos en binario. Por
ejemplo, 1.1 decimal es binario "1.0001100110011 ..."; .1 = 1/16 +
1/32 + 1/256 más un número infinito de términos adicionales. IEEE 754
tiene que cortar ese decimal repetido infinitamente después de 52
dígitos, por lo que la representación es un poco inexacta.

Algunas veces se puede ver esta inexactitud cuando el número es
impreso por pantalla:

   >>> 1.1
   1.1000000000000001

La inexactitud no siempre es visible cuando se imprime el número
porque el punto flotante a decimal y conversión a cadena de texto es
entregada por la librería C y la mayoría de las librerías C tratan de
producir una salida sensible. Incluso si no es mostrado, la
inexactitud sigue ahí y las operaciones subsecuentes pueden agrandar
el error.

Para muchas aplicaciones esto no importa. Si estoy trazando puntos y
mostrándolos en el monitor la diferencia entre 1.1 y
1.1000000000000001 es muy pequeña para ser visible.  Los reportes a
menudo limitan la salida de un cierto número de decimales y si se
redondea el número a dos o tres e incluso a 8 decimales, el error
nunca aparece. Sin embargo, para las aplicaciones donde esto importa,
es una cantidad de trabajo importante el personalizar los cálculos
aritméticos.

Es por eso que el tipo de clase "Decimal" fue creada.


El tipo de clase "Decimal"
--------------------------

Un nuevo módulo, "decimal", fue añadido a la librería estándar de
Python. Esta contiene dos clases, "Decimal" y "Context". Las
instancias de la clase decimal "Decimal" representan números y la
instancia de la "Context" son usadas para condensar varios ajustes
como la precisión y el modo de redondeo por defecto.

Las instancias de la clase "Decimal" son inmutables como los números
enteros y números de punto flotante en Python, una vez han sido
creadas no se puede cambiar el valor de lo que la instancia
representa. Las instancias de la "Decimal" pueden ser creados desde
números enteros o cadenas de texto:

   >>> importar decimal
   >>> decimal.Decimal(1972)
   Decimal("1972")
   >>> decimal.Decimal("1.1")
   Decimal("1.1")

También se pueden proveer tuplas que contentan el signo, la mantisa
representada como una tupla de números decimales y el exponente:

   >>> decimal.Decimal((1, (1, 4, 7, 5), -2))
   Decimal("-14,75")

Precaución: El signo bit es un valor booleano entonces 0 es positivo y
1 es negativo.

Convertir desde números de punto flotante posee un pequeño problema,
el punto flotante representa 1.1 y se convierte en número decimal como
1.1 o por 1.1 mas cualquier inexactitud que se introduzca? La decisión
fue evitar el problema y dejar tal conversión fuera de la API. En su
lugar se debe convertir el número de punto flotante en una cadena con
la precisión deseada y pasar la cadena al constructor "Decimal" :

   >>> f = 1,1
   >>> decimal.Decimal(str(f))
   Decimal("1,1")
   >>> decimal.Decimal('%.12f' % f)
   Decimal("1,100000000000")

Una vez que se tiene la instancia de la clase "Decimal" se pueden
realizar las operaciones matemáticas de rigor. Una limitación, la
exponenciación requiere un exponente expresado en tipo de dato 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 XASDF00b
   Traceback (most recent call last):
     ...
   decimal.InvalidOperation: x ** (no entero)

Se puede combinar la instancia de la clase "Decimal" con enteros pero
no con números de punto flotante:

   >>> a + 4
   Decimal("39.72")
   >>> a + 4.5
   Traceback (última llamada más reciente):
   ...
   TypeError: Solo puede interactuar con Decimal con tipos de datos int, long o Decimal.
   >>>

Los números en la clase "Decimal" pueden ser usados con los módulos
"math" y "cmath" pero es preciso aclarar que ellos serán
inmediatamente convertidos a números de punto flotante antes de
realizar la operación, resultando en una posible perdida de precisión
y exactitud. También obtendrá un número de punto flotante y no una
clase "Decimal":

   >>> importar matemáticas, cmath
   >>> d = decimal.Decimal('123456789012.345')
   >>> matemáticas.sqrt(d)
   351364.18288201344
   >>> cmath.sqrt(-d)
   351364.18288201344j

Las instancias de la clase "Decimal" poseen un método "sqrt()" que
retorna una clase "Decimal" pero si se necesita otro tipo de cosas
como funciones trigonométricas se tendrían que implementar:

   >>> d.sqrt()
   Decimal("351364.1828820134592177245001")


El tipo de clase "Context"
--------------------------

Las instancias de la "Context" encapsulan varios ajustes para
operaciones con decimales:

* atributo "prec" es la precisión del número de decimales.

* El atributo "rounding" especifica el modo de redondeo. El módulo
  "decimal" tiene constantes para varias posibilidades, "ROUND_DOWN",
  "ROUND_CEILING",  "ROUND_HALF_EVEN" y varias otras.

* El atributo "traps" es un diccionario que especifica lo que sucede
  al encontrar ciertas condiciones de error: Ya sea una excepción
  lanzada o un valor es retornado. algunos ejemplos de errores son las
  divisiones por cero, perdida de precisión o desbordamiento.

Hay un contexto predeterminado local de subprocesos disponible
llamando a la función "getcontext()", se puede cambiar las propiedades
de este contexto para alterar la precisión por defecto, redondear o
manejar trampas. el siguiente ejemplo muestra el efecto de cambiar la
precisión del contexto por defecto:

   >>> 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")

Las acciones por defecto para condiciones de error se puede
seleccionar, ya sea que el módulo pueda retornar un valor especial
como un infinito o un valor no numérico NaN o se pueden lanzar
excepciones:

   >>> decimal.Decimal(1) / decimal.Decimal(0)
   Traceback (última llamada más reciente):
   ...
   decimal.DivisionByZero: x / 0
   >>> decimal.getcontext().traps[decimal.DivisionByZero] = False
   >>> decimal.Decimal(1) / decimal.Decimal(0)
   Decimal("Infinito")
   >>>

La instancia de la clase "Context" también tiene varios métodos para
formatear números tales como "to_eng_string()" y "to_sci_string()".

Para mas información, revisar la documentación para el módulo
"decimal" el cual incluye un tutoría de inicio rápido y una
referencia.

Ver también:

  **PEP 327** - Tipo de dato decimal
     Escrito por Facundo Batista e implementado por Facundo Batista,
     Eric Price, Raymond Hettinger, Aahz y Tim Peters.

  http://www.lahey.com/float.htm
     El articulo usa código Fortran para ilustrar varios de los
     problemas que la inexactitud de los puntos flotantes pueden
     causar.

  https://speleotrove.com/decimal/
     Una descripción de una representación basada en decimales. Esta
     representación ha sido propuesta como un estándar y subyace al
     nuevo tipo de dato decimal en Python. La mayor parte de este
     material fue escrita por Mike Cowlishaw, diseñador del lenguaje
     Rexx.


PEP 328: Importaciones multilínea
=================================

Un pequeño cambio en el lenguaje ha sido una modificación a una
sintaxis confusa que ha sido cambiada para hacer mas fácil el agregar
varios nombres en un módulo. En una declaración "from module import
names", *names* es una secuencia de nombres separados por comas. Si la
sentencia es muy larga, se puede ya sea escribir múltiples sentencias
import desde el mismo módulo o se pueden usar barras invertidas para
escapar de los términos de línea como esto:

   de SimpleXMLRPCServer importar SimpleXMLRPCServer,\
   SimpleXMLRPCRequestHandler,\
   CGIXMLRPCRequestHandler,\
   resolve_dotted_attribute

La sintaxis cambió en Python 2.4 y es simplemente el permitir poner
los nombres dentro de paréntesis. Python ignora nuevas líneas dentro
de una expresión entre paréntesis por lo que las barras invertidas ya
no se necesitan:

   from SimpleXMLRPCServer import (SimpleXMLRPCServer,
                                   SimpleXMLRPCRequestHandler,
                                   CGIXMLRPCRequestHandler,
                                   resolve_dotted_attribute)

La convención de estilo también propone que todas las declaraciones
usando  "import" son importaciones absolutas, con el siguiente
carácter "." indica una importación relativa. Esta parte de la
convención de estilo no fue implementada para Python 2.4 pero fue
completada para la versión 2.5.

Ver también:

  **PEP 328** - Importaciones multi línea y absolutas/relativas
     Escrita por Aahz.  Importaciones multi línea fueron implementadas
     por Dima Dorfman.


PEP 331: Conversiones locales-independientes números flotantes/cadenas de texto
===============================================================================

Los módulos "locale" deja que el software de Python seleccione varias
conversiones y despliegue convenciones que están localizadas en un
país particular o lenguaje. Sin embargo, el módulo es cuidadoso en no
cambiar el local numérico porque la implementación de Python requería
que la configuración regional numérica permaneciera establecida en la
configuración regional "'C'" . A menudo, esto se debía a que el código
utilizaba la función "atof()" de la biblioteca C.

No configurar la configuración regional numérica causaba problemas
para las extensiones que usaban librerías externas de C, sin embargo,
porque no configuraban la correcta configuración. El ejemplo mas
patente fue GTK+, cuya interfaz de usuario no mostraba números en la
ubicación actual.

La solución descrita en la convención de estilo es añadir tres nuevas
funciones a la API de python que ejecuta solo conversiones a ASCII,
ignorando las configuraciones locales:

* "PyOS_ascii_strtod(str, ptr)" y "PyOS_ascii_atof(str, ptr)"
  convierten una cadena en C double.

* "PyOS_ascii_formatd(buffer, buf_len, format, d)" convierte un double
  en una cadena ASCII.

El código para estas funciones proviene de la biblioteca GLib (https
://developer-old.gnome.org/glib/2.26/), cuyos desarrolladores
amablemente renovaron la licencia de las funciones relevantes y las
donaron a la Python Software Foundation. El módulo "locale" ahora
puede cambiar la configuración regional numérica, lo que permite que
extensiones como GTK+ produzcan los resultados correctos.

Ver también:

  **PEP 331** Conversiones Local-Independiente flotante/cadena de
  texto
     Escrito por Christian R. Reis, e implementado por Gustavo
     Carneiro.


Otros cambios en el lenguaje
============================

Aquí están todos los cambios que Python 2.4 ha hecho al core del
lenguaje Python.

* Fueron añadidos decoraciones para funciones (**PEP 318**).

* Funciones de conjuntos integrados "set()" y "frozenset()" fueron
  añadidas (**PEP 218**). Otras nuevas funciones de conjuntos
  integrados incluyen la función "reversed(seq)" (**PEP 322**).

* Generador de expresiones fueron añadidas (**PEP 289**).

* Algunas expresiones numéricas ya no retornan valores restringidos a
  32 o 64 bits (**PEP 237**).

* Se puede poner entre paréntesis una lista de nombres en la
  declaración "from module import names" (**PEP 328**).

* El método "dict.update()" ahora acepta el mismo argumento que el
  constructor de la "dict". Esto incluye cualquier tipo de mapeo,
  iterable pares de clave/valor y argumentos de palabra clave.
  (Contribución de Raymond Hettinger)

* Los métodos de cadena de caracteres "ljust()", "rjust()" y
  "center()" ahora toman un argumento de tipo opcional para
  especificar un carácter de relleno que no sea un espacio.
  (Contribución de Raymond Hettinger).

* Cadenas de caracteres también han ganado un método "rsplit()" que
  funciona como el método "split()" pero divide desde el final de la
  cadena de caracteres. (Contribución de Sean Reifschneider)

     >>> 'www.python.org'.split('.', 1)
     ['www', 'python.org']
     'www.python.org'.rsplit('.', 1)
     ['www.python', 'org']

* Tres parámetros de argumentos de palabra clave *cmp*, *key* y
  *reverse* fueron añadidos al método de listas "sort()". Estos
  parámetros hacen algunos usos comunes del método "sort()" mas
  simple. Todos estos parámetros son opcionales.

  Para el parámetro *cmp*  el valor debe ser una función comparativa
  que toma dos parámetros y retorna -1, 0 o + 1 dependiendo de como
  compare los parámetros. Esta función será usada para ordenar la
  lista. Previamente esto era el único parámetro que podía ser
  entregado al "sort()".

  *key* debe ser una función con un solo parámetro que toma un
  elemento de la lista y retorna una llave de comparación para el
  elemento. Entonces la lista es ordenado usando las claves de
  comparación. El siguiente ejemplo ordena una lista sin distinción de
  mayúsculas ni minúsculas:

     >>> L = ['A', 'b', 'c', 'D']
     >>> L.sort() # Ordenación que distingue entre mayúsculas y minúsculas
     >>> 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']
     >>> # Método tradicional
     >>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()))
     >>> L
     ['A', 'b', 'c', 'D']

  El ultimo ejemplo el cual usa el parámetro *cmp*  es la antigua
  forma de ejecutar el orden sin distinción de mayúsculas y
  minúsculas. Funciona pero es mas lento en vez de usar el parámetro
  *key*.  El uso de *key* llama al método "lower()" una vez para cada
  elemento de la lista mientras el uso de *cmp* lo llamara dos veces
  para cada comparación, entonces al usar * key * se guardan las
  llamadas del método "lower()".

  Para funciones de clave sencillas y comparativas es a menudo posible
  el obviar la palabra clave "lambda" usando un método sin ligar en
  reemplazo. El siguiente ejemplo de orden sin importar mayúsculas ni
  minúsculas es mejor escrito como se muestra:

     >>> L.sort(key=str.lower)
     >>> L
     ['A', 'b', 'c', 'D']

  Finalmente el parámetro *reverse* toma un valor de tipo booleano. Si
  el valor es verdadero la lista será ordenada de forma inversa. En
  vez de "L.sort(); L.reverse()" ahora se puede escribir
  "L.sort(reverse=True)".

  Los resultados del ordenamiento ahora están garantizados que son
  estables. Esto significa que dos entradas con iguales claves serán
  retiradas en el mismo orden en que fueron ingresadas. Por ejemplo se
  puede ordenar una lista de personas por el nombre y entonces
  ordenarla por edad, resultando en una lista ordenada donde las
  personas con la misma edad están en el mismo orden por nombre.

  (Todos los cambios al método "sort()" fueron realizados por Raymond
  Hettinger.)

* Se tiene una nueva función incorporada "sorted(iterable)" que
  trabaja como el método in situ "list.sort()" que se puede usar en
  expresiones. Las diferencias son:

* el dato de entrada puede ser algún iterable;

* se ordena una copia recién formada, manteniendo el original intacto
  y

* la expresión retorna una nueva copia ordenada

     >>> L = [9,7,8,3,2,4,1,6,5]
     >>> [10+i for i in sorted(L)] # utilizable en una comprensión de lista
     [11, 12, 13, 14, 15, 16, 17, 18, 19]
     >>> L # el original no se modifica
     [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']

     >>> # Lista el contenido de un diccionario ordenado por valores clave
     >>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5)
     >>> for k, v en sorted(colormap.iteritems()):
     ... imprimir k, v
     ...
     negro 4
     azul 2
     verde 3
     rojo 1
     amarillo 5

  (Contribución de Raymond Hettinger.)

* Operaciones de números enteros no lanzaran una excepción
  "OverflowWarning". La advertencia sobre "OverflowWarning"
  desaparecerá en Python 2.5.

* Se añadió al interprete una nueva opción de cambio "-m" la cual toma
  un nombre, busca el módulo correspondiente en "sys.path" y corre el
  módulo como script. Ahora por ejemplo se puede correr el perfilador
  de Python con "python -m profile". (Contribución de Nick Coghlan)

* La expresión "eval(expr, globals, locals)" la función
  "execfile(filename, globals, locals)" y la sentencia "exec" ahora
  aceptan cualquier tipo de mapeo para parámetros locales. Previamente
  esto era parte de un diccionario de Python. (Contribución de Raymond
  Hettinger.)

* La función incorporada "zip()" y la función "itertools.izip()" ahora
  retornan una lista hacia si se llama sin argumentos. Previamente
  estos lanzaban una excepción de tipo "TypeError". Esto lo hace mas
  apropiado de usar con listas de argumentos de longitud variable:

     >>> def transpose(matriz):
     ... return zip(*matriz)
     ...
     >>> transpose([(1,2,3), (4,5,6)])
     [(1, 4), (2, 5), (3, 6)]
     >>> transpose([])
     []

  (Contribución de Raymond Hettinger.)

* Encontrar un error al importar un módulo ya no deja un objeto de
  módulo parcialmente inicializado en "sys.modules". El objeto de
  módulo incompleto que se deja atrás engañaría a las importaciones
  posteriores del mismo módulo para que tuvieran éxito, lo que
  generaría errores confusos. (Reparado por Tim Peters.)

* "None`es ahora una constante, el código que une un nuevo valor con
  el nombre :const:`None" es ahora un error de sintaxis (Contribución
  de Raymond Hettinger)


Optimizaciones
--------------

* Los bucles internos para separar listas y tuplas fueron optimizados
  y ahora corren un tercio mas rápido. Los bucles internos para
  diccionarios también fueron optimizados resultando en una mejora en
  el rendimiento para "keys()", "values()", "items()", "iterkeys()",
  "itervalues()", y "iteritems()". (Contribución de Raymond Hettinger)

* El mecanismo para mejorar y contraer listas fue optimizada  para
  efectos de velocidad y eficiencia en la utilización de recursos.
  Anexar y quitar elementos de una lista es ahora mas rápido debido al
  código mas eficiente y al menos frecuente uso de la función
  subyacente  "realloc()". Las listas por comprensión también son
  beneficiadas, el método "list.extend()" fue también optimizado y ya
  no convierte mas el argumento en una lista temporal antes de
  extender la lista base. (Contribución de Raymond Hettinger)

* Las funciones "list()", "tuple()", "map()", "filter()" y "zip()"
  ahora corren mucho mas rápido con argumentos no secuenciales que
  ahora suministra el método "__len__()". (Contribución Raymond
  Hettinger.)

* Los métodos "list.__getitem__()", "dict.__getitem__()" y
  "dict.__contains__()"  ahora son implementados como objetos de la
  clase "method_descriptor" en vez de los objetos de la clase
  "wrapper_descriptor" . Este acceso dobla el rendimiento y hace que
  sea mas apropiado para ser usado como argumentos
  de:"map(mydict.__getitem__, keylist)". (Contribución de Raymond
  Hettinger)

* Adicionalmente se ha agregado a un nuevo código de operación
  "LIST_APPEND" esto simplifica la generación de código a nivel de
  byte para las listas por comprensión y las agiliza en
  aproximadamente un tercio.

* El optimizador de código a nivel de byte ha sido mejorado para
  producir código a nivel de byte mas corto y rápido. Esto resulta en
  código mas legible. (Contribución de Raymond Hettinger)

* La concatenación de cadenas de texto en la declaración de "s = s +
  "abc"" and "s += "abc"" ahora son ejecutadas de forma mas eficiente
  en ciertas circunstancias. Esta optimizaciones no serán mostradas en
  otras implementaciones de Python tales como Python, entonces no se
  debe utilizar, es mejor seguir utilizando el método "join()" de
  cadenas de caracteres si se quiere mantener la eficiencia de
  concatenar un largo número de cadenas de caracteres. (Contribución
  de Armin Rigo.)

El resultado de las optimizaciones de la versión 2.4 es que tomando
Python 2.4 como punto de referencia corre alrededor de un 5% mas
rápido que Python 2.3 y un 35% mas rápido que Python 2.2 (pystone no
es particularmente un buen punto de referencia pero es el mas usado
para medir rendimiento en Python. Sus propias aplicaciones pueden
mostrar beneficios mas grandes o mínimos desde Python 2.4)


Módulos nuevos, mejorados y obsoletos
=====================================

Como es usual, la librería estándar de Python recibió un número de
mejoras y corrección de errores. Aquí hay una lista parcial de los
cambios mas notables, ordenados alfabéticamente por nombre de módulo.
Consulte el archivo "Misc/NEWS" en la estructura del directorio para
una completa lista de los cambios o se puede buscar a través del
registro CVS para obtener todos los detalles.

* La función "loop()" del módulo "asyncore" ahora tiene un parámetro
  *count* que le permite realizar una cantidad limitada de pasadas a
  través del bucle de sondeo. El valor predeterminado sigue siendo el
  bucle indefinidamente.

* El módulo "base64" ahora tiene un soporte mas completo **RFC 3548**
  para Base64, Base32 y  Base16 para codificación y descodificación,
  incluyendo procesos de convertir caracteres a minúsculas y alfabetos
  alternativos. (Contribución de Barry Warsaw)

* El módulo "bisect" ahora tiene una implementación C subyacente para
  mejorar el rendimiento. (Contribuido por Dmitry Vasiliev.)

* Las colecciones CJKCodecs de códecs de Asia oriental, mantenidas por
  Hye-Shik Chang, se integraron en 2.4. Las nuevas codificaciones son:

* Chino (PRC): gb2312, gbk, gb18030, big5hkscs, hz

* Chino (República de China): big5, cp950

* Japonés: cp932, euc-jis-2004, euc-jp, euc-jisx0213, iso-2022-jp,
     iso-2022-jp-1, iso-2022-jp-2, iso-2022-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 agregaron algunas otras codificaciones nuevas: HP Roman8,
  ISO_8859-11, ISO_8859-16, PCTP-154 y TIS-620.

* Los códecs UTF-8 y UTF-16 ahora se adaptan mejor a la recepción de
  entradas parciales. Anteriormente, la clase "StreamReader" intentaba
  leer más datos, lo que hacía imposible reanudar la decodificación
  desde el flujo. El método "read()" ahora devolverá tantos datos como
  pueda y las llamadas futuras reanudarán la decodificación donde lo
  dejaron las anteriores. (Implementado por Walter Dörwald.)

* Hay un nuevo módulo "collections" para varios tipos de datos de
  recopilación especializados. Actualmente contiene solo un tipo,
  "deque", una cola de dos extremos que admite la adición y
  eliminación de elementos de manera eficiente desde cualquier
  extremo:

     >>> from collections import deque
     >>> d = deque('ghi') # crea un nuevo deque con tres elementos
     >>> d.append('j') # agrega una nueva entrada al lado derecho
     >>> d.appendleft('f') # agrega una nueva entrada al lado izquierdo
     >>> d # muestra la representación del deque
     deque(['f', 'g', 'h', 'i', 'j'])
     >>> d.pop() # devuelve y elimina el elemento más a la derecha
     'j'
     >>> d.popleft() # devuelve y elimina el elemento más a la izquierda
     'f'
     >>> list(d) # lista el contenido del deque
     ['g', 'h', 'i']
     >>> 'h' in d # busca el deque
     True

  Varios módulos, como los módulos "Queue" y "threading", ahora
  aprovechan "collections.deque" para mejorar el rendimiento.
  (Contribuido por Raymond Hettinger.)

* Las clases "ConfigParser" se han mejorado ligeramente. El método
  "read()" ahora devuelve una lista de los archivos que se analizaron
  correctamente y el método "set()" genera "TypeError" si se le pasa
  un argumento *value* que no sea una cadena. (Contribuido por John
  Belmonte y David Goodger).

* El módulo "curses" ahora admite la extensión ncurses
  "use_default_colors()". En plataformas donde el terminal admite
  transparencia, esto permite utilizar un fondo transparente.
  (Contribución de Jörg Lehmann.)

* El módulo "difflib" ahora incluye una clase "HtmlDiff" que crea una
  tabla HTML que muestra una comparación lado a lado de dos versiones
  de un texto. (Contribuido por Dan Gass.)

* El paquete "email" se actualizó a la versión 3.0, que eliminó varias
  API obsoletas y elimina la compatibilidad con versiones de Python
  anteriores a la 2.3. La versión 3.0 del paquete usa un nuevo
  analizador incremental para mensajes MIME, disponible en el módulo
  "email.FeedParser". El nuevo analizador no requiere leer todo el
  mensaje en la memoria y no genera excepciones si un mensaje tiene un
  formato incorrecto; en su lugar, registra cualquier problema en el
  atributo "defect" del mensaje. (Desarrollado por Anthony Baxter,
  Barry Warsaw, Thomas Wouters y otros).

* El módulo "heapq" se ha convertido a C. La mejora de diez veces
  resultante en la velocidad hace que el módulo sea adecuado para
  manejar grandes volúmenes de datos. Además, el módulo tiene dos
  funciones nuevas "nlargest()" y "nsmallest()" que usan montones para
  encontrar los N valores más grandes o más pequeños en un conjunto de
  datos sin el gasto de una clasificación completa. (Contribuido por
  Raymond Hettinger.)

* El módulo "httplib" ahora contiene constantes para los códigos de
  estado HTTP definidos en varios documentos RFC relacionados con
  HTTP. Las constantes tienen nombres como "OK", "CREATED", "CONTINUE"
  y "MOVED_PERMANENTLY"; utilice pydoc para obtener una lista
  completa. (Contribuido por Andrew Eland).

* El módulo "imaplib" ahora es compatible con el comando THREAD de
  IMAP (aportado por Yves Dionne) y los nuevos métodos "deleteacl()" y
  "myrights()" (aportado por Arnaud Mazin).

* El módulo "itertools" ganó una función "groupby(iterable[,
  *func*])". El parámetro *iterable* is something that can be iterated
  over to return a stream of elements, and the optional *func* es una
  función que toma un elemento y devuelve un valor clave; si se omite,
  la clave es simplemente el elemento en sí. "groupby()" luego agrupa
  los elementos en subsecuencias que tienen valores coincidentes de la
  clave y devuelve una serie de 2 tuplas que contienen el valor de la
  clave y un iterador sobre la subsecuencia.

  Aquí hay un ejemplo para aclarar esto. La función *key* simplemente
  devuelve si un número es par o impar, por lo que el resultado de
  "groupby()" es devolver series consecutivas de números pares o
  impares.

     >>> importar itertools
     >>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14]
     >>> para key_val, it en itertools.groupby(L, lambda x: x % 2):
     ... imprimir key_val, list(it)
     ...
     0 [2, 4, 6]
     1 [7]
     0 [8]
     1 [9, 11]
     0 [12, 14]
     >>>

  "groupby()" se utiliza normalmente con entrada ordenada. La lógica
  para "groupby()" es similar al filtro Unix "uniq", lo que lo hace
  útil para eliminar, contar o identificar elementos duplicados:

     >>> palabra = 'abracadabra'
     >>> letras = sorted(palabra) # Convierte una cadena en una lista ordenada de letras
     >>> letras
     ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']
     >>> for k, g in itertools.groupby(letters):
     ... print k, list(g)
     ...
     a ['a', 'a', 'a', 'a', 'a']
     b ['b', 'b']
     c ['c']
     d ['d']
     r ['r', 'r']
     >>> # Lista de letras únicas
     >>> [k for k, g in groupby(letters)]
     ['a', 'b', 'c', 'd', 'r']
     >>> # Cuenta las ocurrencias de las letras
     >>> [(k, len(lista(g))) para k, g en groupby(letras)]
     [('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]

  (Contribuido por Hye-Shik Chang.)

* "itertools" también obtuvo una función denominada "tee(iterator, N)"
  que devuelve *N* independent iterators that replicate *iterator*.
  If *N* se omite, el valor predeterminado es 2.

     >>> L = [1,2,3]
     >>> i1, i2 = itertools.tee(L)
     >>> i1,i2
     (<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>)
     >>> list(i1) # Ejecuta el primer iterador hasta el agotamiento
     [1, 2, 3]
     >>> list(i2) # Ejecuta el segundo iterador hasta el agotamiento
     [1, 2, 3]

  Tenga en cuenta que "tee()" debe mantener copias de los valores
  devueltos por el iterador; en el peor de los casos, es posible que
  deba conservarlos todos. Por lo tanto, esto debe usarse con cuidado
  si el iterador principal puede ejecutarse muy por delante del
  iterador final en un flujo largo de entradas. Si la separación es
  grande, entonces también podría usar "list()" en su lugar. Cuando
  los iteradores se siguen de cerca entre sí, "tee()" es ideal. Las
  posibles aplicaciones incluyen marcadores, ventanas o iteradores de
  anticipación. (Contribuido por Raymond Hettinger.)

* Se agregaron 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
  mensajes en la codificación elegida. (Contribuido por Gustavo
  Niemeyer.)

* Se agregaron algunos argumentos de palabras clave a la función
  "basicConfig()" del paquete "logging" para simplificar la
  configuración del registro. El comportamiento predeterminado es
  registrar mensajes con error estándar, pero se pueden especificar
  varios argumentos de palabras clave para registrar en un archivo en
  particular, cambiar el formato de registro o establecer el nivel de
  registro. Por ejemplo:

     importar registro
     logging.basicConfig(filename='/var/log/application.log',
     level=0, # Registrar todos los mensajes
     format='%(levelname):%(process):%(thread):%(message)')

  Otras adiciones al paquete "logging" incluyen un método de
  conveniencia "log(level, msg)", así como una clase
  "TimedRotatingFileHandler" que rota sus archivos de registro en un
  intervalo cronometrado. El módulo ya tenía "RotatingFileHandler",
  que rotaba los registros una vez que el archivo excedía un cierto
  tamaño. Ambas clases derivan de una nueva clase
  "BaseRotatingHandler" que se puede utilizar para implementar otros
  controladores rotativos.

  (Cambios implementados por Vinay Sajip.)

* El módulo "marshal" ahora comparte cadenas internas al desempaquetar
  una estructura de datos. Esto puede reducir el tamaño de ciertas
  cadenas de pickle, pero el efecto principal es hacer que los
  archivos ".pyc" sean significativamente más pequeños. (Contribución
  de Martin von Löwis.)

* La clase "NNTP" del módulo "nntplib" obtuvo los métodos
  "description()" y "descriptions()" para recuperar descripciones de
  grupos de noticias para un solo grupo o para un rango de grupos.
  (Contribución de Jürgen A. Erhard).

* Se agregaron dos nuevas funciones al módulo "operator",
  "attrgetter(attr)" y "itemgetter(index)". Ambas funciones devuelven
  invocables que toman un solo argumento y devuelven el atributo o
  elemento correspondiente; estos llamables son excelentes extractores
  de datos cuando se utilizan con "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)) # Ordenar la lista por el segundo elemento de la tupla
     [('d', 1), ('c', 2), ('b', 3), ('a', 4)]

  (Contribución de Raymond Hettinger.)

* El módulo "optparse" se actualizó de varias formas. El módulo ahora
  pasa sus mensajes a través de "gettext.gettext()", lo que permite
  internacionalizar los mensajes de error y ayuda de Optik. Los
  mensajes de ayuda para las opciones ahora pueden incluir la cadena
  "'%default'", que será reemplazada por el valor predeterminado de la
  opción. (Contribuido por Greg Ward.)

* El plan a largo plazo es dejar obsoleto el módulo "rfc822" en alguna
  versión futura de Python a favor del paquete "email". Con este fin,
  se ha modificado la función "email.Utils.formatdate" para que pueda
  utilizarse como reemplazo de "rfc822.formatdate()". Es posible que
  desee escribir un nuevo código de procesamiento de correo
  electrónico teniendo esto en cuenta. (Cambio implementado por
  Anthony Baxter).

* Se agregó una nueva función "urandom(n)" al módulo "os", que
  devuelve una cadena que contiene *n* bytes de datos aleatorios. Esta
  función proporciona acceso a fuentes de aleatoriedad específicas de
  la plataforma, como "/dev/urandom" en Linux o Windows CryptoAPI.
  (Contribuido por Trevor Perrin.)

* Otra función nueva: "os.path.lexists(path)" devuelve verdadero si el
  archivo especificado por *path* exists, whether or not it's a
  symbolic link.  This differs from the existing ASDF01 function,
  which returns false if *path* es un enlace simbólico que apunta a un
  destino que no existe. (Contribuido por Beni Cherniavsky.)

* Se agregó una nueva función "getsid()" al módulo "posix" que subyace
  al módulo "os". (Contribuido por J. Raynor.)

* El módulo "poplib" ahora admite POP sobre SSL. (Contribuido por
  Héctor Urtubia.)

* El módulo "profile" ahora puede perfilar funciones de extensión C.
  (Contribuido por Nick Bastin.)

* El módulo "random" tiene un nuevo método llamado "getrandbits(N)"
  que devuelve un entero largo *N* bits de longitud. El método
  "randrange()" existente ahora usa "getrandbits()" cuando
  corresponde, lo que hace que la generación de números aleatorios
  arbitrariamente grandes sea más eficiente. (Contribuido por Raymond
  Hettinger.)

* El lenguaje de expresiones regulares aceptado por el módulo "re" se
  amplió con expresiones condicionales simples, escritas como
  "(?(group)A|B)". En su lugar, se utilizará *group* is either a
  numeric group ID or a group name defined with ASDF02 earlier in the
  expression.  If the specified group matched, the regular expression
  pattern *A* will be tested against the string; if the group didn't
  match, the pattern *B*. (Contribución de Gustavo Niemeyer.)

* El módulo "re" ya no es recursivo, gracias a la enorme cantidad de
  trabajo de Gustavo Niemeyer. En un motor de expresión regular
  recursivo, ciertos patrones dan como resultado que se consuma una
  gran cantidad de espacio de pila de C y es posible desbordar la
  pila. Por ejemplo, si comparó una cadena de 30000 bytes de
  caracteres "a" con la expresión "(a|b)+", se consumió un marco de
  pila por carácter. Python 2.3 intentó verificar el desbordamiento de
  la pila y generar una excepción "RuntimeError", pero ciertos
  patrones podrían eludir la verificación y, si no tuvo suerte, Python
  podría segregar. El motor de expresiones regulares de Python 2.4
  puede coincidir con este patrón sin problemas.

* El módulo "signal" ahora realiza una verificación de errores más
  estricta en los parámetros de la función "signal.signal()". Por
  ejemplo, no puede establecer un controlador en la señal "SIGKILL";
  las versiones anteriores de Python aceptarían silenciosamente esto,
  pero 2.4 lanzará una excepción "RuntimeError".

* Se agregaron dos nuevas funciones al módulo "socket". "socketpair()"
  devuelve un par de sockets conectados y "getservbyport(port)" busca
  el nombre del servicio para un número de puerto determinado.
  (Contribuido por Dave Cole y Barry Warsaw.)

* La función "sys.exitfunc()" ha quedado obsoleta. El código debe usar
  el módulo "atexit" existente, que maneja correctamente la llamada a
  múltiples funciones de salida. Finalmente, "sys.exitfunc()" se
  convertirá en una interfaz puramente interna, a la que solo accederá
  "atexit".

* El módulo "tarfile" ahora genera archivos tar en formato GNU de
  forma predeterminada. (Contribución de Lars Gustäbel.)

* El módulo "threading" ahora tiene una forma elegante y sencilla de
  admitir datos locales de subprocesos. El módulo contiene una clase
  "local" cuyos valores de atributo son locales para diferentes
  subprocesos.

     importar subprocesos

     datos = threading.local()
     datos.number = 42
     datos.url = ('www.python.org', 80)

  Otros subprocesos pueden asignar y recuperar sus propios valores
  para los atributos "number" y "url". Puede crear una subclase de
  "local" para inicializar atributos o agregar métodos. (Contribuido
  por Jim Fulton.)

* El módulo "timeit" ahora deshabilita automáticamente la recolección
  de basura periódica durante el ciclo de temporización. Este cambio
  hace que los tiempos consecutivos sean más comparables. (Contribuido
  por Raymond Hettinger.)

* El módulo "weakref" ahora admite una variedad más amplia de objetos,
  incluidas funciones de Python, instancias de clases, conjuntos,
  frozensets, deques, matrices, archivos, sockets y objetos de
  patrones de expresión regular. (Contribuido por Raymond Hettinger.)

* El módulo "xmlrpclib" ahora admite una extensión de múltiples
  llamadas para transmitir múltiples llamadas XML-RPC en una sola
  operación HTTP. (Contribuido por Brian Quinlan).

* Se han eliminado los módulos "mpz", "rotor" y "xreadlines".


cookielib
---------

La biblioteca "cookielib" admite el manejo de cookies HTTP por parte
del cliente, lo que refleja la compatibilidad con cookies del lado del
servidor del módulo "Cookie". Las cookies se almacenan en contenedores
de cookies; la biblioteca almacena de forma transparente las cookies
ofrecidas por el servidor web en el contenedor de cookies y recupera
la cookie del contenedor cuando se conecta al servidor. Al igual que
en los navegadores web, los objetos de política controlan si se
aceptan o no las cookies.

Para almacenar cookies entre sesiones, se proporcionan dos
implementaciones de tarros de cookies: una que almacena cookies en
formato Netscape para que las aplicaciones puedan usar los archivos de
cookies de Mozilla o Lynx, y otra que almacena cookies en el mismo
formato que la biblioteca libwww de Perl.

Se ha modificado "urllib2" para interactuar con "cookielib":
"HTTPCookieProcessor" administra un contenedor de cookies que se
utiliza al acceder a las URL.

Este módulo fue una contribución de John J. Lee.


doctest
-------

El módulo "doctest" se sometió a una refactorización considerable
gracias a Edward Loper y Tim Peters. Las pruebas pueden ser tan
simples como ejecutar "doctest.testmod()", pero las refactorizaciones
permiten personalizar el funcionamiento del módulo de varias formas.

La nueva clase "DocTestFinder" extrae las pruebas de las cadenas de
documentos de un objeto dado:

   def f (x, y):
   """>>> f(2,2)
   4
   >>> f(3,2)
   6
   """
   return x*y

   finder = doctest.DocTestFinder()

   # Obtener la lista de instancias de DocTest
   tests = finder.find(f)

La nueva clase "DocTestRunner" luego ejecuta pruebas individuales y
puede producir un resumen de los resultados:

   runner = doctest.DocTestRunner()
   para t en pruebas:
   intentado, fallido = runner.run(t)

   runner.summarize(verbose=1)

El ejemplo anterior produce la siguiente salida:

   1 ítems pasaron todas las pruebas:
   2 pruebas en f
   2 pruebas en 1 ítem.
   2 pasaron y 0 reprobaron.
   Prueba aprobada.

"DocTestRunner" usa una instancia de la clase "OutputChecker" para
comparar la salida esperada con la salida real. Esta clase toma varios
indicadores diferentes que personalizan su comportamiento; Los
usuarios ambiciosos también pueden escribir una subclase completamente
nueva de "OutputChecker".

El comprobador de salida predeterminado proporciona una serie de
funciones útiles. Por ejemplo, con el indicador de opción
"doctest.ELLIPSIS", una elipsis ("...") en la salida esperada coincide
con cualquier subcadena, lo que facilita la adaptación de salidas que
varían en formas menores:

   def o (n):
       """>>> o(1)
   <__main__.C instance at 0x...>
   >>>
   """

Otra cadena especial, "<BLANKLINE>", coincide con una línea en blanco:

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

Otra nueva capacidad es producir una visualización de estilo diff de
la salida especificando "doctest.REPORT_UDIFF" (diferencias
unificadas), "doctest.REPORT_CDIFF" (diferencias de contexto), o
"doctest.REPORT_NDIFF" Indicadores de opción (estilo delta). Por
ejemplo:

   def g (n):
       """>>> g(4)
   here
   is
   a
   lengthy
   >>>"""
       L = 'here is a rather lengthy list of words'.split()
       for word in L[:n]:
           print word

Al ejecutar las pruebas de la función anterior con
"doctest.REPORT_UDIFF" especificado, 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 @@
        is
        a
       -lengthy
       +rather
   **********************************************************************


Cambios en la API de Build y C
==============================

Algunos de los cambios en el proceso de compilación de Python y en la
API de C son:

* Se agregaron tres nuevas macros de conveniencia para valores de
  retorno comunes de funciones de extensión: "Py_RETURN_NONE",
  "Py_RETURN_TRUE", y "Py_RETURN_FALSE". (Contribuido por Brett
  Cannon.)

* Otra macro nueva, "Py_CLEAR", reduce el recuento de referencias de
  *obj* y establece *obj* en el puntero nulo. (Aportado por Jim
  Fulton.)

* Una nueva función, "PyTuple_Pack(N, obj1, obj2, ..., objN)",
  construye tuplas a partir de una lista de argumentos de longitud
  variable de objetos Python. (Contribuido por Raymond Hettinger.)

* Una nueva función, "PyDict_Contains(d, k)", implementa búsquedas
  rápidas de diccionarios sin enmascarar las excepciones que surgen
  durante el proceso de búsqueda. (Contribuido por Raymond Hettinger.)

* La macro Py_IS_NAN(X) retorna 1 si su argumento flotante o doble *X*
  es un NaN. (Aportado por Tim Peters.)

* El código C puede evitar el bloqueo innecesario mediante el uso de
  la nueva función "PyEval_ThreadsInitialized()" para saber si se ha
  realizado alguna operación de subproceso. Si esta función devuelve
  falso, no se necesitan operaciones de bloqueo. (Contribuido por Nick
  Coghlan.)

* Una nueva función, "PyArg_VaParseTupleAndKeywords()", es la misma
  que "PyArg_ParseTupleAndKeywords()" pero toma un "va_list" en lugar
  de varios argumentos. (Contribuido por Greg Chapman.)

* Un nuevo indicador de método, "METH_COEXISTS", permite que una
  función definida en ranuras coexista con un "PyCFunction" que tiene
  el mismo nombre. Esto puede reducir a la mitad el tiempo de acceso
  para un método como "set.__contains__()". (Contribuido por Raymond
  Hettinger.)

* Python ahora se puede construir con perfiles adicionales para el
  intérprete en sí, con la intención de ayudar a las personas que
  desarrollan el núcleo de Python. Proporcionar " - enable-profiling"
  al **configure** script le permitirá perfilar el intérprete con
  **gprof**, y proporcionar el " - with-tsc" switch permite la
  creación de perfiles utilizando el registro de contador de marcas de
  tiempo del Pentium. Tenga en cuenta que el conmutador " - with-tsc"
  tiene un nombre ligeramente incorrecto, porque la función de
  creación de perfiles también funciona en la plataforma PowerPC,
  aunque la arquitectura del procesador no llama a ese registro" el
  registro TSC ". (Contribuido por Jeremy Hylton.)

* El tipo "tracebackobject" ha sido renombrado a "PyTracebackObject".


Cambios específicos del puerto
------------------------------

* El puerto de Windows ahora se construye bajo MSVC ++ 7.1 y también
  con la versión 6. (Contribuido por Martin von Löwis).


Portar a Python 2.4
===================

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

* Los desplazamientos a la izquierda y las constantes hexadecimales /
  octales que son demasiado grandes ya no activan un "FutureWarning" y
  devuelven un valor limitado a 32 o 64 bits; en su lugar, devuelven
  un entero largo.

* Operaciones de números enteros no lanzaran una excepción
  "OverflowWarning". La advertencia sobre "OverflowWarning"
  desaparecerá en Python 2.5.

* La función de conjunto integrado "zip()" y la "itertools.izip()"
  ahora retornan una lista hacia en vez de lanzar una excepción de
  tipo "TypeError" si son llamados sin argumentos.

* Ya no puede comparar las instancias "date" y "datetime"
  proporcionadas por el módulo "datetime". Dos instancias de clases
  diferentes ahora siempre serán desiguales, y las comparaciones
  relativas ("<", ">") lanzarán un "TypeError".

* "dircache.listdir()" ahora pasa excepciones a la persona que llama
  en lugar de devolver listas vacías.

* "LexicalHandler.startDTD()" solía recibir los identificadores
  públicos y del sistema en el orden incorrecto. Esto ha sido
  corregido; las aplicaciones que se basan en el orden incorrecto
  deben corregirse.

* "fcntl.ioctl()" ahora advierte si el argumento *mutate* se omite y
  es relevante.

* El módulo "tarfile" ahora genera archivos de GNU tar-formato por
  defecto.

* Encontrar un error al importar un módulo ya no deja un objeto de
  módulo parcialmente inicializado en "sys.modules".

* "None" ahora es una constante; El código que une un nuevo valor al
  nombre "None" ahora es un error de sintaxis.

* La función "signals.signal()" ahora genera una excepción
  "RuntimeError" para ciertos valores ilegales; anteriormente estos
  errores pasaban silenciosamente. Por ejemplo, ya no puede configurar
  un controlador en la señal "SIGKILL".


Agradecimientos
===============

El autor desea agradecer a las siguientes personas por ofrecer
sugerencias, correcciones y ayuda con varios borradores de este
artículo: Koray Can, Hye-Shik Chang, Michael Dyck, Raymond Hettinger,
Brian Hurt, Hamish Lawson, Fredrik Lundh, Sean Reifschneider,
Sadruddin Rejeb.
