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

Autor:
   A.M. Kuchling


Introducción
============

Este artículo explica las nuevas características en Python 2.2.2,
publicado el 14 de octubre de 2002. Python 2.2.2 es una versión de
corrección de errores de Python 2.2, lanzada originalmente el 21 de
diciembre de 2001.

Python 2.2 se puede considerar como la "versión de limpieza". Hay
algunas características como los generadores e iteradores que son
completamente nuevas, pero la mayoría de los cambios, aunque sean
significativos y de gran alcance, tienen como objetivo limpiar las
irregularidades y los rincones oscuros del diseño del lenguaje.

Este artículo no procura proporcionar una especificación completa de
las nuevas características, pero en su lugar proporciona una
descripción general conveniente. Para más detalles, deberías consultar
la documentación de Python 2.2, como Python Library Reference y Python
Reference Manual. Si quieres comprender la justificación completa de
la implementación y el diseño de un cambio, consultar la PEP para
conocer una característica nueva en particular.


PEPs 252 y 253: Cambios de tipo y clase
=======================================

Los cambios más grandes y de mayor alcance en Python 2.2 son el modelo
de objetos y clases de Python. Los cambios deben ser compatibles con
versiones anteriores, por lo que es probable que tu código continuará
ejecutándose sin cambios, pero los cambios proporcionan algunas
capacidades nuevas increíbles. Antes de comenzar esta, la sección más
larga y complicada de este artículo, brindaré una descripción general
de los cambios y ofreceré algunos comentarios.

Hace mucho tiempo escribí una página web en la que enumeraba los
defectos de diseño de Python. Uno de los defectos más importantes era
que resulta imposible crear subclases de los tipos de Python
implementados en C. En particular, no es posible crear subclases de
los tipos integrados, por lo que no se pueden crear subclases de, por
ejemplo, listas para añadirles un único método útil. El módulo
"UserList" proporciona una clase que admite todos los métodos de las
listas y que se puede subclasificar aún más, pero hay mucho código C
que espera una lista de Python normal y no acepta una instancia de
"UserList".

Python 2.2 corrige esto y, en el proceso, agrega algunas capacidades
nuevas interesantes. Un breve resumen:

* Puedes subclasificar tipos incorporados como listas e incluso
  enteros, y tus subclases deberían funcionar en todos los lugares que
  requieran el tipo original.

* Ahora es posible definir métodos estáticos y de clase, además de los
  métodos de instancia disponibles en versiones anteriores de Python.

* También es posible llamar automáticamente a métodos al acceder o
  configurar un atributo de instancia mediante un nuevo mecanismo
  llamado *properties*. Muchos usos de "__getattr__()" se pueden
  reescribir para utilizar propiedades en su lugar, lo que hace que el
  código resultante sea más simple y rápido. Como pequeño beneficio
  adicional, los atributos ahora también pueden tener cadenas de
  documentación.

* La lista de atributos legales para una instancia se puede limitar a
  un conjunto particular usando *slots*, lo que hace posible
  protegerse contra errores tipográficos y quizás hacer posibles más
  optimizaciones en versiones futuras de Python.

Algunos usuarios han expresado preocupación por todos estos cambios.
Claro, dicen, las nuevas características son ordenadas y se prestan a
todo tipo de trucos que no eran posibles en versiones anteriores de
Python, pero también hacen que el lenguaje sea más complicado. Algunas
personas han dicho que siempre han recomendado Python por su
simplicidad, y sienten que su simplicidad se está perdiendo.

Personalmente. pienso que no hay que preocuparse. Muchas de las nuevas
características son bastante esotéricas, y puedes escribir mucho
código de Python sin tener que estar al tanto de ellas. Escribir una
clase simple no es más difícil de lo que nunca fue, así que no
necesitas molestarte en aprender o enseñarlos a menos que realmente
sean necesarios. Algunas tareas muy complicadas que antes solo eran
posibles desde C ahora serán posibles en Python puro, y en mi opinión,
esto es todo para mejor.

No voy a intentar cubrir todas los casos de las esquinas y los
pequeños cambios que fueron necesarios para hacer que las nuevas
características funcionen. En su lugar, esta sección pintará solo a
grandes rasgos. Consultar la sección Enlaces relacionados, "Enlaces
relacionados", para más fuentes de información sobre el nuevo modelo
de objetos de Python 2.2.


Clases antiguas y nuevas
------------------------

Primero, debes saber que realmente Python 2.2 tiene dos tipos de
clases: clases clásicas o de estilo antiguo y clases de estilo nuevo.
El modelo de clase de estilo antiguo exactamente es el mismo que el
modelo de clase en versiones anteriores de Python. Todas las nuevas
características descritas en esta sección se aplican solo a las clases
de estilo nuevo. Esta divergencia no está destinada a durar para
siempre; eventualmente las clases de estilo antiguo se eliminarán,
posiblemente en Python 3.0.

Entonces, ¿cómo defines una clase de estilo nuevo? Lo haces
subclasificando una clases de estilo nuevo existente. La mayoría de
los tipos integrados de Python, como enteros, listas, diccionarios e
incluso archivos, ahora son clases de estilo nuevo. También se agregó
una clase de estilo nuevo llamada "object", la clase base para todos
los tipos integrados, por lo que si ningún tipo integrado es
apropiado, puedes solo subclasificar "object":

   clase C(objeto):
   def __init__(self):
   ...
   ...

Esto significa que las instrucciones "class" que no tienen ninguna
clase base siempre son clases clásicas en Python 2.2. (En realidad,
también puede cambiar esto configurando una variable a nivel de módulo
llamada "__metaclass__" --- consulte **PEP 253** para obtener más
detalles --- pero es más fácil simplemente subclasificar "object").

Los objetos de tipo para los tipos integrados están disponibles como
incorporados, nombrados mediante un truco inteligente. Python siempre
ha tenido funciones incorporadas llamadas "int()", "float()" y
"str()". En la versión 2.2, ya no son funciones, sino objetos de tipo
que se comportan como fábricas cuando se les llaman.

   >>> int
   <tipo 'int'>
   >>> int('123')
   123

Para completar el conjunto de tipos, se han añadido nuevos objetos de
tipo, como "dict()" y "file()". A continuación, se muestra un ejemplo
más interesante, en el que se añade un método "lock()" a los objetos
de archivo:

   clase LockableFile(archivo):
   def lock (self, operación, longitud=0, inicio=0, origen=0):
   import fcntl
   return fcntl.lockf(self.fileno(), operación,
   longitud, inicio, origen)

El módulo "posixfile", ahora obsoleto, contenía una clase que emulaba
todos los métodos de un objeto de archivo y también agregaba un método
"lock()", pero esta clase no podía pasarse a funciones internas que
esperaban un archivo integrado, algo que es posible con nuestro nuevo
"LockableFile".


Descriptores
------------

En versiones anteriores de Python, no había una forma consistente de
descubrir qué atributos y métodos eran compatibles con un objeto.
Existían algunas convenciones informales, como definir los atributos
"__members__" y "__methods__" que eran listas de nombres, pero a
menudo el autor de un tipo de extensión o una clase no se molestaba en
definirlos. Se podía recurrir a inspeccionar el "__dict__" de un
objeto, pero cuando se utilizaba la herencia de clase o un gancho
"__getattr__()" arbitrario, esto podía seguir siendo inexacto.

La única gran idea que subyace al nuevo modelo de clases es que se ha
formalizado una API para describir los atributos de un objeto usando
*descriptors*. Los descriptores especifican el valor de un atributo,
indicando si es un método o un campo. Con la API de un descriptor, los
métodos estáticos y de clase se vuelven posibles, así como constructos
más exóticos.

Los descriptores de atributos son objetos que viven dentro de los
objetos de clase y tienen algunos atributos propios:

* "__name__" es el nombre del atributo.

* "__doc__" es el docstring del atributo.

* "__get__(object)" es un método que recupera el valor del atributo de
  *object*.

* "__set__(object, value)" establece el atributo de *object* en
  *value*.

* "__delete__(object, value)" elimina el atributo *value* de *object*.

Por ejemplo, cuando escribes "obj.x", los pasos que realmente Python
realiza son:

   descriptor = obj.__class__.x
   descriptor.__get__(obj)

Para los métodos, "descriptor.__get__" devuelve un objeto temporal que
se puede llamar y envuelve la instancia y el método que se llamará en
él. Esta es también la razón por la que ahora son posibles los métodos
estáticos y los métodos de clase; tienen descriptores que envuelven
solo el método, o el método y la clase. Como breve explicación de
estos nuevos tipos de métodos, los métodos estáticos no se pasan a la
instancia y, por lo tanto, se parecen a las funciones normales. A los
métodos de clase se les pasa la clase del objeto, pero no el objeto en
sí. Los métodos estáticos y de clase se definen de la siguiente
manera:

   clase C(objeto):
   def f(arg1, arg2):
   ...
   f = método estático(f)

   def g(cls, arg1, arg2):
   ...
   g = método de clase(g)

La función "staticmethod()" toma la función "f()" y la devuelve
envuelta en un descriptor para que pueda almacenarse en el objeto de
clase. Se podría esperar que existiera una sintaxis especial para
crear dichos métodos ("def static f", "defstatic f()" o algo similar),
pero aún no se ha definido dicha sintaxis; eso se ha dejado para
futuras versiones de Python.

También se implementan más características nuevas, como ranuras y
propiedades, como nuevos tipos de descriptores, y no es difícil
escribir una clase de descriptor que haga algo nuevo. Por ejemplo,
sería posible escribir una clase de descriptor que hiciera posible
escribir condiciones previas al estilo Eiffel y posteriores para un
método. Una clase que usó esta característica podría definirse así:

   from eiffel import eiffelmethod

   class C(object):
   def f(self, arg1, arg2):
   # La función actual
   ...
   def pre_f(self):
   # Verificar condiciones previas
   ...
   def post_f(self):
   # Verificar condiciones posteriores
   ...

   f = eiffelmethod(f, pre_f, post_f)

Tenga en cuenta que una persona que utilice el nuevo "eiffelmethod()"
no tiene por qué entender nada sobre descriptores. Por eso creo que
las nuevas características no aumentan la complejidad básica del
lenguaje. Habrá algunos expertos que necesitarán saber sobre él para
escribir "eiffelmethod()" o ZODB o lo que sea, pero la mayoría de los
usuarios simplemente escribirán código sobre las bibliotecas
resultantes e ignorarán los detalles de implementación.


Herencia múltiple: la regla del diamante
----------------------------------------

La herencia múltiple también se ha hecho más útil al cambiar las
reglas bajo las cuales se resuelven los nombres. Considera este
conjunto de clases (diagrama tomado de **PEP 253** de Guido van
Rossum):

   clase A:
   ^ ^ def save(self): ...
   / \
   / \
   / \
   / \
   clase B clase C:
   ^ ^ def save(self): ...
   \ /
   \ /
   \ /
   \ /
   clase D

La regla de búsqueda para las clases clásicas es simple pero no muy
inteligente; las clases base se buscan primero en profundidad, de
izquierda a derecha. Una referencia a "D.save()" buscará las clases
"D", "B" y luego "A", donde se encontraría y devolvería "save()".
"C.save()" nunca se encontraría. Esto es malo, porque si el método
"save()" de "C" está guardando algún estado interno específico de "C",
no llamarlo hará que ese estado nunca se guarde.

Las clases de estilo nuevo siguen un algoritmo diferente que es más
complicado de explicar, pero hace lo correcto en esta situación. (Toma
en cuenta que Python 2.3 cambia este algoritmo a uno que produce los
mismos resultados en la mayoría de los casos, pero produce resultados
más útiles para gráficos de herencia realmente complicados.)

1. Enumere todas las clases base siguiendo la regla de búsqueda
   clásica e incluya una clase varias veces si se la visita
   repetidamente. En el ejemplo anterior, la lista de clases visitadas
   es ["D", "B", "A", "C", "A"].

2. Examine la lista en busca de clases duplicadas. Si encuentra
   alguna, elimine todas las instancias excepto una y deje la *last*
   en la lista. En el ejemplo anterior, la lista se convierte en ["D",
   "B", "C", "A"] después de eliminar los duplicados.

Siguiendo esta regla, al hacer referencia a "D.save()" se devolverá
"C.save()", que es el comportamiento que buscamos. Esta regla de
búsqueda es la misma que sigue Common Lisp. Una nueva función
incorporada, "super()", proporciona una forma de acceder a las
superclases de una clase sin tener que volver a implementar el
algoritmo de Python. La forma más utilizada será "super(class, obj)",
que devuelve un objeto de superclase enlazado (no el objeto de clase
real). Esta forma se utilizará en métodos para llamar a un método en
la superclase; por ejemplo, el método "save()" de "D" se vería así:

   clase D (B,C):
   def save (self):
   # Llamar a la superclase .save()
   super(D, self).save()
   # Guardar la información privada de D aquí
   ...

También "super()" puede retornar objetos de superclase no vinculados
cuando se llama como "super(class)" o "super(class1, class2)", pero
probablemente esto no sea útil a menudo.


Acceso a atributos
------------------

Una buena cantidad de clases sofisticadas de Python definen ganchos
para el acceso a atributos mediante "__getattr__()"; lo más común es
que esto se haga por conveniencia, para que el código sea más legible
al asignar automáticamente un acceso a atributos como "obj.parent" a
una llamada de método como "obj.get_parent". Python 2.2 agrega algunas
formas nuevas de controlar el acceso a atributos.

Primero, "__getattr__(attr_name)" aún es compatible con las clases de
nuevo estilo, y nada al respecto ha cambiado. Como antes, se llamará
cuando se intente acceder a "obj.foo" y no se encuentre ningún
atributo llamado "foo" en el diccionario de la instancia.

Las clases de nuevo estilo también admiten un nuevo método,
"__getattribute__(attr_name)". La diferencia entre los dos métodos es
que "__getattribute__()" se llama *always* siempre que se accede a un
atributo, mientras que el antiguo "__getattr__()" solo se llama si
"foo" no se encuentra en el diccionario de la instancia.

Sin embargo, el soporte de Python 2.2 para *properties* será a menudo
una forma más sencilla de atrapar referencias de atributos. Escribir
un método "__getattr__()" es complicado porque para evitar la
recursión no se pueden utilizar accesos a atributos regulares dentro
de ellos, y en su lugar hay que jugar con el contenido de "__dict__".
Los métodos "__getattr__()" también terminan siendo llamados por
Python cuando comprueba otros métodos como "__repr__()" o
"__coerce__()", y por lo tanto tienen que ser escritos con esto en
mente. Finalmente, llamar a una función en cada acceso a un atributo
da como resultado una pérdida de rendimiento considerable.

"property" es un nuevo tipo integrado que incluye tres funciones que
obtienen, establecen o eliminan un atributo y una cadena de
documentación. Por ejemplo, si desea definir un atributo "size" que se
calcule, pero que también se pueda configurar, puede escribir:

   clase C(objeto):
   def get_size (self):
   result = ... computation ...
   return result
   def set_size (self, size):
   ... calcula algo en función del tamaño
   y establece el estado interno de forma adecuada ...

   # Define una propiedad. El método 'eliminar este atributo'
   # se define como None, por lo que el atributo
   # no se puede eliminar.
   size = property(get_size, set_size,
   None,
   "Tamaño de almacenamiento de esta instancia")

Sin duda, esto es más claro y más fácil de escribir que un par de
métodos "__getattr__()"/"__setattr__()" que comprueban el atributo
"size" y lo gestionan de forma especial mientras recuperan todos los
demás atributos del "__dict__" de la instancia. Los accesos a "size"
también son los únicos que tienen que realizar el trabajo de llamar a
una función, por lo que las referencias a otros atributos se ejecutan
a su velocidad habitual.

Finalmente, es posible restringir la lista de atributos que se pueden
referenciar en un objeto usando el nuevo atributo de clase
"__slots__". Los objetos de Python por lo general son muy dinámicos;
en cualquier momento es posible definir un nuevo atributo en una
instancia haciendo simplemente "obj.new_attr=1". Una clase de estilo
nuevo puede definir un atributo de clase llamado "__slots__" para
limitar los atributos legales a un conjunto particular de nombres. Un
ejemplo hará esto claro:

   >>> class C(object):
   ... __slots__ = ('template', 'name')
   ...
   >>> obj = C()
   >>> print obj.template
   None
   >>> obj.template = 'Test'
   >>> print obj.template
   Test
   >>> obj.newattr = None
   Traceback (última llamada más reciente):
   Archivo "<stdin>", línea 1, en ?
   AttributeError: el objeto 'C' no tiene el atributo 'newattr'

Toma en cuenta cómo obtienes un "AttributeError" en el intento de
asignar a un atributo que no aparece en "__slots__".


Enlaces relacionados
--------------------

Esta sección solo ha sido una descripción rápida de las nuevas
características, brindando una explicación suficiente para comenzar a
programar, pero muchos detalles se han simplificado o ignorado. ¿Dónde
deberías ir para obtener una imagen más completa?

Descriptor Guide es una introducción extensa y tutorial a las
características del descriptor, escrita por Guido van Rossum. Si mi
descripción le ha abierto el apetito, lea este tutorial a
continuación, porque brinda mucho más detalle sobre las nuevas
características y sigue siendo bastante fácil de leer.

A continuación, hay dos PEPs relevantes, **PEP 252** y **PEP 253**.
**PEP 252** se titula "Hacer que los tipos se parezcan más a las
clases", y cubre la API del descriptor. **PEP 253** se titula
"Subtipado de tipos incorporados", y describe los cambios de los
objetos de tipo que hacen posible el subtipo de objetos incorporados.
**PEP 253** es la PEP más complicada de las dos, y en algunos puntos
las explicaciones necesarias de tipos y meta-tipos pueden causar que
tu cabeza explote. Ambas PEPs se escribieron e implementaron por Guido
van Rossum con la asistencia sustancial del resto del equipo de Zope
Corp.

Finalmente, está la máxima autoridad: el código fuente. La mayoría de
la maquinaria para el manejo de tipos está en "Objects/typeobject.c",
pero solo debes recurrir a él después de que se hayan agotado todas
las demás vías, incluida la publicación de una pregunta en python-list
o python-dev.


PEP 234: Iteradores
===================

Otra adición significativa a la versión 2.2 es una interfaz de
iteración tanto a nivel de C como de Python.  Los objetos pueden
definir cómo pueden ser iterados por quienes los llaman.

En las versiones de Python hasta la 2.1, la forma habitual de hacer
que funcione "for item in obj" es definir un método "__getitem__()"
que se parezca a esto:

   def __getitem__(self, index):
   return <siguiente elemento>

"__getitem__()" se utiliza de forma más adecuada para definir una
operación de indexación en un objeto, de modo que pueda escribir
"obj[5]" para recuperar el sexto elemento. Es un poco engañoso cuando
se utiliza esto solo para admitir bucles "for". Considere un objeto
similar a un archivo que desea ser recorrido en bucle; el parámetro
*index* esencialmente no tiene sentido, ya que la clase probablemente
asume que se realizará una serie de llamadas "__getitem__()" con
*index* incrementándose en uno cada vez. En otras palabras, la
presencia del método "__getitem__()" no significa que el uso de
"file[5]" para acceder aleatoriamente al sexto elemento funcionará,
aunque realmente debería funcionar.

En Python 2.2, la iteración se puede implementar por separado y los
métodos "__getitem__()" se pueden limitar a las clases que realmente
admiten el acceso aleatorio. La idea básica de los iteradores es
simple. Se utiliza una nueva función incorporada, "iter(obj)" o
"iter(C, sentinel)", para obtener un iterador. "iter(obj)" devuelve un
iterador para el objeto *obj*, mientras que "iter(C, sentinel)"
devuelve un iterador que invocará el objeto invocable *C* hasta que
devuelva *sentinel* para indicar que el iterador ha finalizado.

Las clases de Python pueden definir un método "__iter__()", que debe
crear y devolver un nuevo iterador para el objeto; si el objeto es su
propio iterador, este método puede devolver simplemente "self". En
particular, los iteradores normalmente serán sus propios iteradores.
Los tipos de extensión implementados en C pueden implementar una
función "tp_iter" para devolver un iterador, y los tipos de extensión
que quieran comportarse como iteradores pueden definir una función
"tp_iternext".

Entonces, después de todo esto, ¿qué hacen realmente los iteradores?
Tienen un método obligatorio, "next()", que no toma argumentos y
retorna el siguiente valor.  Cuando no hay más valores que retornar,
la llamada a "next()" debería lanzar la excepción "StopIteration".

   >>> L = [1,2,3]
   >>> i = iter(L)
   >>> print i
   <iterator object at 0x8116870>
   >>> i.next()
   1
   >>> i.next()
   2
   >>> i.next()
   3
   >>> i.next()
   Traceback (última llamada más reciente):
   Archivo "<stdin>", línea 1, en ?
   StopIteration
   >>>

En la versión 2.2, la declaración "for" de Python ya no espera una
secuencia, sino algo para lo que "iter()" devolverá un iterador. Para
mayor comodidad y compatibilidad con versiones anteriores, se
construye automáticamente un iterador para las secuencias que no
implementan "__iter__()" o una ranura "tp_iter", por lo que "for i in
[1,2,3]" seguirá funcionando. Siempre que el intérprete de Python
recorra una secuencia, se ha modificado para utilizar el protocolo de
iterador. Esto significa que puede hacer cosas como esta:

   >>> L = [1,2,3]
   >>> i = iter(L)
   >>> a,b,c = i
   >>> a,b,c
   (1, 2, 3)

Se ha añadido soporte de iteradores a algunos de los tipos básicos de
Python.   Llamar a "iter()" sobre un diccionario retornará un iterador
que hace un bucle sobre sus claves:

   >>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
   ...      'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
   >>> for key in m: print key, m[key]
   ...
   Mar 3
   Feb 2
   Aug 8
   Sep 9
   May 5
   Jun 6
   Jul 7
   Jan 1
   Apr 4
   Nov 11
   Dec 12
   Oct 10

Ese es simplemente el comportamiento predeterminado. Si desea iterar
sobre claves, valores o pares clave/valor, puede llamar explícitamente
a los métodos "iterkeys()", "itervalues()" o "iteritems()" para
obtener un iterador adecuado. En un cambio menor relacionado, el
operador "in" ahora funciona en diccionarios, por lo que "key in dict"
ahora es equivalente a "dict.has_key(key)".

Los archivos también proporcionan un iterador, que llama al método
"readline()" hasta que no hay más líneas en el archivo.  Esto
significa que ahora puede leer cada línea de un archivo utilizando un
código como este:

   for line in file:
       # do something for each line
       ...

Tenga en cuenta que sólo puede avanzar en un iterador; no hay forma de
obtener el elemento anterior, reiniciar el iterador o hacer una copia
del mismo. Un objeto iterador podría proporcionar estas capacidades
adicionales, pero el protocolo iterador sólo requiere un método
"next()".

Ver también:

  **PEP 234** - Iteradores
     Escrito por Ka-Ping Yee y GvR; implementado por el equipo de
     Python Labs, principalmente por GvR y Tim Peters.


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

Los generadores son otra novedad que interactúa con la introducción de
los iteradores.

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.  Debido a la introducción de una nueva palabra clave, los
generadores deben ser explícitamente habilitados en un módulo
incluyendo una declaración "from __future__ import generators" cerca
de la parte superior del código fuente del módulo.  En Python 2.3 esta
declaración será innecesaria.

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"...`"finally"; 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 sentencia "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 lució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 Icon (https://www2.cs.arizona.edu/icon/),
donde la idea de los generadores es central. En Icon, cada expresión y
llamada a 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
se ve esto:

   sentence := "Store it in the neighboring harbor"
   if (i := find("or", sentence)) > 5 then 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 una nueva 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 237: Unificación de enteros largos y enteros
================================================

En versiones recientes, la distinción entre números enteros regulares,
que son valores de 32 bits en la mayoría de las máquinas, y números
enteros largos, que pueden ser de tamaño arbitrario, se estaba
volviendo una molestia. Por ejemplo, en plataformas que admiten
archivos de más de bytes que "2**32", el método "tell()" de objetos de
archivo tiene que devolver un número entero largo. Sin embargo, había
varias partes de Python que esperaban números enteros simples y
generarían un error si se proporcionaba un número entero largo en su
lugar. Por ejemplo, en Python 1.5, solo se podían usar números enteros
regulares como índice de segmento, y "'abc'[1L:]" generaría una
excepción "TypeError" con el mensaje 'el índice de segmento debe ser
int'.

Python 2.2 cambiará los valores de enteros cortos a enteros largos
según sea necesario. El sufijo 'L' ya no es necesario para indicar un
literal entero largo, ya que ahora el compilador elegirá el tipo
apropiado.  (El uso del sufijo 'L' se desaconsejará en futuras
versiones 2.x de Python, provocando una advertencia en Python 2.4, y
probablemente se eliminará en Python 3.0)  Muchas operaciones que
solían lanzar un "OverflowError" ahora retornarán un entero largo como
resultado.  Por ejemplo:

   >>> 1234567890123
   1234567890123L
   >>> 2 ** 64
   18446744073709551616L

En la mayoría de los casos, los enteros y los enteros largos se
tratarán ahora de forma idéntica.  Todavía se pueden distinguir con la
función incorporada "type()", pero rara vez se necesita.

Ver también:

  **PEP 237** - Unificación de enteros largos y enteros
     Escrito por Moshe Zadka y Guido van Rossum.  Implementado
     principalmente por Guido van Rossum.


PEP 238: Cambio del operador de división
========================================

El cambio más controvertido de Python 2.2 anuncia el inicio de un
esfuerzo por arreglar un viejo defecto de diseño que ha estado en
Python desde el principio. Actualmente, el operador de división de
Python, "/", se comporta como el operador de división de C cuando se
le presentan dos argumentos enteros: retorna un resultado entero que
se trunca cuando hay una parte fraccionaria.  Por ejemplo, "3/2" es 1,
no 1,5, y "(-1)/2" es -1, no -0,5.  Esto significa que los resultados
de la división pueden variar inesperadamente dependiendo del tipo de
los dos operandos y, como Python está tipado dinámicamente, puede ser
difícil determinar los posibles tipos de los operandos.

(La controversia se centra en si esto es *realmente* un defecto de
diseño, y si vale la pena romper el código existente para arreglarlo.
Ha provocado interminables discusiones en python-dev, y en julio de
2001 estalló una tormenta de publicaciones ácidamente sarcásticas en
*comp.lang.python*. No argumentaré aquí a favor de ninguno de los dos
bandos y me limitaré a describir lo que se ha implementado en la 2.2.
Lea **PEP 238** para un resumen de los argumentos y contra-argumentos)

Debido a que este cambio podría romper el código, se está
introduciendo de forma muy gradual. Python 2.2 comienza la transición,
pero el cambio no será completo hasta Python 3.0.

En primer lugar, tomaré prestada alguna terminología de **PEP 238**.
La "división verdadera" es la división con la que la mayoría de los no
programadores están familiarizados: 3/2 es 1,5, 1/4 es 0,25, y así
sucesivamente. La "división entera a la baja" es lo que hace
actualmente el operador "/" de Python cuando se le dan operandos
enteros; el resultado es el redondeo a la baja (*floor*) del valor
retornado por la división verdadera. La "división clásica" es el
comportamiento mixto actual de "/"; retorna el resultado de la
división entera a la baja cuando los operandos son enteros, y retorna
el resultado de la división verdadera cuando uno de los operandos es
un número de punto flotante.

Estos son los cambios que introduce la versión 2.2:

* Un nuevo operador, "//", es el operador de división entera a la
  baja. (Sí, ya sabemos que se parece al símbolo de comentario de
  C++.) "//" *siempre* realiza la división entera a la baja sin
  importar los tipos de sus operandos, así que "1 // 2" es 0 y "1.0 //
  2.0" también es 0.0.

  "//" está siempre disponible en Python 2.2; no es necesario
  habilitarlo mediante una sentencia "__future__".

* Al incluir una declaración "from __future__ import division" en un
  módulo, el operador "/" se cambiará para retornar el resultado de la
  división verdadera, por lo que "1/2" es 0,5.  Sin la declaración
  "__future__", "/" sigue significando la división clásica. El
  significado por defecto de "/" no cambiará hasta Python 3.0.

* Las clases pueden definir métodos denominados "__truediv__()" y
  "__floordiv__()" para sobrecargar los dos operadores de división. En
  el nivel C, también hay espacios en la estructura "PyNumberMethods"
  para que los tipos de extensión puedan definir los dos operadores.

* Python 2.2 admite algunos argumentos de línea de comandos para
  comprobar si el código funcionará con la semántica de división
  modificada.  Ejecutar python con "-Q warn" hará que se emita una
  advertencia cada vez que se aplique la división a dos enteros.
  Puedes usar esto para encontrar el código que está afectado por el
  cambio y arreglarlo.  Por defecto, Python 2.2 simplemente realizará
  la división clásica sin una advertencia; la advertencia se activará
  por defecto en Python 2.3.

Ver también:

  **PEP 238** - Cambio del operador de división
     Escrito por Moshe Zadka y Guido van Rossum.  Implementado por
     Guido van Rossum..


Cambios en Unicode
==================

El soporte de Unicode de Python se ha mejorado un poco en la versión
2.2.  Las cadenas Unicode se almacenan normalmente como UCS-2, como
enteros sin signo de 16 bits. Python 2.2 también puede ser compilado
para usar UCS-4, enteros sin signo de 32 bits, como su codificación
interna suministrando "--enable-unicode=ucs4" al script de
configuración.   (También es posible especificar "--disable-unicode"
para desactivar completamente el soporte de Unicode)

Cuando se crea para utilizar UCS-4 (un "Python ancho"), el intérprete
puede manejar de forma nativa caracteres Unicode desde U+000000 hasta
U+110000, por lo que el rango de valores legales para la función
"unichr()" se amplía en consecuencia. Si se utiliza un intérprete
compilado para utilizar UCS-2 (un "Python estrecho"), los valores
mayores que 65535 seguirán haciendo que "unichr()" genere una
excepción "ValueError". Todo esto se describe en **PEP 261**,
"Compatibilidad con caracteres Unicode 'anchos'"; consúltelo para
obtener más detalles.

Otro cambio es más sencillo de explicar. Desde su introducción, las
cadenas Unicode admiten un método "encode()" para convertir la cadena
a una codificación seleccionada, como UTF-8 o Latin-1. En la versión
2.2 se ha añadido un método "decode([*encoding*])" simétrico a las
cadenas de 8 bits (aunque no a las cadenas Unicode). "decode()" supone
que la cadena está en la codificación especificada y la decodifica,
devolviendo lo que devuelva el códec.

Gracias a esta nueva función, se han añadido códecs para tareas no
relacionadas directamente con Unicode.  Por ejemplo, se han añadido
códecs para la codificación uu, la codificación base64 de MIME y la
compresión con el módulo "zlib":

   >>> s = """Aquí hay un largo fragmento de texto redundante, excesivamente verboso,
   ... y repetitivo.
   ... """
   >>> data = s.encode('zlib')
   >>> data
   'x\x9c\r\xc9\xc1\r\x80 \x10\x04\xc0?Ul...'
   >>> data.decode('zlib')
   'Aquí hay un largo fragmento de texto redundante, excesivamente verboso,\ny repetitivo.\n'
   >>> print s.encode('uu')
   begin 666 <datos>
   M2&5R92!I<R!A(&QE;F=T:'D@<&EE8V4@;V8@<F5D=6YD86YT+"!O=F5R;'D@
   >=F5R8F]S92P*86YD(')E<&5T:71I=F4@=&5X="X*

   fin
   >>> "caramba".encode('rot-13')
   'furrfu'

Para convertir una instancia de clase a Unicode, se puede definir un
método "__unicode__()" mediante una clase, análogo a "__str__()".

Marc-André Lemburg implementó "encode()", "decode()" y
"__unicode__()". Fredrik Lundh y Martin von Löwis implementaron los
cambios para admitir el uso interno de UCS-4.

Ver también:

  **PEP 261** - Soporte para caracteres Unicode 'anchos'
     Escrito por Paul Prescod.


PEP 227: Ámbitos anidados
=========================

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

El mayor cambio introducido en Python 2.1, y completado en 2.2, es el
de las reglas de alcance de Python.  En Python 2.0, en cualquier
momento hay como máximo tres espacios de nombres utilizados para
buscar nombres de variables: local, a nivel de módulo y el espacio de
nombres incorporado.  Esto a menudo sorprendía a la gente porque no
coincidía con sus expectativas intuitivas.  Por ejemplo, una
definición de función recursiva anidada no funciona:

   def f():
   ...
   def g(valor):
   ...
   return g(valor-1) + 1
   ...

La función "g()" siempre generará una excepción "NameError", porque la
vinculación del nombre "g" no está en su espacio de nombres local ni
en el espacio de nombres a nivel de módulo. Esto no es un gran
problema en la práctica (¿con qué frecuencia se definen recursivamente
funciones internas como esta?), pero esto también hizo que el uso de
la expresión "lambda" fuera más complicado, y esto fue un problema en
la práctica. En el código que usa "lambda", a menudo se pueden
encontrar variables locales que se copian al pasarlas como valores
predeterminados de los argumentos.

   def find(self, name):
   "Devuelve una lista de todas las entradas iguales a 'name'"
   L = filter(lambda x, name=name: x == name,
   self.list_attribute)
   return L

La legibilidad del código Python escrito en un estilo fuertemente
funcional sufre mucho como resultado.

El cambio más significativo de Python 2.2 es que se ha añadido al
lenguaje el ámbito estático para solucionar este problema.  Como
primer efecto, el argumento por defecto "name=name" es ahora
innecesario en el ejemplo anterior.  En pocas palabras, cuando a un
nombre de variable dado no se le asigna un valor dentro de una función
(mediante una asignación, o las sentencias "def", "class", o
"import"), las referencias a la variable se buscarán en el espacio de
nombres local del ámbito que la rodea.  Puede encontrar una
explicación más detallada de las reglas y una disección de la
implementación en el PEP.

Este cambio puede causar algunos problemas de compatibilidad para el
código en el que el mismo nombre de variable se utiliza tanto a nivel
de módulo como de variable local dentro de una función que contiene
otras definiciones de función. Sin embargo, esto parece bastante
improbable, ya que dicho código habría sido bastante confuso de leer
en primer lugar.

Un efecto secundario del cambio es que las sentencias "from module
import *" y "exec" se han hecho ilegales dentro del ámbito de una
función bajo ciertas condiciones.  El manual de referencia de Python
ha dicho todo el tiempo que "from module import *" sólo es legal en el
nivel superior de un módulo, pero el intérprete de CPython nunca ha
aplicado esto antes.  Como parte de la implementación de los ámbitos
anidados, el compilador que convierte el código fuente de Python en
bytecodes tiene que generar un código diferente para acceder a las
variables de un ámbito contenedor.  Los códigos "from module import *"
y "exec" hacen que el compilador no pueda averiguar esto, porque
añaden nombres al espacio de nombres local que son desconocidos en
tiempo de compilación. Por lo tanto, si una función contiene
definiciones de funciones o expresiones "lambda" con variables libres,
el compilador lo señalará lanzando una excepción "SyntaxError".

Para que la explicación anterior quede un poco más clara, he aquí un
ejemplo:

   x = 1
   def f():
   # La siguiente línea es un error de sintaxis
   exec 'x=2'
   def g():
   return x

La línea 4 que contiene la declaración "exec" es un error de sintaxis,
ya que "exec" definiría una nueva variable local denominada "x" a cuyo
valor debería acceder "g()".

Esto no debería ser una gran limitación, ya que "exec" rara vez se
utiliza en la mayoría del código de Python (y cuando se utiliza, a
menudo es un signo de un mal diseño de todos modos).

Ver también:

  **PEP 227** - Ámbitos anidados estáticamente
     Escrito e implementado por Jeremy Hylton.


Módulos nuevos y mejorados
==========================

* El módulo "xmlrpclib" fue aportado a la biblioteca estándar por
  Fredrik Lundh, que proporciona soporte para escribir clientes XML-
  RPC. XML-RPC es un protocolo simple de llamada a procedimiento
  remoto creado sobre HTTP y XML. Por ejemplo, el siguiente fragmento
  recupera una lista de canales RSS de la red O'Reilly y, a
  continuación, enumera los titulares recientes de un canal:

     import xmlrpclib
     s = xmlrpclib.Server(
     'http://www.oreillynet.com/meerkat/xml-rpc/server.php')
     channels = s.meerkat.getChannels()
     # channels es una lista de diccionarios, como esta:
     # [{'id': 4, 'title': 'Freshmeat Daily News'}
     # {'id': 190, 'title': '32Bits Online'},
     # {'id': 4549, 'title': '3DGamers'}, ... ]

     # Obtener los elementos de un canal
     items = s.meerkat.getItems( {'channel': 4} )

     # 'items' es otra lista de diccionarios, como esta:
     # [{'link': 'http://freshmeat.net/releases/52719/',
     # 'description': 'Una utilidad que convierte HTML a XSL FO.',
     # 'title': 'html2fo 0.3 (Predeterminado)'}, ... ]

  El módulo "SimpleXMLRPCServer" facilita la creación de servidores
  XML-RPC sencillos. Consulte http://xmlrpc.scripting.com/ para
  obtener más información sobre XML-RPC.

* El nuevo módulo "hmac" implementa el algoritmo HMAC descrito por
  **RFC 2104**. (Contribución de Gerhard Häring)

* Varias funciones que originalmente devolvían tuplas extensas ahora
  devuelven pseudosecuencias que aún se comportan como tuplas pero que
  también tienen atributos mnemotécnicos como "memberst_mtime" o
  "tm_year". Las funciones mejoradas incluyen "stat()", "fstat()",
  "statvfs()" y "fstatvfs()" en el módulo "os", y "localtime()",
  "gmtime()" y "strptime()" en el módulo "time".

  Por ejemplo, para obtener el tamaño de un archivo utilizando las
  antiguas tuplas, se terminaba escribiendo algo como
  "tamaño_de_archivo = os.stat(nombre_de_archivo)[stat.ST_SIZE]", pero
  ahora se puede escribir más claramente como "tamaño_de_archivo =
  os.stat(nombre_de_archivo).st_size".

  El parche original para esta función fue aportado por Nick
  Mathewson.

* El perfilador de Python ha sido ampliamente revisado y se han
  corregido varios errores en su salida.  (Contribución de Fred L.
  Drake, Jr. y Tim Peters)

* El módulo "socket" puede ser compilado para soportar IPv6;
  especifica la opción "--enable-ipv6" al script configure de Python.
  (Contribución de Jun-ichiro "itojun" Hagino)

* Se agregaron dos nuevos caracteres de formato al módulo "struct"
  para enteros de 64 bits en plataformas que admiten el tipo C long
  long. "q" es para un entero de 64 bits con signo y "Q" es para uno
  sin firmar. El valor se retorna en el tipo de entero largo de
  Python. (Aportado por Tim Peters.)

* En el modo interactivo del intérprete, hay una nueva función
  incorporada "help()" que utiliza el módulo "pydoc" introducido en
  Python 2.1 para proporcionar ayuda interactiva. "help()" sin ningún
  argumento te sitúa en una utilidad de ayuda online, donde puedes
  introducir los nombres de las funciones, clases o módulos para leer
  su texto de ayuda. (Contribuido por Guido van Rossum, usando el
  módulo "pydoc" de Ka-Ping Yee)

* Se han realizado varias correcciones de errores y mejoras de
  rendimiento en el motor SRE subyacente al módulo "re". Por ejemplo,
  las funciones "re.sub()" y "re.split()" se han reescrito en C. Otro
  parche aportado acelera ciertos rangos de caracteres Unicode por un
  factor de dos, y un nuevo método "finditer()" que devuelve un
  iterador sobre todas las coincidencias no superpuestas en una cadena
  dada. (SRE es mantenido por Fredrik Lundh. El parche BIGCHARSET fue
  aportado por Martin von Löwis).

* El módulo "smtplib" soporta ahora **RFC 2487**, "Secure SMTP over
  TLS", por lo que ahora es posible cifrar el tráfico SMTP entre un
  programa Python y el agente de transporte de correo que recibe un
  mensaje. "smtplib" también soporta la autenticación SMTP.
  (Contribución de Gerhard Häring)

* El módulo "imaplib", mantenido por Piers Lauder, tiene soporte para
  varias extensiones nuevas: la extensión NAMESPACE definida en **RFC
  2342**, SORT, GETACL y SETACL.  (Contribución de Anthony Baxter y
  Michel Pelletier)

* El análisis de direcciones de correo electrónico del módulo "rfc822"
  ahora es compatible con **RFC 2822**, una actualización de **RFC
  822**. (El nombre del módulo, *not*, se cambiará a "rfc2822").
  También se ha añadido un nuevo paquete, "email", para analizar y
  generar mensajes de correo electrónico. (Contribuido por Barry
  Warsaw y derivado de su trabajo en Mailman).

* El módulo "difflib" ahora contiene una nueva clase "Differ" para
  producir listas legibles por humanos de cambios (un "delta") entre
  dos secuencias de líneas de texto. También hay dos funciones
  generadoras, "ndiff()" y "restore()", que devuelven respectivamente
  un delta de dos secuencias, o una de las secuencias originales de un
  delta. (Trabajo básico aportado por David Goodger, a partir del
  código ndiff.py de Tim Peters, quien luego realizó la generación).

* Se agregaron las nuevas constantes "ascii_letters",
  "ascii_lowercase" y "ascii_uppercase" al módulo "string". Había
  varios módulos en la biblioteca estándar que usaban "string.letters"
  para referirse a los rangos A-Za-z, pero esa suposición es
  incorrecta cuando se usan las configuraciones regionales, porque
  "string.letters" varía según el conjunto de caracteres legales
  definidos por la configuración regional actual. Todos los módulos
  con errores se han corregido para que usen "ascii_letters" en su
  lugar. (Informado por una persona desconocida; corregido por Fred L.
  Drake, Jr.)

* El módulo "mimetypes" ahora facilita el uso de bases de datos de
  tipo MIME alternativas mediante la incorporación de una clase
  "MimeTypes", que toma una lista de nombres de archivos para
  analizar. (Contribuido por Fred L. Drake, Jr.)

* Se agregó una clase "Timer" al módulo "threading" que permite
  programar una actividad para que se realice en un momento futuro.
  (Contribución de Itamar Shtull-Trauring).


Cambios y correcciones en el intérprete
=======================================

Algunos de los cambios sólo afectan a la gente que trata con el
intérprete de Python a nivel de C porque están escribiendo módulos de
extensión de Python, incrustando el intérprete, o simplemente
hackeando el propio intérprete. Si sólo escribes código Python,
ninguno de los cambios descritos aquí te afectará mucho.

* Las funciones de perfilado y rastreo pueden implementarse ahora en
  C, que puede operar a velocidades mucho mayores que las funciones
  basadas en Python y debería reducir la sobrecarga de perfilado y
  rastreo.  Esto será de interés para los autores de entornos de
  desarrollo para Python.  Se han añadido dos nuevas funciones en C a
  la API de Python, "PyEval_SetProfile()" y "PyEval_SetTrace()". Las
  funciones "sys.setprofile()" y "sys.settrace()" existentes siguen
  existiendo, y simplemente se han cambiado para utilizar la nueva
  interfaz de nivel C.  (Contribución de Fred L. Drake, Jr.)

* Se agregó otra API de bajo nivel, principalmente de interés para los
  implementadores de depuradores y herramientas de desarrollo de
  Python. "PyInterpreterState_Head()" y "PyInterpreterState_Next()"
  permiten que un llamador recorra todos los objetos de intérprete
  existentes; "PyInterpreterState_ThreadHead()" y
  "PyThreadState_Next()" permiten recorrer todos los estados de
  subprocesos para un intérprete determinado. (Contribución de David
  Beazley).

* La interfaz a nivel de C para el recolector de basura ha sido
  cambiada para facilitar la escritura de tipos de extensión que
  soporten la recolección de basura y para depurar los malos usos de
  las funciones. Varias funciones tienen una semántica ligeramente
  diferente, por lo que hubo que cambiar el nombre de un montón de
  funciones.  Las extensiones que utilizan la antigua API seguirán
  compilando pero *no* participarán en la recolección de basura, por
  lo que actualizarlas para la 2.2 debería considerarse de alta
  prioridad.

  Para actualizar un módulo de extensión a la nueva API, realice los
  siguientes pasos:

* Cambia el nombre de "Py_TPFLAGS_GC()" a "PyTPFLAGS_HAVE_GC()".

* Utilice "PyObject_GC_New()" o "PyObject_GC_NewVar()" para asignar
     objetos, y "PyObject_GC_Del()" para desocuparlos.

* Cambie el nombre de "PyObject_GC_Init()" a "PyObject_GC_Track()" y
  de "PyObject_GC_Fini()" a "PyObject_GC_UnTrack()".

* Eliminar "PyGC_HEAD_SIZE" de los cálculos de tamaño de objeto.

* Eliminar llamadas a "PyObject_AS_GC()" y "PyObject_FROM_GC()".

* Se ha añadido una nueva secuencia de formato "et" a
  "PyArg_ParseTuple()"; "et" toma tanto un parámetro como un nombre de
  codificación, y convierte el parámetro a la codificación dada si el
  parámetro resulta ser una cadena Unicode, o lo deja solo si es una
  cadena de 8 bits, asumiendo que ya está en la codificación deseada.
  Esto difiere del carácter de formato "es", que asume que las cadenas
  de 8 bits están en la codificación ASCII por defecto de Python y las
  convierte a la nueva codificación especificada. (Contribuido por
  M.-A. Lemburg, y utilizado para el soporte de MBCS en Windows
  descrito en la siguiente sección)

* Se ha agregado una función de análisis de argumentos diferente,
  "PyArg_UnpackTuple()", que es más simple y presumiblemente más
  rápida. En lugar de especificar una cadena de formato, la persona
  que llama simplemente proporciona el número mínimo y máximo de
  argumentos esperados y un conjunto de punteros a las variables
  PyObject* que se completarán con los valores de los argumentos.

* Hay dos nuevos indicadores "METH_NOARGS" y "METH_O" disponibles en
  las tablas de definición de métodos para simplificar la
  implementación de métodos sin argumentos o con un único argumento
  sin tipo. Llamar a estos métodos es más eficiente que llamar a un
  método correspondiente que utilice "METH_VARARGS". Además, el
  antiguo estilo "METH_OLDARGS" de escribir métodos en C ahora está
  oficialmente obsoleto.

* Se agregaron dos nuevas funciones de contenedor, "PyOS_snprintf()" y
  "PyOS_vsnprintf()", para proporcionar implementaciones
  multiplataforma para las relativamente nuevas API de bibliotecas C
  "snprintf()" y "vsnprintf()". A diferencia de las funciones estándar
  "sprintf()" y "vsprintf()", las versiones de Python verifican los
  límites del búfer utilizado para protegerse contra desbordamientos
  del búfer. (Contribuido por M.-A. Lemburg).

* La función "_PyTuple_Resize()" ha perdido un parámetro que no se
  utilizaba, por lo que ahora toma 2 parámetros en lugar de 3. El
  tercer argumento nunca se utilizaba, y puede descartarse simplemente
  al portar el código de versiones anteriores a Python 2.2.


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

Como es habitual, hubo un montón de otras mejoras y correcciones de
errores repartidas por todo el árbol de fuentes.  Una búsqueda en los
registros de cambios de CVS revela que se aplicaron 527 parches y se
corrigieron 683 errores entre Python 2.1 y 2.2; en 2.2.1 se aplicaron
139 parches y se corrigieron 143 errores; en 2.2.2 se aplicaron 106
parches y se corrigieron 82 errores.  Es probable que estas cifras
estén subestimadas.

Algunos de los cambios más notables son:

* El código del puerto MacOS para Python, mantenido por Jack Jansen,
  se mantiene ahora en el árbol CVS principal de Python, y se han
  realizado muchos cambios para soportar MacOS X.

  El cambio más significativo es la capacidad de construir Python como
  un marco de trabajo, que se activa proporcionando la opción "--
  enable-framework" al script de configuración cuando se compila
  Python.  Según Jack Jansen, "Esto instala una instalación autónoma
  de Python más el "pegamento" del framework de OS X en
  "/Library/Frameworks/Python.framework" (o en otra ubicación de su
  elección). Por ahora hay poco beneficio inmediato añadido a esto (en
  realidad, existe la desventaja de que tienes que cambiar tu PATH
  para poder encontrar Python), pero es la base para crear una
  aplicación Python completa, portar el IDE de MacPython, posiblemente
  usar Python como un lenguaje de scripting estándar de OSA y mucho
  más."

  La mayoría de los módulos de la caja de herramientas de MacPython,
  que interactúan con las APIs de MacOS como ventanas, QuickTime,
  scripts, etc. han sido portados a OS X, pero se han dejado
  comentados en "setup.py".  Las personas que quieran experimentar con
  estos módulos pueden descomentarlos manualmente.

* Los argumentos de palabras clave pasados a funciones incorporadas
  que no los aceptan ahora provocan una excepción "TypeError", con el
  mensaje "*function* no acepta argumentos de palabras clave".

* Las referencias débiles, añadidas en Python 2.1 como un módulo de
  extensión, son ahora parte del núcleo porque se utilizan en la
  implementación de clases de nuevo estilo.  Por lo tanto, la
  excepción "ReferenceError" se ha movido del módulo "weakref" para
  convertirse en una excepción incorporada.

* Un nuevo script, "Tools/scripts/cleanfuture.py" de Tim Peters,
  elimina automáticamente las sentencias "__future__" obsoletas del
  código fuente de Python.

* Se ha añadido un argumento adicional *flags* a la función
  incorporada "compile()", por lo que el comportamiento de las
  sentencias "__future__" puede ahora observarse correctamente en
  shells simulados, como los presentados por IDLE y otros entornos de
  desarrollo.  Esto se describe en **PEP 264**. (Contribución de
  Michael Hudson)

* La nueva licencia introducida con Python 1.6 no era compatible con
  la GPL.  Esto se ha solucionado con algunos cambios textuales
  menores en la licencia 2.2, de modo que ahora es legal volver a
  incrustar Python dentro de un programa con licencia GPL.  Tenga en
  cuenta que Python en sí mismo no es GPL, sino que está bajo una
  licencia que es esencialmente equivalente a la licencia BSD, igual
  que siempre.  Los cambios en la licencia también se aplicaron a las
  versiones 2.0.1 y 2.1.1 de Python.

* Cuando se presenta un nombre de archivo Unicode en Windows, Python
  ahora lo convertirá en una cadena codificada en MBCS, como la que
  utilizan las APIs de archivos de Microsoft.  Como las APIs de
  archivos utilizan explícitamente MBCS, la elección de Python de
  ASCII como codificación por defecto resulta ser una molestia.  En
  Unix, se utiliza el juego de caracteres de la localización si
  "locale.nl_langinfo(CODESET)" está disponible.  (El soporte de
  Windows fue contribuido por Mark Hammond con la ayuda de Marc-André
  Lemburg. El soporte para Unix fue añadido por Martin von Löwis)

* La compatibilidad con archivos de gran tamaño ya está activada en
  Windows.  (Contribución de Tim Peters.)

* El script "Tools/scripts/ftpmirror.py" ahora analiza un archivo
  ".netrc", si tiene uno. (Contribución de Mike Romberg)

* Algunas características del objeto devuelto por la función
  "xrange()" ahora están obsoletas y activan advertencias cuando se
  accede a ellas; desaparecerán en Python 2.3. Los objetos "xrange"
  intentaron simular que eran tipos de secuencia completa al admitir
  la segmentación, la multiplicación de secuencias y el operador "in",
  pero estas características se usaban rara vez y, por lo tanto,
  presentaban errores. El método "tolist()" y los atributos "start",
  "stop" y "step" también están en desuso. En el nivel C, el cuarto
  argumento de la función "PyRange_New()", "repeat", también ha
  quedado en desuso.

* Hubo un montón de parches para la implementación del diccionario,
  sobre todo para arreglar posibles vertidos del núcleo si un
  diccionario contiene objetos que cambian furtivamente su valor hash,
  o mutan el diccionario que contienen. Durante un tiempo python-dev
  cayó en un suave ritmo de Michael Hudson encontrando un caso que
  volcaba el núcleo, Tim Peters corrigiendo el error, Michael
  encontrando otro caso, y así sucesivamente.

* En Windows, Python puede ahora compilarse con Borland C gracias a
  una serie de parches aportados por Stephen Hansen, aunque el
  resultado aún no es totalmente funcional.  (Pero esto *es* un
  progreso...)

* Otra mejora de Windows: Wise Solutions ofreció generosamente a
  PythonLabs el uso de su sistema InstallerMaster 8.1.  Los anteriores
  instaladores de PythonLabs para Windows utilizaban Wise 5.0a, que
  estaba empezando a mostrar su edad.  (Empaquetado por Tim Peters)

* Los archivos que terminan en ".pyw" pueden importarse ahora en
  Windows. ".pyw" es algo exclusivo de Windows, que se utiliza para
  indicar que un script debe ejecutarse utilizando PYTHONW.EXE en
  lugar de PYTHON.EXE para evitar que aparezca una consola DOS para
  mostrar la salida.  Este parche hace posible la importación de tales
  scripts, en caso de que también se puedan utilizar como módulos.
  (Implementado por David Bolen)

* En las plataformas en las que Python utiliza la función C "dlopen()"
  para cargar módulos de extensión, ahora es posible establecer las
  banderas utilizadas por "dlopen()" utilizando las funciones
  "sys.getdlopenflags()" y "sys.setdlopenflags()". (Contribución de
  Bram Stolk.)

* La función incorporada "pow()" ya no admite 3 argumentos cuando se
  suministran números de punto flotante. "pow(x, y, z)" devuelve
  "(x**y) % z", pero esto nunca es útil para números de punto flotante
  y el resultado final varía de manera impredecible según la
  plataforma. Una llamada como "pow(2.0, 8.0, 7.0)" ahora generará una
  excepción "TypeError".


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

El autor desea agradecer a las siguientes personas sus sugerencias,
correcciones y ayuda en varios borradores de este artículo: Fred
Bremmer, Keith Briggs, Andrew Dalke, Fred L. Drake, Jr, Carel
Fellinger, David Goodger, Mark Hammond, Stephen Hansen, Michael
Hudson, Jack Jansen, Marc-André Lemburg, Martin von Löwis, Fredrik
Lundh, Michael McLay, Nick Mathewson, Paul Moore, Gustavo Niemeyer,
Don O'Donnell, Joonas Paalasma, Tim Peters, Jens Quade, Tom Reinhardt,
Neil Schemenauer, Guido van Rossum, Greg Ward, Edward Welbourne.
