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 conjuntos.  La clase "Set" es para conjuntos mutables, conjuntos a
los que se les pueden añadir y eliminar miembros.  La clase
"ImmutableSet" es para los conjuntos que no pueden ser modificados, y
las instancias de "ImmutableSet" pueden por lo tanto ser utilizadas
como claves de diccionario. Los conjuntos se construyen sobre
diccionarios, por lo que los elementos de un conjunto deben ser
hashables.

Aquí hay un ejemplo simple:

   >>> import sets
   >>> S = sets.Set([1,2,3])
   >>> S
   Set([1, 2, 3])
   >>> 1 in S
   True
   >>> 0 in S
   False
   >>> S.add(5)
   >>> S.remove(3)
   >>> S
   Set([1, 2, 5])
   >>>

La unión y la intersección de los conjuntos pueden calcularse con los
métodos "union()" y "intersection()"; una notación alternativa utiliza
los operadores bitácora "&" y "|". Los conjuntos mutables también
tienen versiones in situ de estos métodos, "union_update()" y
"intersection_update()".

   >>> S1 = sets.Set([1,2,3])
   >>> S2 = sets.Set([4,5,6])
   >>> S1.union(S2)
   Set([1, 2, 3, 4, 5, 6])
   >>> S1 | S2                  # Alternative notation
   Set([1, 2, 3, 4, 5, 6])
   >>> S1.intersection(S2)
   Set([])
   >>> S1 & S2                  # Alternative notation
   Set([])
   >>> S1.union_update(S2)
   >>> S1
   Set([1, 2, 3, 4, 5, 6])
   >>>

También es posible tomar la diferencia simétrica de dos conjuntos.
Este es el conjunto de todos los elementos de la unión que no están en
la intersección.  Otra forma de decirlo es que la diferencia simétrica
contiene todos los elementos que están exactamente en un conjunto.  De
nuevo, existe una notación alternativa ("^"), y una versión in-place
con el poco agraciado nombre "symmetric_difference_update()".

   >>> S1 = sets.Set([1,2,3,4])
   >>> S2 = sets.Set([3,4,5,6])
   >>> S1.symmetric_difference(S2)
   Set([1, 2, 5, 6])
   >>> S1 ^ S2
   Set([1, 2, 5, 6])
   >>>

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

   >>> S1 = sets.Set([1,2,3])
   >>> S2 = sets.Set([2,3])
   >>> S2.issubset(S1)
   True
   >>> S1.issubset(S2)
   False
   >>> S1.issuperset(S2)
   True
   >>>

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):
       for i in range(N):
           yield 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
   <generator object at 0x8117f90>
   >>> gen.next()
   0
   >>> gen.next()
   1
   >>> gen.next()
   2
   >>> gen.next()
   Traceback (most recent call last):
     File "stdin", line 1, in ?
     File "stdin", line 2, in 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

   # A recursive generator that generates Tree leaves in in-order.
   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://www.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://www.cs.arizona.edu/icon/docs/ipd266.htm da una idea de cómo es
esto:

   sentence := "Store it in the neighboring harbor"
   if (i := find("or", sentence)) > 5 then write(i)

En Icon la función "find()" retorna los índices en los que se
encuentra la subcadena "o": 3, 23, 33.  En la expresión "if", a "i" se
le asigna primero un valor de 3, pero 3 es menor que 5, por lo que la
comparación falla, e Icon la reintenta 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
   Archive:  /tmp/example.zip
     Length     Date   Time    Name
    --------    ----   ----    ----
        8467  11-26-02 22:30   jwzthreading.py
    --------                   -------
        8467                   1 file
   amk@nyman:~/src/python$ ./python
   Python 2.3 (#1, Aug 1 2003, 19:54:32)
   >>> import sys
   >>> sys.path.insert(0, '/tmp/example.zip')  # Add .zip file to front of path
   >>> import jwzthreading
   >>> jwzthreading.__file__
   '/tmp/example.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 permite ahora utilizar cadenas Unicode arbitrarias (dentro de
las limitaciones del sistema de archivos) para todas las funciones que
esperan nombres de archivos, sobre todo la función incorporada
"open()". Si se pasa una cadena Unicode a "os.listdir()", Python
retorna ahora una lista de cadenas Unicode.  Una nueva función,
"os.getcwdu()", retorna 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".

Otros sistemas también permiten cadenas Unicode como nombres de
archivo, pero las convierten en cadenas de bytes antes de pasarlas al
sistema, lo que puede provocar un "UnicodeError". Las aplicaciones
pueden comprobar si se admiten cadenas Unicode arbitrarias como
nombres de archivo comprobando "os.path.supports_unicode_filenames",
un valor booleano.

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 pueden ahora soportar convenciones de
fin de línea distintas de 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 su lectura en modo *universal newlines*.  Las tres
convenciones de final de línea se traducirán a un "'\n'" en las
cadenas retornadas por los distintos métodos de archivo como "read()"
y "readline()".

El soporte universal de nuevas líneas también se utiliza al importar
módulos y al ejecutar un archivo con la función "execfile()".  Esto
significa que los módulos de Python pueden ser compartidos 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:

   for i in range(len(L)):
       item = L[i]
       # ... compute some result based on item ...
       L[i] = result

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

   for i, item in enumerate(L):
       # ... compute some result based on item ...
       L[i] = result

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 tratará con uno o más objetos "Logger", cada uno 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, puedes
tener instancias de "Logger" llamadas "servidor", "servidor.auth" y
"servidor.network".  Estas dos últimas instancias están por debajo de
"servidor" en la jerarquía.  Esto significa que si aumentas la
verbosidad de "servidor" o diriges los mensajes de "servidor" a un
gestor diferente, los cambios también se aplicarán a los registros de
"servidor.auth" y "servidor.network". También hay un "Logger" raíz que
es el padre de todos los demás loggers.

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

   import logging

   logging.debug('Debugging information')
   logging.info('Informational message')
   logging.warning('Warning:config file %s not found', 'server.conf')
   logging.error('Error occurred')
   logging.critical('Critical error -- shutting down')

Esto produce la siguiente salida:

   WARNING:root:Warning:config file server.conf not found
   ERROR:root:Error occurred
   CRITICAL:root:Critical error -- shutting down

En la configuración por defecto, los mensajes informativos y de
depuración se suprimen 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()" del registrador raíz.

Observe que la llamada "warning()" utiliza operadores de formato de
cadena; todas las funciones para el registro de 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 rastro más
reciente.  Cualquiera de las otras funciones también registrará el
rastro si se especifica un valor verdadero para el argumento de la
palabra clave *exc_info*.

   def f():
       try:    1/0
       except: logging.exception('Problem recorded')

   f()

Esto produce la siguiente salida:

   ERROR:root:Problem recorded
   Traceback (most recent call last):
     File "t.py", line 6, in f
       1/0
   ZeroDivisionError: integer division or modulo by zero

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('server')
    ...
   log.info('Listening on port %i', port)
    ...
   log.critical('Disk full')
    ...

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

Hay más clases proporcionadas por el paquete "logging" que pueden ser
personalizadas.  Cuando una instancia de "Logger" recibe la orden de
registrar un mensaje, crea una instancia de "LogRecord" que se envía a
cualquier número de instancias de "Handler" diferentes.  Los loggers y
handlers también pueden tener una lista adjunta de filtros, y cada
filtro puede hacer que el "LogRecord" sea ignorado o puede modificar
el registro antes de pasarlo.  Cuando finalmente se emiten, las
instancias de "LogRecord" se convierten en texto mediante una clase
"Formatter".  Todas estas clases pueden ser reemplazadas por tus
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 ha añadido un tipo booleano a Python 2.3.  Se añadieron dos nuevas
constantes al módulo "__builtin__", "True" y "False".  (Las constantes
"True" y "False" se añadieron a los módulos incorporados en Python
2.2.1, pero las versiones de 2.2.1 se ajustan simplemente a valores
enteros de 1 y 0 y no son 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)
   True
   >>> bool(0)
   False
   >>> bool([])
   False
   >>> bool( (1,) )
   True

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')
   True
   >>> isinstance(obj, list)
   True
   >>> isinstance(obj, tuple)
   False

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.

   >>> True + 1
   2
   >>> False + 1
   1
   >>> False * 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 hacer el catálogo un poco más útil, se ha añadido un nuevo
argumento opcional de palabra clave *clasificadores* a la función
Distutils "setup()".  Se puede suministrar 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
======================================

Aunque ha sido posible escribir ganchos de importación personalizados
desde que se introdujo el módulo "ihooks" en Python 1.3, nadie ha
estado nunca realmente contento con él 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 ninguno de ellos
ha tenido mucha aceptación, y ninguno era fácilmente utilizable desde
el código C.

**PEP 302** toma prestadas ideas de sus predecesores, especialmente
del módulo "iu" de Gordon McMillan.  Se añaden tres nuevos elementos
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):

   for mp in sys.meta_path:
       loader = mp(fullname)
       if loader is not None:
           <module> = loader.load_module(fullname)

   for path in sys.path:
       for hook in sys.path_hooks:
           try:
               importer = hook(path)
           except ImportError:
               # ImportError, so try the other path hooks
               pass
           else:
               loader = importer.find_module(fullname)
               <module> = loader.load_module(fullname)

   # Not found!
   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:

   Costs,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:

   "Costs",150,200,3.95,"Includes taxes, shipping, and sundry items"

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

   import csv

   input = open('datafile', 'rb')
   reader = csv.reader(input)
   for line in reader:
       print line

La función "reader()" admite varias opciones. El separador de campos
no se limita a la coma y puede cambiarse por cualquier carácter, al
igual que las comillas y el final 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 de la 2.3.  En 2.2, las clases de estilo nuevo
podían ser desempaquetadas sin dificultad, pero no se desempaquetaba
de forma muy compacta; **PEP 307** cita un ejemplo trivial en el que
una clase de estilo nuevo da lugar a una cadena desempaquetada 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 unpickling ya no se considera una operación segura. El "pickle" de
la versión 2.2 proporcionaba ganchos para tratar de evitar que las
clases no seguras fueran deserializadas (específicamente, un atributo
"__safe_for_unpickling__"), pero nada de este código fue nunca
auditado y por lo tanto todo ha sido eliminado en la versión 2.3.  No
se debe deserializar datos no confiables en ninguna versión de Python.

Para reducir la sobrecarga de pickling de las clases de estilo nuevo,
se ha añadido una nueva interfaz para personalizar el pickling
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 = range(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 = range(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 (most recent call last):
     File "<stdin>", line 1, in ?
   ValueError: attempt to assign sequence of size 3 to extended slice of size 2

La eliminación es más sencilla:

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

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

   >>> range(10).__getitem__(slice(0, 5, 2))
   [0, 2, 4]

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

   >>> range(10)[slice(0, 5, 2)]
   [0, 2, 4]

Para simplificar la implementación de secuencias que soportan el corte
extendido, los objetos slice tienen ahora un método "indices(length)"
que, dada la longitud de una secuencia, retorna una tupla "(start,
stop, step)" que puede pasarse directamente a "range()". "indices()"
maneja los índices omitidos y los que están fuera de los límites de
una manera consistente con los slices regulares (¡y esta frase inocua
esconde un montón de detalles confusos!).  El método está pensado para
ser utilizado así:

   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 (most recent call last):
       File "stdin", line 1, in ?
     KeyError: 4
     >>> d.pop(1)
     2
     >>> d.pop(1)
     Traceback (most recent call last):
       File "stdin", line 1, in ?
     KeyError: 'pop(): dictionary is empty'
     >>> 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(red=1, blue=2, green=3, black=4)
     {'blue': 2, 'black': 4, 'green': 3, 'red': 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 son ahora invocables, por lo que
  puedes usarlos para crear nuevos objetos como funciones, clases y
  módulos.  (Esto significa que el módulo "new" puede quedar obsoleto
  en una futura versión de Python, porque ahora puedes utilizar 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:

     >>> import types
     >>> m = types.ModuleType('abc','docstring')
     >>> m
     <module 'abc' (built-in)>
     >>> 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 archivo, introducido en
  Python 2.1, ya no es necesario porque los archivos se comportan
  ahora 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 se puede escribir simplemente "for line in
  file_obj". Los objetos archivo también tienen un nuevo atributo
  "encoding" de sólo 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 los métodos utilizados por las clases del
  nuevo estilo ha cambiado, aunque sólo 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 utilizaba una ordenación topológica de los ancestros
  de una clase, pero 2.3 ahora utiliza el algoritmo C3 como se
  describe en el artículo "A Monotonic Superclass Linearization for
  Dylan". Para entender la motivación de este cambio, lea el artículo
  de Michele Simionato "Python 2.3 Method Resolution Order", o lea 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 multihilo cambiando entre hilos después de
  ejecutar N bytecodes.  El valor por defecto de N se ha incrementado
  de 10 a 100 bytecodes, acelerando las aplicaciones de un solo hilo
  al reducir la sobrecarga de cambio.  Algunas aplicaciones multihilo
  pueden sufrir un tiempo de respuesta más lento, pero eso se arregla
  fácilmente estableciendo el límite a un número menor usando
  "sys.setcheckinterval(N)". El límite puede recuperarse 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 creabas un socket e imprimías su
  "__class__", obtendrías esta salida:

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

  En 2.3, se obtiene esto:

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

* Se ha eliminado una de las incompatibilidades señaladas entre las
  clases de estilo antiguo y las de estilo nuevo: ahora se pueden
  asignar a los atributos "__name__" y "__bases__" de las clases de
  estilo nuevo.  Hay algunas restricciones sobre lo que se puede
  asignar a "__bases__" en la línea de 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' in 'abcd'
     True
     >>> 'ad' in 'abcd'
     False
     >>> '' in 'abcd'
     True

  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()" tienen
  ahora un argumento opcional para especificar los caracteres a
  eliminar.  El valor por defecto 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 tenga 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'
     >>> 'goofy'.zfill(6)
     '0goofy'

  (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)" retornará "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 los objetos de la lista ha sido ampliamente
  reescrito por Tim Peters, y la implementación es significativamente
  más rápida.

* La multiplicación de enteros largos 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*n) requerido para el algoritmo
  de multiplicación de la escuela primaria.  (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 Other Changes and Fixes para una
  explicación más larga. (Eliminado por Michael Hudson)

* Los objetos "xrange()" tienen ahora su propio iterador, haciendo 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 antigua versión del módulo ha sido renombrada como "bsddb185" y
  ya no se construye automáticamente; tendrás que editar
  "Modules/Setup" para activarlo.  Ten en cuenta que el nuevo paquete
  "bsddb" está pensado para ser compatible con el módulo antiguo, así
  que asegúrate de enviar errores si descubres 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 sus archivos de
  base de datos a la nueva versión.  Puede hacerlo fácilmente con los
  nuevos scripts "db2pickle.py" y "pickle2db.py" que encontrará en el
  directorio "Tools/scripts" de la distribución.  Si ya ha estado
  utilizando el paquete PyBSDDB e importándolo como "bsddb3", tendrá
  que cambiar sus sentencias "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 Distutils "Extension" soporta ahora un argumento
  constructor extra llamado *depends* para listar archivos fuente
  adicionales de los que depende una extensión.  Esto permite a
  Distutils recompilar el módulo si se modifica alguno de los archivos
  de dependencia.  Por ejemplo, si "sampmodule.c" incluye el fichero
  de cabecera "sample.h", se crearía el objeto "Extension" así:

     ext = Extension("samp",
                     sources=["sampmodule.c"],
                     depends=["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 comprueba las variables de
  entorno "CC", "CFLAGS", "CPP", "LDFLAGS" y "CPPFLAGS", utilizándolas
  para anular los ajustes de la configuración de Python (contribución
  de Robert Weber).

* Anteriormente el módulo "doctest" sólo buscaba casos de prueba en
  los docstrings de los métodos y funciones públicos, pero ahora
  también examina los 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" ha ganado una nueva función, "gnu_getopt()", que
  admite los mismos argumentos que la función "getopt()" existente,
  pero utiliza el modo de exploración al estilo GNU. La función
  "getopt()" existente deja de procesar las opciones tan pronto como
  se encuentra un argumento que no es una opción, pero en el modo GNU
  el procesamiento continúa, lo que significa que las opciones y los
  argumentos pueden mezclarse.  Por ejemplo:

     >>> getopt.getopt(['-f', 'filename', 'output', '-v'], 'f:v')
     ([('-f', 'filename')], ['output', '-v'])
     >>> getopt.gnu_getopt(['-f', 'filename', 'output', '-v'], 'f:v')
     ([('-f', 'filename'), ('-v', '')], ['output'])

  (Contribución de Peter Åstrand.)

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

     >>> import 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 colas de montón.  Un montón es una estructura de datos similar a
  un array que mantiene los elementos en un orden parcialmente
  ordenado de forma que, para cada índice *k*, "heap[k] <=
  heap[2*k+1]" y "heap[k] <= heap[2*k+2]".  Esto hace que sea rápido
  eliminar el elemento más pequeño, y la inserción de un nuevo
  elemento manteniendo la propiedad del montón es *O(lg n)*.  (Véase
  https://xlinux.nist.gov/dads//HTML/priorityque.html para 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 añadir y eliminar elementos manteniendo la
  propiedad del montón sobre algún otro tipo de secuencia mutable de
  Python.  Aquí hay un ejemplo que utiliza una lista de Python:

     >>> import heapq
     >>> heap = []
     >>> for item in [3, 7, 5, 11, 1]:
     ...    heapq.heappush(heap, item)
     ...
     >>> heap
     [1, 3, 5, 11, 7]
     >>> heapq.heappop(heap)
     1
     >>> heapq.heappop(heap)
     3
     >>> heap
     [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".

* The "imaplib" module now supports IMAP over SSL. (Contributed by
  Piers Lauder and Tino Lange.)

* The "itertools" contains a number of useful functions for use with
  iterators, inspired by various functions provided by the ML and
  Haskell languages.  For example, "itertools.ifilter(predicate,
  iterator)" returns all elements in the iterator for which the
  function "predicate()" returns "True", and "itertools.repeat(obj,
  N)" returns "obj" *N* times. There are a number of other functions
  in the module; see the package's reference documentation for
  details. (Contributed by Raymond Hettinger.)

* Two new functions in the "math" module, "degrees(rads)" and
  "radians(degs)", convert between radians and degrees.  Other
  functions in the "math" module such as "math.sin()" and "math.cos()"
  have always required input values measured in radians.  Also, an
  optional *base* argument was added to "math.log()" to make it easier
  to compute logarithms for bases other than "e" and "10".
  (Contributed by Raymond Hettinger.)

* Several new POSIX functions ("getpgid()", "killpg()", "lchown()",
  "loadavg()", "major()", "makedev()", "minor()", and "mknod()") were
  added to the "posix" module that underlies the "os" module.
  (Contributed by Gustavo Niemeyer, Geert Jansen, and Denis S.
  Otkidach.)

* In the "os" module, the "*stat()" family of functions can now report
  fractions of a second in a timestamp.  Such time stamps are
  represented as floats, similar to the value returned by
  "time.time()".

  During testing, it was found that some applications will break if
  time stamps are floats.  For compatibility, when using the tuple
  interface of the "stat_result" time stamps will be represented as
  integers. When using named fields (a feature first introduced in
  Python 2.2), time stamps are still represented as integers, unless
  "os.stat_float_times()" is invoked to enable float return values:

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

  In Python 2.4, the default will change to always returning floats.

  Application developers should enable this feature only if all their
  libraries work properly when confronted with floating point time
  stamps, or if they use the tuple API. If used, the feature should be
  activated on an application level instead of trying to enable it on
  a per-use basis.

* The "optparse" module contains a new parser for command-line
  arguments that can convert option values to a particular Python type
  and will automatically generate a usage message.  See the following
  section for  more details.

* The old and never-documented "linuxaudiodev" module has been
  deprecated, and a new version named "ossaudiodev" has been added.
  The module was renamed because the OSS sound drivers can be used on
  platforms other than Linux, and the interface has also been tidied
  and brought up to date in various ways. (Contributed by Greg Ward
  and Nicholas FitzRoy-Dale.)

* The new "platform" module contains a number of functions that try to
  determine various properties of the platform you're running on.
  There are functions for getting the architecture, CPU type, the
  Windows OS version, and even the Linux distribution version.
  (Contributed by Marc-André Lemburg.)

* The parser objects provided by the "pyexpat" module can now
  optionally buffer character data, resulting in fewer calls to your
  character data handler and therefore faster performance.  Setting
  the parser object's "buffer_text" attribute to "True" will enable
  buffering.

* The "sample(population, k)" function was added to the "random"
  module.  *population* is a sequence or "xrange" object containing
  the elements of a population, and "sample()" chooses *k* elements
  from the population without replacing chosen elements.  *k* can be
  any value up to "len(population)". For example:

     >>> days = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'St', 'Sn']
     >>> random.sample(days, 3)      # Choose 3 elements
     ['St', 'Sn', 'Th']
     >>> random.sample(days, 7)      # Choose 7 elements
     ['Tu', 'Th', 'Mo', 'We', 'St', 'Fr', 'Sn']
     >>> random.sample(days, 7)      # Choose 7 again
     ['We', 'Mo', 'Sn', 'Fr', 'Tu', 'St', 'Th']
     >>> random.sample(days, 8)      # Can't choose eight
     Traceback (most recent call last):
       File "<stdin>", line 1, in ?
       File "random.py", line 414, in sample
           raise ValueError, "sample larger than population"
     ValueError: sample larger than population
     >>> random.sample(xrange(1,10000,2), 10)   # Choose ten odd nos. under 10000
     [3407, 3805, 1505, 7023, 2401, 2267, 9733, 3151, 8083, 9195]

  The "random" module now uses a new algorithm, the Mersenne Twister,
  implemented in C.  It's faster and more extensively studied than the
  previous algorithm.

  (All changes contributed by Raymond Hettinger.)

* The "readline" module also gained a number of new functions:
  "get_history_item()", "get_current_history_length()", and
  "redisplay()".

* The "rexec" and "Bastion" modules have been declared dead, and
  attempts to import them will fail with a "RuntimeError".  New-style
  classes provide new ways to break out of the restricted execution
  environment provided by "rexec", and no one has interest in fixing
  them or time to do so.  If you have applications using "rexec",
  rewrite them to use something else.

  (Sticking with Python 2.2 or 2.1 will not make your applications any
  safer because there are known bugs in the "rexec" module in those
  versions.  To repeat: if you're using "rexec", stop using it
  immediately.)

* The "rotor" module has been deprecated because the  algorithm it
  uses for encryption is not believed to be secure.  If you need
  encryption, use one of the several AES Python modules that are
  available separately.

* The "shutil" module gained a "move(src, dest)" function that
  recursively moves a file or directory to a new location.

* Support for more advanced POSIX signal handling was added to the
  "signal" but then removed again as it proved impossible to make it
  work reliably across platforms.

* The "socket" module now supports timeouts.  You can call the
  "settimeout(t)" method on a socket object to set a timeout of *t*
  seconds. Subsequent socket operations that take longer than *t*
  seconds to complete will abort and raise a "socket.timeout"
  exception.

  The original timeout implementation was by Tim O'Malley.  Michael
  Gilfix integrated it into the Python "socket" module and shepherded
  it through a lengthy review.  After the code was checked in, Guido
  van Rossum rewrote parts of it.  (This is a good example of a
  collaborative development process in action.)

* On Windows, the "socket" module now ships with Secure  Sockets Layer
  (SSL) support.

* The value of the C "PYTHON_API_VERSION" macro is now exposed at the
  Python level as "sys.api_version".  The current exception can be
  cleared by calling the new "sys.exc_clear()" function.

* The new "tarfile" module  allows reading from and writing to
  **tar**-format archive files. (Contributed by Lars Gustäbel.)

* The new "textwrap" module contains functions for wrapping strings
  containing paragraphs of text.  The "wrap(text, width)" function
  takes a string and returns a list containing the text split into
  lines of no more than the chosen width.  The "fill(text, width)"
  function returns a single string, reformatted to fit into lines no
  longer than the chosen width. (As you can guess, "fill()" is built
  on top of "wrap()".  For example:

     >>> import textwrap
     >>> paragraph = "Not a whit, we defy augury: ... more text ..."
     >>> textwrap.wrap(paragraph, 60)
     ["Not a whit, we defy augury: there's a special providence in",
      "the fall of a sparrow. If it be now, 'tis not to come; if it",
      ...]
     >>> print textwrap.fill(paragraph, 35)
     Not a whit, we defy augury: there's
     a special providence in the fall of
     a sparrow. If it be now, 'tis not
     to come; if it be not to come, it
     will be now; if it be not now, yet
     it will come: the readiness is all.
     >>>

  The module also contains a "TextWrapper" class that actually
  implements the text wrapping strategy.   Both the "TextWrapper"
  class and the "wrap()" and "fill()" functions support a number of
  additional keyword arguments for fine-tuning the formatting; consult
  the module's documentation for details. (Contributed by Greg Ward.)

* The "thread" and "threading" modules now have companion modules,
  "dummy_thread" and "dummy_threading", that provide a do-nothing
  implementation of the "thread" module's interface for platforms
  where threads are not supported.  The intention is to simplify
  thread-aware modules (ones that *don't* rely on threads to run) by
  putting the following code at the top:

     try:
         import threading as _threading
     except ImportError:
         import dummy_threading as _threading

  In this example, "_threading" is used as the module name to make it
  clear that the module being used is not necessarily the actual
  "threading" module. Code can call functions and use classes in
  "_threading" whether or not threads are supported, avoiding an "if"
  statement and making the code slightly clearer.  This module will
  not magically make multithreaded code run without threads; code that
  waits for another thread to return or to do something will simply
  hang forever.

* The "time" module's "strptime()" function has long been an annoyance
  because it uses the platform C library's "strptime()"
  implementation, and different platforms sometimes have odd bugs.
  Brett Cannon contributed a portable implementation that's written in
  pure Python and should behave identically on all platforms.

* The new "timeit" module helps measure how long snippets of Python
  code take to execute.  The "timeit.py" file can be run directly from
  the command line, or the module's "Timer" class can be imported and
  used directly.  Here's a short example that figures out whether it's
  faster to convert an 8-bit string to Unicode by appending an empty
  Unicode string to it or by using the "unicode()" function:

     import timeit

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

     # Run three trials
     print timer1.repeat(repeat=3, number=100000)
     print timer2.repeat(repeat=3, number=100000)

     # On my laptop this outputs:
     # [0.36831796169281006, 0.37441694736480713, 0.35304892063140869]
     # [0.17574405670166016, 0.18193507194519043, 0.17565798759460449]

* The "Tix" module has received various bug fixes and updates for the
  current version of the Tix package.

* The "Tkinter" module now works with a thread-enabled  version of
  Tcl. Tcl's threading model requires that widgets only be accessed
  from the thread in which they're created; accesses from another
  thread can cause Tcl to panic.  For certain Tcl interfaces,
  "Tkinter" will now automatically avoid this  when a widget is
  accessed from a different thread by marshalling a command, passing
  it to the correct thread, and waiting for the results.  Other
  interfaces can't be handled automatically but "Tkinter" will now
  raise an exception on such an access so that you can at least find
  out about the problem.  See https://mail.python.org/pipermail
  /python-dev/2002-December/031107.html for a more detailed
  explanation of this change.  (Implemented by Martin von Löwis.)

* Calling Tcl methods through "_tkinter" no longer  returns only
  strings. Instead, if Tcl returns other objects those objects are
  converted to their Python equivalent, if one exists, or wrapped with
  a "_tkinter.Tcl_Obj" object if no Python equivalent exists. This
  behavior can be controlled through the "wantobjects()" method of
  "tkapp" objects.

  When using "_tkinter" through the "Tkinter" module (as most Tkinter
  applications will), this feature is always activated. It should not
  cause compatibility problems, since Tkinter would always convert
  string results to Python types where possible.

  If any incompatibilities are found, the old behavior can be restored
  by setting the "wantobjects" variable in the "Tkinter" module to
  false before creating the first "tkapp" object.

     import Tkinter
     Tkinter.wantobjects = 0

  Any breakage caused by this change should be reported as a bug.

* The "UserDict" module has a new "DictMixin" class which defines all
  dictionary methods for classes that already have a minimum mapping
  interface.  This greatly simplifies writing classes that need to be
  substitutable for dictionaries, such as the classes in  the "shelve"
  module.

  Adding the mix-in as a superclass provides the full dictionary
  interface whenever the class defines "__getitem__()",
  "__setitem__()", "__delitem__()", and "keys()". For example:

     >>> import UserDict
     >>> class SeqDict(UserDict.DictMixin):
     ...     """Dictionary lookalike implemented with lists."""
     ...     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)      # See that other dictionary methods are implemented
     ['__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', 'values']

  (Contributed by Raymond Hettinger.)

* The DOM implementation in "xml.dom.minidom" can now generate XML
  output in a particular encoding by providing an optional encoding
  argument to the "toxml()" and "toprettyxml()" methods of DOM nodes.

* The "xmlrpclib" module now supports an XML-RPC extension for
  handling nil data values such as Python's "None".  Nil values are
  always supported on unmarshalling an XML-RPC response.  To generate
  requests containing "None", you must supply a true value for the
  *allow_none* parameter when creating a "Marshaller" instance.

* The new "DocXMLRPCServer" module allows writing self-documenting
  XML-RPC servers. Run it in demo mode (as a program) to see it in
  action.   Pointing the Web browser to the RPC server produces pydoc-
  style documentation; pointing xmlrpclib to the server allows
  invoking the actual methods. (Contributed by Brian Quinlan.)

* Support for internationalized domain names (RFCs 3454, 3490, 3491,
  and 3492) has been added. The "idna" encoding can be used to convert
  between a Unicode domain name and the ASCII-compatible encoding
  (ACE) of that name.

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

  The "socket" module has also been extended to transparently convert
  Unicode hostnames to the ACE version before passing them to the C
  library. Modules that deal with hostnames such as "httplib" and
  "ftplib") also support Unicode host names; "httplib" also sends HTTP
  "Host" headers using the ACE version of the domain name.  "urllib"
  supports Unicode URLs with non-ASCII host names as long as the
  "path" part of the URL is ASCII only.

  To implement this change, the "stringprep" module, the
  "mkstringprep" tool and the "punycode" encoding have been added.


Date/Time Type
--------------

Date and time types suitable for expressing timestamps were added as
the "datetime" module.  The types don't support different calendars or
many fancy features, and just stick to the basics of representing
time.

The three primary types are: "date", representing a day, month, and
year; "time", consisting of hour, minute, and second; and "datetime",
which contains all the attributes of both "date" and "time". There's
also a "timedelta" class representing differences between two points
in time, and time zone logic is implemented by classes inheriting from
the abstract "tzinfo" class.

You can create instances of "date" and "time" by either supplying
keyword arguments to the appropriate constructor, e.g.
"datetime.date(year=1972, month=10, day=15)", or by using one of a
number of class methods.  For example, the "date.today()" class method
returns the current local date.

Once created, instances of the date/time classes are all immutable.
There are a number of methods for producing formatted strings from
objects:

   >>> import datetime
   >>> now = datetime.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'

The "replace()" method allows modifying one or more fields  of a
"date" or "datetime" instance, returning a new instance:

   >>> d = datetime.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)
   >>>

Instances can be compared, hashed, and converted to strings (the
result is the same as that of "isoformat()").  "date" and "datetime"
instances can be subtracted from each other, and added to "timedelta"
instances.  The largest missing feature is that there's no standard
library support for parsing strings and getting back a "date" or
"datetime".

For more information, refer to the module's reference documentation.
(Contributed by Tim Peters.)


The optparse Module
-------------------

The "getopt" module provides simple parsing of command-line arguments.
The new "optparse" module (originally named Optik) provides more
elaborate command-line parsing that follows the Unix conventions,
automatically creates the output for "--help", and can perform
different actions for different options.

You start by creating an instance of "OptionParser" and telling it
what your program's options are.

   import sys
   from optparse import OptionParser

   op = OptionParser()
   op.add_option('-i', '--input',
                 action='store', type='string', dest='input',
                 help='set input filename')
   op.add_option('-l', '--length',
                 action='store', type='int', dest='length',
                 help='set maximum length of output')

Parsing a command line is then done by calling the "parse_args()"
method.

   options, args = op.parse_args(sys.argv[1:])
   print options
   print args

This returns an object containing all of the option values, and a list
of strings containing the remaining arguments.

Invoking the script with the various arguments now works as you'd
expect it to. Note that the length argument is automatically converted
to an integer.

   $ ./python opt.py -i data arg1
   <Values at 0x400cad4c: {'input': 'data', 'length': None}>
   ['arg1']
   $ ./python opt.py --input=data --length=4
   <Values at 0x400cad2c: {'input': 'data', 'length': 4}>
   []
   $

The help message is automatically generated for you:

   $ ./python opt.py --help
   usage: opt.py [options]

   options:
     -h, --help            show this help message and exit
     -iINPUT, --input=INPUT
                           set input filename
     -lLENGTH, --length=LENGTH
                           set maximum length of output
   $

See the module's documentation for more details.

Optik was written by Greg Ward, with suggestions from the readers of
the Getopt SIG.


Pymalloc: A Specialized Object Allocator
========================================

Pymalloc, a specialized object allocator written by Vladimir
Marangozov, was a feature added to Python 2.1.  Pymalloc is intended
to be faster than the system "malloc()" and to have less memory
overhead for allocation patterns typical of Python programs. The
allocator uses C's "malloc()" function to get large pools of memory
and then fulfills smaller memory requests from these pools.

In 2.1 and 2.2, pymalloc was an experimental feature and wasn't
enabled by default; you had to explicitly enable it when compiling
Python by providing the "--with-pymalloc" option to the **configure**
script.  In 2.3, pymalloc has had further enhancements and is now
enabled by default; you'll have to supply "--without-pymalloc" to
disable it.

This change is transparent to code written in Python; however,
pymalloc may expose bugs in C extensions.  Authors of C extension
modules should test their code with pymalloc enabled, because some
incorrect code may cause core dumps at runtime.

There's one particularly common error that causes problems.  There are
a number of memory allocation functions in Python's C API that have
previously just been aliases for the C library's "malloc()" and
"free()", meaning that if you accidentally called mismatched functions
the error wouldn't be noticeable. When the object allocator is
enabled, these functions aren't aliases of "malloc()" and "free()" any
more, and calling the wrong function to free memory may get you a core
dump.  For example, if memory was allocated using "PyObject_Malloc()",
it has to be freed using "PyObject_Free()", not "free()".  A few
modules included with Python fell afoul of this and had to be fixed;
doubtless there are more third-party modules that will have the same
problem.

As part of this change, the confusing multiple interfaces for
allocating memory have been consolidated down into two API families.
Memory allocated with one family must not be manipulated with
functions from the other family.  There is one family for allocating
chunks of memory and another family of functions specifically for
allocating Python objects.

* To allocate and free an undistinguished chunk of memory use the "raw
  memory" family: "PyMem_Malloc()", "PyMem_Realloc()", and
  "PyMem_Free()".

* The "object memory" family is the interface to the pymalloc facility
  described above and is biased towards a large number of "small"
  allocations: "PyObject_Malloc()", "PyObject_Realloc()", and
  "PyObject_Free()".

* To allocate and free Python objects, use the "object" family
  "PyObject_New()", "PyObject_NewVar()", and "PyObject_Del()".

Thanks to lots of work by Tim Peters, pymalloc in 2.3 also provides
debugging features to catch memory overwrites and doubled frees in
both extension modules and in the interpreter itself.  To enable this
support, compile a debugging version of the Python interpreter by
running **configure** with "--with-pydebug".

To aid extension writers, a header file "Misc/pymemcompat.h" is
distributed with the source to Python 2.3 that allows Python
extensions to use the 2.3 interfaces to memory allocation while
compiling against any version of Python since 1.5.2.  You would copy
the file from Python's source distribution and bundle it with the
source of your extension.

Ver también:

  https://hg.python.org/cpython/file/default/Objects/obmalloc.c
     For the full details of the pymalloc implementation, see the
     comments at the top of the file "Objects/obmalloc.c" in the
     Python source code. The above link points to the file within the
     python.org SVN browser.


Build and C API Changes
=======================

Changes to Python's build process and to the C API include:

* The cycle detection implementation used by the garbage collection
  has proven to be stable, so it's now been made mandatory.  You can
  no longer compile Python without it, and the "--with-cycle-gc"
  switch to **configure** has been removed.

* Python can now optionally be built as a shared library
  ("libpython2.3.so") by supplying "--enable-shared" when running
  Python's **configure** script.  (Contributed by Ondrej Palkovsky.)

* The "DL_EXPORT" and "DL_IMPORT" macros are now deprecated.
  Initialization functions for Python extension modules should now be
  declared using the new macro "PyMODINIT_FUNC", while the Python core
  will generally use the "PyAPI_FUNC" and "PyAPI_DATA" macros.

* The interpreter can be compiled without any docstrings for the
  built-in functions and modules by supplying "--without-doc-strings"
  to the **configure** script. This makes the Python executable about
  10% smaller, but will also mean that you can't get help for Python's
  built-ins.  (Contributed by Gustavo Niemeyer.)

* The "PyArg_NoArgs()" macro is now deprecated, and code that uses it
  should be changed.  For Python 2.2 and later, the method definition
  table can specify the "METH_NOARGS" flag, signalling that there are
  no arguments, and the argument checking can then be removed.  If
  compatibility with pre-2.2 versions of Python is important, the code
  could use "PyArg_ParseTuple(args, "")" instead, but this will be
  slower than using "METH_NOARGS".

* "PyArg_ParseTuple()" accepts new format characters for various sizes
  of unsigned integers: "B" for "unsigned char", "H" for "unsigned
  short int",  "I" for "unsigned int",  and "K" for "unsigned long
  long".

* A new function, "PyObject_DelItemString(mapping, char *key)" was
  added as shorthand for "PyObject_DelItem(mapping,
  PyString_New(key))".

* File objects now manage their internal string buffer differently,
  increasing it exponentially when needed.  This results in the
  benchmark tests in "Lib/test/test_bufio.py" speeding up considerably
  (from 57 seconds to 1.7 seconds, according to one measurement).

* It's now possible to define class and static methods for a C
  extension type by setting either the "METH_CLASS" or "METH_STATIC"
  flags in a method's "PyMethodDef" structure.

* Python now includes a copy of the Expat XML parser's source code,
  removing any dependence on a system version or local installation of
  Expat.

* If you dynamically allocate type objects in your extension, you
  should be aware of a change in the rules relating to the
  "__module__" and "__name__" attributes.  In summary, you will want
  to ensure the type's dictionary contains a "'__module__'" key;
  making the module name the part of the type name leading up to the
  final period will no longer have the desired effect.  For more
  detail, read the API reference documentation or the  source.


Port-Specific Changes
---------------------

Support for a port to IBM's OS/2 using the EMX runtime environment was
merged into the main Python source tree.  EMX is a POSIX emulation
layer over the OS/2 system APIs.  The Python port for EMX tries to
support all the POSIX-like capability exposed by the EMX runtime, and
mostly succeeds; "fork()" and "fcntl()" are restricted by the
limitations of the underlying emulation layer.  The standard OS/2
port, which uses IBM's Visual Age compiler, also gained support for
case-sensitive import semantics as part of the integration of the EMX
port into CVS.  (Contributed by Andrew MacIntyre.)

On MacOS, most toolbox modules have been weaklinked to improve
backward compatibility.  This means that modules will no longer fail
to load if a single routine is missing on the current OS version.
Instead calling the missing routine will raise an exception.
(Contributed by Jack Jansen.)

The RPM spec files, found in the "Misc/RPM/" directory in the Python
source distribution, were updated for 2.3.  (Contributed by Sean
Reifschneider.)

Other new platforms now supported by Python include AtheOS
(http://www.atheos.cx/), GNU/Hurd, and OpenVMS.


Other Changes and Fixes
=======================

As usual, there were a bunch of other improvements and bugfixes
scattered throughout the source tree.  A search through the CVS change
logs finds there were 523 patches applied and 514 bugs fixed between
Python 2.2 and 2.3.  Both figures are likely to be underestimates.

Some of the more notable changes are:

* If the "PYTHONINSPECT" environment variable is set, the Python
  interpreter will enter the interactive prompt after running a Python
  program, as if Python had been invoked with the "-i" option. The
  environment variable can be set before running the Python
  interpreter, or it can be set by the Python program as part of its
  execution.

* The "regrtest.py" script now provides a way to allow "all resources
  except *foo*."  A resource name passed to the "-u" option can now be
  prefixed with a hyphen ("'-'") to mean "remove this resource."  For
  example, the option '"-uall,-bsddb"' could be used to enable the use
  of all resources except "bsddb".

* The tools used to build the documentation now work under Cygwin as
  well as Unix.

* The "SET_LINENO" opcode has been removed.  Back in the mists of
  time, this opcode was needed to produce line numbers in tracebacks
  and support trace functions (for, e.g., "pdb"). Since Python 1.5,
  the line numbers in tracebacks have been computed using a different
  mechanism that works with "python -O".  For Python 2.3 Michael
  Hudson implemented a similar scheme to determine when to call the
  trace function, removing the need for "SET_LINENO" entirely.

  It would be difficult to detect any resulting difference from Python
  code, apart from a slight speed up when Python is run without "-O".

  C extensions that access the "f_lineno" field of frame objects
  should instead call "PyCode_Addr2Line(f->f_code, f->f_lasti)". This
  will have the added effect of making the code work as desired under
  "python -O" in earlier versions of Python.

  A nifty new feature is that trace functions can now assign to the
  "f_lineno" attribute of frame objects, changing the line that will
  be executed next.  A "jump" command has been added to the "pdb"
  debugger taking advantage of this new feature. (Implemented by
  Richie Hindle.)


Porting to Python 2.3
=====================

This section lists previously described changes that may require
changes to your code:

* "yield" is now always a keyword; if it's used as a variable name in
  your code, a different name must be chosen.

* For strings *X* and *Y*, "X in Y" now works if *X* is more than one
  character long.

* The "int()" type constructor will now return a long integer instead
  of raising an "OverflowError" when a string or floating-point number
  is too large to fit into an integer.

* If you have Unicode strings that contain 8-bit characters, you must
  declare the file's encoding (UTF-8, Latin-1, or whatever) by adding
  a comment to the top of the file.  See section PEP 263: Codificación
  del código fuente for more information.

* Calling Tcl methods through "_tkinter" no longer  returns only
  strings. Instead, if Tcl returns other objects those objects are
  converted to their Python equivalent, if one exists, or wrapped with
  a "_tkinter.Tcl_Obj" object if no Python equivalent exists.

* Large octal and hex literals such as "0xffffffff" now trigger a
  "FutureWarning". Currently they're stored as 32-bit numbers and
  result in a negative value, but in Python 2.4 they'll become
  positive long integers.

  There are a few ways to fix this warning.  If you really need a
  positive number, just add an "L" to the end of the literal.  If
  you're trying to get a 32-bit integer with low bits set and have
  previously used an expression such as "~(1 << 31)", it's probably
  clearest to start with all bits set and clear the desired upper
  bits. For example, to clear just the top bit (bit 31), you could
  write "0xffffffffL &~(1L<<31)".

* You can no longer disable assertions by assigning to "__debug__".

* The Distutils "setup()" function has gained various new keyword
  arguments such as *depends*.  Old versions of the Distutils will
  abort if passed unknown keywords.  A solution is to check for the
  presence of the new "get_distutil_options()" function in your
  "setup.py" and only uses the new keywords with a version of the
  Distutils that supports them:

     from distutils import core

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

* Using "None" as a variable name will now result in a "SyntaxWarning"
  warning.

* Names of extension types defined by the modules included with Python
  now contain the module and a "'.'" in front of the type name.


Acknowledgements
================

The author would like to thank the following people for offering
suggestions, corrections and assistance with various drafts of this
article: 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.
