# Novedades de Python 2.1

Autor

  A.M. Kuchling

## Introducción

Este artículo explica las nuevas características de Python 2.1. Aunque no hay tantos cambios en 2.1 como en Python 2.0, todavía hay algunas sorpresas agradables. La versión 2.1 es la primera que se dirige mediante el uso de Propuestas de Mejora de Python, o PEPs, por lo que la mayoría de los cambios importantes tienen PEPs adjuntos que proporcionan una documentación más completa y una justificación de diseño para el cambio. Este artículo no intenta documentar las nuevas características por completo, sino que simplemente proporciona una visión general de las nuevas características para los programadores de Python. Consulta la documentación de Python 2.1, o el PEP específico, para obtener más detalles sobre cualquier nueva característica que te interese particularmente.

Un objetivo reciente del equipo de desarrollo de Python ha sido acelerar el ritmo de las nuevas versiones, con una nueva versión cada 6 a 9 meses. La versión 2.1 es la primera que sale a este ritmo más rápido, con la primera alfa que apareció en enero, 3 meses después de que se publicara la versión final de la 2.0.

La versión final de Python 2.1 se realizó el 17 de abril de 2001.

## PEP 227: Ámbitos anidados

El mayor cambio en Python 2.1 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(value):
            ...
            return g(value-1) + 1
        ...

La función `g()` siempre lanzará una excepción `NameError`, porque el enlace del nombre `g` no está ni 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 interiores como ésta?), pero esto también hacía más torpe el uso de la expresión `lambda`, y esto era un problema en la práctica. En el código que utiliza `lambda` a menudo se pueden encontrar variables locales que se copian al pasarlas como valores por defecto de los argumentos.

    def find(self, name):
        "Return list of any entries equal to '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.1 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():
        # The next line is a syntax error
        exec 'x=2'
        def g():
            return x

La línea 4 que contiene la sentencia `exec` es un error de sintaxis, ya que `exec` definiría una nueva variable local llamada `x` cuyo valor debería ser accedido por `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).

Los problemas de compatibilidad han llevado a que los ámbitos anidados se introduzcan gradualmente; en Python 2.1, no están habilitados por defecto, pero pueden activarse dentro de un módulo utilizando una sentencia future como se describe en PEP 236. (En Python 2.2, los ámbitos anidados se convertirán en el valor por defecto y no habrá forma de desactivarlos, pero los usuarios habrán tenido toda la vida de la versión 2.1 para arreglar cualquier rotura resultante de su introducción.

Ver también

PEP 227 - Ámbitos anidados estáticamente

  Escrito e implementado por Jeremy Hylton.

## PEP 236: Directivas __future__

La reacción a los ámbitos anidados fue una preocupación generalizada sobre los peligros de romper el código con la versión 2.1, y fue lo suficientemente fuerte como para que los Pythonistas adoptaran un enfoque más conservador. Este enfoque consiste en introducir una convención para habilitar una funcionalidad opcional en la versión N que se convertirá en obligatoria en la versión N+1.

La sintaxis utiliza una sentencia `from...import` utilizando el nombre de módulo reservado `__future__`. Los ámbitos anidados pueden habilitarse mediante la siguiente sentencia:

    from __future__ import nested_scopes

Aunque parece una sentencia `import` normal, no lo es; hay reglas estrictas sobre dónde se puede poner una sentencia future. Sólo pueden estar en la parte superior de un módulo, y deben preceder a cualquier código Python o a las sentencias `import` normales. Esto se debe a que tales declaraciones pueden afectar a la forma en que el compilador de código de bytes de Python analiza el código y genera el código de bytes, por lo que deben preceder a cualquier declaración que dé lugar a la producción de códigos de bytes.

Ver también

PEP 236 - De vuelta al `__future__`

  Escrito por Tim Peters, y ejecutado principalmente por Jeremy Hylton.

## PEP 207: Comparaciones Enriquecidas

En versiones anteriores, el soporte de Python para implementar comparaciones en clases definidas por el usuario y tipos de extensión era bastante simple. Las clases podían implementar un método `__cmp__()` al que se le daban dos instancias de una clase, y sólo podía retornar 0 si eran iguales o +1 o -1 si no lo eran; el método no podía lanzar una excepción ni retornar nada más que un valor booleano. Los usuarios de Python Numérico a menudo encontraban este modelo demasiado débil y restrictivo, porque en los programas de cálculo de números para los que se utiliza Numeric Python, sería más útil poder realizar comparaciones por elementos de dos matrices, retornando una matriz que contenga los resultados de una comparación dada para cada elemento. Si las dos matrices son de diferente tamaño, entonces el comparador tiene que ser capaz de lanzar una excepción para señalar el error.

En Python 2.1, se añadieron comparaciones enriquecidas para dar soporte a esta necesidad. Las clases de Python pueden ahora sobrecargar individualmente cada una de las operaciones `<`, `<=`, `>`, ``>=`, `==` y `!=`. Los nuevos nombres de métodos mágicos son:

Operación | Nombre del método
--- | ---
`<` | `__lt__()`
`<=` | `__le__()`
`>` | `__gt__()`
`>=` | `__ge__()`
`==` | `__eq__()`
`!=` | `__ne__()`

(Los métodos mágicos se denominan como los correspondientes operadores de Fortran `.LT.`. `.LE.`, &c. Los programadores numéricos están casi seguramente bastante familiarizados con estos nombres y los encontrarán fáciles de recordar.)

Cada uno de estos métodos mágicos tiene la forma `method(self, other)`, donde `self` será el objeto que se encuentre en el lado izquierdo del operador, mientras que `other` será el objeto que se encuentre en el lado derecho. Por ejemplo, la expresión `A < B` hará que se llame a `A.__lt__(B)`.

Cada uno de estos métodos mágicos puede retornar cualquier cosa: un booleano, una matriz, una lista o cualquier otro objeto de Python. También pueden lanzar una excepción si la comparación es imposible, inconsistente o no tiene sentido.

La función incorporada `cmp(A,B)` puede utilizar la comparación enriquecida, y ahora acepta un argumento opcional que especifica la operación de comparación a utilizar; esto se da como una de las cadenas `"<"`, `"<="`, `">"`, `">="`, `"=="`, o `"!="`. Si se llama sin el tercer argumento opcional, `cmp()` sólo retornará -1, 0 o +1 como en versiones anteriores de Python; en caso contrario, llamará al método apropiado y puede retornar cualquier objeto de Python.

También hay cambios correspondientes de interés para los programadores de C; hay una nueva ranura `tp_richcmp` en los objetos de tipo y una API para realizar una comparación rica determinada. No cubrirá la API de C aquí, sino que le remitiré a PEP 207, o a la documentación de la API de C de 2.1, para la lista completa de funciones relacionadas.

Ver también

PEP 207 - Comparaciones enriquecidas

  Escrito por Guido van Rossum, basado en gran medida en un trabajo anterior de David Ascher, e implementado por Guido van Rossum.

## PEP 230: Marco de advertencia

A lo largo de sus 10 años de existencia, Python ha acumulado un cierto número de módulos y características obsoletas en el camino. Es difícil saber cuándo es seguro eliminar una característica, ya que no hay manera de saber cuánto código la utiliza — tal vez ningún programa depende de la característica, o tal vez muchos lo hacen. Para permitir la eliminación de características antiguas de una manera más estructurada, se añadió un marco de advertencia. Cuando los desarrolladores de Python quieran deshacerse de una característica, primero se activará una advertencia en la siguiente versión de Python. La siguiente versión de Python puede entonces eliminar la característica, y los usuarios habrán tenido un ciclo de lanzamiento completo para eliminar los usos de la antigua característica.

Python 2.1 añade el marco de trabajo de las advertencias para ser utilizado en este esquema. Añade un módulo `warnings` que proporciona funciones para emitir advertencias, y para filtrar las advertencias que no se quieren mostrar. Los módulos de terceros también pueden utilizar este marco de trabajo para dejar de lado funciones antiguas que ya no desean soportar.

Por ejemplo, en Python 2.1 el módulo `regex` está obsoleto, por lo que al importarlo se imprime una advertencia:

    >>> import regex
    __main__:1: DeprecationWarning: the regex module
             is deprecated; please use the re module
    >>>

Las advertencias se pueden emitir llamando a la función `warnings.warn()`:

    warnings.warn("feature X no longer supported")

El primer parámetro es el mensaje de advertencia; se pueden utilizar otros parámetros opcionales para especificar una categoría de advertencia concreta.

Se pueden añadir filtros para desactivar ciertas advertencias; se puede aplicar un patrón de expresión regular al mensaje o al nombre del módulo para suprimir una advertencia. Por ejemplo, puede tener un programa que utilice el módulo `regex` y no querer dedicar tiempo a convertirlo para que utilice el módulo `re` en este momento. La advertencia puede suprimirse llamando a

    import warnings
    warnings.filterwarnings(action = 'ignore',
                            message='.*regex module is deprecated',
                            category=DeprecationWarning,
                            module = '__main__')

Esto añade un filtro que se aplicará sólo a las advertencias de la clase `DeprecationWarning` lanzadas en el módulo `__main__`, y aplica una expresión regular para que sólo coincida con el mensaje sobre el módulo `regex` que está obsoleto, y hará que tales advertencias sean ignoradas. Las advertencias también pueden imprimirse sólo una vez, imprimirse cada vez que se ejecute el código infractor, o convertirse en excepciones que harán que el programa se detenga (a menos que las excepciones se atrapen de la forma habitual, por supuesto).

También se agregaron funciones a la API de C de Python para emitir advertencias; consulte el PEP 230 o la documentación de la API de Python para conocer los detalles.

Ver también

PEP 5 - Directrices para la evolución del lenguaje

  Escrito por Paul Prescod, para especificar los procedimientos a seguir cuando se eliminan características antiguas de PythonLa política descrita en este PEP no ha sido adoptada oficialmente, pero la política final probablemente no será muy diferente de la propuesta de Prescod.

PEP 230 - Marco de advertencia

  Escrito y ejecutado por Guido van Rossum.

## PEP 229: Sistema de construcción nuevo

Al compilar Python, el usuario tenía que entrar y editar el archivo `Modules/Setup` para habilitar varios módulos adicionales; el conjunto por defecto es relativamente pequeño y se limita a los módulos que se compilan en la mayoría de las plataformas Unix. Esto significa que en plataformas Unix con muchas más características, sobre todo Linux, las instalaciones de Python no suelen contener todos los módulos útiles que podrían.

Python 2.0 añadió los Distutils, un conjunto de módulos para distribuir e instalar extensiones. En Python 2.1, los Distutils se utilizan para compilar gran parte de la biblioteca estándar de módulos de extensión, autodetectando cuáles son compatibles con la máquina actual Se espera que esto haga que las instalaciones de Python sean más fáciles y tengan más funciones.

En lugar de tener que editar el archivo `Modules/Setup` para habilitar los módulos, un script `setup.py` en el directorio superior de la distribución de fuentes de Python se ejecuta en el momento de la compilación, e intenta descubrir qué módulos pueden ser habilitados examinando los módulos y archivos de cabecera en el sistema. Si un módulo está configurado en `Modules/Setup`, el script `setup.py` no intentará compilar ese módulo y se remitirá al contenido del archivo `Modules/Setup`. Esto proporciona una manera de especificar cualquier flag de línea de comandos extraña o bibliotecas que se requieren para una plataforma específica.

En otro cambio de gran alcance en el mecanismo de construcción, Neil Schemenauer reestructuró las cosas para que Python ahora utilice un único makefile que no es recursivo, en lugar de makefiles en el directorio superior y en cada uno de los subdirectorios `Python/`, `Parser/`, `Objects/`, y `Modules/`. Esto hace que la construcción de Python sea más rápida y también hace que el hackeo de los Makefiles sea más claro y sencillo.

Ver también

PEP 229 - Uso de Distutils para construir Python

  Escrito y ejecutado por A.M. Kuchling.

## PEP 205: Referencias débiles

Las referencias débiles, disponibles a través del módulo `weakref`, son un nuevo tipo de datos menor pero útil en la caja de herramientas del programador de Python.

Almacenar una referencia a un objeto (por ejemplo, en un diccionario o una lista) tiene el efecto secundario de mantener ese objeto vivo para siempre. Hay algunos casos específicos en los que este comportamiento es indeseable, siendo las cachés de objetos el más común, y otro son las referencias circulares en estructuras de datos como los árboles.

Por ejemplo, considere una función de memoización que almacena en caché los resultados de otra función `f(x)` almacenando el argumento de la función y su resultado en un diccionario:

    _cache = {}
    def memoize(x):
        if _cache.has_key(x):
            return _cache[x]

        retval = f(x)

        # Cache the returned object
        _cache[x] = retval

        return retval

Esta versión funciona para cosas simples como los enteros, pero tiene un efecto secundario; el diccionario `_cache` mantiene una referencia a los valores retornados, por lo que nunca serán desocupados hasta que el proceso de Python salga y se limpie. Esto no es muy notable para los enteros, pero si `f()` retorna un objeto, o una estructura de datos que ocupa mucha memoria, esto puede ser un problema.

Las referencias débiles proporcionan una forma de implementar una caché que no mantendrá los objetos vivos más allá de su tiempo. Si un objeto sólo es accesible a través de referencias débiles, el objeto será desasignado y las referencias débiles indicarán ahora que el objeto al que se refería ya no existe. Una referencia débil a un objeto obj se crea llamando `wr = weakref.ref(obj)``El objeto al que se hace referencia se retorna llamando a la referencia débil como si fuera una función: ``wr()` retornará el objeto referenciado, o `None` si el objeto ya no existe.

Esto hace posible escribir una función `memoize()` cuya caché no mantenga objetos vivos, almacenando referencias débiles en la caché.

    _cache = {}
    def memoize(x):
        if _cache.has_key(x):
            obj = _cache[x]()
            # If weak reference object still exists,
            # return it
            if obj is not None: return obj

        retval = f(x)

        # Cache a weak reference
        _cache[x] = weakref.ref(retval)

        return retval

El módulo `weakref` también permite crear objetos proxy que se comportan como referencias débiles — un objeto referenciado sólo por objetos proxy es desasignado - pero en lugar de requerir una llamada explícita para recuperar el objeto, el proxy reenvía de forma transparente todas las operaciones al objeto mientras éste siga existiendo. Si el objeto es desocupado, el intento de usar un proxy causará una excepción `weakref.ReferenceError`.

    proxy = weakref.proxy(obj)
    proxy.attr   # Equivalent to obj.attr
    proxy.meth() # Equivalent to obj.meth()
    del obj
    proxy.attr   # raises weakref.ReferenceError

Ver también

PEP 205 - Referencias débiles

  Escrito e implementado por Fred L. Drake, Jr.

## PEP 232: Atributos de la función

En Python 2.1, las funciones ahora pueden tener información arbitraria adjunta a ellas. La gente solía utilizar docstrings para mantener la información sobre las funciones y los métodos, porque el atributo `__doc__` era la única manera de adjuntar cualquier información a una función. Por ejemplo, en el servidor de aplicaciones web Zope, las funciones se marcan como seguras para el acceso público teniendo un docstring, y en el marco de análisis SPARK de John Aycock, los docstrings contienen partes de la gramática BNF para ser analizada. Esta sobrecarga es desafortunada, ya que los docstrings están realmente pensados para contener la documentación de una función; por ejemplo, significa que no puedes documentar adecuadamente las funciones destinadas al uso privado en Zope.

Ahora se pueden establecer y recuperar atributos arbitrarios en las funciones utilizando la sintaxis normal de Python:

    def f(): pass

    f.publish = 1
    f.secure = 1
    f.grammar = "A ::= B (C D)*"

Se puede acceder al diccionario que contiene los atributos como `__dict__` de la función. A diferencia del atributo `__dict__` de las instancias de clase, en las funciones se puede asignar un nuevo diccionario a `__dict__`, aunque el nuevo valor está restringido a un diccionario normal de Python; no se puede ser complicado y establecerlo como una instancia de `UserDict`, o cualquier otro objeto aleatorio que se comporte como un mapeo.

Ver también

PEP 232 - Atributos de la función

  Escrito y ejecutado por Barry Warsaw.

## PEP 235: Importación de módulos en plataformas que no distinguen entre mayúsculas y minúsculas

Algunos sistemas operativos tienen sistemas de archivos que no distinguen entre mayúsculas y minúsculas, siendo MacOS y Windows los principales ejemplos; en estos sistemas, es imposible distinguir los nombres de archivo `FILE.PY` y `file.py`, aunque almacenan el nombre del archivo en su caso original (también preservan las mayúsculas).

En Python 2.1, la sentencia `import` funcionará para simular la distinción entre mayúsculas y minúsculas en plataformas que no las distinguen. Python buscará ahora la primera coincidencia entre mayúsculas y minúsculas por defecto, lanzando un `ImportError` si no se encuentra dicho fichero, por lo que `import file` no importará un módulo llamado `FILE.PY`. La coincidencia insensible a mayúsculas y minúsculas puede solicitarse estableciendo la variable de entorno `PYTHONCASEOK` antes de iniciar el intérprete de Python.

## PEP 217: Gancho de pantalla interactivo

Cuando se utiliza el intérprete de Python de forma interactiva, la salida de los comandos se muestra utilizando la función incorporada `repr()`. En Python 2.1, la variable `sys.displayhook()` puede establecerse a un objeto invocable que será llamado en lugar de `repr()`. Por ejemplo, puede establecerla a una función especial de impresión bonita:

    >>> # Create a recursive data structure
    ... L = [1,2,3]
    >>> L.append(L)
    >>> L # Show Python's default output
    [1, 2, 3, [...]]
    >>> # Use pprint.pprint() as the display function
    ... import sys, pprint
    >>> sys.displayhook = pprint.pprint
    >>> L
    [1, 2, 3,  <Recursion on list with id=135143996>]
    >>>

Ver también

PEP 217 - Gancho de visualización para uso interactivo

  Escrito y ejecutado por Moshe Zadka.

## PEP 208: Nuevo modelo de coerción

Se ha modificado significativamente la forma en que se realiza la coerción numérica a nivel de C. Esto sólo afectará a los autores de las extensiones de C a Python, permitiéndoles más flexibilidad a la hora de escribir tipos de extensión que soporten operaciones numéricas.

Los tipos de extensión pueden ahora establecer el indicador de tipo `Py_TPFLAGS_CHECKTYPES` en su estructura `PyTypeObject` para indicar que soportan el nuevo modelo de coerción. En tales tipos de extensión, las funciones numéricas de ranura ya no pueden asumir que se les pasarán dos argumentos del mismo tipo; en su lugar, se les pueden pasar dos argumentos de tipos diferentes, y entonces pueden realizar su propia coerción interna. Si a la función de ranura se le pasa un tipo que no puede manejar, puede indicar el fallo retornando una referencia al valor singleton `Py_NotImplemented`. Las funciones numéricas del otro tipo serán entonces probadas, y quizás puedan manejar la operación; si el otro tipo también retorna `Py_NotImplemented`, entonces se levantará un `TypeError`Los métodos numéricos escritos en Python también pueden retornar ``Py_NotImplemented``, haciendo que el intérprete actúe como si el método no existiera (tal vez lanzando un `TypeError`, tal vez probando los métodos numéricos de otro objeto).

Ver también

PEP 208 - Reformulación del modelo de coerción

  Escrito e implementado por Neil Schemenauer, basado en gran medida en el trabajo anterior de Marc-André Lemburg. Léalo para entender los puntos finos de cómo las operaciones numéricas serán ahora procesadas en el nivel C.

## PEP 241: Metadatos en paquetes de Python

A common complaint from Python users is that there’s no single catalog of all the Python modules in existence. T. Middleton’s Vaults of Parnassus at `www.vex.net/parnassus/` (retired in February 2009, available in the Internet Archive Wayback Machine) was the largest catalog of Python modules, but registering software at the Vaults is optional, and many people did not bother.

Como primer pequeño paso para solucionar el problema, el software de Python empaquetado con el comando sdist de Distutils incluirá un archivo llamado `PKG-INFO` que contiene información sobre el paquete, como su nombre, versión y autor (metadatos, en terminología de catalogación). PEP 241 contiene la lista completa de campos que pueden estar presentes en el archivo `PKG-INFO`A medida que la gente empiece a empaquetar su software usando Python 2.1, más y más paquetes incluirán metadatos, haciendo posible construir sistemas de catalogación automatizados y experimentar con ellosCon la experiencia resultante, tal vez sea posible diseñar un catálogo realmente bueno y luego construir soporte para él en Python 2.2. Por ejemplo, los comandos Distutils :command:`sdist` y bdist_* podrían soportar una opción `upload` que subiera automáticamente tu paquete a un servidor de catálogos.

Puedes empezar a crear paquetes que contengan `PKG-INFO` incluso si no estás usando Python 2.1, ya que se hará una nueva versión de las Distutils para los usuarios de versiones anteriores de PythonLa versión 1.0.2 de las Distutils incluye los cambios descritos en PEP 241, así como varias correcciones de errores y mejoras. Estará disponible en el SIG de Distutils en https://www.python.org/community/sigs/current/distutils-sig/.

Ver también

PEP 241 - Metadatos para paquetes de software de Python

  Escrito y ejecutado por A.M. Kuchling.

PEP 243 - Mecanismo de carga del repositorio de módulos

  Escrito por Sean Reifschneider, este borrador de PEP describe un mecanismo propuesto para subir paquetes de Python a un servidor central.

## Módulos nuevos y mejorados

- Ka-Ping Yee ha contribuido con dos nuevos módulos: `inspect.py`, un módulo para obtener información sobre código Python en vivo, y `pydoc.py`, un módulo para convertir interactivamente docstrings a HTML o texto. Además, `Tools/scripts/pydoc`, que se instala automáticamente, utiliza `pydoc.py` para mostrar la documentación de un módulo, paquete o clase de Python. Por ejemplo, `pydoc xml.dom` muestra lo siguiente:

      Python Library Documentation: package xml.dom in xml

      NAME
          xml.dom - W3C Document Object Model implementation for Python.

      FILE
          /usr/local/lib/python2.1/xml/dom/__init__.pyc

      DESCRIPTION
          The Python mapping of the Document Object Model is documented in the
          Python Library Reference in the section on the xml.dom package.

          This package contains the following modules:
            ...

  `pydoc` también incluye un navegador de ayuda interactiva basado en Tk. `pydoc` se vuelve rápidamente adictivo; ¡pruébalo!

- Se han añadido a la biblioteca estándar dos módulos diferentes para realizar pruebas unitarias. El módulo `doctest`, aportado por Tim Peters, proporciona un marco de pruebas basado en la ejecución de ejemplos incrustados en docstrings y la comparación de los resultados con la salida esperadaPyUnit, contribuido por Steve Purcell, es un marco de pruebas unitarias inspirado en JUnit, que a su vez fue una adaptación del marco de pruebas Smalltalk de Kent BeckConsulte http://pyunit.sourceforge.net/ para obtener más información sobre PyUnit.

- El módulo `difflib` contiene una clase, `SequenceMatcher`, que compara dos secuencias y calcula los cambios necesarios para transformar una secuencia en la otra. Por ejemplo, este módulo puede utilizarse para escribir una herramienta similar al programa diff de Unix, y de hecho el programa de ejemplo `Tools/scripts/ndiff.py` demuestra cómo escribir un script de este tipo.

- `curses.panel`, una envoltura para la biblioteca de paneles, parte de ncurses y de curses SYSV, fue contribuida por Thomas Gellekum. La biblioteca de paneles proporciona ventanas con la característica adicional de la profundidad. Las ventanas pueden ser movidas más arriba o más abajo en el ordenamiento de la profundidad, y la librería de paneles calcula dónde se superponen los paneles y qué secciones son visibles.

- El paquete PyXML ha pasado por varias versiones desde Python 2.0, y Python 2.1 incluye una versión actualizada del paquete `xml`. Algunos de los cambios notables incluyen soporte para Expat 1.2 y versiones posteriores, la capacidad de los analizadores Expat para manejar archivos en cualquier codificación soportada por Python, y varias correcciones de errores para SAX, DOM, y el módulo `minidom`.

- Ping también contribuyó con otro gancho para manejar excepciones no detectadas. `sys.excepthook()` se puede configurar como un objeto invocable. Cuando una excepción no es detectada por ningún bloque `try`…`except`, la excepción se pasará a `sys.excepthook()`, que puede hacer lo que quiera. En la Novena Conferencia de Python, Ping demostró una aplicación para este gancho: imprimir un rastreo extendido que no solo enumera los marcos de la pila, sino que también enumera los argumentos de la función y las variables locales para cada marco.

- Varias funciones del módulo `time`, como `asctime()` y `localtime()`, requieren un argumento de punto flotante que contiene el tiempo en segundos desde la época. El uso más común de estas funciones es trabajar con la hora actual, por lo que el argumento de punto flotante se ha hecho opcional; cuando no se proporciona un valor, se utilizará la hora actual. Por ejemplo, las entradas de archivos de registro suelen necesitar una cadena que contenga la hora actual; en Python 2.1, se puede utilizar `time.asctime()`, en lugar del más largo `time.asctime(time.localtime(time.time()))` que se requería anteriormente.

  Este cambio fue propuesto y aplicado por Thomas Wouters.

- El módulo `ftplib` ahora recupera por defecto los ficheros en modo pasivo, porque es más probable que el modo pasivo funcione desde detrás de un cortafuegos. Esta petición vino del sistema de seguimiento de errores de Debian, ya que otros paquetes de Debian utilizan `ftplib` para recuperar archivos y entonces no funcionan desde detrás de un cortafuegos. Se considera poco probable que esto cause problemas a nadie, porque Netscape utiliza por defecto el modo pasivo y poca gente se queja, pero si el modo pasivo no es adecuado para su aplicación o configuración de red, llame a `set_pasv(0)` en los objetos FTP para desactivar el modo pasivo.

- Se ha añadido soporte para el acceso a sockets sin procesar en el módulo `socket`, aportado por Grant Edwards.

- El módulo `pstats` contiene ahora un sencillo navegador de estadísticas interactivo para mostrar los perfiles de tiempo de los programas de Python, invocado cuando el módulo se ejecuta como un script. Contribuido por Eric S. Raymond.

- Se ha agregado una nueva función dependiente de la implementación, `sys._getframe([depth])`, para devolver un objeto de marco determinado de la pila de llamadas actual. `sys._getframe()` devuelve el marco en la parte superior de la pila de llamadas; si el argumento de entero opcional depth is supplied, the function returns the frame that is depth llama debajo de la parte superior de la pila. Por ejemplo, `sys._getframe(1)` devuelve el objeto de trama de la persona que llama.

  Esta función sólo está presente en CPython, no en Jython ni en la implementación de .NET. Utilízala para depurar, y resiste la tentación de ponerla en el código de producción.

## Otros cambios y correcciones

En Python 2.1 se hicieron relativamente pocos cambios pequeños debido al ciclo de publicación más corto. Una búsqueda en los registros de cambios de CVS muestra 117 parches aplicados y 136 errores corregidos; es probable que ambas cifras estén subestimadas. Algunos de los cambios más notables son:

- Ahora está disponible opcionalmente un asignador de objetos especializado, que debería ser más rápido que el sistema `malloc()` y tener menos sobrecarga de memoria. El asignador utiliza la función `malloc()` de C para obtener grandes reservas de memoria, y luego satisface las peticiones de memoria más pequeñas de estas reservas. Puede activarse proporcionando la opción `--with-pymalloc` al script configure; véase `Objects/obmalloc.c` para los detalles de la implementación.

  Los autores de los módulos de extensión de C deberían probar su código con el asignador de objetos activado, porque algún código incorrecto puede romperse, causando volcados del núcleo en tiempo de ejecución. Hay un montón de funciones de asignación de memoria en la API de C de Python que anteriormente eran sólo alias de `malloc()` y `free()` de la biblioteca de C, lo que significa que si accidentalmente llamabas a funciones que no coincidían, el error no se notaba. Cuando el asignador de objetos está habilitado, estas funciones ya no son alias de `malloc()` y `free()`, y llamar a la función incorrecta para liberar memoria te hará un volcado del núcleo. Por ejemplo, si la memoria fue asignada usando `PyMem_New()`, tiene que ser liberada usando `PyMem_Del()`, no `free()`. Unos cuantos módulos incluidos en Python han caído en la trampa y han tenido que ser corregidos; sin duda hay más módulos de terceros que tendrán el mismo problema.

  El asignador de objetos fue aportado por Vladimir Marangozov.

- La velocidad de la E/S de archivos orientada a líneas se ha mejorado porque la gente suele quejarse de su falta de velocidad, y porque a menudo se ha utilizado como referencia ingenua. El método `readline()` de los objetos de archivo ha sido reescrito para ser mucho más rápido. La cantidad exacta de la aceleración variará de una plataforma a otra dependiendo de la lentitud del método `getc()` de la biblioteca C, pero es alrededor del 66%, y potencialmente mucho más rápido en algunos sistemas operativos concretos. Tim Peters hizo gran parte de la evaluación comparativa y la codificación de este cambio, motivado por una discusión en comp.lang.python.

  También se ha añadido un nuevo módulo y método para objetos de archivo, aportado por Jeff Epler. El nuevo método, `xreadlines()`, es similar al ya existente `xrange()` incorporado. `xreadlines()` retorna un objeto de secuencia opaco que sólo admite ser iterado, leyendo una línea en cada iteración pero no leyendo todo el archivo en memoria como hace el método `readlines()` existente. Se usaría así:

      for line in sys.stdin.xreadlines():
          # ... do something for each line ...
          ...

  Para una discusión más completa de los cambios en la línea de E/S, véase el resumen de python-dev del 1 al 15 de enero de 2001 en https://mail.python.org/pipermail/python-dev/2001-January/.

- Se ha añadido un nuevo método, `popitem()`, a los diccionarios para permitir la iteración destructiva a través del contenido de un diccionario; esto puede ser más rápido para diccionarios grandes porque no hay necesidad de construir una lista que contenga todas las claves o valores. `D.popitem()` elimina un par aleatorio `(key, value)` del diccionario `D` y lo retorna como una 2-tupla. Esto fue implementado principalmente por Tim Peters y Guido van Rossum, después de una sugerencia y un parche preliminar de Moshe Zadka.

- Ahora los módulos pueden controlar qué nombres se importan cuando se utiliza `from module import *`, definiendo un atributo `__all__` que contiene una lista de nombres que se importarán. Una queja común es que si el módulo importa otros módulos como `sys` o `string`, `from module import *` los añadirá al espacio de nombres del módulo importador. Para arreglar esto, simplemente liste los nombres públicos en `__all__`:

      # List public names
      __all__ = ['Database', 'open']

  Una versión más estricta de este parche fue primero sugerida e implementada por Ben Wolfson, pero después de algunas discusiones de python-dev, una versión final más débil fue revisada.

- Al aplicar `repr()` a las cadenas, antes se utilizaban escapes octales para los caracteres no imprimibles; por ejemplo, una nueva línea era `'012'``Esto era un vestigio de la ascendencia de Python en C, pero hoy en día el octal tiene muy poco uso prácticoKa-Ping Yee sugirió usar escapes hexadecimales en lugar de octales, y usar los escapes ``n`, `t`, `r` para los caracteres apropiados, e implementó este nuevo formato.

- Los errores de sintaxis detectados en tiempo de compilación pueden ahora lanzar excepciones que contienen el nombre del archivo y el número de línea del error, un agradable efecto secundario de la reorganización del compilador realizada por Jeremy Hylton.

- Las extensiones C que importan otros módulos han sido cambiadas para usar `PyImport_ImportModule()`, lo que significa que usarán cualquier gancho de importación que haya sido instalado. Esto también se fomenta para las extensiones de terceros que necesitan importar algún otro módulo desde el código C.

- El tamaño de la base de datos de caracteres Unicode se redujo en otros 340K gracias a Fredrik Lundh.

- Se han aportado algunos puertos nuevos: MacOS X (por Steven Majewski), Cygwin (por Jason Tishler); RISCOS (por Dietmar Schwertberger); Unixware 7 (por Billy G. Allie).

Y hay la lista habitual de correcciones de errores menores, fugas de memoria menores, ediciones de docstrings, y otros ajustes, demasiado largos para que valga la pena detallarlos; vea los registros de CVS para los detalles completos si los quiere.

## Agradecimientos

El autor desea agradecer a las siguientes personas sus sugerencias sobre varios borradores de este artículo: Graeme Cross, David Goodger, Jay Graves, Michael Hudson, Marc-André Lemburg, Fredrik Lundh, Neil Schemenauer, Thomas Wouters.