Qué hay de nuevo en 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(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.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():
   # La siguiente línea es un error de sintaxis
   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:

   desde __future__ importar ámbitos anidados

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 solo
podía devolver 0 si eran iguales o +1 o -1 si no lo eran; el método no
podía generar una excepción o devolver nada más que un valor booleano.
Los usuarios de Python numérico a menudo encontraban que este modelo
era demasiado débil y restrictivo, porque en los programas de
procesamiento numérico para los que se usa Python numérico, sería más
útil poder realizar comparaciones elemento por elemento de dos
matrices, devolviendo una matriz que contenga los resultados de una
comparación dada para cada elemento. Si las dos matrices son de
diferentes tamaños, entonces la comparación tiene que poder generar
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 "cmp(A,B)" incorporada puede utilizar la rica maquinaria de
comparación y ahora acepta un argumento opcional que especifica qué
operación de comparación utilizar; esto se proporciona como una de las
cadenas ""<"", ""<="", "">"", "">="", ""=="" o ""!="". Si se llama sin
el tercer argumento opcional, "cmp()" solo devolverá -1, 0 o +1 como
en versiones anteriores de Python; de lo contrario, llamará al método
apropiado y puede devolver 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: el módulo regex
   está obsoleto; utilice el módulo re
   >>>

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

   advertencias.warn("la función X ya no es compatible")

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 agregar 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 utiliza el módulo "regex" y no desea perder tiempo en
convertirlo para que utilice el módulo "re" en este momento. La
advertencia se puede suprimir llamando a

   advertencias de importación
   warnings.filterwarnings(action = 'ignore',
   message='.*regex module is obsolete',
   category=DeprecationWarning,
   module = '__main__')

Esto agrega un filtro que se aplicará solo a las advertencias de la
clase "DeprecationWarning" activadas en el módulo "__main__" y aplica
una expresión regular para que coincida solo con el mensaje sobre que
el módulo "regex" está obsoleto y hará que se ignoren dichas
advertencias. Las advertencias también se pueden imprimir solo una
vez, imprimirse cada vez que se ejecuta el código infractor o
convertirse en excepciones que harán que el programa se detenga (a
menos que las excepciones se detecten de la manera 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)

   # Almacenar en caché el objeto devuelto
   _cache[x] = retval

   return retval

Esta versión funciona para cosas simples como números enteros, pero
tiene un efecto secundario: el diccionario "_cache" contiene una
referencia a los valores de retorno, por lo que nunca se desasignarán
hasta que el proceso de Python salga y limpie. Esto no es muy notorio
para los números enteros, pero si "f()" devuelve 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 permite escribir una función "memoize()" cuyo caché no mantiene
vivos los objetos, almacenando referencias débiles en el caché.

   _cache = {}
   def memoize(x):
   if _cache.has_key(x):
   obj = _cache[x]()
   # Si el objeto de referencia débil aún existe,
   # lo devuelve
   if obj no es None: return obj

   retval = f(x)

   # Almacena en caché una referencia débil
   _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 al que sólo hacen
referencia objetos proxy se desasigna), 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 se desasigna el objeto, intentar usar un proxy
provocará que se genere una excepción "weakref.ReferenceError".

   proxy = weakref.proxy(obj)
   proxy.attr # Equivalente a obj.attr
   proxy.meth() # Equivalente a obj.meth()
   del obj
   proxy.attr # lanza 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 pueden tener información arbitraria
adjunta. La gente solía usar cadenas de documentación para guardar
información sobre funciones y métodos, porque el atributo "__doc__"
era la única forma de adjuntar 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 al tener una cadena de documentación, y
en el marco de análisis SPARK de John Aycock, las cadenas de
documentación contienen partes de la gramática BNF que se analizarán.
Esta sobrecarga es desafortunada, ya que las cadenas de documentación
están realmente pensadas para guardar la documentación de una función;
por ejemplo, significa que no se pueden documentar adecuadamente las
funciones destinadas a un 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 Python normal; *can't* puede ser astuto y establecerlo en
una instancia "UserDict" o cualquier otro objeto aleatorio que se
comporte como una asignación.

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:

   >>> # Crea una estructura de datos recursiva
   ... L = [1,2,3]
   >>> L.append(L)
   >>> L # Muestra la salida predeterminada de Python
   [1, 2, 3, [...]]
   >>> # Usa pprint.pprint() como función de visualización
   ... 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
========================================

Una queja común de los usuarios de Python es que no existe un solo
catálogo de todos los módulos de Python existentes.  T. Middleton's
Vault of Parnassus en "www.vex.net/parnassus/" (borrado en febrero de
2009, disponible en Internet Archive Wayback Machine) fue uno de los
mayores catálogos de módulos de Python, pero registrar software en los
archivos es opcional, y a mucha gente no le importó.

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 contribuyó 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 de forma interactiva cadenas de
  documentación a HTML o texto. Como beneficio adicional,
  "Tools/scripts/pydoc", que ahora se instala automáticamente, utiliza
  "pydoc.py" para mostrar la documentación según el nombre de un
  módulo, paquete o clase de Python. Por ejemplo, "pydoc xml.dom"
  muestra lo siguiente:

     Documentación de la biblioteca de Python: paquete xml.dom en xml

     NOMBRE
     xml.dom: implementación del modelo de objetos de documento del W3C para Python.

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

     DESCRIPCIÓN
     La asignación de Python del modelo de objetos de documento está documentada en la
     Referencia de la biblioteca de Python en la sección sobre el paquete xml.dom.

     Este paquete contiene los siguientes módulos:
     ...

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

* Se agregaron dos módulos diferentes para pruebas unitarias a la
  biblioteca estándar. El módulo "doctest", aportado por Tim Peters,
  proporciona un marco de pruebas basado en la ejecución de ejemplos
  integrados en cadenas de documentación y la comparación de los
  resultados con la salida esperada. PyUnit, aportado 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
  Beck. Consulte https://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 se
  puede utilizar 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 compatibilidad con Expat
  1.2 y versiones posteriores, la capacidad de los analizadores de
  Expat para manejar archivos en cualquier codificación compatible con
  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 contenga
  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 vuelto opcional; cuando no se proporciona un
  valor, se utilizará la hora actual. Por ejemplo, las entradas de
  archivos de registro generalmente necesitan una cadena que contenga
  la hora actual; en Python 2.1, se puede utilizar "time.asctime()",
  en lugar del "time.asctime(time.localtime(time.time()))" más extenso
  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 "malloc()" del
  sistema y tener menos sobrecarga de memoria. El asignador utiliza la
  función "malloc()" de C para obtener grandes grupos de memoria y
  luego cumple con las solicitudes de memoria más pequeñas de estos
  grupos. Se puede habilitar proporcionando la opción "--with-
  pymalloc" al script **configure**; consulte "Objects/obmalloc.c"
  para obtener los detalles de implementación.

  Los autores de módulos de extensión de C deberían probar su código
  con el asignador de objetos habilitado, porque algún código
  incorrecto puede fallar, causando volcados de memoria 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 solo alias para "malloc()"
  y "free()" de la biblioteca de C, lo que significa que si
  accidentalmente llamabas a funciones que no coinciden, el error no
  sería perceptible. 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 dará un volcado de
  memoria. Por ejemplo, si la memoria se asignó usando "PyMem_New",
  debe liberarse usando "PyMem_Del()", no "free()". Algunos módulos
  incluidos con Python tuvieron problemas con esto y tuvieron que ser
  reparados; 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 un punto de referencia ingenuo. Por lo
  tanto, el método "readline()" de objetos de archivo se ha reescrito
  para que sea mucho más rápido. La cantidad exacta de la aceleración
  variará de una plataforma a otra dependiendo de lo lento que fuera
  el "getc()" de la biblioteca C, pero es de alrededor del 66% y
  potencialmente mucho más rápido en algunos sistemas operativos
  particulares. Tim Peters realizó gran parte de la evaluación
  comparativa y la codificación para este cambio, motivado por una
  discusión en comp.lang.python.

  También se agregó un nuevo módulo y método para objetos de archivo,
  aportado por Jeff Epler. El nuevo método, "xreadlines()", es similar
  al "xrange()" existente. "xreadlines()" devuelve un objeto de
  secuencia opaca que solo admite iteraciones, leyendo una línea en
  cada iteración, pero no leyendo el archivo completo en la memoria
  como lo hace el método "readlines()" existente. Lo usaría de esta
  manera:

     para la línea en sys.stdin.xreadlines():
     # ... hacer algo para cada línea ...
     ...

  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 agregó 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 devuelve como una tupla de 2. 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__":

     # Lista de nombres públicos
     __all__ = ['Base de datos', 'abierta']

  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áctico. Ka-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 se han modificado para
  utilizar "PyImport_ImportModule()", lo que significa que utilizarán
  cualquier gancho de importación que se haya instalado. Esto también
  se recomienda para extensiones de terceros que necesiten 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.
