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

Autor:
   A.M. Kuchling

Este artículo explica las nuevas características de Python 2.3.
Python 2.3 se publicó el 29 de julio de 2003.

Los temas principales de Python 2.3 son el pulido de algunas de las
características añadidas en la 2.2, la adición de varias mejoras
pequeñas pero útiles al núcleo del lenguaje y la ampliación de la
biblioteca estándar.  El nuevo modelo de objetos introducido en la
versión anterior se ha beneficiado de 18 meses de correcciones de
errores y de esfuerzos de optimización que han mejorado el rendimiento
de las clases de nuevo estilo.  Se han añadido algunas funciones
incorporadas, como "sum()" y "enumerate()".  El operador "in" puede
utilizarse ahora para búsquedas de subcadenas (por ejemplo, ""ab" en
"abc"" retorna "True").

Algunas de las nuevas características de la biblioteca son los tipos
de datos booleanos, de conjunto, de montón y de fecha/hora, la
posibilidad de importar módulos desde archivos con formato ZIP, el
soporte de metadatos para el tan esperado catálogo de Python, una
versión actualizada de IDLE y módulos para registrar mensajes,
envolver texto, analizar archivos CSV, procesar opciones de línea de
comandos, utilizar bases de datos BerkeleyDB... la lista de módulos
nuevos y mejorados es larga.

Este artículo no pretende proporcionar una especificación completa de
las nuevas características, sino que proporciona una visión general
conveniente.  Para obtener todos los detalles, debes consultar la
documentación de Python 2.3, como la Referencia de la Biblioteca de
Python y el Manual de Referencia de Python.  Si quieres entender la
implementación completa y los fundamentos del diseño, consulta el PEP
de una nueva característica en particular.


PEP 218: Un tipo de datos de conjunto estándar
==============================================

El nuevo módulo "sets" contiene una implementación de un tipo de datos
de conjunto. La clase "Set" es para conjuntos mutables, conjuntos a
los que se les pueden agregar y quitar miembros. La clase
"ImmutableSet" es para conjuntos que no se pueden modificar y, por lo
tanto, las instancias de "ImmutableSet" se pueden usar como claves de
diccionario. Los conjuntos se construyen sobre diccionarios, por lo
que los elementos dentro de un conjunto deben ser codificables.

Aquí hay un ejemplo simple:

   >>> importar conjuntos
   >>> S = conjuntos.Set([1,2,3])
   >>> S
   Set([1, 2, 3])
   >>> 1 en S
   Verdadero
   >>> 0 en S
   Falso
   >>> S.add(5)
   >>> S.remove(3)
   >>> S
   Set([1, 2, 5])
   >>>

The union and intersection of sets can be computed with the "union()"
and "intersection()" methods; an alternative notation uses the bitwise
operators "&" and "|". Mutable sets also have in-place versions of
these methods, "union_update()" and "intersection_update()".

   >>> S1 = conjuntos.Set([1,2,3])
   >>> S2 = conjuntos.Set([4,5,6])
   >>> S1.union(S2)
   Set([1, 2, 3, 4, 5, 6])
   >>> S1 | S2 # Notación alternativa
   Set([1, 2, 3, 4, 5, 6])
   >>> S1.intersection(S2)
   Set([])
   >>> S1 y S2 # Notación alternativa
   Set([])
   >>> S1.union_update(S2)
   >>> S1
   Set([1, 2, 3, 4, 5, 6])
   >>>

It's also possible to take the symmetric difference of two sets.  This
is the set of all elements in the union that aren't in the
intersection.  Another way of putting it is that the symmetric
difference contains all elements that are in exactly one set.  Again,
there's an alternative notation ("^"), and an in-place version with
the ungainly name "symmetric_difference_update()".

   >>> S1 = conjuntos.Conjunto([1,2,3,4])
   >>> S2 = conjuntos.Conjunto([3,4,5,6])
   >>> S1.diferencia_simétrica(S2)
   Conjunto([1, 2, 5, 6])
   >>> S1 ^ S2
   Conjunto([1, 2, 5, 6])
   >>>

También existen los métodos "issubset()" y "issuperset()" para
comprobar si un conjunto es un subconjunto o superconjunto de otro:

   >>> S1 = conjuntos.Set([1,2,3])
   >>> S2 = conjuntos.Set([2,3])
   >>> S2.issubset(S1)
   Verdadero
   >>> S1.issubset(S2)
   Falso
   >>> S1.issuperset(S2)
   Verdadero
   >>>

Ver también:

  **PEP 218** - Añadiendo un tipo de objeto de conjunto incorporado
     PEP escrito por Greg V. Wilson. Implementado por Greg V. Wilson,
     Alex Martelli y GvR.


PEP 255: Generadores simples
============================

En Python 2.2, los generadores se añadieron como una característica
opcional, que se activaba mediante una directiva "from __future__
import generators".  En 2.3 los generadores ya no necesitan ser
habilitados especialmente, y ahora están siempre presentes; esto
significa que "yield" es ahora siempre una palabra clave.  El resto de
esta sección es una copia de la descripción de los generadores del
documento "What's New in Python 2.2"; si lo leíste cuando salió Python
2.2, puedes saltarte el resto de esta sección.

Sin duda estás familiarizado con cómo funcionan las llamadas a
funciones en Python o C. Cuando llamas a una función, ésta obtiene un
espacio de nombres privado donde se crean sus variables locales.
Cuando la función llega a una declaración "return", las variables
locales se destruyen y el valor resultante se retorna a quien la
llamó.  Una llamada posterior a la misma función obtendrá un nuevo
conjunto de variables locales. Pero, ¿qué pasaría si las variables
locales no se tiraran al salir de una función? ¿Qué pasaría si
pudieras reanudar la función donde la dejaste?  Esto es lo que
proporcionan los generadores; se puede pensar en ellos como funciones
reanudables.

Este es el ejemplo más sencillo de una función generadora:

   def generate_ints(N):
   para i en rango(N):
   rendimiento i

Se ha introducido una nueva palabra clave, "yield", para los
generadores.  Cualquier función que contenga una declaración "yield"
es una función generadora; esto es detectado por el compilador de
código de bits de Python que compila la función especialmente como
resultado.

Cuando se llama a una función generadora, ésta no retorna un único
valor, sino que retorna un objeto generador que soporta el protocolo
de los iteradores.  Al ejecutar la sentencia "yield", el generador
retorna el valor de "i", de forma similar a una sentencia "return".
La gran diferencia entre "yield" y una sentencia "return" es que al
llegar a una sentencia "yield" se suspende el estado de ejecución del
generador y se conservan las variables locales.  En la siguiente
llamada al método ".next()" del generador, la función se reanudará la
ejecución inmediatamente después de la sentencia "yield".  (Por
razones complicadas, la sentencia "yield" no está permitida dentro del
bloque "try" de una sentencia "try"...`; lea **PEP 255** para una
explicación completa de la interacción entre "yield" y las
excepciones)

Este es un ejemplo de uso del generador "generate_ints()":

   >>> gen = generate_ints(3)
   >>> gen
   <objeto generador en 0x8117f90>
   >>> gen.next()
   0
   >>> gen.next()
   1
   >>> gen.next()
   2
   >>> gen.next()
   Traceback (última llamada más reciente):
   Archivo "stdin", línea 1, en ?
   Archivo "stdin", línea 2, en generate_ints
   StopIteration

También podrías escribir "for i in generate_ints(5)", o "a,b,c =
generate_ints(3)".

Dentro de una función generadora, la expresión "return" sólo puede
usarse sin un valor, y señala el final de la procesión de valores;
después el generador no puede retornar más valores. "return" con un
valor, como "return 5", es un error de sintaxis dentro de una función
generadora.  El final de los resultados del generador también puede
indicarse levantando manualmente "StopIteration", o simplemente
dejando que el flujo de ejecución caiga en el fondo de la función.

Puedes conseguir el efecto de los generadores manualmente escribiendo
tu propia clase y almacenando todas las variables locales del
generador como variables de instancia.  Por ejemplo, la devolución de
una lista de enteros podría hacerse estableciendo "self.count" a 0, y
haciendo que el método "next()" incremente "self.count" y lo retorne.
Sin embargo, para un generador medianamente complicado, escribir la
clase correspondiente sería mucho más complicado.
"Lib/test/test_generators.py" contiene varios ejemplos más
interesantes.  El más sencillo implementa un recorrido en orden de un
árbol utilizando generadores de forma recursiva

   # Un generador recursivo que genera hojas de árboles en orden.
   def inorder(t):
   if t:
   for x in inorder(t.left):
   yield x
   yield t.label
   for x in inorder(t.right):
   yield x

Otros dos ejemplos en "Lib/test/test_generators.py" producen
soluciones para el problema de las N reinas (colocar $N$ reinas en un
tablero de ajedrez $NxN$ de forma que ninguna reina amenace a otra) y
el recorrido del caballero (una ruta que lleva a un caballo a cada
casilla de un tablero de ajedrez $NxN$ sin visitar ninguna casilla dos
veces).

La idea de los generadores proviene de otros lenguajes de
programación, especialmente de Icon
(https://www2.cs.arizona.edu/icon/), donde la idea de los generadores
es fundamental.  En Icon, cada expresión y llamada a una función se
comporta como un generador.  Un ejemplo de "*An Overview of the Icon
Programming Language*" en
https://www2.cs.arizona.edu/icon/docs/ipd266.htm da una idea de cómo
es esto:

   oración := "Guardarlo en el puerto vecino"
   si (i := find("o", oración)) > 5 entonces write(i)

En Icon, la función "find()" devuelve los índices en los que se
encuentra la subcadena "o": 3, 23, 33. En la declaración "if", a "i"
primero se le asigna un valor de 3, pero 3 es menor que 5, por lo que
la comparación falla y Icon la vuelve a intentar con el segundo valor
de 23. 23 es mayor que 5, por lo que la comparación ahora tiene éxito
y el código imprime el valor 23 en la pantalla.

Python no va tan lejos como Icon en la adopción de generadores como
concepto central.  Los generadores se consideran parte del núcleo del
lenguaje Python, pero aprenderlos o utilizarlos no es obligatorio; si
no resuelven ningún problema que tengas, siéntete libre de ignorarlos.
Una característica novedosa de la interfaz de Python en comparación
con la de Icon es que el estado de un generador se representa como un
objeto concreto (el iterador) que puede pasarse a otras funciones o
almacenarse en una estructura de datos.

Ver también:

  **PEP 255** - Generadores simples
     Escrito por Neil Schemenauer, Tim Peters, Magnus Lie Hetland.
     Implementado principalmente por Neil Schemenauer y Tim Peters,
     con otras correcciones del equipo de Python Labs.


PEP 263: Codificación del código fuente
=======================================

Los archivos fuente de Python ahora pueden declararse con diferentes
codificaciones de conjuntos de caracteres.  Las codificaciones se
declaran incluyendo un comentario con formato especial en la primera o
segunda línea del archivo fuente.  Por ejemplo, un archivo UTF-8 puede
declararse con:

   #!/usr/bin/env python
   # -*- coding: UTF-8 -*-

Sin esta declaración de codificación, la codificación por defecto
utilizada es ASCII de 7 bits. Ejecutar o importar módulos que
contengan literales de cadena con caracteres de 8 bits y que no tengan
una declaración de codificación dará lugar a un "DeprecationWarning"
señalado por Python 2.3; en 2.4 será un error de sintaxis.

La declaración de codificación sólo afecta a los literales de cadena
Unicode, que se convertirán a Unicode utilizando la codificación
especificada.  Ten en cuenta que los identificadores de Python siguen
restringidos a caracteres ASCII, por lo que no puedes tener nombres de
variables que utilicen caracteres fuera de los alfanuméricos
habituales.

Ver también:

  **PEP 263** - Definición de las codificaciones del código fuente de
  Python
     Escrito por Marc-André Lemburg y Martin von Löwis; realizado por
     Suzuki Hisao y Martin von Löwis.


PEP 273: Importar módulos desde archivos ZIP
============================================

El nuevo módulo "zipimport" añade soporte para importar módulos desde
un archivo en formato ZIP.  No es necesario importar el módulo
explícitamente; se importará automáticamente si se añade el nombre de
un archivo ZIP a "sys.path". Por ejemplo:

   amk@nyman:~/src/python$ unzip -l /tmp/example.zip
   Archivo: /tmp/example.zip
   Longitud Fecha Hora Nombre
   -------- ---- ---- ----
   8467 11-26-02 22:30 jwzthreading.py
   -------- -------
   8467 1 archivo
   amk@nyman:~/src/python$ ./python
   Python 2.3 (#1, 1 de agosto de 2003, 19:54:32)
   >>> import sys
   >>> sys.path.insert(0, '/tmp/example.zip') # Agregar archivo .zip al principio de la ruta
   >>> import jwzthreading
   >>> jwzthreading.__file__
   '/tmp/ejemplo.zip/jwzthreading.py'
   >>>

Una entrada en "sys.path" puede ser ahora el nombre de un archivo ZIP.
El archivo ZIP puede contener cualquier tipo de ficheros, pero sólo se
pueden importar los ficheros llamados "*.py", "*.pyc", o "*.pyo".  Si
un archivo sólo contiene ficheros "*.py", Python no intentará
modificar el archivo añadiendo el correspondiente fichero "*.pyc", lo
que significa que si un archivo ZIP no contiene ficheros "*.pyc", la
importación puede ser bastante lenta.

También se puede especificar una ruta dentro del archivo para importar
sólo de un subdirectorio; por ejemplo, la ruta "/tmp/example.zip/lib/"
sólo importaría del subdirectorio "lib/" dentro del archivo.

Ver también:

  **PEP 273** - Importación de módulos desde archivos Zip
     Escrito por James C. Ahlstrom, que también proporcionó una
     implementación. Python 2.3 sigue la especificación en **PEP
     273**, pero utiliza una implementación escrita por Just van
     Rossum que utiliza los ganchos de importación descritos en **PEP
     302**. Vea la sección PEP 302: Nuevos ganchos de importación para
     una descripción de los nuevos ganchos de importación.


PEP 277: Soporte de nombres de archivo Unicode para Windows NT
==============================================================

En Windows NT, 2000 y XP, el sistema almacena los nombres de archivo
como cadenas Unicode. Tradicionalmente, Python ha representado los
nombres de archivo como cadenas de bytes, lo cual es inadecuado porque
hace que algunos nombres de archivo sean inaccesibles.

Python ahora permite el uso de cadenas Unicode arbitrarias (dentro de
las limitaciones del sistema de archivos) para todas las funciones que
esperan nombres de archivos, en particular la función incorporada
"open()". Si se pasa una cadena Unicode a "os.listdir()", Python ahora
devuelve una lista de cadenas Unicode. Una nueva función,
"os.getcwdu()", devuelve el directorio actual como una cadena Unicode.

Las cadenas de bytes siguen funcionando como nombres de archivo, y en
Windows Python las convertirá de forma transparente a Unicode
utilizando la codificación "mbcs".

Other systems also allow Unicode strings as file names but convert
them to byte strings before passing them to the system, which can
cause a "UnicodeError" to be raised. Applications can test whether
arbitrary Unicode strings are supported as file names by checking
"os.path.supports_unicode_filenames", a Boolean value.

En MacOS, "os.listdir()" ahora puede retornar nombres de archivo
Unicode.

Ver también:

  **PEP 277** - Soporte de nombres de archivo Unicode para Windows NT
     Escrito por Neil Hodgson; realizado por Neil Hodgson, Martin von
     Löwis y Mark Hammond.


PEP 278: Soporte universal de nuevas líneas
===========================================

Los tres principales sistemas operativos que se utilizan hoy en día
son Microsoft Windows, el sistema operativo Macintosh de Apple y los
diversos derivados de Unix.  Una pequeña molestia del trabajo entre
plataformas es que estas tres plataformas utilizan diferentes
caracteres para marcar el final de las líneas en los archivos de
texto.  Unix utiliza el salto de línea (carácter ASCII 10), MacOS
utiliza el retorno de carro (carácter ASCII 13), y Windows utiliza una
secuencia de dos caracteres de un retorno de carro más una nueva
línea.

Los objetos de archivo de Python ahora pueden admitir convenciones de
fin de línea distintas a la que sigue la plataforma en la que se
ejecuta Python. Al abrir un archivo con el modo "'U'" o "'rU'", se
abrirá un archivo para leer en modo *universal newlines*. Las tres
convenciones de fin de línea se traducirán a "'\n'" en las cadenas
devueltas por los distintos métodos de archivo, como "read()" y
"readline()".

También se utiliza la compatibilidad universal con saltos de línea al
importar módulos y al ejecutar un archivo con la función "execfile()".
Esto significa que los módulos de Python se pueden compartir entre los
tres sistemas operativos sin necesidad de convertir los finales de
línea.

Esta función puede desactivarse al compilar Python especificando la
opción "--without-universal-newlines" al ejecutar el script
**configure** de Python.

Ver también:

  **PEP 278** - Soporte universal de nuevas líneas
     Escrito y ejecutado por Jack Jansen.


PEP 279: enumerate()
====================

Una nueva función incorporada, "enumerate()", hará que ciertos bucles
sean un poco más claros.  "enumerate(cosa)", donde *cosa* es un
iterador o una secuencia, retorna un iterador que retornará "(0,
cosa[0])", "(1, cosa[1])", "(2, cosa[2])", y así sucesivamente.

Un modismo común para cambiar cada elemento de una lista tiene el
siguiente aspecto:

   para i en rango(len(L)):
   item = L[i]
   # ... calcular algún resultado basado en el elemento ...
   L[i] = resultado

Esto se puede reescribir usando "enumerate()" como:

   para i, elemento en enumerate(L):
   # ... calcular algún resultado basado en el elemento ...
   L[i] = resultado

Ver también:

  **PEP 279** - La función incorporada enumerate()
     Escrito y ejecutado por Raymond D. Hettinger.


PEP 282: El paquete de registro
===============================

Se ha añadido a Python 2.3 un paquete estándar para escribir
registros, "logging".  Proporciona un mecanismo potente y flexible
para generar salidas de registro que pueden ser filtradas y procesadas
de varias maneras.  Se puede utilizar un archivo de configuración
escrito en un formato estándar para controlar el comportamiento de
registro de un programa.  Python incluye manejadores que escribirán
los registros en el error estándar o en un archivo o socket, los
enviarán al registro del sistema, o incluso los enviarán por correo
electrónico a una dirección particular; por supuesto, también es
posible escribir tus propias clases de manejadores.

La clase "Logger" es la clase principal. La mayoría del código de la
aplicación se ocupará de uno o más objetos "Logger", cada uno de ellos
utilizado por un subsistema particular de la aplicación. Cada "Logger"
se identifica con un nombre, y los nombres se organizan en una
jerarquía utilizando "." como separador de componentes. Por ejemplo,
puede tener instancias "Logger" denominadas "server", "server.auth" y
"server.network". Las dos últimas instancias están por debajo de
"server" en la jerarquía. Esto significa que si aumenta el nivel de
detalle de "server" o dirige los mensajes "server" a un controlador
diferente, los cambios también se aplicarán a los registros
registrados en "server.auth" y "server.network". También hay un
"Logger" raíz que es el padre de todos los demás registradores.

Para usos sencillos, el paquete "logging" contiene algunas funciones
de conveniencia que siempre utilizan la raíz log:

   import logging

   logging.debug('Información de depuración')
   logging.info('Mensaje informativo')
   logging.warning('Advertencia: no se encontró el archivo de configuración %s', 'server.conf')
   logging.error('Se produjo un error')
   logging.critical('Error crítico: apagando el sistema')

Esto produce la siguiente salida:

   ADVERTENCIA:root:Advertencia:no se encontró el archivo de configuración server.conf
   ERROR:root:Se produjo un error
   CRÍTICO:root:Error crítico: se está apagando

En la configuración predeterminada, se suprimen los mensajes
informativos y de depuración y la salida se envía al error estándar.
Puede habilitar la visualización de mensajes informativos y de
depuración llamando al método "setLevel()" en el registrador raíz.

Observe el uso de operadores de formato de cadena en la llamada
"warning()"; todas las funciones para registrar mensajes toman los
argumentos "(msg, arg1, arg2, ...)" y registran la cadena resultante
de "msg % (arg1, arg2, ...)".

También hay una función "exception()" que registra el seguimiento más
reciente. Cualquiera de las otras funciones también registrará el
seguimiento si especifica un valor verdadero para el argumento de
palabra clave *exc_info*.

   def f():
   try: 1/0
   except: logging.exception('Problema registrado')

   f()

Esto produce la siguiente salida:

   ERROR:root:Problema registrado
   Traceback (última llamada más reciente):
   Archivo "t.py", línea 6, en f
   1/0
   ZeroDivisionError: división entera o módulo por cero

Los programas un poco más avanzados utilizarán un logger distinto del
logger raíz. La función "getLogger(nombre)" se utiliza para obtener un
registro en particular, creándolo si aún no existe. "getLogger(None)"
retorna el logger raíz.

   log = logging.getLogger('servidor')
   ...
   log.info('Escuchando en el puerto %i', puerto)
   ...
   log.critical('Disco lleno')
   ...

Los registros normalmente se propagan hacia arriba en la jerarquía,
por lo que un mensaje registrado en "server.auth" también es visto por
"server" y "root", pero un "Logger" puede evitar esto configurando su
atributo "propagate" en "False".

El paquete "logging" proporciona más clases que se pueden
personalizar. Cuando se le indica a una instancia "Logger" que
registre un mensaje, crea una instancia "LogRecord" que se envía a
cualquier cantidad de instancias "Handler" diferentes. Los
registradores y controladores también pueden tener una lista adjunta
de filtros, y cada filtro puede hacer que se ignore el "LogRecord" o
puede modificar el registro antes de pasarlo. Cuando finalmente se
generan, las instancias "LogRecord" se convierten en texto mediante
una clase "Formatter". Todas estas clases se pueden reemplazar por sus
propias clases especialmente escritas.

Con todas estas características, el paquete "logging" debería
proporcionar suficiente flexibilidad incluso para las aplicaciones más
complicadas.  Esto es sólo un resumen incompleto de sus
características, así que por favor consulte la documentación de
referencia del paquete para todos los detalles.  La lectura de **PEP
282** también será útil.

Ver también:

  **PEP 282** - Un sistema de registro
     Escrito por Vinay Sajip y Trent Mick; implementado por Vinay
     Sajip.


PEP 285: Un tipo booleano
=========================

Se agregó un tipo booleano a Python 2.3. Se agregaron dos nuevas
constantes al módulo "__builtin__", "True" y "False". (Las constantes
"True" y "False" se agregaron a las funciones integradas en Python
2.2.1, pero las versiones 2.2.1 simplemente se configuran en valores
enteros de 1 y 0 y no son de un tipo diferente).

El objeto de tipo para este nuevo tipo se denomina "bool"; su
constructor toma cualquier valor de Python y lo convierte en "True" o
"False".

   >>> bool(1)
   Verdadero
   >>> bool(0)
   Falso
   >>> bool([])
   Falso
   >>> bool( (1,) )
   Verdadero

La mayoría de los módulos de la biblioteca estándar y las funciones
incorporadas se han modificado para retornar booleanos.

   >>> obj = []
   >>> hasattr(obj, 'append')
   Verdadero
   >>> isinstance(obj, lista)
   Verdadero
   >>> isinstance(obj, tupla)
   Falso

Los booleanos de Python se añadieron con el objetivo principal de
hacer el código más claro.  Por ejemplo, si estás leyendo una función
y te encuentras con la sentencia "return 1", podrías preguntarte si el
"1" representa un valor de verdad booleano, un índice o un coeficiente
que multiplica alguna otra cantidad.  Sin embargo, si la sentencia es
"return True", el significado del valor de retorno es bastante claro.

Los booleanos de Python *no* se añadieron en aras de una comprobación
de tipos estricta.  Un lenguaje muy estricto como Pascal también le
impediría realizar aritmética con booleanos, y requeriría que la
expresión en una declaración "if" siempre se evaluara a un resultado
booleano.  Python no es tan estricto y nunca lo será, como dice
explícitamente **PEP 285**.  Esto significa que puede utilizar
cualquier expresión en una sentencia "if", incluso las que se evalúan
a una lista o tupla o algún objeto aleatorio.  El tipo Booleano es una
subclase de la clase "int" por lo que la aritmética que utiliza un
Booleano sigue funcionando.

   >>> Verdadero + 1
   2
   >>> Falso + 1
   1
   >>> Falso * 75
   0
   >>> True * 75
   75

Para resumir "True" and "False"  en una frase: son formas alternativas
de deletrear los valores enteros 1 y 0, con la única diferencia de que
"str()" y "repr()" retornan las cadenas "Verdadero" y "Falso" en lugar
de "1" y "0".

Ver también:

  **PEP 285** - Añadir un tipo booleano
     Escrito y ejecutado por GvR.


PEP 293: Llamadas de retorno para el manejo de errores del códec
================================================================

Al codificar una cadena Unicode en una cadena de bytes, pueden
encontrarse caracteres no codificables.  Hasta ahora, Python ha
permitido especificar el procesamiento del error como "estricto"
(lanzando "UnicodeError"), "ignorar" (saltando el carácter), o
"reemplazar" (usando un signo de interrogación en la cadena de
salida), siendo "estricto" el comportamiento por defecto. Puede ser
deseable especificar un procesamiento alternativo de tales errores,
como insertar una referencia de carácter XML o una referencia de
entidad HTML en la cadena convertida.

Python tiene ahora un marco flexible para añadir diferentes
estrategias de procesamiento.  Se pueden añadir nuevos manejadores de
errores con "codecs.register_error()", y los códecs pueden acceder al
manejador de errores con "codecs.lookup_error()". Se ha añadido una
API en C equivalente para los códecs escritos en C. El gestor de
errores obtiene la información de estado necesaria, como la cadena que
se está convirtiendo, la posición en la cadena donde se ha detectado
el error y la codificación de destino.  El controlador puede entonces
lanzar una excepción o retornar una cadena de reemplazo.

Se han implementado dos manejadores de error adicionales utilizando
este marco: "backslashreplace" utiliza las comillas de barra invertida
de Python para representar los caracteres no codificables y
"xmlcharrefreplace" emite referencias de caracteres XML.

Ver también:

  **PEP 293** - Retrollamadas de manejo de errores del códec
     Escrito y ejecutado por Walter Dörwald.


PEP 301: Índice de paquetes y metadatos para Distutils
======================================================

La compatibilidad con el catálogo de Python, largamente solicitada,
hace su primera aparición en 2.3.

El corazón del catálogo es el nuevo comando **register** de Distutils.
Ejecutando "python setup.py register" se recogen los metadatos que
describen un paquete, como su nombre, versión, mantenedor,
descripción, etc., y se envían a un servidor de catálogo central.  El
catálogo resultante está disponible en https://pypi.org.

Para que el catálogo sea un poco más útil, se ha añadido un nuevo
argumento de palabra clave opcional *classifiers* a la función
"setup()" de Distutils. Se puede proporcionar una lista de cadenas de
estilo Trove para ayudar a clasificar el software.

Aquí hay un ejemplo "setup.py" con clasificadores, escrito para que
sea compatible con las versiones más antiguas de Distutils:

   from distutils import core
   kw = {'name': "Quixote",
         'version': "0.5.1",
         'description': "A highly Pythonic Web application framework",
         # ...
         }

   if (hasattr(core, 'setup_keywords') and
       'classifiers' in core.setup_keywords):
       kw['classifiers'] = \
           ['Topic :: Internet :: WWW/HTTP :: Dynamic Content',
            'Environment :: No Input/Output (Daemon)',
            'Intended Audience :: Developers'],

   core.setup(**kw)

La lista completa de clasificadores se puede obtener ejecutando
"python setup.py register --list-classifiers".

Ver también:

  **PEP 301** - Índice de paquetes y metadatos para Distutils
     Escrito y ejecutado por Richard Jones.


PEP 302: Nuevos ganchos de importación
======================================

Si bien ha sido posible escribir ganchos de importación personalizados
desde que se introdujo el módulo "ihooks" en Python 1.3, nadie ha
estado realmente satisfecho con ello porque escribir nuevos ganchos de
importación es difícil y complicado. Se han propuesto varias
alternativas, como los módulos "imputil" y "iu", pero ninguna de ellas
ha tenido mucha aceptación y ninguna de ellas se podía usar fácilmente
desde el código C.

**PEP 302** toma prestadas ideas de sus predecesores, especialmente
del módulo "iu" de Gordon McMillan. Se han añadido tres elementos
nuevos al módulo "sys":

* "sys.path_hooks" es una lista de objetos invocables; la mayoría de
  las veces serán clases.  Cada llamada toma una cadena que contiene
  una ruta y retorna un objeto importador que manejará las
  importaciones desde esta ruta o lanza una excepción "ImportError" si
  no puede manejar esta ruta.

* "sys.path_importer_cache" almacena en caché los objetos del
  importador para cada ruta, por lo que "sys.path_hooks" sólo tendrá
  que ser recorrido una vez para cada ruta.

* "sys.meta_path" es una lista de objetos importadores que se
  recorrerán antes de comprobar "sys.path".  Esta lista está
  inicialmente vacía, pero el código de usuario puede añadir objetos a
  ella.  Los módulos adicionales incorporados y congelados pueden ser
  importados por un objeto añadido a esta lista.

Los objetos importadores deben tener un único método,
"find_module(fullname, path=None)".  *fullname* será un nombre de
módulo o paquete, por ejemplo "string" o "distutils.core".
"find_module()" debe retornar un objeto cargador que tenga un único
método, "load_module(fullname)", que cree y retorne el objeto módulo
correspondiente.

Por lo tanto, el pseudocódigo de la nueva lógica de importación de
Python es algo así (simplificado un poco; véase **PEP 302** para los
detalles completos):

   para mp en sys.meta_path:
   loader = mp(fullname)
   si loader no es None:
   <module> = loader.load_module(fullname)

   para path en sys.path:
   para hook en sys.path_hooks:
   try:
   importer = hook(path)
   except ImportError:
   # ImportError, así que prueba los otros ganchos de path
   pass
   de lo contrario:
   loader = importer.find_module(fullname)
   <module> = loader.load_module(fullname)

   # ¡No encontrado!
   raise ImportError

Ver también:

  **PEP 302** - Nuevos ganchos de importación
     Escrito por Just van Rossum y Paul Moore. Implementado por Just
     van Rossum.


PEP 305: Archivos separados por comas
=====================================

Los archivos separados por comas son un formato frecuentemente
utilizado para exportar datos de bases de datos y hojas de cálculo.
Python 2.3 añade un analizador de archivos separados por comas.

El formato separado por comas es engañosamente sencillo a primera
vista:

   Costos,150,200,3.95

Leer una línea y llamar a "line.split(',')": ¿qué puede ser más
sencillo? Pero si se añaden datos de cadena que pueden contener comas,
las cosas se complican:

   "Costos",150,200,3.95,"Incluye impuestos, envío y artículos varios"

Una expresión regular grande y fea puede analizar esto, pero usar el
nuevo paquete "csv" es mucho más sencillo:

   importar csv

   entrada = open('archivo_datos', 'rb')
   lector = csv.reader(entrada)
   para línea en lector:
   imprimir línea

La función "reader()" acepta varias opciones diferentes. El separador
de campo no se limita a la coma y se puede cambiar por cualquier
carácter, al igual que los caracteres de comillas y de fin de línea.

Se pueden definir y registrar diferentes dialectos de archivos
separados por comas; actualmente hay dos dialectos, ambos utilizados
por Microsoft Excel. Una clase "csv.writer" independiente generará
archivos separados por comas a partir de una sucesión de tuplas o
listas, citando cadenas que contengan el delimitador.

Ver también:

  **PEP 305** - API de archivos CSV
     Escrito y realizado por Kevin Altis, Dave Cole, Andrew McNamara,
     Skip Montanaro, Cliff Wells.


PEP 307: Mejoras en Pickle
==========================

Los módulos "pickle" y "cPickle" recibieron cierta atención durante el
ciclo de desarrollo 2.3. En 2.2, las clases de nuevo estilo podían ser
encurtidas sin dificultad, pero no de forma muy compacta; **PEP 307**
cita un ejemplo trivial en el que una clase de nuevo estilo da como
resultado una cadena encurtida tres veces más larga que la de una
clase clásica.

La solución fue inventar un nuevo protocolo pickle.  La función
"pickle.dumps()" soporta desde hace tiempo una bandera de texto o
binario.  En la versión 2.3, esta bandera se ha redefinido, pasando de
ser un booleano a un entero: 0 es el antiguo formato pickle en modo
texto, 1 es el antiguo formato binario, y ahora 2 es un nuevo formato
específico de 2.3.  Una nueva constante, "pickle.HIGHEST_PROTOCOL",
puede utilizarse para seleccionar el protocolo más elegante
disponible.

El desempaquetado ya no se considera una operación segura. "pickle" de
la versión 2.2 proporcionaba ganchos para intentar evitar que se
desempaquetaran clases no seguras (específicamente, un atributo
"__safe_for_unpickling__"), pero ninguno de este código fue auditado
y, por lo tanto, todo se eliminó en la versión 2.3. No debe
desempaquetar datos no confiables en ninguna versión de Python.

Para reducir la sobrecarga de decapado para las clases de estilo
nuevo, se agregó una nueva interfaz para personalizar el decapado
mediante tres métodos especiales: "__getstate__()", "__setstate__()" y
"__getnewargs__()". Consulte **PEP 307** para conocer la semántica
completa de estos métodos.

Como forma de comprimir aún más los pickles, ahora es posible utilizar
códigos enteros en lugar de cadenas largas para identificar las clases
serializadas. La Python Software Foundation mantendrá una lista de
códigos estandarizados; también hay una gama de códigos para uso
privado.  Actualmente no se ha especificado ningún código.

Ver también:

  **PEP 307** - Extensiones del protocolo pickle
     Escrito y ejecutado por Guido van Rossum y Tim Peters.


Rebanadas ampliadas
===================

Desde la versión 1.4 de Python, la sintaxis de corte admite un tercer
argumento opcional "paso" o "zancada".  Por ejemplo, estas son todas
las sintaxis legales de Python: "L[1:10:2]", "L[:-1:1]", "L[::-1]".
Esto se añadió a Python a petición de los desarrolladores de Numerical
Python, que utiliza ampliamente el tercer argumento.  Sin embargo, los
tipos de secuencias de listas, tuplas y cadenas incorporados en Python
nunca han soportado esta característica, y lanzan un "TypeError" si lo
intentas. Michael Hudson ha contribuido con un parche para solucionar
este problema.

Por ejemplo, ahora puede extraer fácilmente los elementos de una lista
que tengan índices pares:

   >>> L = rango(10)
   >>> L[::2]
   [0, 2, 4, 6, 8]

Los valores negativos también sirven para hacer una copia de la misma
lista en orden inverso:

   >>> L[::-1]
   [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Esto también funciona para tuplas, arrays y cadenas:

   >>> s='abcd'
   >>> s[::2]
   'ac'
   >>> s[::-1]
   'dcba'

Si tienes una secuencia mutable, como una lista o un array, puedes
asignar o eliminar una rebanada extendida, pero hay algunas
diferencias entre la asignación a rebanadas extendidas y regulares.
La asignación a una rebanada regular se puede utilizar para cambiar la
longitud de la secuencia:

   >>> a = rango(3)
   >>> a
   [0, 1, 2]
   >>> a[1:3] = [4, 5, 6]
   >>> a
   [0, 4, 5, 6]

Las rebanadas extendidas no son tan flexibles.  Cuando se asigna a una
rebanada extendida, la lista a la derecha de la declaración debe
contener el mismo número de elementos que la rebanada que está
reemplazando:

   >>> a = range(4)
   >>> a
   [0, 1, 2, 3]
   >>> a[::2]
   [0, 2]
   >>> a[::2] = [0, -1]
   >>> a
   [0, 1, -1, 3]
   >>> a[::2] = [0,1,2]
   Traceback (última llamada más reciente):
   Archivo "<stdin>", línea 1, en ?
   ValueError: intento de asignar una secuencia de tamaño 3 a una porción extendida de tamaño 2

La eliminación es más sencilla:

   >>> a = rango(4)
   >>> a
   [0, 1, 2, 3]
   >>> a[::2]
   [0, 2]
   >>> del a[::2]
   >>> a
   [1, 3]

Ahora también se pueden pasar objetos de corte a los métodos
"__getitem__()" de las secuencias integradas:

   >>> rango(10).__getitem__(sección(0, 5, 2))
   [0, 2, 4]

O utilizar los objetos de corte directamente en los subíndices:

   >>> rango(10)[segmento(0, 5, 2)]
   [0, 2, 4]

Para simplificar la implementación de secuencias que admiten cortes
extendidos, los objetos de corte ahora tienen un método
"indices(length)" que, dada la longitud de una secuencia, devuelve una
tupla "(start, stop, step)" que se puede pasar directamente a
"range()". "indices()" maneja los índices omitidos y fuera de límites
de una manera consistente con los cortes regulares (¡y esta frase
inocua esconde una maraña de detalles confusos!). El método está
pensado para usarse de esta manera:

   class FakeSeq:
       ...
       def calc_item(self, i):
           ...
       def __getitem__(self, item):
           if isinstance(item, slice):
               indices = item.indices(len(self))
               return FakeSeq([self.calc_item(i) for i in range(*indices)])
           else:
               return self.calc_item(i)

En este ejemplo también se puede ver que el objeto incorporado "slice"
es ahora el objeto tipo para el tipo slice, y ya no es una función.
Esto es consistente con Python 2.2, donde "int", "str", etc.,
sufrieron el mismo cambio.


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

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

* La expresión "yield" es ahora siempre una palabra clave, como se
  describe en la sección PEP 255: Generadores simples de este
  documento.

* Se ha añadido una nueva función incorporada "enumerate()", como se
  describe en la sección PEP 279: enumerate() de este documento.

* Se han añadido dos nuevas constantes, "True" y "False" junto con el
  tipo incorporado "bool", como se describe en la sección PEP 285: Un
  tipo booleano de este documento.

* El constructor de tipo "int()" ahora retornará un entero largo en
  lugar de lanzar un "OverflowError" cuando una cadena o un número de
  punto flotante es demasiado grande para caber en un entero.  Esto
  puede llevar al resultado paradójico de que
  "isinstance(int(expresión), int)" sea falso, pero parece poco
  probable que cause problemas en la práctica.

* Los tipos incorporados ahora soportan la sintaxis de rebanado
  extendida, como se describe en la sección Rebanadas ampliadas de
  este documento.

* Una nueva función incorporada, "suma(iterable, start=0)", suma los
  elementos numéricos en el objeto iterable y retorna su suma.
  "suma()" sólo acepta números, lo que significa que no se puede
  utilizar para concatenar un montón de cadenas. (Contribución de Alex
  Martelli)

* "list.insert(pos, valor)" solía insertar *valor* al principio de la
  lista cuando *pos* era negativo.  El comportamiento ha sido cambiado
  para ser consistente con la indexación de las rebanadas, así que
  cuando *pos* es -1 el valor será insertado antes del último
  elemento, y así sucesivamente.

* "list.index(value)", que busca *valor* dentro de la lista y retorna
  su índice, ahora toma los argumentos opcionales *start* y *stop*
  para limitar la búsqueda sólo a una parte de la lista.

* Los diccionarios tienen un nuevo método, "pop(key[, *default*])",
  que retorna el valor correspondiente a *key* y elimina ese par
  clave/valor del diccionario.  Si la clave solicitada no está
  presente en el diccionario, se retorna *default* si está
  especificada y se lanza "KeyError" si no lo está:

     >>> d = {1:2}
     >>> d
     {1: 2}
     >>> d.pop(4)
     Traceback (última llamada más reciente):
     Archivo "stdin", línea 1, en ?
     KeyError: 4
     >>> d.pop(1)
     2
     >>> d.pop(1)
     Traceback (última llamada más reciente):
     Archivo "stdin", línea 1, en ?
     KeyError: 'pop(): el diccionario está vacío'
     >>> d
     {}
     >>>

  También hay un nuevo método de clase, "dict.fromkeys(iterable,
  value)", que crea un diccionario con claves tomadas del iterador
  *iterable* suministrado y todos los valores establecidos a *value*,
  por defecto a "None".

  (Parches aportados por Raymond Hettinger)

  Además, el constructor "dict()" ahora acepta argumentos de palabras
  clave para simplificar la creación de pequeños diccionarios:

     >>> dict(rojo=1, azul=2, verde=3, negro=4)
     {'azul': 2, 'negro': 4, 'verde': 3, 'rojo': 1}

  (Contribución de Just van Rossum.)

* La expresión "assert" ya no comprueba la bandera "debug__", por lo
  que ya no se pueden desactivar las aserciones asignando a
  "__debug__". Ejecutar Python con la opción "-O" seguirá generando
  código que no ejecute ninguna aserción.

* La mayoría de los objetos de tipo ahora se pueden llamar, por lo que
  puede usarlos para crear nuevos objetos, como funciones, clases y
  módulos. (Esto significa que el módulo "new" puede quedar obsoleto
  en una versión futura de Python, porque ahora puede usar los objetos
  de tipo disponibles en el módulo "types"). Por ejemplo, puede crear
  un nuevo objeto de módulo con el siguiente código:

     >>> tipos de importación
     >>> m = tipos.ModuleType('abc','docstring')
     >>> m
     <módulo 'abc' (integrado)>
     >>> m.__doc__
     'docstring'

* Se ha añadido una nueva advertencia, "PendingDeprecationWarning"
  para indicar las características que están en proceso de ser
  obsoletas.  La advertencia no se imprimirá por defecto.  Para
  comprobar el uso de funciones que quedarán obsoletas en el futuro,
  proporcione "-Walways::PendingDeprecationWarning::" en la línea de
  comandos o utilice "warnings.filterwarnings()".

* Ha comenzado el proceso de desaprobación de las excepciones basadas
  en cadenas, como en "lanzamiento de "Error ocurred”".  Al lanzar una
  cadena, ahora se activará "PendingDeprecationWarning".

* El uso de "None" como nombre de una variable ahora resultará en una
  advertencia "SyntaxWarning".  En una futura versión de Python,
  "None" podría convertirse en una palabra clave.

* El método "xreadlines()" de los objetos de archivo, introducido en
  Python 2.1, ya no es necesario porque los archivos ahora se
  comportan como su propio iterador. "xreadlines()" se introdujo
  originalmente como una forma más rápida de recorrer todas las líneas
  de un archivo, pero ahora puedes escribir simplemente "for line in
  file_obj". Los objetos de archivo también tienen un nuevo atributo
  "encoding" de solo lectura que proporciona la codificación utilizada
  por el archivo; las cadenas Unicode escritas en el archivo se
  convertirán automáticamente a bytes utilizando la codificación dada.

* El orden de resolución de métodos utilizado por las clases de nuevo
  estilo ha cambiado, aunque solo notarás la diferencia si tienes una
  jerarquía de herencia realmente complicada. Las clases clásicas no
  se ven afectadas por este cambio. Python 2.2 originalmente usaba una
  clasificación topológica de los ancestros de una clase, pero 2.3
  ahora usa el algoritmo C3 como se describe en el artículo "A
  Monotonic Superclass Linearization for Dylan". Para entender la
  motivación de este cambio, lee el artículo The Python 2.3 Method
  Resolution Order de Michele Simionato, o lee el hilo en python-dev
  que comienza con el mensaje en https://mail.python.org/pipermail
  /python-dev/2002-October/029035.html. Samuele Pedroni fue el primero
  en señalar el problema y también implementó la solución codificando
  el algoritmo C3.

* Python ejecuta programas multiproceso alternando entre subprocesos
  después de ejecutar N bytecodes. El valor predeterminado de N se ha
  incrementado de 10 a 100 bytecodes, lo que acelera las aplicaciones
  de un solo subproceso al reducir la sobrecarga de conmutación.
  Algunas aplicaciones multiproceso pueden sufrir un tiempo de
  respuesta más lento, pero eso se soluciona fácilmente estableciendo
  el límite en un número menor utilizando "sys.setcheckinterval(N)".
  El límite se puede recuperar con la nueva función
  "sys.getcheckinterval()".

* Un cambio menor pero de gran alcance es que los nombres de los tipos
  de extensión definidos por los módulos incluidos con Python ahora
  contienen el módulo y un "'.'" delante del nombre del tipo. Por
  ejemplo, en Python 2.2, si creaba un socket e imprimía su
  "__class__", obtenía este resultado:

     >>> s = socket.socket()
     >>> s.__class__
     <tipo 'socket'>

  En 2.3, se obtiene esto:

     >>> s.__class__
     <tipo '_socket.socket'>

* Se ha eliminado una de las incompatibilidades observadas entre las
  clases de estilo antiguo y nuevo: ahora se pueden asignar atributos
  "__name__" y "__bases__" a las clases de estilo nuevo. Existen
  algunas restricciones sobre lo que se puede asignar a "__bases__"
  similares a las relacionadas con la asignación al atributo
  "__class__" de una instancia.


Cambios en las cadenas de texto
-------------------------------

* El operador "in" ahora funciona de forma diferente para las cadenas.
  Antes, cuando se evaluaba "X en Y" donde *X* y *Y* eran cadenas, *X*
  sólo podía ser un único carácter. Esto ha cambiado; *X* puede ser
  una cadena de cualquier longitud, y "X en Y" retornará "True" si *X*
  es una subcadena de *Y*.  Si *X* es una cadena vacía, el resultado
  es siempre "True".

     >>> 'ab' en 'abcd'
     Verdadero
     >>> 'ad' en 'abcd'
     Falso
     >>> '' en 'abcd'
     Verdadero

  Tenga en cuenta que esto no le dice dónde empieza la subcadena; si
  necesita esa información, utilice el método "find()" string.

* Los métodos de cadena "strip()", "lstrip()" y "rstrip()" ahora
  tienen un argumento opcional para especificar los caracteres que se
  eliminarán. El valor predeterminado sigue siendo eliminar todos los
  caracteres de espacio en blanco:

     >>> ' abc '.strip()
     'abc'
     >>> '><><abc<><><>'.strip('<>')
     'abc'
     >>> '><><abc<><><>\n'.strip('<>')
     'abc<><><>\n'
     >>> u'\u4000\u4001abc\u4000'.strip(u'\u4000')
     u'\u4001abc'
     >>>

  (Sugerido por Simon Brunning y aplicado por Walter Dörwald)

* Los métodos de cadena "startswith()" y "endswith()" ahora aceptan
  números negativos para los parámetros *start* y *end*.

* Otro nuevo método de cadena es "zfill()", originalmente una función
  del módulo "string". "zfill()" rellena una cadena numérica con ceros
  a la izquierda hasta que alcanza el ancho especificado. Tenga en
  cuenta que el operador "%" sigue siendo más flexible y potente que
  "zfill()".

     >>> '45'.zfill(4)
     '0045'
     >>> '12345'.zfill(4)
     '12345'
     >>> 'tonto'.zfill(6)
     '0tonto'

  (Contribución de Walter Dörwald.)

* Se ha añadido un nuevo tipo de objeto, "basestring". Tanto las
  cadenas de 8 bits como las cadenas Unicode heredan de este tipo, por
  lo que "isinstance(obj, basestring)" devolverá "True" para cualquier
  tipo de cadena. Es un tipo completamente abstracto, por lo que no se
  pueden crear instancias de "basestring".

* Las cadenas internas ya no son inmortales y ahora serán recolectadas
  de la forma habitual cuando la única referencia a ellas sea desde el
  diccionario interno de cadenas internas.  (Implementado por Oren
  Tirosh)


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

* La creación de instancias de clases de estilo nuevo se ha hecho
  mucho más rápida; ¡ahora son más rápidas que las clases clásicas!

* El método "sort()" de objetos de lista ha sido reescrito ampliamente
  por Tim Peters, y la implementación es significativamente más
  rápida.

* La multiplicación de números enteros grandes es ahora mucho más
  rápida gracias a una implementación de la multiplicación Karatsuba,
  un algoritmo que escala mejor que el *O*(*n*^2) requerido para el
  algoritmo de multiplicación de nivel primario. (Parche original de
  Christopher A. Craig y reelaborado significativamente por Tim
  Peters).

* El opcode "SET_LINENO" ha desaparecido.  Esto puede proporcionar un
  pequeño aumento de velocidad, dependiendo de la idiosincrasia de su
  compilador. Vea la sección Otros cambios y correcciones para una
  explicación más larga. (Eliminado por Michael Hudson)

* Los objetos "xrange()" ahora tienen su propio iterador, lo que hace
  que "for i in xrange(n)" sea ligeramente más rápido que "for i in
  range(n)". (Parche de Raymond Hettinger).

* Se han realizado una serie de pequeños reajustes en varios puntos
  conflictivos para mejorar el rendimiento, como por ejemplo alinear
  una función o eliminar algo de código.  (Implementado principalmente
  por GvR, pero mucha gente ha contribuido con cambios individuales)

El resultado neto de las optimizaciones de la versión 2.3 es que
Python 2.3 ejecuta el benchmark pystone alrededor de un 25% f más
rápido que Python 2.2.


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

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

* El módulo "array" soporta ahora matrices de caracteres Unicode que
  utilizan el carácter de formato "'u".  Las matrices también soportan
  ahora el uso del operador de asignación "+=" para añadir el
  contenido de otra matriz, y el operador de asignación "*=" para
  repetir una matriz. (Contribución de Jason Orendorff)

* El módulo "bsddb" ha sido reemplazado por la versión 4.1.6 del
  paquete PyBSDDB, proporcionando una interfaz más completa para las
  características transaccionales de la biblioteca BerkeleyDB.

  La versión anterior del módulo ha cambiado de nombre a "bsddb185" y
  ya no se compila automáticamente; deberá editar "Modules/Setup" para
  habilitarlo. Tenga en cuenta que el nuevo paquete "bsddb" está
  pensado para ser compatible con el módulo anterior, así que
  asegúrese de informar de los errores si descubre alguna
  incompatibilidad. Al actualizar a Python 2.3, si el nuevo intérprete
  se compila con una nueva versión de la biblioteca BerkeleyDB
  subyacente, es casi seguro que tendrá que convertir los archivos de
  su base de datos a la nueva versión. Puede hacerlo con bastante
  facilidad con los nuevos scripts "db2pickle.py" y "pickle2db.py" que
  encontrará en el directorio "Tools/scripts" de la distribución. Si
  ya ha estado usando el paquete PyBSDDB y lo ha importado como
  "bsddb3", tendrá que cambiar sus declaraciones "import" para
  importarlo como "bsddb".

* El nuevo módulo "bz2" es una interfaz para la biblioteca de
  compresión de datos bz2. Los datos comprimidos con bz2 suelen ser
  más pequeños que los correspondientes datos comprimidos con "zlib".
  (Contribución de Gustavo Niemeyer)

* Se ha añadido un conjunto de tipos de fecha/hora estándar en el
  nuevo módulo "datetime".  Consulte la siguiente sección para obtener
  más detalles.

* La clase "Extension" de Distutils ahora admite un argumento de
  constructor adicional llamado *depends* para enumerar archivos de
  origen adicionales de los que depende una extensión. Esto permite
  que Distutils vuelva a compilar el módulo si se modifica alguno de
  los archivos de dependencia. Por ejemplo, si "sampmodule.c" incluye
  el archivo de encabezado "sample.h", crearía el objeto "Extension"
  de la siguiente manera:

     ext = Extensión("samp",
     fuentes=["sampmodule.c"],
     depende=["sample.h"])

  La modificación de "sample.h" haría que el módulo se recompilara.
  (Contribución de Jeremy Hylton)

* Otros cambios menores en Distutils: ahora verifica las variables de
  entorno "CC", "CFLAGS", "CPP", "LDFLAGS" y "CPPFLAGS", usándolas
  para anular las configuraciones en la configuración de Python
  (contribuido por Robert Weber).

* Anteriormente, el módulo "doctest" solo buscaba casos de prueba en
  las cadenas de documentación de métodos y funciones públicos, pero
  ahora también examina los casos de prueba privados. La función
  "DocTestSuite()" crea un objeto "unittest.TestSuite" a partir de un
  conjunto de pruebas "doctest".

* La nueva función "gc.get_referents(object)" retorna una lista de
  todos los objetos referenciados por *object*.

* El módulo "getopt" obtuvo una nueva función, "gnu_getopt()", que
  admite los mismos argumentos que la función "getopt()" existente,
  pero utiliza el modo de escaneo de estilo GNU. El módulo "getopt()"
  existente deja de procesar opciones tan pronto como se encuentra un
  argumento que no es una opción, pero en el modo de estilo GNU el
  procesamiento continúa, lo que significa que se pueden mezclar
  opciones y argumentos. Por ejemplo:

     >>> getopt.getopt(['-f', 'nombrearchivo', 'salida', '-v'], 'f:v')
     ([('-f', 'nombrearchivo')], ['salida', '-v'])
     >>> getopt.gnu_getopt(['-f', 'nombrearchivo', 'salida', '-v'], 'f:v')
     ([('-f', 'nombrearchivo'), ('-v', '')], ['salida'])

  (Contribución de Peter Åstrand.)

* Los módulos "grp", "pwd" y "resource" retornan ahora tuplas
  mejoradas:

     >>> importar grp
     >>> g = grp.getgrnam('amk')
     >>> g.gr_name, g.gr_gid
     ('amk', 500)

* El módulo "gzip" ahora puede manejar archivos de más de 2 GiB.

* El nuevo módulo "heapq" contiene una implementación de un algoritmo
  de cola de montón. Un montón es una estructura de datos similar a
  una matriz que mantiene los elementos en un orden parcialmente
  ordenado de modo que, para cada índice *k*, "heap[k] <= heap[2*k+1]"
  y "heap[k] <= heap[2*k+2]", se elimina rápidamente el elemento más
  pequeño y se inserta un elemento nuevo mientras se mantiene la
  propiedad de montón *O*(log *n*). (Consulte
  https://xlinux.nist.gov/dads//HTML/priorityque.html para obtener más
  información sobre la estructura de datos de la cola de prioridad).

  El módulo "heapq" proporciona las funciones "heappush()" y
  "heappop()" para agregar y eliminar elementos mientras se mantiene
  la propiedad de montón sobre algún otro tipo de secuencia mutable de
  Python. Aquí hay un ejemplo que utiliza una lista de Python:

     >>> import heapq
     >>> montón = []
     >>> para el elemento en [3, 7, 5, 11, 1]:
     ... heapq.heappush(montón, elemento)
     ...
     >>> montón
     [1, 3, 5, 11, 7]
     >>> heapq.heappop(montón)
     1
     >>> heapq.heappop(montón)
     3
     >>> montón
     [5, 7, 11]

  (Contribución de Kevin O'Connor.)

* El entorno de desarrollo integrado IDLE ha sido actualizado
  utilizando el código del proyecto IDLEfork
  (http://idlefork.sourceforge.net).  La característica más notable es
  que el código que se está desarrollando se ejecuta ahora en un
  subproceso, lo que significa que ya no es necesario realizar
  operaciones manuales de "reload()". El código central de IDLE ha
  sido incorporado a la biblioteca estándar como el paquete "idlelib".

* El módulo "imaplib" ahora admite IMAP sobre SSL. (Contribuido por
  Piers Lauder y Tino Lange.)

* "itertools" contiene varias funciones útiles para usar con
  iteradores, inspiradas en varias funciones proporcionadas por los
  lenguajes ML y Haskell. Por ejemplo, "itertools.ifilter(predicate,
  iterator)" devuelve todos los elementos del iterador para los que la
  función "predicate()" devuelve "True", y "itertools.repeat(obj, N)"
  devuelve "obj" *N* veces. Hay varias otras funciones en el módulo;
  consulte la documentación de referencia del paquete para obtener más
  detalles. (Contribuido por Raymond Hettinger).

* Dos nuevas funciones en el módulo "math", "degrees(rads)" y
  "radians(degs)", convierten entre radianes y grados. Otras funciones
  del módulo "math", como "math.sin()" y "math.cos()", siempre han
  requerido valores de entrada medidos en radianes. Además, se agregó
  un argumento opcional *base* a "math.log()" para facilitar el
  cálculo de logaritmos para bases distintas de "e" y "10".
  (Contribuido por Raymond Hettinger.)

* Se agregaron varias funciones POSIX nuevas ("getpgid()", "killpg()",
  "lchown()", "loadavg()", "major()", "makedev()", "minor()" y
  "mknod()") al módulo "posix" que sirve de base al módulo "os".
  (Contribución de Gustavo Niemeyer, Geert Jansen y Denis S.
  Otkidach).

* En el módulo "os", la familia de funciones "*stat()" ahora puede
  informar fracciones de segundo en una marca de tiempo. Dichas marcas
  de tiempo se representan como números flotantes, similares al valor
  devuelto por "time.time()".

  Durante las pruebas, se descubrió que algunas aplicaciones fallan si
  las marcas de tiempo son números de punto flotante. Por cuestiones
  de compatibilidad, al usar la interfaz de tupla de "stat_result",
  las marcas de tiempo se representarán como números enteros. Al usar
  campos con nombre (una característica introducida por primera vez en
  Python 2.2), las marcas de tiempo aún se representan como números
  enteros, a menos que se invoque "os.stat_float_times()" para
  habilitar los valores de retorno de punto flotante:

     >>> os.stat("/tmp").st_mtime
     1034791200
     >>> os.stat_float_times(Verdadero)
     >>> os.stat("/tmp").st_mtime
     1034791200.6335014

  En Python 2.4, el valor predeterminado cambiará para devolver
  siempre flotantes.

  Los desarrolladores de aplicaciones deberían habilitar esta función
  solo si todas sus bibliotecas funcionan correctamente cuando se
  enfrentan a marcas de tiempo de punto flotante o si utilizan la API
  de tuplas. Si se utiliza, la función debería activarse a nivel de
  aplicación en lugar de intentar habilitarla según el uso.

* El módulo "optparse" contiene un nuevo analizador para argumentos de
  línea de comandos que puede convertir valores de opción a un tipo de
  Python en particular y generará automáticamente un mensaje de uso.
  Consulte la siguiente sección para obtener más detalles.

* El antiguo módulo "linuxaudiodev", que nunca se documentó, ha
  quedado obsoleto y se ha añadido una nueva versión denominada
  "ossaudiodev". El módulo ha cambiado de nombre porque los
  controladores de sonido OSS se pueden utilizar en plataformas
  distintas a Linux y la interfaz también se ha ordenado y actualizado
  de varias maneras. (Contribución de Greg Ward y Nicholas FitzRoy-
  Dale).

* El nuevo módulo "platform" contiene una serie de funciones que
  intentan determinar varias propiedades de la plataforma en la que se
  está ejecutando. Hay funciones para obtener la arquitectura, el tipo
  de CPU, la versión del sistema operativo Windows e incluso la
  versión de distribución de Linux. (Contribución de Marc-André
  Lemburg.)

* Los objetos del analizador proporcionados por el módulo "pyexpat"
  ahora pueden almacenar en búfer datos de caracteres de manera
  opcional, lo que genera menos llamadas al controlador de datos de
  caracteres y, por lo tanto, un rendimiento más rápido. Si se
  configura el atributo "buffer_text" del objeto del analizador en
  "True", se habilitará el almacenamiento en búfer.

* Se agregó la función "sample(population, k)" al módulo "random".
  *population* es una secuencia o un objeto "xrange" que contiene los
  elementos de una población y "sample()" elige elementos *k* de la
  población sin reemplazar los elementos elegidos. *k* puede ser
  cualquier valor hasta "len(population)". Por ejemplo:

     >>> days = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'St', 'Sn']
     >>> random.sample(days, 3) # Elige 3 elementos
     ['St', 'Sn', 'Th']
     >>> random.sample(days, 7) # Elige 7 elementos
     ['Tu', 'Th', 'Mo', 'We', 'St', 'Fr', 'Sn']
     >>> random.sample(days, 7) # Elige 7 nuevamente
     ['We', 'Mo', 'Sn', 'Fr', 'Tu', 'St', 'Th']
     >>> random.sample(days, 8) # No se pueden elegir ocho
     Traceback (última llamada más reciente):
     Archivo "<stdin>", línea 1, en ?
     Archivo "random.py", línea 414, en ejemplo
     genera ValueError, "muestra mayor que la población"
     ValueError: muestra mayor que la población
     >>> random.sample(xrange(1,10000,2), 10) # Elige diez números impares menores a 10000
     [3407, 3805, 1505, 7023, 2401, 2267, 9733, 3151, 8083, 9195]

  El módulo "random" ahora usa un nuevo algoritmo, el Mersenne
  Twister, implementado en C. Es más rápido y más estudiado que el
  algoritmo anterior.

  (Parches aportados por Raymond Hettinger)

* El módulo "readline" también obtuvo una serie de nuevas funciones:
  "get_history_item()", "get_current_history_length()" y
  "redisplay()".

* Los módulos "rexec" y "Bastion" se han declarado inactivos y los
  intentos de importarlos fallarán con un "RuntimeError". Las clases
  de nuevo estilo proporcionan nuevas formas de salir del entorno de
  ejecución restringido que ofrece "rexec" y nadie tiene interés en
  arreglarlas ni tiempo para hacerlo. Si tiene aplicaciones que
  utilizan "rexec", reescríbalas para utilizar algo diferente.

  (Seguir usando Python 2.2 o 2.1 no hará que sus aplicaciones sean
  más seguras porque hay errores conocidos en el módulo "rexec" en
  esas versiones. Para repetir: si está usando "rexec", deje de usarlo
  inmediatamente).

* El módulo "rotor" ha quedado obsoleto porque se cree que el
  algoritmo que utiliza para el cifrado no es seguro. Si necesita
  cifrado, utilice uno de los diversos módulos AES de Python que están
  disponibles por separado.

* El módulo "shutil" obtuvo una función "move(src, dest)" que mueve
  recursivamente un archivo o directorio a una nueva ubicación.

* Se agregó soporte para un manejo de señal POSIX más avanzado al
  "signal", pero luego se eliminó nuevamente, ya que resultó imposible
  hacerlo funcionar de manera confiable en todas las plataformas.

* El módulo "socket" ahora admite tiempos de espera. Puede llamar al
  método "settimeout(t)" en un objeto de socket para establecer un
  tiempo de espera de *t* seconds. Subsequent socket operations that
  take longer than *t* segundos para completar, abortará y lanzará una
  excepción "socket.timeout".

  La implementación del tiempo de espera original fue realizada por
  Tim O'Malley. Michael Gilfix lo integró en el módulo Python "socket"
  y lo guió a través de una extensa revisión. Después de que se
  registró el código, Guido van Rossum reescribió partes del mismo.
  (Este es un buen ejemplo de un proceso de desarrollo colaborativo en
  acción).

* En Windows, el módulo "socket" ahora se envía con compatibilidad con
  Secure Sockets Layer (SSL).

* El valor de la macro C "PYTHON_API_VERSION" ahora se expone en el
  nivel de Python como "sys.api_version". La excepción actual se puede
  eliminar llamando a la nueva función "sys.exc_clear()".

* El nuevo módulo "tarfile" permite leer y escribir en: programa:
  *tar* -format archivos de almacenamiento. (Contribución de Lars
  Gustäbel.)

* El nuevo módulo "textwrap" contiene funciones para encapsular
  cadenas que contienen párrafos de texto. La función "wrap(text,
  width)" toma una cadena y devuelve una lista que contiene el texto
  dividido en líneas de un ancho no mayor que el elegido. La función
  "fill(text, width)" devuelve una sola cadena, reformateada para que
  quepa en líneas de un ancho no mayor que el elegido. (Como puede
  adivinar, "fill()" está construido sobre "wrap()". Por ejemplo:

     >>> import textwrap
     >>> párrafo = "Ni un ápice, desafiamos el augurio: ... más texto ..."
     >>> textwrap.wrap(párrafo, 60)
     ["Ni un ápice, desafiamos el augurio: hay una providencia especial en",
     "la caída de un gorrión. Si es ahora, no está por venir; si",
     ...]
     >>> print textwrap.fill(párrafo, 35)
     Ni un ápice, desafiamos el augurio: hay
     una providencia especial en la caída de
     un gorrión. Si es ahora, no está por venir; si no está por venir,
     será ahora; si no es ahora, aún
     vendrá: la preparación lo es todo.
     >>>

  El módulo también contiene una clase "TextWrapper" que implementa la
  estrategia de ajuste de texto. Tanto la clase "TextWrapper" como las
  funciones "wrap()" y "fill()" admiten una serie de argumentos de
  palabras clave adicionales para ajustar el formato; consulte la
  documentación del módulo para obtener más detalles. (Contribuido por
  Greg Ward).

* Los módulos "thread" y "threading" ahora tienen módulos
  complementarios, "dummy_thread" y "dummy_threading", que
  proporcionan una implementación sin hacer nada de la interfaz del
  módulo "thread" para plataformas donde no se admiten subprocesos. La
  intención es simplificar los módulos que admiten subprocesos
  (aquellos que dependen de subprocesos para ejecutarse) colocando el
  siguiente código en la parte superior:

     Intente:
     importar subprocesos como _threading
     excepto ImportError:
     importar dummy_threading como _threading

  En este ejemplo, se utiliza "_threading" como nombre del módulo para
  dejar claro que el módulo que se utiliza no es necesariamente el
  módulo "threading" real. El código puede llamar a funciones y usar
  clases en "_threading" independientemente de si se admiten
  subprocesos o no, lo que evita una declaración "if" y hace que el
  código sea un poco más claro. Este módulo no hará que el código
  multiproceso se ejecute mágicamente sin subprocesos; el código que
  espera a que otro subproceso regrese o haga algo simplemente se
  bloqueará para siempre.

* La función "strptime()" del módulo "time" ha sido una molestia
  durante mucho tiempo porque utiliza la implementación "strptime()"
  de la biblioteca de la plataforma C, y a veces las diferentes
  plataformas tienen errores extraños. Brett Cannon contribuyó con una
  implementación portátil que está escrita en Python puro y debería
  comportarse de manera idéntica en todas las plataformas.

* El nuevo módulo "timeit" ayuda a medir cuánto tardan en ejecutarse
  fragmentos de código Python. El archivo "timeit.py" se puede
  ejecutar directamente desde la línea de comandos, o se puede
  importar y utilizar directamente la clase "Timer" del módulo. A
  continuación, se incluye un breve ejemplo que determina si es más
  rápido convertir una cadena de 8 bits a Unicode añadiéndole una
  cadena Unicode vacía o utilizando la función "unicode()":

     import timeit

     timer1 = timeit.Timer('unicode("abc")')
     timer2 = timeit.Timer('"abc" + u""')

     # Ejecutar tres pruebas
     print timer1.repeat(repeat=3, number=100000)
     print timer2.repeat(repeat=3, number=100000)

     # En mi computadora portátil, esto genera:
     # [0.36831796169281006, 0.37441694736480713, 0.35304892063140869]
     # [0.17574405670166016, 0.18193507194519043, 0.17565798759460449]

* El módulo "Tix" ha recibido varias correcciones de errores y
  actualizaciones para la versión actual del paquete Tix.

* El módulo "Tkinter" ahora funciona con una versión de Tcl habilitada
  para subprocesos. El modelo de subprocesos de Tcl requiere que solo
  se acceda a los widgets desde el subproceso en el que se crearon;
  los accesos desde otro subproceso pueden hacer que Tcl entre en
  pánico. Para ciertas interfaces de Tcl, "Tkinter" ahora evitará esto
  automáticamente cuando se acceda a un widget desde un subproceso
  diferente mediante la ordenación de un comando, pasándolo al
  subproceso correcto y esperando los resultados. Otras interfaces no
  se pueden manejar automáticamente, pero "Tkinter" ahora generará una
  excepción en dicho acceso para que al menos pueda averiguar sobre el
  problema. Consulte https://mail.python.org/pipermail/python-
  dev/2002-December/031107.html para obtener una explicación más
  detallada de este cambio. (Implementado por Martin von Löwis).

* La llamada a métodos Tcl a través de "_tkinter" ya no devuelve solo
  cadenas. En cambio, si Tcl devuelve otros objetos, esos objetos se
  convierten en su equivalente de Python, si existe uno, o se
  encapsulan con un objeto "_tkinter.Tcl_Obj" si no existe un
  equivalente de Python. Este comportamiento se puede controlar a
  través del método "wantobjects()" de los objetos "tkapp".

  Al utilizar "_tkinter" a través del módulo "Tkinter" (como lo hacen
  la mayoría de las aplicaciones de Tkinter), esta función siempre
  está activada. No debería causar problemas de compatibilidad, ya que
  Tkinter siempre convertiría los resultados de cadenas a tipos de
  Python cuando fuera posible.

  Si se encuentran incompatibilidades, se puede restaurar el
  comportamiento anterior configurando la variable "wantobjects" en el
  módulo "Tkinter" como falsa antes de crear el primer objeto "tkapp".

     importar Tkinter
     Tkinter.wantobjects = 0

  Cualquier rotura causada por este cambio debe notificarse como un
  error.

* El módulo "UserDict" tiene una nueva clase "DictMixin" que define
  todos los métodos de diccionario para las clases que ya tienen una
  interfaz de mapeo mínima. Esto simplifica enormemente la escritura
  de clases que deben ser sustituibles por diccionarios, como las
  clases del módulo "shelve".

  Al agregar la combinación como superclase, se obtiene la interfaz de
  diccionario completa siempre que la clase defina "__getitem__()",
  "__setitem__()", "__delitem__()" y "keys()". Por ejemplo:

     >>> import UserDict
     >>> class SeqDict(UserDict.DictMixin):
     ... """Similar a un diccionario implementado con listas."""
     ... def __init__(self):
     ... self.keylist = []
     ... self.valuelist = []
     ... def __getitem__(self, key):
     ... try:
     ... i = self.keylist.index(key)
     ... except ValueError:
     ... raise KeyError
     ... return self.valuelist[i]
     ... def __setitem__(self, key, value):
     ... try:
     ... i = self.keylist.index(key)
     ... self.valuelist[i] = value
     ... except ValueError:
     ... self.keylist.append(key)
     ... self.valuelist.append(value)
     ... def __delitem__(self, key):
     ... try:
     ... i = self.keylist.index(key)
     ... except ValueError:
     ... raise KeyError
     ... self.keylist.pop(i)
     ... self.valuelist.pop(i)
     ... def keys(self):
     ... return list(self.keylist)
     ...
     >>> s = SeqDict()
     >>> dir(s) # Verificar que se implementen otros métodos de diccionario
     ['__cmp__', '__contains__', '__delitem__', '__doc__', '__getitem__',
     '__init__', '__iter__', '__len__', '__module__', '__repr__',
     '__setitem__', 'clear', 'get', 'has_key', 'items', 'iteritems',
     'iterkeys', 'itervalues', 'keylist', 'keys', 'pop', 'popitem',
     'setdefault', 'update', 'valuelist', 'valores']

  (Parches aportados por Raymond Hettinger)

* La implementación de DOM en "xml.dom.minidom" ahora puede generar
  salida XML en una codificación particular al proporcionar un
  argumento de codificación opcional a los métodos "toxml()" y
  "toprettyxml()" de los nodos DOM.

* El módulo "xmlrpclib" ahora admite una extensión XML-RPC para
  manejar valores de datos nulos, como "None" de Python. Los valores
  nulos siempre se admiten al desagrupar una respuesta XML-RPC. Para
  generar solicitudes que contengan "None", debe proporcionar un valor
  verdadero para el parámetro *allow_none* al crear una instancia
  "Marshaller".

* El nuevo módulo "DocXMLRPCServer" permite escribir servidores XML-
  RPC autodocumentados. Ejecútelo en modo de demostración (como
  programa) para verlo en acción. Al apuntar el navegador web al
  servidor RPC se genera documentación de estilo pydoc; al apuntar
  xmlrpclib al servidor se pueden invocar los métodos reales.
  (Contribuido por Brian Quinlan.)

* Se ha agregado soporte para nombres de dominio internacionalizados
  (RFCs 3454, 3490, 3491 y 3492). La codificación "idna" se puede
  utilizar para convertir entre un nombre de dominio Unicode y la
  codificación compatible con ASCII (ACE) de ese nombre.

     >{}>{}> u"www.Alliancefrançaise.nu".encode("idna")
     'www.xn--alliancefranaise-npb.nu'

  El módulo "socket" también se ha ampliado para convertir de forma
  transparente los nombres de host Unicode a la versión ACE antes de
  pasarlos a la biblioteca C. Los módulos que se ocupan de los nombres
  de host, como "httplib" y "ftplib", también admiten nombres de host
  Unicode; "httplib" también envía encabezados HTTP "Host" utilizando
  la versión ACE del nombre de dominio. "urllib" admite URL Unicode
  con nombres de host que no sean ASCII siempre que la parte "path" de
  la URL sea solo ASCII.

  Para implementar este cambio, se han agregado el módulo
  "stringprep", la herramienta "mkstringprep" y la codificación
  "punycode".


Tipo de fecha / hora
--------------------

Se agregaron tipos de fecha y hora adecuados para expresar marcas de
tiempo como módulo "datetime". Los tipos no admiten diferentes
calendarios ni muchas funciones sofisticadas, y solo se ciñen a los
conceptos básicos de la representación del tiempo.

Los tres tipos principales son: "date", que representa un día, un mes
y un año; "time", que consta de horas, minutos y segundos; y
"datetime", que contiene todos los atributos de "date" y "time".
También existe una clase "timedelta" que representa las diferencias
entre dos puntos en el tiempo, y la lógica de la zona horaria se
implementa mediante clases que heredan de la clase abstracta "tzinfo".

Puede crear instancias de "date" y "time" proporcionando argumentos de
palabras clave al constructor adecuado, por ejemplo,
"datetime.date(year=1972, month=10, day=15)", o utilizando uno de los
diversos métodos de clase. Por ejemplo, el método de clase "today()"
devuelve la fecha local actual.

Una vez creadas, las instancias de las clases de fecha / hora son
inmutables. Hay varios métodos para producir cadenas formateadas a
partir de objetos:

   >>> import datetime as dt
   >>> now = dt.datetime.now()
   >>> now.isoformat()
   '2002-12-30T21:27:03.994956'
   >>> now.ctime()  # Only available on date, datetime
   'Mon Dec 30 21:27:03 2002'
   >>> now.strftime('%Y %d %b')
   '2002 30 Dec'

El método "replace()" permite modificar uno o más campos de una
instancia "date" o "datetime", devolviendo una nueva instancia:

   >>> d = dt.datetime.now()
   >>> d
   datetime.datetime(2002, 12, 30, 22, 15, 38, 827738)
   >>> d.replace(year=2001, hour=12)
   datetime.datetime(2001, 12, 30, 12, 15, 38, 827738)
   >>>

Las instancias se pueden comparar, codificar y convertir en cadenas
(el resultado es el mismo que el de "isoformat()"). Las instancias
"date" y "datetime" se pueden restar entre sí y agregar a las
instancias "timedelta". La característica que falta más es que no hay
compatibilidad con la biblioteca estándar para analizar cadenas y
obtener un "date" o "datetime".

Para obtener más información, consulte la documentación de referencia
del módulo. (Contribuido por Tim Peters.)


El módulo optparse
------------------

El módulo "getopt" proporciona un análisis sencillo de los argumentos
de la línea de comandos. El nuevo módulo "optparse" (originalmente
llamado Optik) proporciona un análisis de línea de comandos más
elaborado que sigue las convenciones de Unix, crea automáticamente la
salida para "--help" y puede realizar diferentes acciones para
diferentes opciones.

Comienza creando una instancia de "OptionParser" y diciéndole cuáles
son las opciones de tu programa.

   import sys
   from optparse import OptionParser

   op = OptionParser()
   op.add_option('-i', '--input',
   action='store', type='string', dest='input',
   help='establecer nombre de archivo de entrada')
   op.add_option('-l', '--length',
   action='store', type='int', dest='length',
   help='establecer longitud máxima de salida')

Luego, el análisis de una línea de comando se realiza llamando al
método "parse_args()".

   opciones, args = op.parse_args(sys.argv[1:])
   imprimir opciones
   imprimir argumentos

Esto devuelve un objeto que contiene todos los valores de las opciones
y una lista de cadenas que contienen los argumentos restantes.

Invocar el script con los distintos argumentos ahora funciona como era
de esperar. Tenga en cuenta que el argumento de longitud se convierte
automáticamente en un número entero.

   $ ./python opt.py -i data arg1
   <Valores en 0x400cad4c: {'entrada': 'datos', 'longitud': Ninguno}>
   ['arg1']
   $ ./python opt.py --input=data --length=4
   <Valores en 0x400cad2c: {'entrada': 'datos', 'longitud': 4}>
   []
   $

El mensaje de ayuda se genera automáticamente para usted:

   $ ./python opt.py --help
   uso: opt.py [opciones]

   opciones:
   -h, --help muestra este mensaje de ayuda y sale
   -iINPUT, --input=INPUT
   establece el nombre del archivo de entrada
   -lLENGTH, --length=LENGTH
   establece la longitud máxima de salida
   $

Consulte la documentación del módulo para obtener más detalles.

Optik fue escrito por Greg Ward, con sugerencias de los lectores de
Getopt SIG.


Pymalloc: un asignador de objetos especializado
===============================================

Pymalloc, un asignador de objetos especializado escrito por Vladimir
Marangozov, fue una característica agregada a Python 2.1. Pymalloc
está diseñado para ser más rápido que el sistema "malloc()" y tener
menos sobrecarga de memoria para los patrones de asignación típicos de
los programas Python. El asignador utiliza la función "malloc()" de C
para obtener grandes grupos de memoria y luego satisface las
solicitudes de memoria más pequeñas de estos grupos.

En 2.1 y 2.2, pymalloc era una función experimental y no estaba
habilitada de forma predeterminada; tenía que habilitarlo
explícitamente al compilar Python proporcionando la opción "--with-
pymalloc" al script: program: *configure*. En 2.3, pymalloc ha tenido
más mejoras y ahora está habilitado de forma predeterminada; tendrá
que suministrar "--without-pymalloc" para deshabilitarlo.

Este cambio es transparente para el código escrito en Python; sin
embargo, pymalloc puede exponer errores en las extensiones C. Los
autores de los módulos de extensión C deben probar su código con
pymalloc habilitado, ya que algunos códigos incorrectos pueden causar
volcados de núcleo en tiempo de ejecución.

Hay un error particularmente común que causa problemas. Hay una serie
de funciones de asignación de memoria en la API C de Python que
anteriormente solo eran alias para "malloc()" y "free()" de la
biblioteca C, lo que significa que si llama accidentalmente a
funciones que no coinciden, el error no se notará. Cuando el asignador
de objetos está habilitado, estas funciones ya no son alias de
"malloc()" y "free()", y llamar a la función incorrecta para liberar
memoria puede generar un volcado de memoria. Por ejemplo, si la
memoria se asignó utilizando "PyObject_Malloc()", debe liberarse
utilizando "PyObject_Free()", no "free()". Algunos módulos incluidos
con Python entraron en conflicto con esto y tuvieron que ser
reparados; sin duda hay más módulos de terceros que tendrán el mismo
problema.

Como parte de este cambio, las confusas interfaces múltiples para
asignar memoria se han consolidado en dos familias de API. La memoria
asignada a una familia no debe manipularse con funciones de la otra
familia. Hay una familia para asignar fragmentos de memoria y otra
familia de funciones específicamente para asignar objetos Python.

* Para asignar y liberar una porción de memoria no distinguida, use la
  familia de "memoria sin procesar": "PyMem_Malloc()",
  "PyMem_Realloc()" y "PyMem_Free()".

* La familia de "memoria de objetos" es la interfaz para la
  instalación de pymalloc descrita anteriormente y está sesgada hacia
  un gran número de asignaciones "pequeñas": "PyObject_Malloc()",
  "PyObject_Realloc()" y "PyObject_Free()".

* Para asignar y liberar objetos de Python, utilice la familia de
  "objetos" "PyObject_New", "PyObject_NewVar" y "PyObject_Del()".

Gracias al gran trabajo de Tim Peters, pymalloc en 2.3 también
proporciona funciones de depuración para detectar sobrescrituras de
memoria y liberaciones duplicadas en ambos módulos de extensión y en
el propio intérprete. Para habilitar este soporte, compile una versión
de depuración del intérprete de Python ejecutando: programa:
*configure* con "--with-pydebug".

Para ayudar a los escritores de extensiones, se distribuye un archivo
de encabezado "Misc/pymemcompat.h" con la fuente a Python 2.3 que
permite que las extensiones de Python usen las interfaces 2.3 para la
asignación de memoria mientras se compila con cualquier versión de
Python desde la 1.5.2. Debería copiar el archivo de la distribución
fuente de Python y empaquetarlo con la fuente de su extensión.

Ver también:

  https://hg.python.org/cpython/file/default/Objects/obmalloc.c
     Para obtener todos los detalles de la implementación de pymalloc,
     consulte los comentarios en la parte superior del archivo
     "Objects/obmalloc.c" en el código fuente de Python. El enlace
     anterior apunta al archivo dentro del navegador SVN de
     python.org.


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

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

* La implementación de detección de ciclos utilizada por la
  recolección de basura ha demostrado ser estable, por lo que ahora se
  ha hecho obligatoria. Ya no puede compilar Python sin él, y el
  cambio "--with-cycle-gc" a: program: *configure* ha sido eliminado.

* Python ahora se puede construir opcionalmente como una biblioteca
  compartida ("libpython2.3.so") proporcionando "--enable-shared"
  cuando se ejecuta el script Python: program: *configure*.
  (Contribuido por Ondrej Palkovsky.)

* Las macros "DL_EXPORT" y "DL_IMPORT" ahora están en desuso. Las
  funciones de inicialización para los módulos de extensión de Python
  ahora deben declararse usando la nueva macro "PyMODINIT_FUNC",
  mientras que el núcleo de Python generalmente usará las macros
  "PyAPI_FUNC" y "PyAPI_DATA".

* El intérprete se puede compilar sin ninguna cadena de documentación
  para las funciones y módulos incorporados proporcionando "--without-
  doc-strings" al script: program: *configure*. Esto hace que el
  ejecutable de Python sea un 10% más pequeño, pero también significa
  que no puede obtener ayuda para las funciones integradas de Python.
  (Contribución de Gustavo Niemeyer.)

* La macro "PyArg_NoArgs()" ahora está en desuso y el código que la
  usa debe cambiarse. Para Python 2.2 y versiones posteriores, la
  tabla de definición de métodos puede especificar la marca
  "METH_NOARGS", lo que indica que no hay argumentos, y luego se puede
  eliminar la verificación de argumentos. Si la compatibilidad con las
  versiones anteriores a la 2.2 de Python es importante, el código
  podría usar "PyArg_ParseTuple(args, "")" en su lugar, pero esto será
  más lento que usar "METH_NOARGS".

* "PyArg_ParseTuple()" acepta caracteres de nuevo formato para varios
  tamaños de enteros sin signo: "B" para unsigned char, "H" para
  unsigned short int, "I" para unsigned int, y "K" para unsigned long
  long.

* Se agregó una nueva función, "PyObject_DelItemString(mapping, char
  *key)", como abreviatura de "PyObject_DelItem(mapping,
  PyString_New(key))".

* Los objetos de archivo ahora administran su búfer de cadena interno
  de manera diferente, incrementándolo exponencialmente cuando es
  necesario. Esto da como resultado que las pruebas de referencia en
  "Lib/test/test_bufio.py" se aceleren considerablemente (de 57
  segundos a 1,7 segundos, según una medición).

* Ahora es posible definir métodos estáticos y de clase para un tipo
  de extensión C configurando los indicadores "METH_CLASS" o
  "METH_STATIC" en la estructura "PyMethodDef" de un método.

* Python ahora incluye una copia del código fuente del analizador XML
  de Expat, eliminando cualquier dependencia de una versión del
  sistema o instalación local de Expat.

* Si asigna objetos de tipo de forma dinámica en su extensión, debe
  tener en cuenta un cambio en las reglas relacionadas con los
  atributos "__module__" y "__name__". En resumen, deberá asegurarse
  de que el diccionario del tipo contenga una clave "'__module__'";
  hacer que el nombre del módulo sea la parte del nombre del tipo que
  precede al punto final ya no tendrá el efecto deseado. Para obtener
  más detalles, lea la documentación de referencia de la API o el
  código fuente.


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

El soporte para un puerto para el sistema operativo IBM OS/2 que
utiliza el entorno de ejecución EMX se fusionó con el árbol de código
fuente principal de Python. EMX es una capa de emulación POSIX sobre
las API del sistema OS/2. El puerto de Python para EMX intenta
soportar toda la capacidad similar a POSIX expuesta por el entorno de
ejecución EMX y, en su mayoría, lo logra; "fork()" y "fcntl()" están
restringidos por las limitaciones de la capa de emulación subyacente.
El puerto estándar para OS/2, que utiliza el compilador Visual Age de
IBM, también obtuvo soporte para semánticas de importación que
distinguen entre mayúsculas y minúsculas como parte de la integración
del puerto EMX en CVS. (Contribuido por Andrew MacIntyre.)

En MacOS, la mayoría de los módulos de la caja de herramientas tienen
vínculos débiles para mejorar la compatibilidad con versiones
anteriores. Esto significa que los módulos ya no dejarán de cargarse
si falta una rutina en la versión actual del sistema operativo. En su
lugar, llamar a la rutina que falta lanzará una excepción.
(Contribuido por Jack Jansen.)

Los archivos de especificaciones de RPM, que se encuentran en el
directorio "Misc/RPM/" en la distribución fuente de Python, se
actualizaron para la versión 2.3. (Contribución de Sean
Reifschneider.)

Otras plataformas nuevas ahora compatibles con Python incluyen AtheOS
(http://www.atheos.cx/), GNU / Hurd y OpenVMS.


Otros cambios y correcciones
============================

Como de costumbre, hubo un montón de otras mejoras y correcciones de
errores esparcidas por todo el árbol de fuentes. Una búsqueda en los
registros de cambios de CVS encuentra que se aplicaron 523 parches y
se corrigieron 514 errores entre Python 2.2 y 2.3. Es probable que
ambas cifras estén subestimadas.

Algunos de los cambios más notables son:

* Si se establece la variable de entorno "PYTHONINSPECT", el
  intérprete de Python ingresará al indicador interactivo después de
  ejecutar un programa de Python, como si Python hubiera sido invocado
  con la opción "-i". La variable de entorno se puede configurar antes
  de ejecutar el intérprete de Python, o el programa Python puede
  configurarla como parte de su ejecución.

* El script "regrtest.py" ahora proporciona una forma de permitir
  "todos los recursos excepto *foo*". Un nombre de recurso pasado a la
  opción "-u" ahora se puede prefijar con un guión ("'-'") para
  significar "eliminar este recurso". Por ejemplo, la opción
  '"-uall,-bsddb"' podría usarse para habilitar el uso de todos los
  recursos excepto "bsddb".

* Las herramientas utilizadas para crear la documentación ahora
  funcionan tanto en Cygwin como en Unix.

* Se ha eliminado el código de operación "SET_LINENO". En la noche de
  los tiempos, este código de operación era necesario para producir
  números de línea en rastreos y admitir funciones de rastreo (para,
  por ejemplo, "pdb"). Desde Python 1.5, los números de línea en los
  rastreos se han calculado utilizando un mecanismo diferente que
  funciona con "python -O". Para Python 2.3, Michael Hudson implementó
  un esquema similar para determinar cuándo llamar a la función de
  seguimiento, eliminando por completo la necesidad de "SET_LINENO".

  Sería difícil detectar cualquier diferencia resultante del código
  Python, aparte de una ligera aceleración cuando Python se ejecuta
  sin "-O".

  Las extensiones de C que acceden al campo "f_lineno" de los objetos
  de marco deberían llamar a "PyCode_Addr2Line(f->f_code,
  f->f_lasti)". Esto tendrá el efecto adicional de hacer que el código
  funcione como se desea con "python -O" en versiones anteriores de
  Python.

  Una característica nueva y elegante es que las funciones de
  seguimiento ahora pueden asignarse al atributo "f_lineno" de los
  objetos de marco, lo que cambia la línea que se ejecutará a
  continuación. Se ha agregado un comando "jump" al depurador "pdb"
  que aprovecha esta nueva característica. (Implementado por Richie
  Hindle).


Portar a Python 2.3
===================

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

* "yield" ahora es siempre una palabra clave; si se usa como nombre de
  variable en su código, se debe elegir un nombre diferente.

* Para cadenas, *X* and *Y*, ASDF00 now works if *X* tiene más de un
  carácter.

* El constructor de tipo "int()" ahora retornará un entero largo en
  lugar de lanzar un "OverflowError" cuando una cadena o un número de
  punto flotante es demasiado grande para caber en un entero.  Esto
  puede llevar al resultado paradójico de que
  "isinstance(int(expresión), int)" sea falso, pero parece poco
  probable que cause problemas en la práctica.

* Si tiene cadenas Unicode que contienen caracteres de 8 bits, debe
  declarar la codificación del archivo (UTF-8, Latin-1 o lo que sea)
  agregando un comentario en la parte superior del archivo. Consulte
  la sección PEP 263: Codificación del código fuente para obtener más
  información.

* La llamada a métodos Tcl a través de "_tkinter" ya no devuelve solo
  cadenas. En cambio, si Tcl devuelve otros objetos, esos objetos se
  convierten en su equivalente de Python, si existe uno, o se
  encapsulan con un objeto "_tkinter.Tcl_Obj" si no existe un
  equivalente de Python.

* Grandes literales octales y hexadecimales como "0xffffffff" ahora
  activan un "FutureWarning". Actualmente se almacenan como números de
  32 bits y dan como resultado un valor negativo, pero en Python 2.4
  se convertirán en enteros largos positivos.

  Hay varias formas de corregir esta advertencia. Si realmente
  necesita un número positivo, simplemente agregue un "L" al final del
  literal. Si está tratando de obtener un entero de 32 bits con bits
  bajos establecidos y ha usado previamente una expresión como "~(1 <<
  31)", probablemente sea más claro comenzar con todos los bits
  establecidos y borrar los bits superiores deseados. Por ejemplo,
  para borrar solo el bit superior (bit 31), puede escribir
  "0xffffffffL &~(1L<<31)".

* Ya no puede deshabilitar las aserciones asignando a "__debug__".

* La función "setup()" de Distutils ha obtenido varios argumentos de
  palabras clave nuevos, como *depends*. Las versiones anteriores de
  Distutils se interrumpirán si se les pasan palabras clave
  desconocidas. Una solución es comprobar la presencia de la nueva
  función "get_distutil_options()" en su "setup.py" y utilizar las
  nuevas palabras clave solo con una versión de Distutils que las
  admita:

     from distutils import core

     kw = {'sources': 'foo.c', ...}
     if hasattr(core, 'get_distutil_options'):
         kw['depends'] = ['foo.h']
     ext = Extension(**kw)

* El uso de "None" como nombre de una variable ahora resultará en una
  advertencia "SyntaxWarning".  En una futura versión de Python,
  "None" podría convertirse en una palabra clave.

* Los nombres de los tipos de extensión definidos por los módulos
  incluidos con Python ahora contienen el módulo y un "'.'" delante
  del nombre del tipo.


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

El autor desea agradecer a las siguientes personas por ofrecer
sugerencias, correcciones y ayuda con varios borradores de este
artículo: Jeff Bauer, Simon Brunning, Brett Cannon, Michael Chermside,
Andrew Dalke, Scott David Daniels, Fred L. Drake, Jr., David Fraser,
Kelly Gerber, Raymond Hettinger, Michael Hudson, Chris Lambert, Detlef
Lannert, Martin von Löwis, Andrew MacIntyre, Lalo Martins, Chad
Netzer, Gustavo Niemeyer, Neal Norwitz, Hans Nowak, Chris Reedy,
Francesco Ricciardi, Vinay Sajip, Neil Schemenauer, Roman Suzi, Jason
Tishler, Just van Rossum.
