Novedades de Python 2.5¶
- Autor
A.M. Kuchling
Este artículo explica las nuevas características de Python 2.5. La versión final de Python 2.5 está prevista para agosto de 2006; PEP 356 describe el calendario de publicación previsto.
Los cambios en Python 2.5 son una interesante mezcla de mejoras en el lenguaje y en las bibliotecas. Las mejoras de la biblioteca serán más importantes para la comunidad de usuarios de Python, creo, porque se han añadido varios paquetes muy útiles. Los nuevos módulos incluyen ElementTree para el procesamiento de XML (xml.etree
), el módulo de base de datos SQLite (sqlite
), y el módulo ctypes
para llamar a funciones C.
Los cambios en el lenguaje son de mediana importancia. Se han añadido algunas características nuevas y agradables, pero la mayoría de ellas no son características que vaya a utilizar todos los días. Las expresiones condicionales fueron finalmente añadidas al lenguaje usando una nueva sintaxis; ver sección PEP 308: Expresiones condicionales. La nueva sentencia “with
” facilitará la escritura de código de limpieza (sección PEP 343: La declaración «con). Ahora se pueden pasar valores a los generadores (sección PEP 342: Nuevas funciones del generador). Las importaciones son ahora visibles como absolutas o relativas (sección PEP 328: Importaciones absolutas y relativas). Se han mejorado algunos casos de manejo de excepciones (sección PEP 341: Try/except/finally unificados). Todas estas mejoras merecen la pena, pero son mejoras de una u otra característica específica del lenguaje; ninguna de ellas es una modificación amplia de la semántica de Python.
Además de las adiciones al lenguaje y a la biblioteca, se han realizado otras mejoras y correcciones de errores en todo el árbol de código fuente. Una búsqueda en los registros de cambios del SVN revela que se aplicaron 353 parches y se corrigieron 458 errores entre Python 2.4 y 2.5. (Es probable que ambas cifras estén subestimadas)
Este artículo no pretende ser una especificación completa de las nuevas características; en su lugar, los cambios se introducen brevemente utilizando ejemplos útiles. Para obtener todos los detalles, siempre debes consultar la documentación de Python 2.5 en https://docs.python.org. Si quieres entender la implementación completa y los fundamentos del diseño, consulta el PEP de una nueva característica en particular.
Son bienvenidos los comentarios, las sugerencias y los informes de errores para este documento; por favor, envíelos por correo electrónico al autor o abra un error en el rastreador de errores de Python.
PEP 308: Expresiones condicionales¶
Durante mucho tiempo, la gente ha solicitado una forma de escribir expresiones condicionales, que son expresiones que devuelven el valor A o el valor B dependiendo de si un valor booleano es verdadero o falso. Una expresión condicional le permite escribir una única sentencia de asignación que tiene el mismo efecto que la siguiente:
if condition:
x = true_value
else:
x = false_value
Ha habido interminables y tediosas discusiones sobre la sintaxis tanto en python-dev como en comp.lang.python. Incluso se llevó a cabo una votación en la que se descubrió que la mayoría de los votantes querían expresiones condicionales de alguna forma, pero no había ninguna sintaxis que fuera preferida por una clara mayoría. Los candidatos incluían cond ? true_v : false_v
, if cond then true_v else false_v
, y otras 16 variaciones.
Guido van Rossum eligió finalmente una sintaxis sorprendente:
x = true_value if condition else false_value
La evaluación sigue siendo perezosa como en las expresiones booleanas existentes, por lo que el orden de evaluación salta un poco. La expresión condición del medio se evalúa primero, y la expresión valor_verdadero se evalúa sólo si la condición es verdadera. Del mismo modo, la expresión valor_falso sólo se evalúa cuando la condición es falsa.
Esta sintaxis puede parecer extraña y retrógrada; ¿por qué la condición va en el medio de la expresión, y no en la parte delantera como en c ? x : y
de C? La decisión se comprobó aplicando la nueva sintaxis a los módulos de la biblioteca estándar y viendo cómo se leía el código resultante. En muchos casos en los que se utiliza una expresión condicional, un valor parece ser el «caso común» y otro valor es un «caso excepcional», utilizado sólo en las raras ocasiones en las que no se cumple la condición. La sintaxis condicional hace que este patrón sea un poco más obvio:
contents = ((doc + '\n') if doc else '')
Leo la afirmación anterior en el sentido de que «aquí se asigna a contents un valor de doc+'\n'
; a veces doc está vacío, en cuyo caso especial se devuelve una cadena vacía» Dudo que use expresiones condicionales muy a menudo donde no hay un caso común y no común claro.
Hubo alguna discusión sobre si el lenguaje debería requerir rodear las expresiones condicionales con paréntesis. Se tomó la decisión de no requerir paréntesis en la gramática del lenguaje Python, pero como una cuestión de estilo creo que siempre deberías usarlos. Considere estas dos declaraciones:
# First version -- no parens
level = 1 if logging else 0
# Second version -- with parens
level = (1 if logging else 0)
En la primera versión, creo que el ojo de un lector podría agrupar la sentencia en “nivel = 1”, “si registro”, “si no 0”, y pensar que la condición decide si se realiza la asignación a nivel. La segunda versión se lee mejor, en mi opinión, porque deja claro que la asignación se realiza siempre y que se está eligiendo entre dos valores.
Otra razón para incluir los paréntesis: algunas combinaciones extrañas de comprensiones de listas y lambdas podrían parecer expresiones condicionales incorrectas. Véase PEP 308 para algunos ejemplos. Si pone paréntesis alrededor de sus expresiones condicionales, no se encontrará con este caso.
Ver también
- PEP 308 - Expresiones condicionales
PEP escrito por Guido van Rossum y Raymond D. Hettinger; implementado por Thomas Wouters.
PEP 309: Aplicación parcial de funciones¶
El módulo functools
está destinado a contener herramientas para la programación de estilo funcional.
Una herramienta útil de este módulo es la función partial()
. Para los programas escritos en un estilo funcional, a veces querrá construir variantes de funciones existentes que tengan algunos de los parámetros rellenados. Considere una función Python f(a, b, c)
; podría crear una nueva función g(b, c)
que fuera equivalente a f(1, b, c)
. Esto se llama «aplicación parcial de funciones».
parcial()
toma los argumentos (function, arg1, arg2, ... kwarg1=valor1, kwarg2=valor2)
. El objeto resultante es invocable, por lo que puedes llamarlo para invocar la función con los argumentos rellenados.
He aquí un pequeño pero realista ejemplo:
import functools
def log (message, subsystem):
"Write the contents of 'message' to the specified subsystem."
print '%s: %s' % (subsystem, message)
...
server_log = functools.partial(log, subsystem='server')
server_log('Unable to open socket')
Aquí hay otro ejemplo, de un programa que utiliza PyGTK. Aquí se está construyendo dinámicamente un menú emergente sensible al contexto. El callback proporcionado para la opción de menú es una versión parcialmente aplicada del método open_item()
, donde se ha proporcionado el primer argumento
...
class Application:
def open_item(self, path):
...
def init (self):
open_func = functools.partial(self.open_item, item_path)
popup_menu.append( ("Open", open_func, 1) )
Otra función del módulo functools
es la función update_wrapper(wrapper, wrapped)
que le ayuda a escribir decoradores con un buen comportamiento. update_wrapper()
copia el nombre, el módulo y el atributo docstring a una función wrapper para que las trazas dentro de la función envuelta sean más fáciles de entender. Por ejemplo, puedes escribir:
def my_decorator(f):
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
functools.update_wrapper(wrapper, f)
return wrapper
wraps()
es un decorador que se puede utilizar dentro de sus propios decoradores para copiar la información de la función envuelta. Una versión alternativa del ejemplo anterior sería:
def my_decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwds):
print 'Calling decorated function'
return f(*args, **kwds)
return wrapper
Ver también
- PEP 309 - Aplicación parcial de funciones
PEP propuesto y escrito por Peter Harris; implementado por Hye-Shik Chang y Nick Coghlan, con adaptaciones de Raymond Hettinger.
PEP 314: Metadatos para paquetes de software Python v1.1¶
Se ha añadido a Distutils un sencillo soporte de dependencias. La función setup()
ahora tiene parámetros de palabras clave requires
, provides
y obsoletes
. Cuando se construye una distribución de origen utilizando el comando sdist
, la información de las dependencias se registrará en el archivo PKG-INFO
.
Otro nuevo parámetro de palabra clave es download_url
, que debe establecerse como una URL para el código fuente del paquete. Esto significa que ahora es posible buscar una entrada en el índice de paquetes, determinar las dependencias de un paquete y descargar los paquetes necesarios.
VERSION = '1.0'
setup(name='PyPackage',
version=VERSION,
requires=['numarray', 'zlib (>=1.1.4)'],
obsoletes=['OldPackage']
download_url=('http://www.example.com/pypackage/dist/pkg-%s.tar.gz'
% VERSION),
)
Otra nueva mejora en el índice de paquetes de Python en https://pypi.org es el almacenamiento de archivos fuente y binarios de un paquete. El nuevo comando upload de Distutils subirá un paquete al repositorio.
Antes de poder subir un paquete, debes ser capaz de construir una distribución usando el comando sdist de Distutils. Una vez que funcione, puedes ejecutar python setup.py upload
para añadir tu paquete al archivo PyPI. Opcionalmente puedes firmar el paquete con GPG suministrando las opciones --sign
y --identity
.
La carga de paquetes fue implementada por Martin von Löwis y Richard Jones.
Ver también
- PEP 314 - Metadatos para paquetes de software Python v1.1
PEP propuesto y redactado por A.M. Kuchling, Richard Jones y Fred Drake; aplicado por Richard Jones y Fred Drake.
PEP 328: Importaciones absolutas y relativas¶
La parte más sencilla de PEP 328 se implementó en Python 2.4: los paréntesis podían utilizarse ahora para encerrar los nombres importados de un módulo utilizando la sentencia from ... import ...
, facilitando la importación de muchos nombres diferentes.
La parte más complicada se ha implementado en Python 2.5: la importación de un módulo puede especificarse para utilizar importaciones absolutas o relativas al paquete. El plan es hacer que las importaciones absolutas sean el valor por defecto en futuras versiones de Python.
Digamos que tienes un directorio de paquetes como este:
pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py
Esto define un paquete llamado pkg
que contiene los submódulos pkg.main
y pkg.string
.
Considera el código del módulo main.py
. ¿Qué ocurre si ejecuta la sentencia importar cadena
? En Python 2.4 y anteriores, primero buscará en el directorio del paquete para realizar una importación relativa, encuentra pkg/string.py
, importa el contenido de ese archivo como el módulo pkg.string
, y ese módulo se vincula al nombre string
en el espacio de nombres del módulo pkg.main
.
Eso está bien si pkg.string
era lo que querías. ¿Pero qué pasa si quieres el módulo estándar de Python string
? No hay una forma limpia de ignorar pkg.string
y buscar el módulo estándar; generalmente tienes que mirar el contenido de sys.modules
, lo cual es ligeramente sucio. El paquete py.std
de Holger Krekel proporciona una forma más ordenada de realizar importaciones desde la biblioteca estándar, import py; py.std.string.join()
, pero ese paquete no está disponible en todas las instalaciones de Python.
La lectura de código que depende de importaciones relativas también es menos clara, porque un lector puede confundirse sobre qué módulo, cadena
o cadena.pkg
, se pretende utilizar. Los usuarios de Python aprendieron pronto a no duplicar los nombres de los módulos de la biblioteca estándar en los nombres de los submódulos de sus paquetes, pero no puedes protegerte de que el nombre de tu submódulo se utilice para un nuevo módulo añadido en una futura versión de Python.
En Python 2.5, puedes cambiar el comportamiento de import
a importaciones absolutas usando una directiva from __future__ import absolute_import
. Este comportamiento de importación absoluta será el predeterminado en una versión futura (probablemente Python 2.7). Una vez que las importaciones absolutas sean el valor por defecto, import string
siempre encontrará la versión de la biblioteca estándar. Se sugiere que los usuarios comiencen a usar importaciones absolutas tanto como sea posible, así que es preferible comenzar a escribir de pkg import string
en su código.
Las importaciones relativas siguen siendo posibles añadiendo un punto inicial al nombre del módulo cuando se utiliza la forma from ... import
:
# Import names from pkg.string
from .string import name1, name2
# Import pkg.string
from . import string
Esto importa el módulo string
relativo al paquete actual, así que en pkg.main
esto importará nombre1 y nombre2 de pkg.string
. Los puntos iniciales adicionales realizan la importación relativa empezando por el padre del paquete actual. Por ejemplo, el código en el módulo A.B.C
puede hacer:
from . import D # Imports A.B.D
from .. import E # Imports A.E
from ..F import G # Imports A.F.G
Los puntos suspensivos no pueden usarse con la forma importar nombre de modelo
de la sentencia import, sólo con la forma de ... import
.
Ver también
- PEP 328 - Importaciones: Multilínea y Absoluto/Relativo
PEP escrito por Aahz; implementado por Thomas Wouters.
- https://pylib.readthedocs.io/
La biblioteca py de Holger Krekel, que contiene el paquete
py.std
.
PEP 338: Ejecutando Módulos como Scripts¶
El conmutador -m
añadido en Python 2.4 para ejecutar un módulo como un script ganó algunas habilidades más. En lugar de estar implementado en código C dentro del intérprete de Python, el interruptor ahora utiliza una implementación en un nuevo módulo, runpy
.
El módulo runpy
implementa un mecanismo de importación más sofisticado de forma que ahora es posible ejecutar módulos en un paquete como pychecker.checker
. El módulo también soporta mecanismos de importación alternativos como el módulo zipimport
. Esto significa que puede añadir la ruta de un archivo .zip a sys.path
y luego utilizar el modificador -m
para ejecutar el código del archivo.
Ver también
- PEP 338 - Ejecución de módulos como scripts
PEP escrito e implementado por Nick Coghlan.
PEP 341: Try/except/finally unificados¶
Hasta la versión 2.5 de Python, la sentencia try
tenía dos variantes. Podías usar un bloque finally
para asegurarte de que el código se ejecutaba siempre, o uno o más bloques except
para capturar excepciones específicas. No podías combinar ambos bloques except
y un bloque finally
, porque generar el bytecode correcto para la versión combinada era complicado y no estaba claro cuál debía ser la semántica de la sentencia combinada.
Guido van Rossum pasó algún tiempo trabajando con Java, que sí soporta el equivalente de combinar bloques except
y un bloque finally
, y esto aclaró lo que debería significar la declaración. En Python 2.5, ahora se puede escribir:
try:
block-1 ...
except Exception1:
handler-1 ...
except Exception2:
handler-2 ...
else:
else-block
finally:
final-block
Se ejecuta el código del bloque-1. Si el código lanza una excepción, se comprueban los distintos bloques except
: si la excepción es de clase Exception1
, se ejecuta handler-1; en caso contrario, si es de clase Exception2
, se ejecuta handler-2, y así sucesivamente. Si no se produce ninguna excepción, se ejecuta el bloque else.
No importa lo que haya sucedido previamente, el bloque final se ejecuta una vez que el bloque de código se ha completado y se han manejado las excepciones planteadas. Incluso si hay un error en un manejador de excepciones o en el bloque else y se lanza una nueva excepción, el código del bloque final se sigue ejecutando.
Ver también
- PEP 341 - Unificar try-except y try-finally
PEP escrito por Georg Brandl; implementación por Thomas Lee.
PEP 342: Nuevas funciones del generador¶
Python 2.5 añade una forma sencilla de pasar valores a un generador. Tal y como se introdujo en Python 2.3, los generadores sólo producen salida; una vez que se invoca el código de un generador para crear un iterador, no hay forma de pasar ninguna información nueva a la función cuando se reanuda su ejecución. A veces, la capacidad de pasar alguna información sería útil. Las soluciones más ingeniosas para esto incluyen hacer que el código del generador mire a una variable global y luego cambie el valor de la variable global, o pasar algún objeto mutable que los llamadores luego modifiquen.
Para refrescar la memoria de los generadores básicos, he aquí un ejemplo sencillo:
def counter (maximum):
i = 0
while i < maximum:
yield i
i += 1
Cuando se llama a contador(10)
, el resultado es un iterador que devuelve los valores de 0 a 9. Al encontrar la sentencia yield
, el iterador devuelve el valor proporcionado y suspende la ejecución de la función, preservando las variables locales. La ejecución se reanuda en la siguiente llamada al método next()
del iterador, retomando después de la sentencia yield
.
En Python 2.3, yield
era una declaración; no devolvía ningún valor. En 2.5, yield
es ahora una expresión, que devuelve un valor que se puede asignar a una variable o que se puede operar de otra manera:
val = (yield i)
Te recomiendo que siempre pongas paréntesis alrededor de una expresión yield
cuando estés haciendo algo con el valor devuelto, como en el ejemplo anterior. Los paréntesis no siempre son necesarios, pero es más fácil añadirlos siempre en lugar de tener que recordar cuándo son necesarios.
(PEP 342 explica las reglas exactas, que consisten en que una expresión yield
debe ir siempre entre paréntesis, excepto cuando ocurre en la expresión de nivel superior en el lado derecho de una asignación. Esto significa que puedes escribir val = yield i
pero tienes que usar paréntesis cuando hay una operación, como en val = (yield i) + 12
)
Los valores se envían a un generador llamando a su método send(value)
. El código del generador se reanuda y la expresión yield
devuelve el valor especificado. Si se llama al método regular next()
, la expresión yield
devuelve None
.
Aquí está el ejemplo anterior, modificado para permitir cambiar el valor del contador interno.
def counter (maximum):
i = 0
while i < maximum:
val = (yield i)
# If value provided, change counter
if val is not None:
i = val
else:
i += 1
Y aquí hay un ejemplo de cambio de contador:
>>> it = counter(10)
>>> print it.next()
0
>>> print it.next()
1
>>> print it.send(8)
8
>>> print it.next()
9
>>> print it.next()
Traceback (most recent call last):
File "t.py", line 15, in ?
print it.next()
StopIteration
yield
normalmente devolverá None
, por lo que siempre debes comprobar este caso. No utilices su valor en las expresiones sin más, a menos que estés seguro de que el método send()
será el único utilizado para reanudar tu función generadora.
Además de send()
, hay otros dos nuevos métodos en los generadores:
throw(type, value=None, traceback=None)
se utiliza para lanzar una excepción dentro del generador; la excepción es lanzada por la expresiónyield
donde la ejecución del generador se pausa.close()
lanza una nueva excepciónGeneratorExit
dentro del generador para terminar la iteración. Al recibir esta excepción, el código del generador debe lanzarGeneratorExit
oStopIteration
. Capturar la excepciónGeneratorExit
y devolver un valor es ilegal y provocará unRuntimeError
; si la función lanza alguna otra excepción, esa excepción se propaga a quien la llama.close()
también será llamado por el recolector de basura de Python cuando el generador sea recolectado.Si necesitas ejecutar código de limpieza cuando se produce un
GeneratorExit
, te sugiero que utilices un conjuntotry: ... finally:
en lugar de atraparGeneratorExit
.
El efecto acumulativo de estos cambios es que los generadores pasan de ser productores unidireccionales de información a ser tanto productores como consumidores.
Los generadores también se convierten en corutinas, una forma más generalizada de subrutinas. Las subrutinas se introducen en un punto y se salen en otro (la parte superior de la función, y una declaración return
), pero las coroutines pueden introducirse, salirse y reanudarse en muchos puntos diferentes (las declaraciones yield
). Tendremos que descubrir patrones para usar coroutines de forma efectiva en Python.
La adición del método close()
tiene un efecto secundario que no es obvio. close()
es llamado cuando un generador es recogido por la basura, lo que significa que el código del generador tiene una última oportunidad de ejecutarse antes de que el generador sea destruido. Esta última oportunidad significa que ahora se puede garantizar que las sentencias intentar...finalmente
en los generadores funcionen; la cláusula finally
ahora siempre tendrá una oportunidad de ejecutarse. Por lo tanto, se ha eliminado la restricción sintáctica que impedía mezclar sentencias yield
con un conjunto try...finally
. Esto parece una trivialidad menor del lenguaje, pero el uso de generadores y try...finally
es realmente necesario para implementar la sentencia with
descrita por PEP 343. Veré esta nueva sentencia en la siguiente sección.
Otro efecto aún más esotérico de este cambio: antes, el atributo gi_frame
de un generador era siempre un objeto frame. Ahora es posible que gi_frame
sea None
una vez que el generador se ha agotado.
Ver también
- PEP 342 - Coroutines mediante generadores mejorados
PEP escrito por Guido van Rossum y Phillip J. Eby; implementado por Phillip J. Eby. Incluye ejemplos de algunos usos más sofisticados de los generadores como coroutines.
Versiones anteriores de estas características fueron propuestas en PEP 288 por Raymond Hettinger y PEP 325 por Samuele Pedroni.
- https://en.wikipedia.org/wiki/Coroutine
La entrada de Wikipedia para las coroutines.
- http://www.sidhe.org/~dan/blog/archivos/000178.html
Una explicación de las coroutines desde el punto de vista de Perl, escrita por Dan Sugalski.
PEP 343: La declaración «con¶
La sentencia “with
” aclara el código que antes utilizaba bloques try...finally
” para asegurar que se ejecuta el código de limpieza. En esta sección, hablaré de la sentencia tal y como se utiliza habitualmente. En la siguiente sección, examinaré los detalles de la implementación y mostraré cómo escribir objetos para usar con esta sentencia.
La declaración “with
” es una nueva estructura de flujo de control cuya estructura básica es:
with expression [as variable]:
with-block
La expresión se evalúa y debe dar como resultado un objeto que soporte el protocolo de gestión de contextos (es decir, que tenga los métodos __enter__()
y __exit__()
).
El __enter__()
del objeto es llamado antes de que se ejecute with-block y por lo tanto puede ejecutar código de configuración. También puede devolver un valor ligado al nombre variable, si se da. (Observe cuidadosamente que a variable no se le asigna el resultado de la expresión)
Una vez finalizada la ejecución del with-block, se llama al método __exit__()
del objeto, incluso si el bloque lanzó una excepción, y por lo tanto puede ejecutar código de limpieza.
Para habilitar la declaración en Python 2.5, debe añadir la siguiente directiva a su módulo:
from __future__ import with_statement
La declaración siempre estará habilitada en Python 2.6.
Algunos objetos estándar de Python soportan ahora el protocolo de gestión de contextos y pueden utilizarse con la sentencia “with
””. Los objetos de archivo son un ejemplo:
with open('/etc/passwd', 'r') as f:
for line in f:
print line
... more processing code ...
Después de que esta sentencia se haya ejecutado, el objeto archivo en f se habrá cerrado automáticamente, incluso si el bucle for
lanzó una excepción a mitad del bloque.
Nota
En este caso, f es el mismo objeto creado por open()
, porque file.__enter__()
devuelve self.
Los bloqueos y las variables de condición del módulo threading
también soportan la sentencia “with
”:
lock = threading.Lock()
with lock:
# Critical section of code
...
El bloqueo se adquiere antes de que se ejecute el bloque y siempre se libera una vez que el bloque se ha completado.
La nueva función localcontext()
del módulo decimal
facilita el guardado y la restauración del contexto decimal actual, que encapsula las características de precisión y redondeo deseadas para los cálculos:
from decimal import Decimal, Context, localcontext
# Displays with default precision of 28 digits
v = Decimal('578')
print v.sqrt()
with localcontext(Context(prec=16)):
# All code in this block uses a precision of 16 digits.
# The original context is restored on exiting the block.
print v.sqrt()
Redacción de Gestores de Contexto¶
Bajo el capó, la sentencia “with
” es bastante complicada. La mayoría de la gente sólo utilizará “with
” en compañía de objetos existentes y no necesita conocer estos detalles, así que puedes saltarte el resto de esta sección si quieres. Los autores de nuevos objetos necesitarán entender los detalles de la implementación subyacente y deberían seguir leyendo.
Una explicación de alto nivel del protocolo de gestión del contexto es:
La expresión se evalúa y debe dar como resultado un objeto llamado «gestor de contexto». El gestor de contexto debe tener métodos
__enter__()
y__exit__()
.Se llama al método
__enter__()
del gestor de contexto. El valor devuelto se asigna a VAR. Si no está presente la cláusula'as VAR'
, el valor simplemente se descarta.Se ejecuta el código en BLOQUE.
Si BLOCK lanza una excepción, se llama a
__exit__(type, value, traceback)
con los detalles de la excepción, los mismos valores devueltos porsys.exc_info()
. El valor de retorno del método controla si la excepción se vuelve a lanzar: cualquier valor falso vuelve a lanzar la excepción, yTrue
resultará en suprimirla. Sólo en raras ocasiones querrá suprimir la excepción, porque si lo hace el autor del código que contiene la declaración “with
” nunca se dará cuenta de que algo ha ido mal.Si BLOCK no lanzó una excepción, el método
__exit__()
sigue siendo llamado, pero type, value, y traceback son todosNone
.
Pensemos en un ejemplo. No presentaré un código detallado, sino que sólo esbozaré los métodos necesarios para una base de datos que soporte transacciones.
(Para quienes no estén familiarizados con la terminología de las bases de datos: un conjunto de cambios en la base de datos se agrupa en una transacción. Las transacciones pueden ser confirmadas, lo que significa que todos los cambios se escriben en la base de datos, o revertidas, lo que significa que todos los cambios se descartan y la base de datos no se modifica. Consulte cualquier libro de texto sobre bases de datos para obtener más información)
Supongamos que hay un objeto que representa una conexión a la base de datos. Nuestro objetivo será permitir que el usuario escriba código como este:
db_connection = DatabaseConnection()
with db_connection as cursor:
cursor.execute('insert into ...')
cursor.execute('delete from ...')
# ... more operations ...
La transacción debe ser confirmada si el código en el bloque se ejecuta sin problemas o revertida si hay una excepción. Aquí está la interfaz básica para DatabaseConnection
que voy a asumir:
class DatabaseConnection:
# Database interface
def cursor (self):
"Returns a cursor object and starts a new transaction"
def commit (self):
"Commits current transaction"
def rollback (self):
"Rolls back current transaction"
El método __enter__()
es bastante sencillo, ya que sólo hay que iniciar una nueva transacción. Para esta aplicación el objeto cursor resultante sería un resultado útil, por lo que el método lo devolverá. El usuario puede entonces añadir as cursor
a su sentencia “with
” para ligar el cursor a un nombre de variable.
class DatabaseConnection:
...
def __enter__ (self):
# Code to start a new transaction
cursor = self.cursor()
return cursor
El método __exit__()
es el más complicado porque es donde hay que hacer la mayor parte del trabajo. El método tiene que comprobar si se produjo una excepción. Si no hubo ninguna excepción, la transacción es confirmada. La transacción es revertida si hubo una excepción.
En el código de abajo, la ejecución simplemente caerá al final de la función, devolviendo el valor por defecto de None
. None
es falso, por lo que la excepción se volverá a lanzar automáticamente. Si lo desea, puede ser más explícito y añadir una declaración return
en el lugar marcado.
class DatabaseConnection:
...
def __exit__ (self, type, value, tb):
if tb is None:
# No exception, so commit
self.commit()
else:
# Exception occurred, so rollback.
self.rollback()
# return False
El módulo contextlib¶
El nuevo módulo contextlib
proporciona algunas funciones y un decorador que son útiles para escribir objetos para usar con la sentencia “with
”.
El decorador se llama contextmanager()
, y permite escribir una única función generadora en lugar de definir una nueva clase. El generador debe producir exactamente un valor. El código hasta la palabra clave yield
se ejecutará como el método __enter__()
, y el valor producido será el valor de retorno del método que se vinculará a la variable en la cláusula with
de la sentencia as
, si existe. El código después de yield
se ejecutará en el método __exit__()
. Cualquier excepción lanzada en el bloque será lanzada por la sentencia yield
.
Nuestro ejemplo de base de datos de la sección anterior podría escribirse utilizando este decorador como:
from contextlib import contextmanager
@contextmanager
def db_transaction (connection):
cursor = connection.cursor()
try:
yield cursor
except:
connection.rollback()
raise
else:
connection.commit()
db = DatabaseConnection()
with db_transaction(db) as cursor:
...
El módulo contextlib
también tiene una función anidada(mgr1, mgr2, ...)
que combina varios gestores de contexto para que no sea necesario escribir sentencias “with
” anidadas. En este ejemplo, la única sentencia “with`
inicia una transacción de base de datos y adquiere un bloqueo de hilo:
lock = threading.Lock()
with nested (db_transaction(db), lock) as (cursor, locked):
...
Por último, la función closing(object)
devuelve el objeto para que pueda ser vinculado a una variable, y llama a object.close
al final del bloque.
import urllib, sys
from contextlib import closing
with closing(urllib.urlopen('http://www.yahoo.com')) as f:
for line in f:
sys.stdout.write(line)
Ver también
- PEP 343 - La declaración «con»
PEP escrito por Guido van Rossum y Nick Coghlan; implementado por Mike Bland, Guido van Rossum y Neal Norwitz. El PEP muestra el código generado para una sentencia “
with
”, que puede ser útil para aprender cómo funciona la sentencia.
La documentación del módulo contextlib
.
PEP 352: Las excepciones como clases de nuevo estilo¶
Las clases de excepción ahora pueden ser clases de nuevo estilo, no sólo clases clásicas, y la clase incorporada Exception
y todas las excepciones incorporadas estándar (NameError
, ValueError
, etc.) son ahora clases de nuevo estilo.
La jerarquía de herencia de las excepciones se ha reordenado un poco. En 2.5, las relaciones de herencia son:
BaseException # New in Python 2.5
|- KeyboardInterrupt
|- SystemExit
|- Exception
|- (all other current built-in exceptions)
Esta reorganización se hizo porque la gente a menudo quiere atrapar todas las excepciones que indican errores del programa. KeyboardInterrupt
y SystemExit
no son errores, sin embargo, y por lo general representan una acción explícita como el usuario pulsando Control-C o el código llamando a sys.exit()
. Una simple except:
atrapará todas las excepciones, por lo que comúnmente se necesita listar KeyboardInterrupt
y SystemExit
para volver a lanzarlas. El patrón habitual es:
try:
...
except (KeyboardInterrupt, SystemExit):
raise
except:
# Log error...
# Continue running program...
En Python 2.5, ahora puedes escribir except Exception
para conseguir el mismo resultado, capturando todas las excepciones que suelen indicar errores pero dejando KeyboardInterrupt
y SystemExit
en paz. Como en versiones anteriores, un except:
desnudo sigue capturando todas las excepciones.
El objetivo de Python 3.0 es requerir que cualquier clase lanzada como excepción derive de BaseException
o de algún descendiente de BaseException
, y las futuras versiones de la serie Python 2.x pueden empezar a imponer esta restricción. Por lo tanto, sugiero que empieces a hacer que todas tus clases de excepción deriven de Exception
ahora. Se ha sugerido que la forma desnuda except:
sea eliminada en Python 3.0, pero Guido van Rossum no ha decidido si hacerlo o no.
El lanzamiento de cadenas como excepciones, como en la declaración raise "Error occurred"
, está obsoleto en Python 2.5 y provocará una advertencia. El objetivo es poder eliminar la función de excepción de cadena en algunas versiones.
Ver también
- PEP 352 - Superclase necesaria para las excepciones
PEP escrito por Brett Cannon y Guido van Rossum; implementado por Brett Cannon.
PEP 353: Uso de ssize_t como tipo de índice¶
Un amplio cambio en la API C de Python, que utiliza una nueva definición de tipo Py_ssize_t
en lugar de int
, permitirá al intérprete manejar más datos en plataformas de 64 bits. Este cambio no afecta a la capacidad de Python en plataformas de 32 bits.
Varias partes del intérprete de Python utilizaban el tipo int
de C para almacenar tamaños o recuentos; por ejemplo, el número de elementos de una lista o tupla se almacenaba en un int
. Los compiladores de C para la mayoría de las plataformas de 64 bits siguen definiendo int
como un tipo de 32 bits, lo que significa que las listas sólo pueden contener hasta 2**31 - 1
= 2147483647 elementos. (En realidad, hay algunos modelos de programación diferentes que los compiladores de C de 64 bits pueden utilizar – véase http://www.unix.org/version2/whatsnew/lp64_wp.html para una discusión – pero el modelo más comúnmente disponible deja int
como de 32 bits)
Un límite de 2147483647 elementos no importa realmente en una plataforma de 32 bits porque te quedarás sin memoria antes de alcanzar el límite de longitud. Cada elemento de la lista requiere espacio para un puntero, que es de 4 bytes, más espacio para un PyObject
que representa el elemento. 2147483647*4 ya son más bytes de los que puede contener un espacio de direcciones de 32 bits.
Sin embargo, es posible direccionar esa cantidad de memoria en una plataforma de 64 bits. Los punteros para una lista de ese tamaño sólo requerirían 16 GiB de espacio, por lo que no es descabellado que los programadores de Python puedan construir listas tan grandes. Por lo tanto, el intérprete de Python tuvo que ser cambiado para usar algún tipo diferente a int
, y este será un tipo de 64 bits en plataformas de 64 bits. El cambio causará incompatibilidades en las máquinas de 64 bits, por lo que se consideró que valía la pena hacer la transición ahora, mientras el número de usuarios de 64 bits es todavía relativamente pequeño. (En 5 o 10 años, puede que todos estemos en máquinas de 64 bits, y la transición sería entonces más dolorosa)
Este cambio afecta en mayor medida a los autores de módulos de extensión de C. Las cadenas de Python y los tipos contenedores como las listas y las tuplas utilizan ahora Py_ssize_t
para almacenar su tamaño. Funciones como PyList_Size()
ahora devuelven Py_ssize_t
. Por lo tanto, el código de los módulos de extensión puede necesitar cambiar algunas variables a Py_ssize_t
.
Las funciones PyArg_ParseTuple()
y Py_BuildValue()
tienen un nuevo código de conversión, n
, para Py_ssize_t
. Las funciones PyArg_ParseTuple()
s#
y t#
siguen devolviendo int
por defecto, pero puedes definir la macro PY_SSIZE_T_CLEAN
antes de incluir Python.h
para que devuelvan Py_ssize_t
.
PEP 353 tiene una sección sobre directrices de conversión que los autores de extensiones deberían leer para aprender a soportar plataformas de 64 bits.
Ver también
- PEP 353 - Uso de ssize_t como tipo de índice
PEP escrito y aplicado por Martin von Löwis.
PEP 357: El método “__index__”¶
Los desarrolladores de NumPy tenían un problema que sólo podía resolverse añadiendo un nuevo método especial, __index__()
. Cuando se utiliza la notación de trozos, como en [start:stop:step]
, los valores de los índices start, stop y step deben ser todos enteros o enteros largos. NumPy define una variedad de tipos de enteros especializados que corresponden a enteros sin signo y con signo de 8, 16, 32 y 64 bits, pero no había forma de señalar que estos tipos pudieran usarse como índices de trozos.
El rebanado no puede utilizar el método __int__()
existente porque ese método también se utiliza para implementar la coerción a enteros. Si el rebanado utilizara __int__()
, los números de punto flotante también se convertirían en índices de rebanada legales y eso es claramente un comportamiento indeseable.
En su lugar, se ha añadido un nuevo método especial llamado __index__()
. No toma argumentos y devuelve un entero que da el índice de corte a utilizar. Por ejemplo:
class C:
def __index__ (self):
return self.value
El valor devuelto debe ser un entero de Python o un entero largo. El intérprete comprobará que el tipo devuelto es correcto, y lanza un TypeError
si no se cumple este requisito.
Se ha añadido la correspondiente ranura nb_index
a la estructura PyNumberMethods
de nivel C para que las extensiones C puedan implementar este protocolo. El código de la extensión puede utilizar PyNumber_Index(obj)
para llamar a la función __index__()
y obtener su resultado.
Ver también
- PEP 357 - Permitir el uso de cualquier objeto para rebanar
PEP escrito e implementado por Travis Oliphant.
Otros cambios lingüísticos¶
Estos son todos los cambios que Python 2.5 introduce en el núcleo del lenguaje Python.
El tipo
dict
tiene un nuevo gancho para permitir que las subclases proporcionen un valor por defecto cuando una clave no está contenida en el diccionario. Cuando no se encuentre una clave, se llamará al métodomissing__(key)
del diccionario. Este hook se utiliza para implementar la nueva clasedefaultdict
en el módulocollections
. El siguiente ejemplo define un diccionario que devuelve cero para cualquier clave que falte:class zerodict (dict): def __missing__ (self, key): return 0 d = zerodict({1:1, 2:2}) print d[1], d[2] # Prints 1, 2 print d[3], d[4] # Prints 0, 0
Tanto las cadenas de 8 bits como las de Unicode tienen nuevos métodos
partition(sep)
yrpartition(sep)
que simplifican un caso de uso común.El método
find(S)
se utiliza a menudo para obtener un índice que luego se utiliza para cortar la cadena y obtener las piezas que están antes y después del separador. El métodopartition(sep)
condensa este patrón en una sola llamada al método que devuelve una tripleta que contiene la subcadena antes del separador, el propio separador y la subcadena después del separador. Si no se encuentra el separador, el primer elemento de la tupla es la cadena completa y los otros dos elementos están vacíos.rpartition(sep)
también devuelve una tupla de 3 elementos, pero empieza a buscar desde el final de la cadena; lar
significa «al revés».Algunos ejemplos:
>>> ('http://www.python.org').partition('://') ('http', '://', 'www.python.org') >>> ('file:/usr/share/doc/index.html').partition('://') ('file:/usr/share/doc/index.html', '', '') >>> (u'Subject: a quick question').partition(':') (u'Subject', u':', u' a quick question') >>> 'www.python.org'.rpartition('.') ('www.python', '.', 'org') >>> 'www.python.org'.rpartition(':') ('', '', 'www.python.org')
(Implementado por Fredrik Lundh tras una sugerencia de Raymond Hettinger)
Los métodos
startswith()
yendswith()
de los tipos de cadena aceptan ahora tuplas de cadenas para su comprobación.def is_image_file (filename): return filename.endswith(('.gif', '.jpg', '.tiff'))
(Implementado por Georg Brandl tras una sugerencia de Tom Lynn)
Las funciones incorporadas
min()
ymax()
han ganado un parámetro de palabra clavekey
análogo al argumentokey
desort()
. Este parámetro proporciona una función que toma un único argumento y es llamada para cada valor de la lista;min()
/max()
devolverá el elemento con el valor de retorno más pequeño/más grande de esta función. Por ejemplo, para encontrar la cadena más larga de una lista, puede hacer:L = ['medium', 'longest', 'short'] # Prints 'longest' print max(L, key=len) # Prints 'short', because lexicographically 'short' has the largest value print max(L)
(Contribución de Steven Bethard y Raymond Hettinger)
Dos nuevas funciones incorporadas,
any()
yall()
, evalúan si un iterador contiene algún valor verdadero o falso.any()
devuelveTrue
si cualquier valor devuelto por el iterador es verdadero; en caso contrario devolveráFalse
.all()
devuelveTrue
sólo si todos los valores devueltos por el iterador se evalúan como verdaderos. (Sugerido por Guido van Rossum, e implementado por Raymond Hettinger)El resultado del método
__hash__()
de una clase puede ser ahora un entero largo o un entero normal. Si se devuelve un entero largo, se toma el hash de ese valor. En versiones anteriores se requería que el valor del hash fuera un entero regular, pero en 2.5 el built-inid()
se cambió para devolver siempre números no negativos, y los usuarios parecen utilizar a menudoid(self)
en los métodos__hash__()
(aunque esto se desaconseja).ASCII es ahora la codificación por defecto para los módulos. Ahora es un error de sintaxis si un módulo contiene literales de cadena con caracteres de 8 bits pero no tiene una declaración de codificación. En Python 2.4 esto provocaba una advertencia, no un error de sintaxis. Vea en PEP 263 cómo declarar la codificación de un módulo; por ejemplo, puede añadir una línea como ésta cerca de la parte superior del fichero fuente:
# -*- coding: latin1 -*-
Una nueva advertencia,
UnicodeWarning
, se activa cuando se intenta comparar una cadena Unicode y una cadena de 8 bits que no se puede convertir a Unicode utilizando la codificación ASCII por defecto. El resultado de la comparación es falso:>>> chr(128) == unichr(128) # Can't convert chr(128) to Unicode __main__:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal False >>> chr(127) == unichr(127) # chr(127) can be converted True
Anteriormente, esto lanzaba una excepción
UnicodeDecodeError
, pero en 2.5 esto podía dar lugar a problemas desconcertantes al acceder a un diccionario. Si se buscabaunichr(128)
y se utilizabachr(128)
como clave, se producía una excepciónUnicodeDecodeError
. Otros cambios en la versión 2.5 hicieron que esta excepción se lanzara en lugar de ser suprimida por el código dedictobject.c
que implementa los diccionarios.Lanzar una excepción para tal comparación es estrictamente correcto, pero el cambio podría haber roto el código, así que en su lugar se introdujo
UnicodeWarning
.(Implementado por Marc-André Lemburg.)
Un error que a veces cometen los programadores de Python es olvidarse de incluir un módulo
__init__.py
en el directorio de un paquete. Depurar este error puede ser confuso, y normalmente requiere ejecutar Python con el modificador-v
para registrar todas las rutas buscadas. En Python 2.5, una nueva advertenciaImportWarning
se activa cuando una importación habría recogido un directorio como paquete pero no se encontró ningún__init__.py
. Esta advertencia se ignora silenciosamente por defecto; proporcione la opción-Wd
cuando ejecute el ejecutable de Python para mostrar el mensaje de advertencia. (Implementado por Thomas Wouters)</-W>La lista de clases base en una definición de clase ahora puede estar vacía. Como ejemplo, esto es ahora legal:
class C(): pass
(Implementado por Brett Cannon.)
Cambios en el intérprete interactivo¶
En el intérprete interactivo, quit
y exit
han sido durante mucho tiempo cadenas para que los nuevos usuarios obtengan un mensaje algo útil cuando intenten salir:
>>> quit
'Use Ctrl-D (i.e. EOF) to exit.'
En Python 2.5, quit
y exit
son ahora objetos que siguen produciendo representaciones de cadena de sí mismos, pero también son invocables. Los novatos que prueben quit()
o exit()
ahora saldrán del intérprete como se espera. (Implementado por Georg Brandl.)
El ejecutable de Python ahora acepta las opciones largas estándar --help
y --version
; en Windows, también acepta la opción /?
para mostrar un mensaje de ayuda. (Implementado por Georg Brandl)
Optimizaciones¶
Varias de las optimizaciones se desarrollaron en el sprint NeedForSpeed, un evento celebrado en Reikiavik, Islandia, del 21 al 28 de mayo de 2006. El sprint se centró en las mejoras de velocidad de la implementación de CPython y fue financiado por EWT LLC con el apoyo local de CCP Games. Las optimizaciones añadidas en este sprint están especialmente marcadas en la siguiente lista.
Cuando se introdujeron en Python 2.4, los tipos incorporados
set
yfrozenset
se construyeron sobre el tipo diccionario de Python. En 2.5 la estructura de datos interna se ha personalizado para implementar conjuntos, y como resultado los conjuntos utilizarán un tercio menos de memoria y son algo más rápidos. (Implementado por Raymond Hettinger)Se ha mejorado la velocidad de algunas operaciones Unicode, como la búsqueda de subcadenas, la división de cadenas y la codificación y decodificación de mapas de caracteres. (Las mejoras en la búsqueda de subcadenas y la división fueron añadidas por Fredrik Lundh y Andrew Dalke en el sprint NeedForSpeed. Los mapas de caracteres fueron mejorados por Walter Dörwald y Martin von Löwis)
La función
long(str, base)
es ahora más rápida en cadenas de dígitos largos porque se calculan menos resultados intermedios. El máximo es para cadenas de alrededor de 800-1000 dígitos, donde la función es 6 veces más rápida. (Aportado por Alan McIntyre y comprometido en el sprint NeedForSpeed)Ahora es ilegal mezclar la iteración sobre un fichero con
for line in file
y llamar a los métodosread()
/readline()
/readlines()
del objeto fichero. La iteración utiliza un buffer interno y los métodosread*()
no utilizan ese buffer. En su lugar, devolverán los datos que siguen al buffer, haciendo que los datos aparezcan desordenados. Mezclar la iteración y estos métodos provocará ahora unValueError
del métodoread*()
. (Implementado por Thomas Wouters)El módulo
struct
ahora compila cadenas de formato de estructura en una representación interna y almacena en caché esta representación, lo que supone una mejora del 20% s. (Contribuido por Bob Ippolito en el sprint NeedForSpeed)El módulo
re
obtuvo un 1 o 2% s de velocidad al cambiar a las funciones asignadoras de Python en lugar de lasmalloc()
yfree()
del sistema. (Contribuido por Jack Diederich en el sprint NeedForSpeed)El optimizador de la mirilla del generador de código realiza ahora un simple plegado de constantes en las expresiones. Si escribes algo como
a = 2+3
, el generador de código hará la aritmética y producirá el código correspondiente aa = 5
. (Propuesto e implementado por Raymond Hettinger)Las llamadas a funciones son ahora más rápidas porque los objetos de código guardan ahora el último fotograma terminado (un «fotograma zombi») en un campo interno del objeto de código, reutilizándolo la próxima vez que se invoque el objeto de código. (Parche original de Michael Hudson, modificado por Armin Rigo y Richard Jones; confirmado en el sprint NeedForSpeed) Los objetos marco son también ligeramente más pequeños, lo que puede mejorar la localidad de la caché y reducir un poco el uso de la memoria. (Contribución de Neal Norwitz)
Las excepciones incorporadas en Python son ahora clases de nuevo estilo, un cambio que acelera considerablemente la instanciación. El manejo de excepciones en Python 2.5 es, por tanto, un 30% f más rápido que en 2.4. (Contribución de Richard Jones, Georg Brandl y Sean Reifschneider en el sprint NeedForSpeed)
La importación ahora almacena en caché las rutas intentadas, registrando si existen o no para que el intérprete haga menos llamadas a
open()
ystat()
al iniciar. (Contribución de Martin von Löwis y Georg Brandl)
Módulos nuevos, mejorados y eliminados¶
La biblioteca estándar ha recibido muchas mejoras y correcciones de errores en Python 2.5. Aquí hay una lista parcial de los cambios más notables, ordenados alfabéticamente por el nombre del módulo. Consulte el archivo Misc/NEWS
en el árbol de fuentes para obtener una lista más completa de los cambios, o busque en los registros de SVN para obtener todos los detalles.
El módulo
audioop
soporta ahora la codificación a-LAW, y se ha mejorado el código para la codificación u-LAW. (Contribución de Lars Immisch)El módulo
codecs
ha ganado soporte para códecs incrementales. La funcióncodec.lookup()
devuelve ahora una instancia deCodecInfo
en lugar de una tupla. Las instancias deCodecInfo
se comportan como una cuádruple tupla para preservar la compatibilidad con versiones anteriores, pero también tienen los atributosencode
,decode
,incrementalencoder
,incrementaldecoder
,streamwriter
ystreamreader
. Los códecs incrementales pueden recibir la entrada y producir la salida en varios trozos; la salida es la misma que si la entrada completa fuera alimentada por el códec no incremental. Consulte la documentación del módulocodecs
para más detalles. (Diseñado e implementado por Walter Dörwald)El módulo
collections
ha ganado un nuevo tipo,defaultdict
, que subclasifica el tipo estándardict
. El nuevo tipo se comporta principalmente como un diccionario pero construye un valor por defecto cuando una clave no está presente, añadiéndolo automáticamente al diccionario para el valor de la clave solicitada.El primer argumento del constructor de
defaultdict
es una función de fábrica que se llama cada vez que se solicita una clave pero no se encuentra. Esta función de fábrica no recibe argumentos, por lo que puede utilizar constructores de tipo incorporado comolist()
oint()
. Por ejemplo, puedes hacer un índice de palabras basado en su letra inicial así:words = """Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura che la diritta via era smarrita""".lower().split() index = defaultdict(list) for w in words: init_letter = w[0] index[init_letter].append(w)
Al imprimir
index
se obtiene la siguiente salida:defaultdict(<type 'list'>, {'c': ['cammin', 'che'], 'e': ['era'], 'd': ['del', 'di', 'diritta'], 'm': ['mezzo', 'mi'], 'l': ['la'], 'o': ['oscura'], 'n': ['nel', 'nostra'], 'p': ['per'], 's': ['selva', 'smarrita'], 'r': ['ritrovai'], 'u': ['una'], 'v': ['vita', 'via']}
(Contribución de Guido van Rossum.)
El tipo de cola doble
deque
suministrado por el módulocollections
tiene ahora un métodoremove(value)
que elimina la primera aparición de value en la cola, lanzandoValueError
si no se encuentra el valor. (Contribución de Raymond Hettinger)Nuevo módulo: El módulo
contextlib
contiene funciones de ayuda para usar con la nueva sentencia “with
”. Consulte la sección El módulo contextlib para obtener más información sobre este módulo.Nuevo módulo: El módulo
cProfile
es una implementación en C del módulo existenteprofile
que tiene una sobrecarga mucho menor. La interfaz del módulo es la misma que la deprofile
: se ejecutacProfile.run('main()')
para perfilar una función, se pueden guardar los datos del perfil en un archivo, etc. Todavía no se sabe si el perfilador Hotshot, que también está escrito en C pero no coincide con la interfaz del móduloprofile
, seguirá manteniéndose en futuras versiones de Python. (Contribución de Armin Rigo.)Además, el módulo
pstats
para analizar los datos medidos por el perfilador ahora soporta dirigir la salida a cualquier objeto archivo suministrando un argumento stream al constructorStats
. (Contribución de Skip Montanaro)El módulo
csv
, que analiza archivos en formato de valores separados por comas, ha recibido varias mejoras y una serie de correcciones de errores. Ahora se puede establecer el tamaño máximo en bytes de un campo llamando a la funcióncsv.field_size_limit(new_limit)
; si se omite el argumento new_limit se devolverá el límite establecido actualmente. La clasereader
tiene ahora un atributoline_num
que cuenta el número de líneas físicas leídas de la fuente; los registros pueden abarcar varias líneas físicas, por lo queline_num
no es lo mismo que el número de registros leídos.El analizador CSV es ahora más estricto con los campos entrecomillados de varias líneas. Anteriormente, si una línea terminaba dentro de un campo entre comillas sin un carácter de nueva línea final, se insertaba una nueva línea en el campo devuelto. Este comportamiento causaba problemas cuando se leían archivos que contenían caracteres de retorno de carro dentro de los campos, por lo que se cambió el código para devolver el campo sin insertar nuevas líneas. Como consecuencia, si las nuevas líneas incrustadas dentro de los campos son importantes, la entrada debe dividirse en líneas de manera que se conserven los caracteres de nueva línea.
(Contribución de Skip Montanaro y Andrew McNamara)
La clase
datetime
del módulodatetime
tiene ahora un métodostrptime(string, format)
para analizar cadenas de fechas, aportado por Josh Spoerri. Utiliza los mismos caracteres de formato quetime.strptime()
ytime.strftime()
:from datetime import datetime ts = datetime.strptime('10:13:15 2006-03-07', '%H:%M:%S %Y-%m-%d')
El método
SequenceMatcher.get_matching_blocks()
del módulodifflib
garantiza ahora la devolución de una lista mínima de bloques que describen subsecuencias coincidentes. Anteriormente, el algoritmo rompía ocasionalmente un bloque de elementos coincidentes en dos entradas de la lista. (Mejora realizada por Tim Peters)El módulo
doctest
ha ganado una opciónSKIP
que impide que un ejemplo se ejecute en absoluto. Esto está pensado para los fragmentos de código que son ejemplos de uso destinados al lector y que no son realmente casos de prueba.Se ha añadido un parámetro encoding a la función
testfile()
y a la claseDocFileSuite
para especificar la codificación del archivo. Esto facilita el uso de caracteres no ASCII en las pruebas contenidas en un docstring. (Contribución de Bjorn Tillenius)El paquete
email
ha sido actualizado a la versión 4.0. (Contribución de Barry Warsaw.)El módulo
fileinput
se ha hecho más flexible. Ahora se soportan los nombres de archivo Unicode, y se ha añadido un parámetro mode que por defecto es"r"
a la funcióninput()
para permitir la apertura de archivos en modo binario o universal newlines. Otro nuevo parámetro, openhook, permite utilizar una función distinta deopen()
para abrir los ficheros de entrada. Una vez que se itera sobre el conjunto de archivos, el nuevofileno()
del objetoFileInput
devuelve el descriptor de archivo del archivo actualmente abierto. (Contribuido por Georg Brandl.)En el módulo
gc
, la nueva funciónget_count()
devuelve una 3-tupla que contiene los recuentos de recolección actuales para las tres generaciones de GC. Se trata de información contable para el recolector de basura; cuando estos recuentos alcanzan un umbral especificado, se realiza un barrido de recolección de basura. La funcióngc.collect()
existente ahora toma un argumento opcional generación de 0, 1 o 2 para especificar qué generación recoger. (Contribución de Barry Warsaw)Las funciones
nsmallest()
ynlargest()
del móduloheapq
soportan ahora un parámetro de palabra clavekey
similar al proporcionado por las funcionesmin()
/max()
y los métodossort()
. Por ejemplo:>>> import heapq >>> L = ["short", 'medium', 'longest', 'longer still'] >>> heapq.nsmallest(2, L) # Return two lowest elements, lexicographically ['longer still', 'longest'] >>> heapq.nsmallest(2, L, key=len) # Return two shortest elements ['short', 'medium']
(Contribución de Raymond Hettinger.)
La función
itertools.islice()
ahora aceptaNone
para los argumentos de inicio y paso. Esto la hace más compatible con los atributos de los objetos slice, por lo que ahora se puede escribir lo siguiente:s = slice(5) # Create slice object itertools.islice(iterable, s.start, s.stop, s.step)
(Contribución de Raymond Hettinger.)
Se ha modificado la función
format()
del módulolocale
y se han añadido dos nuevas funciones,format_string()
ycurrency()
.El parámetro val de la función
format()
podía ser antes una cadena siempre que no apareciera más de un especificador %char; ahora el parámetro debe ser exactamente un especificador %char sin texto alrededor. También se ha añadido un parámetro opcional monetario que, si esVerdadero
, utilizará las reglas de la configuración regional para formatear la moneda al colocar un separador entre grupos de tres dígitos.Para formatear cadenas con múltiples especificadores %char, utilice la nueva función
format_string()
que funciona comoformat()
pero que también permite mezclar especificadores %char con texto arbitrario.También se ha añadido una nueva función
currency()
que formatea un número de acuerdo con la configuración local actual.(Contribución de Georg Brandl.)
El módulo
mailbox
ha sido reestructurado de forma masiva para añadir la capacidad de modificar los buzones además de leerlos. Un nuevo conjunto de clases que incluyenmbox
,MH
, yMaildir
se utilizan para leer buzones, y tienen un métodoadd(message)
para añadir mensajes,remove(key)
para eliminar mensajes, ylock()
/unlock()
para bloquear/desbloquear el buzón. El siguiente ejemplo convierte un buzón con formato maildir en uno con formato mbox:import mailbox # 'factory=None' uses email.Message.Message as the class representing # individual messages. src = mailbox.Maildir('maildir', factory=None) dest = mailbox.mbox('/tmp/mbox') for msg in src: dest.add(msg)
(Contribución de Gregory K. Johnson. La financiación fue proporcionada por el Summer of Code 2005 de Google)
Nuevo módulo: el módulo
msilib
permite crear archivos.msi
de Microsoft Installer y archivos CAB. También se incluye soporte para la lectura de la base de datos.msi
. (Contribución de Martin von Löwis)El módulo
nis
soporta ahora el acceso a dominios distintos del dominio por defecto del sistema proporcionando un argumento dominio a las funcionesnis.match()
ynis.maps()
. (Contribución de Ben Bell)Las funciones
operator
del móduloitemgetter()
yattrgetter()
ahora soportan múltiples campos. Una llamada comooperator.attrgetter('a', 'b')
devolverá una función que recupera los atributosa
yb
. La combinación de esta nueva función con el parámetrokey
del métodosort()
permite ordenar fácilmente las listas utilizando varios campos. (Contribución de Raymond Hettinger)El módulo
optparse
se ha actualizado a la versión 1.5.1 de la biblioteca Optik. La claseOptionParser
obtuvo un atributoepilog
, una cadena que se imprimirá después del mensaje de ayuda, y un métododestroy()
para romper los ciclos de referencia creados por el objeto. (Contribuido por Greg Ward.)El módulo
os
ha sufrido varios cambios. La variablestat_float_times
ahora está predeterminada a true, lo que significa queos.stat()
ahora devolverá los valores de tiempo como flotantes. (Esto no significa necesariamente queos.stat()
devolverá tiempos con una precisión de fracciones de segundo; no todos los sistemas soportan dicha precisión)Se han añadido las constantes
os.SEEK_SET
,os.SEEK_CUR
yos.SEEK_END
, que son los parámetros de la funciónos.lseek()
. Dos nuevas constantes para el bloqueo sonos.O_SHLOCK
yos.O_EXLOCK
.Se han añadido dos nuevas funciones,
wait3()
ywait4()
. Son similares a la funciónwaitpid()
que espera la salida de un proceso hijo y devuelve una tupla con el ID del proceso y su estado de salida, perowait3()
ywait4()
devuelven información adicional.wait3()
no toma un ID de proceso como entrada, por lo que espera a que cualquier proceso hijo salga y devuelve una tupla de id de proceso, estado de salida, uso de recursos tal y como se devuelve desde la funciónresource.getrusage()
.wait4(pid)
toma un ID de proceso. (Contribuido por Chad J. Schroeder.)En FreeBSD, la función
os.stat()
devuelve ahora tiempos con resolución de nanosegundos, y el objeto devuelto tiene ahorast_gen
yst_birthtime
. El atributost_flags
también está disponible, si la plataforma lo soporta. (Contribución de Antti Louko y Diego Pettenò)El depurador de Python proporcionado por el módulo
pdb
puede ahora almacenar listas de comandos a ejecutar cuando se alcanza un punto de ruptura y se detiene la ejecución. Una vez creado el punto de interrupción nº 1, introduzcacomandos 1
e introduzca una serie de comandos a ejecutar, terminando la lista conend
. La lista de comandos puede incluir comandos que reanuden la ejecución, comocontinue
onext
. (Contribución de Grégoire Dooms.)Los módulos
pickle
ycPickle
ya no aceptan un valor de retorno deNone
del método__reduce__()
; el método debe devolver una tupla de argumentos. La capacidad de devolverNone
fue obsoleta en Python 2.4, así que esto completa la eliminación de la función.El módulo
pkgutil
, que contiene varias funciones de utilidad para encontrar paquetes, fue mejorado para soportar los ganchos de importación de PEP 302 y ahora también funciona para paquetes almacenados en archivos con formato ZIP. (Contribución de Phillip J. Eby)El conjunto de pruebas pybench de Marc-André Lemburg se incluye ahora en el directorio
Tools/pybench
. El conjunto de pruebas pybench es una mejora del programapystone.py
de uso común, ya que pybench proporciona una medición más detallada de la velocidad del intérprete. Calcula el tiempo de determinadas operaciones como las llamadas a funciones, el corte de tuplas, las búsquedas de métodos y las operaciones numéricas, en lugar de realizar muchas operaciones diferentes y reducir el resultado a un único número como hacepystone.py
.El módulo
pyexpat
utiliza ahora la versión 2.0 del analizador sintáctico Expat. (Contribución de Trent Mick)La clase
Queue
proporcionada por el móduloQueue
ha ganado dos nuevos métodos.join()
bloquea hasta que todos los elementos de la cola han sido recuperados y todo el trabajo de procesamiento de los elementos ha sido completado. Los hilos de trabajo llaman al otro método nuevo,task_done()
, para indicar que el procesamiento de un elemento ha finalizado. (Contribución de Raymond Hettinger)Los antiguos módulos
regex
yregsub
, obsoletos desde Python 2.0, han sido finalmente eliminados. Otros módulos eliminados:statcache
,tzparse
,whrandom
.También se ha eliminado el directorio
lib-old
, que incluye módulos antiguos comodircmp
yni
.lib-old
no estaba en el directorio por defectosys.path
, así que a menos que tus programas añadan explícitamente el directorio asys.path
, esta eliminación no debería afectar a tu código.El módulo
rlcompleter
ya no depende de la importación del móduloreadline
y, por lo tanto, ahora funciona en plataformas no Unix. (Parche de Robert Kiendl.)Las clases
SimpleXMLRPCServer
yDocXMLRPCServer
tienen ahora un atributorpc_paths
que restringe las operaciones XML-RPC a un conjunto limitado de rutas URL; por defecto sólo se permiten'/'
y'/RPC2'
. Establecerrpc_paths
comoNone
o una tupla vacía desactiva esta comprobación de rutas.El módulo
socket
ahora soporta socketsAF_NETLINK
en Linux, gracias a un parche de Philippe Biondi. Los sockets Netlink son un mecanismo específico de Linux para las comunicaciones entre un proceso en el espacio del usuario y el código del kernel; hay un artículo introductorio sobre ellos en https://www.linuxjournal.com/article/7356. En el código Python, las direcciones de netlink se representan como una tupla de 2 enteros,(pid, group_mask)
.Dos nuevos métodos en objetos socket,
recv_into(buffer)
yrecvrom_into(buffer)
, almacenan los datos recibidos en un objeto que soporta el protocolo de buffer en lugar de devolver los datos como una cadena. Esto significa que puedes poner los datos directamente en un array o en un archivo mapeado en memoria.Los objetos Socket también han ganado métodos de acceso
getfamily()
,gettype()
ygetproto()
para recuperar los valores de familia, tipo y protocolo del socket.Nuevo módulo: el módulo
spwd
proporciona funciones para acceder a la base de datos de contraseñas en la sombra en sistemas que soportan contraseñas en la sombra.El módulo
struct
es ahora más rápido porque compila cadenas de formato en objetosStruct
con métodospack()
yunpack()
. Esto es similar a cómo el módulore
permite crear objetos de expresión regular compilados. Puede seguir utilizando las funcionespack()
yunpack()
a nivel de módulo; éstas crearán objetosStruct
y los almacenarán en caché. O puede utilizar directamente las instancias deStruct
:s = struct.Struct('ih3s') data = s.pack(1972, 187, 'abc') year, number, name = s.unpack(data)
También puedes empaquetar y desempaquetar datos hacia y desde objetos buffer directamente usando los métodos
pack_into(buffer, offset, v1, v2, ...)
yunpack_from(buffer, offset)
. Esto te permite almacenar datos directamente en un array o en un archivo mapeado en memoria.(
Struct
objects fueron implementados por Bob Ippolito en el sprint NeedForSpeed. El soporte para los objetos buffer fue añadido por Martin Blais, también en el sprint NeedForSpeed)Los desarrolladores de Python cambiaron de CVS a Subversion durante el proceso de desarrollo de la versión 2.5. La información sobre la versión exacta de construcción está disponible como la variable
sys.subversion
, una 3-tupla de(nombre del intérprete, nombre de la rama, rango de revisión)
. Por ejemplo, en el momento de escribir esto, mi copia de 2.5 informaba de('CPython', 'trunk', '45313:45315')
.Esta información también está disponible para las extensiones de C a través de la función
Py_GetBuildInfo()
que devuelve una cadena de información de compilación como esta"trunk:45355:45356M, Apr 13 2006, 07:42:19"
. (Contribuido por Barry Warsaw.)Otra nueva función,
sys._current_frames()
, devuelve los marcos de pila actuales para todos los hilos en ejecución como un diccionario que asigna los identificadores de los hilos al marco de pila superior actualmente activo en ese hilo en el momento en que se llama a la función. (Contribuido por Tim Peters.)La clase
TarFile
del módulotarfile
tiene ahora un métodoextractall()
que extrae todos los miembros del archivo en el directorio de trabajo actual. También es posible establecer un directorio diferente como destino de la extracción, y desempaquetar sólo un subconjunto de los miembros del archivo.La compresión utilizada para un archivo tar abierto en modo stream puede ahora ser autodetectada utilizando el modo
'r|*'
. (Contribución de Lars Gustäbel)El módulo
threading
permite ahora establecer el tamaño de la pila utilizado cuando se crean nuevos hilos. La funciónstack_size([*size*])
devuelve el tamaño de pila actualmente configurado, y suministrando el parámetro opcional size establece un nuevo valor. No todas las plataformas soportan el cambio del tamaño de la pila, pero Windows, POSIX threading y OS/2 lo hacen. (Contribución de Andrew MacIntyre)El módulo
unicodedata
ha sido actualizado para utilizar la versión 4.1.0 de la base de datos de caracteres Unicode. La versión 3.2.0 es requerida por algunas especificaciones, por lo que sigue estando disponible comounicodedata.ucd_3_2_0
.Nuevo módulo: el módulo
uuid
genera identificadores únicos universales (UUID) de acuerdo con RFC 4122. El RFC define varias versiones diferentes de UUID que se generan a partir de una cadena inicial, de propiedades del sistema o de forma puramente aleatoria. Este módulo contiene una claseUUID
y funciones llamadasuuid1()
,uuid3()
,uuid4()
, yuuid5()
para generar diferentes versiones de UUID. (Los UUID de la versión 2 no se especifican en RFC 4122 y no están soportados por este módulo)>>> import uuid >>> # make a UUID based on the host ID and current time >>> uuid.uuid1() UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') >>> # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') >>> # make a random UUID >>> uuid.uuid4() UUID('16fd2706-8baf-433b-82eb-8c7fada847da') >>> # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
(Contribución de Ka-Ping Yee.)
Los tipos
weakref
del móduloWeakKeyDictionary
yWeakValueDictionary
han obtenido nuevos métodos para iterar sobre las referencias débiles contenidas en el diccionario. Se han añadido los métodositerkeyrefs()
ykeyrefs()
aWeakKeyDictionary
, yitervaluerefs()
yvaluerefs()
aWeakValueDictionary
. (Contribución de Fred L. Drake, Jr.)El módulo
webbrowser
ha recibido una serie de mejoras. Ahora se puede utilizar como un script conpython -m webbrowser
, tomando una URL como argumento; hay una serie de interruptores para controlar el comportamiento (-n
para una nueva ventana del navegador,-t
para una nueva pestaña). Se han añadido nuevas funciones a nivel de módulo,open_new()
yopen_new_tab()
, para soportar esto. La funciónopen()
del módulo soporta una característica adicional, un parámetro autoraise que señala si se debe levantar la ventana abierta cuando sea posible. Se añadieron varios navegadores adicionales a la lista de soportados, como Firefox, Opera, Konqueror y elinks. (Contribución de Oleg Broytmann y Georg Brandl)El módulo
xmlrpclib
ahora soporta la devolución de objetosdatetime
para el tipo de fecha XML-RPC. Proporcioneuse_datetime=True
a la funciónloads()
o a la claseUnmarshaller
para activar esta característica. (Contribución de Skip Montanaro)El módulo
zipfile
ahora soporta la versión ZIP64 del formato, lo que significa que un archivo .zip ahora puede ser mayor de 4 GiB y puede contener archivos individuales mayores de 4 GiB. (Contribución de Ronald Oussoren)Los objetos
zlib
yDecompress
del módulozlib
soportan ahora un métodocopy()
que realiza una copia del estado interno del objeto y devuelve un nuevo objetoCompress
oDecompress
. (Contribución de Chris AtLee)
El paquete ctypes¶
El paquete ctypes
, escrito por Thomas Heller, se ha añadido a la biblioteca estándar. ctypes
permite llamar a funciones arbitrarias en bibliotecas compartidas o DLL. Los usuarios veteranos recordarán el módulo dl
, que proporciona funciones para cargar bibliotecas compartidas y llamar a las funciones que contienen. El paquete ctypes
es mucho más sofisticado.
Para cargar una biblioteca compartida o DLL, debes crear una instancia de la clase CDLL
y proporcionar el nombre o la ruta de la biblioteca compartida o DLL. Una vez hecho esto, puedes llamar a funciones arbitrarias accediendo a ellas como atributos del objeto CDLL
.
import ctypes
libc = ctypes.CDLL('libc.so.6')
result = libc.printf("Line of output\n")
Se proporcionan constructores de tipos para los distintos tipos de C: c_int()
, c_float()
, c_double()
, c_char_p()
(equivalente a char *
), etc. A diferencia de los tipos de Python, las versiones de C son todas mutables; puedes asignar a su atributo value
para cambiar el valor envuelto. Los enteros y las cadenas de Python se convertirán automáticamente a los tipos C correspondientes, pero para otros tipos debes llamar al constructor de tipo correcto. (Y quiero decir debe; si se equivoca, a menudo el intérprete se bloquea con un fallo de segmentación)
No debería usar c_char_p()
con una cadena de Python cuando la función C vaya a modificar el área de memoria, porque se supone que las cadenas de Python son inmutables; romper esta regla causará errores desconcertantes. Cuando necesite un área de memoria modificable, utilice create_string_buffer()
:
s = "this is a string"
buf = ctypes.create_string_buffer(s)
libc.strfry(buf)
Se supone que las funciones en C devuelven números enteros, pero se puede establecer el atributo restype
del objeto de la función para cambiar esto:
>>> libc.atof('2.71828')
-1783957616
>>> libc.atof.restype = ctypes.c_double
>>> libc.atof('2.71828')
2.71828
ctypes
también proporciona una envoltura para la API de C de Python como el objeto ctypes.pythonapi
. Este objeto no libera el bloqueo global del intérprete antes de llamar a una función, porque el bloqueo debe mantenerse cuando se llama al código del intérprete. Hay un constructor de tipo py_object()
que creará un puntero PyObject *
. Un uso sencillo:
import ctypes
d = {}
ctypes.pythonapi.PyObject_SetItem(ctypes.py_object(d),
ctypes.py_object("abc"), ctypes.py_object(1))
# d is now {'abc', 1}.
No olvides usar py_object()
; si se omite acabas con un fallo de segmentación.
ctypes
existe desde hace tiempo, pero la gente sigue escribiendo y distribuyendo módulos de extensión codificados a mano porque no se puede confiar en que ctypes
esté presente. Quizás los desarrolladores empiecen a escribir envoltorios de Python sobre una biblioteca a la que se accede a través de ctypes
en lugar de módulos de extensión, ahora que ctypes
está incluido en el núcleo de Python.
Ver también
- http://starship.python.net/crew/theller/ctypes/
La página web de ctypes, con un tutorial, referencias y preguntas frecuentes.
La documentación del módulo ctypes
.
El paquete ElementTree¶
Un subconjunto de la biblioteca ElementTree de Fredrik Lundh para el procesamiento de XML se ha añadido a la biblioteca estándar como xml.etree
. Los módulos disponibles son ElementTree
, ElementPath
y ElementInclude
de ElementTree 1.2.6. También se incluye el módulo acelerador cElementTree
.
The rest of this section will provide a brief overview of using ElementTree. Full documentation for ElementTree is available at https://web.archive.org/web/20201124024954/http://effbot.org/zone/element-index.htm.
ElementTree representa un documento XML como un árbol de nodos de elementos. El contenido de texto del documento se almacena como los atributos text
y tail
de (Esta es una de las principales diferencias entre ElementTree y el Modelo de Objetos del Documento; en el DOM hay muchos tipos diferentes de nodo, incluyendo TextNode
)
La función de análisis más utilizada es parse()
, que toma una cadena (se supone que contiene un nombre de archivo) o un objeto similar a un archivo y devuelve una instancia de ElementTree
:
from xml.etree import ElementTree as ET
tree = ET.parse('ex-1.xml')
feed = urllib.urlopen(
'http://planet.python.org/rss10.xml')
tree = ET.parse(feed)
Una vez que tengas una instancia de ElementTree
, puedes llamar a su método getroot()
para obtener el nodo raíz de Element
.
También hay una función XML()
que toma un literal de cadena y devuelve un nodo Element
(no un ElementTree
). Esta función proporciona una forma ordenada de incorporar fragmentos XML, acercándose a la comodidad de un literal XML:
svg = ET.XML("""<svg width="10px" version="1.0">
</svg>""")
svg.set('height', '320px')
svg.append(elem1)
Cada elemento XML admite algunos métodos de acceso tipo diccionario y otros tipo lista. Las operaciones tipo diccionario se utilizan para acceder a los valores de los atributos, y las operaciones tipo lista se utilizan para acceder a los nodos hijos.
Operación |
Resultado |
---|---|
|
Devuelve el elemento hijo enésimo. |
|
Devuelve la lista de m’s a n’s elementos hijos. |
|
Devuelve el número de elementos hijos. |
|
Devuelve la lista de elementos hijos. |
|
Añade elemento2 como hijo. |
|
Inserta elemento2 en el lugar especificado. |
|
Elimina el elemento hijo enésimo. |
|
Devuelve la lista de nombres de atributos. |
|
Devuelve el valor del atributo nombre. |
|
Establece el nuevo valor del atributo nombre. |
|
Recupera el diccionario que contiene los atributos. |
|
Borra el atributo nombre. |
Los comentarios y las instrucciones de procesamiento también se representan como nodos Element
. Para comprobar si un nodo es un comentario o unas instrucciones de procesamiento:
if elem.tag is ET.Comment:
...
elif elem.tag is ET.ProcessingInstruction:
...
Para generar una salida XML, debes llamar al método ElementTree.write()
. Al igual que parse()
, puede tomar una cadena o un objeto tipo archivo:
# Encoding is US-ASCII
tree.write('output.xml')
# Encoding is UTF-8
f = open('output.xml', 'w')
tree.write(f, encoding='utf-8')
(Atención: la codificación por defecto utilizada para la salida es ASCII. Para el trabajo general de XML, donde el nombre de un elemento puede contener caracteres Unicode arbitrarios, ASCII no es una codificación muy útil porque lanzará una excepción si el nombre de un elemento contiene cualquier carácter con valores superiores a 127. Por lo tanto, es mejor especificar una codificación diferente, como UTF-8, que puede manejar cualquier carácter Unicode)
Esta sección es sólo una descripción parcial de las interfaces de ElementTree. Por favor, lee la documentación oficial del paquete para más detalles.
Ver también
- https://web.archive.org/web/20201124024954/http://effbot.org/zone/element-index.htm
Documentación oficial de ElementTree.
El paquete hashlib¶
Se ha añadido un nuevo módulo hashlib
, escrito por Gregory P. Smith, para sustituir a los módulos md5
y sha
. hashlib
añade soporte para hashes seguros adicionales (SHA-224, SHA-256, SHA-384 y SHA-512). Cuando está disponible, el módulo utiliza OpenSSL para implementaciones rápidas de algoritmos optimizados para la plataforma.
Los antiguos módulos md5
y sha
siguen existiendo como envoltorios de hashlib para preservar la compatibilidad hacia atrás. La interfaz del nuevo módulo es muy parecida a la de los módulos antiguos, pero no es idéntica. La diferencia más significativa es que las funciones constructoras para crear nuevos objetos hashing tienen un nombre diferente
# Old versions
h = md5.md5()
h = md5.new()
# New version
h = hashlib.md5()
# Old versions
h = sha.sha()
h = sha.new()
# New version
h = hashlib.sha1()
# Hash that weren't previously available
h = hashlib.sha224()
h = hashlib.sha256()
h = hashlib.sha384()
h = hashlib.sha512()
# Alternative form
h = hashlib.new('md5') # Provide algorithm as a string
Una vez que se ha creado un objeto hash, sus métodos son los mismos que antes: actualizar(cadena)
convierte la cadena especificada en el estado de resumen actual, digest()
y hexdigest()
devuelven el valor de resumen como una cadena binaria o una cadena de dígitos hexadecimales, y copiar()
devuelve un nuevo objeto hash con el mismo estado de resumen.
Ver también
La documentación del módulo hashlib
.
El paquete sqlite3¶
El módulo pysqlite (http://www.pysqlite.org), una envoltura para la base de datos incrustada SQLite, se ha añadido a la biblioteca estándar bajo el nombre de paquete sqlite3
.
SQLite es una biblioteca en C que proporciona una base de datos ligera basada en disco que no requiere un proceso de servidor independiente y permite acceder a la base de datos utilizando una variante no estándar del lenguaje de consulta SQL. Algunas aplicaciones pueden utilizar SQLite para el almacenamiento interno de datos. También es posible crear un prototipo de una aplicación utilizando SQLite y luego portar el código a una base de datos más grande como PostgreSQL u Oracle.
pysqlite fue escrito por Gerhard Häring y proporciona una interfaz SQL que cumple con la especificación DB-API 2.0 descrita por PEP 249.
Si estás compilando el código fuente de Python tú mismo, ten en cuenta que el árbol de código fuente no incluye el código de SQLite, sólo el módulo envolvente. Necesitarás tener las librerías y cabeceras de SQLite instaladas antes de compilar Python, y el proceso de construcción compilará el módulo cuando las cabeceras necesarias estén disponibles.
Para utilizar el módulo, primero hay que crear un objeto Connection
que represente la base de datos. Aquí los datos se almacenarán en el archivo /tmp/example
:
conn = sqlite3.connect('/tmp/example')
También puede suministrar el nombre especial :memory:
para crear una base de datos en la RAM.
Una vez que tengas una Connection
, puedes crear un objeto Cursor
y llamar a su método execute()
para realizar comandos SQL:
c = conn.cursor()
# Create table
c.execute('''create table stocks
(date text, trans text, symbol text,
qty real, price real)''')
# Insert a row of data
c.execute("""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)""")
Normalmente tus operaciones SQL necesitarán usar valores de variables de Python. No deberías montar tu consulta usando las operaciones de cadena de Python porque hacerlo es inseguro; hace que tu programa sea vulnerable a un ataque de inyección SQL.
En su lugar, utilice la sustitución de parámetros de la DB-API. Ponga ?
como marcador de posición donde quiera usar un valor, y luego proporcione una tupla de valores como segundo argumento al método execute()
del cursor. (Otros módulos de base de datos pueden utilizar un marcador de posición diferente, como %s
o :1
) Por ejemplo:
# Never do this -- insecure!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)
# Do this instead
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)
# Larger example
for t in (('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00),
('2006-04-06', 'SELL', 'IBM', 500, 53.00),
):
c.execute('insert into stocks values (?,?,?,?,?)', t)
Para recuperar datos después de ejecutar una sentencia SELECT, puede tratar el cursor como un iterador, llamar al método fetchone()
del cursor para recuperar una sola fila que coincida, o llamar a fetchall()
para obtener una lista de las filas que coincidan.
Este ejemplo utiliza la forma del iterador:
>>> c = conn.cursor()
>>> c.execute('select * from stocks order by price')
>>> for row in c:
... print row
...
(u'2006-01-05', u'BUY', u'RHAT', 100, 35.140000000000001)
(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0)
(u'2006-04-06', u'SELL', u'IBM', 500, 53.0)
(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0)
>>>
Para más información sobre el dialecto SQL soportado por SQLite, consulte https://www.sqlite.org.
Ver también
- http://www.pysqlite.org
La página web de pysqlite.
- https://www.sqlite.org
La página web de SQLite; la documentación describe la sintaxis y los tipos de datos disponibles para el dialecto SQL soportado.
La documentación del módulo sqlite3
.
- PEP 249 - Especificación de la API de la base de datos 2.0
PEP escrito por Marc-André Lemburg.
El paquete wsgiref¶
La Interfaz de Pasarela del Servidor Web (WSGI) v1.0 define una interfaz estándar entre los servidores web y las aplicaciones web de Python y se describe en PEP 333. El paquete wsgiref
es una implementación de referencia de la especificación WSGI.
El paquete incluye un servidor HTTP básico que ejecutará una aplicación WSGI; este servidor es útil para la depuración pero no está pensado para su uso en producción. La configuración de un servidor sólo requiere unas pocas líneas de código:
from wsgiref import simple_server
wsgi_app = ...
host = ''
port = 8000
httpd = simple_server.make_server(host, port, wsgi_app)
httpd.serve_forever()
Ver también
- http://www.wsgi.org
Un sitio web central para los recursos relacionados con WSGI.
- PEP 333 - Interfaz del servidor web Python v1.0
PEP escrito por Phillip J. Eby.
Cambios en la API de construcción y C¶
Los cambios en el proceso de construcción de Python y en la API de C incluyen:
El árbol de fuentes de Python fue convertido de CVS a Subversion, en un complejo procedimiento de migración que fue supervisado y llevado a cabo de forma impecable por Martin von Löwis. El procedimiento se desarrolló como PEP 347.
Coverity, una empresa que comercializa una herramienta de análisis de código fuente llamada Prevent, proporcionó los resultados de su examen del código fuente de Python. El análisis encontró alrededor de 60 errores que fueron rápidamente corregidos. Muchos de los errores eran problemas de recuento, que a menudo se producen en el código de gestión de errores. Consulte las estadísticas en https://scan.coverity.com.
El mayor cambio en la API de C proviene de PEP 353, que modifica el intérprete para utilizar una definición de tipo
Py_ssize_t
en lugar deint
. Vea la sección anterior PEP 353: Uso de ssize_t como tipo de índice para una discusión de este cambio.El diseño del compilador de código de bytes ha cambiado mucho, ya no genera código de bytes recorriendo el árbol de análisis sintáctico. En su lugar, el árbol de análisis se convierte en un árbol de sintaxis abstracta (o AST), y es el árbol de sintaxis abstracta el que se recorre para producir el código de bytes.
Es posible que el código Python obtenga objetos AST utilizando el built-in
compile()
y especificando_ast.PyCF_ONLY_AST
como valor del parámetro flags:from _ast import PyCF_ONLY_AST ast = compile("""a=0 for i in range(10): a += i """, "<string>", 'exec', PyCF_ONLY_AST) assignment = ast.body[0] for_loop = ast.body[1]
Todavía no se ha escrito ninguna documentación oficial para el código AST, pero PEP 339 discute el diseño. Para empezar a conocer el código, lea la definición de los distintos nodos AST en
Parser/Python.asdl
. Un script de Python lee este archivo y genera un conjunto de definiciones de estructuras C enInclude/Python-ast.h
. Las funcionesPyParser_ASTFromString()
yPyParser_ASTFromFile()
, definidas enInclude/pythonrun.h
, toman el código fuente de Python como entrada y devuelven la raíz de un AST que representa el contenido. Este AST puede convertirse en un objeto de código mediantePyAST_Compile()
. Para más información, lea el código fuente, y luego haga preguntas en python-dev.El código de la AST fue desarrollado bajo la dirección de Jeremy Hylton, e implementado por (en orden alfabético) Brett Cannon, Nick Coghlan, Grant Edwards, John Ehresman, Kurt Kaiser, Neal Norwitz, Tim Peters, Armin Rigo y Neil Schemenauer, además de los participantes en varios sprints de la AST en conferencias como la PyCon.
Se aplicó el parche de Evan Jones a obmalloc, descrito por primera vez en una charla en la PyCon DC 2005. Python 2.4 asignaba objetos pequeños en arenas de 256K, pero nunca liberaba arenas. Con este parche, Python liberará arenas cuando estén vacías. El efecto neto es que en algunas plataformas, cuando se asignan muchos objetos, el uso de la memoria de Python puede realmente caer cuando se borran y la memoria puede ser devuelta al sistema operativo. (Implementado por Evan Jones, y reelaborado por Tim Peters)
Tenga en cuenta que este cambio significa que los módulos de extensión deben ser más cuidadosos al asignar memoria. La API de Python tiene muchas funciones diferentes para asignar memoria que se agrupan en familias. Por ejemplo,
PyMem_Malloc()
,PyMem_Realloc()
, yPyMem_Free()
son una familia que asigna memoria en bruto, mientras quePyObject_Malloc()
,PyObject_Realloc()
, yPyObject_Free()
son otra familia que se supone que se utiliza para crear objetos de Python.Anteriormente estas diferentes familias se reducían a las funciones
malloc()
yfree()
de la plataforma. Esto significaba que no importaba si te equivocabas y asignabas memoria con la funciónPyMem()
pero la liberabas con la funciónPyObject()
. Con los cambios de la versión 2.5 en obmalloc, estas familias hacen ahora cosas diferentes y los desajustes probablemente darán lugar a un fallo de seguridad. Deberías probar cuidadosamente tus módulos de extensión C con Python 2.5.Los tipos de conjuntos incorporados tienen ahora una API oficial en C. Llame a
PySet_New()
yPyFrozenSet_New()
para crear un nuevo conjunto,PySet_Add()
yPySet_Discard()
para añadir y eliminar elementos, yPySet_Contains()
yPySet_Size()
para examinar el estado del conjunto. (Contribución de Raymond Hettinger)El código C puede ahora obtener información sobre la revisión exacta del intérprete de Python llamando a la función
Py_GetBuildInfo()
que devuelve una cadena de información de compilación como esta"trunk:45355:45356M, Apr 13 2006, 07:42:19"
. (Contribuido por Barry Warsaw.)Se pueden utilizar dos nuevas macros para indicar las funciones C que son locales al fichero actual, de modo que se pueda utilizar una convención de llamada más rápida.
Py_LOCAL(type)
declara que la función devuelve un valor del tipo especificado y utiliza un calificador de llamada rápida.Py_LOCAL_INLINE(type)
hace lo mismo y también solicita que la función sea inline. SiPY_LOCAL_AGGRESSIVE()
se define antes de que se incluyapython.h
, se habilita un conjunto de optimizaciones más agresivas para el módulo; debería comparar los resultados para averiguar si estas optimizaciones realmente hacen el código más rápido. (Contribuido por Fredrik Lundh en el sprint NeedForSpeed)PyErr_NewException(name, base, dict)
ahora puede aceptar una tupla de clases base como su argumento base. (Contribuido por Georg Brandl.)La función
PyErr_Warn()
para emitir avisos está ahora obsoleta en favor dePyErr_WarnEx(category, message, stacklevel)
que permite especificar el número de marcos de pila que separan esta función y la que la llama. Un stacklevel de 1 es la función que llama aPyErr_WarnEx()
, 2 es la función que está por encima, y así sucesivamente. (Añadido por Neal Norwitz.)El intérprete de CPython sigue estando escrito en C, pero el código ahora puede ser compilado con un compilador de C++ sin errores. (Implementado por Anthony Baxter, Martin von Löwis, Skip Montanaro)
Se ha eliminado la función
PyRange_New()
. Nunca se documentó, nunca se utilizó en el código del núcleo, y tenía una comprobación de errores peligrosamente laxa. En el improbable caso de que sus extensiones la utilizaran, puede sustituirla por algo como lo siguiente:range = PyObject_CallFunction((PyObject*) &PyRange_Type, "lll", start, stop, step);
Cambios específicos en los puertos¶
MacOS X (10.3 y superior): la carga dinámica de módulos utiliza ahora la función
dlopen()
en lugar de funciones específicas de MacOS.MacOS X: se ha añadido una opción
--enable-universalsdk
al script configure que compila el intérprete como un binario universal capaz de funcionar tanto en procesadores PowerPC como Intel. (Contribución de Ronald Oussoren; bpo-2573.)Windows:
.dll
ya no se admite como extensión de nombre de archivo para los módulos de extensión..pyd
es ahora la única extensión de nombre de archivo que se buscará.
Adaptación a Python 2.5¶
Esta sección enumera los cambios descritos anteriormente que pueden requerir cambios en su código:
ASCII es ahora la codificación por defecto para los módulos. Ahora es un error de sintaxis si un módulo contiene literales de cadena con caracteres de 8 bits pero no tiene una declaración de codificación. En Python 2.4 esto provocaba una advertencia, no un error de sintaxis.
Anteriormente, el atributo
gi_frame
de un generador era siempre un objeto frame. Debido a los cambios de PEP 342 descritos en la sección PEP 342: Nuevas funciones del generador, ahora es posible quegi_frame
seaNone
.Una nueva advertencia,
UnicodeWarning
, se lanza cuando se intenta comparar una cadena Unicode y una cadena de 8 bits que no puede ser convertida a Unicode utilizando la codificación ASCII por defecto. Anteriormente estas comparaciones lanzaban una excepciónUnicodeDecodeError
.Biblioteca: el módulo
csv
es ahora más estricto con los campos citados en varias líneas. Si sus archivos contienen nuevas líneas incrustadas dentro de los campos, la entrada debe dividirse en líneas de manera que se conserven los caracteres de nueva línea.Biblioteca: la función
format()
del módulolocale
aceptaba antes cualquier cadena siempre que no apareciera más de un especificador %char. En Python 2.5, el argumento debe ser exactamente un especificador %char sin texto alrededor.Biblioteca: Los módulos
pickle
ycPickle
ya no aceptan un valor de retorno deNone
del método__reduce__()
; el método debe devolver una tupla de argumentos. Los módulos tampoco aceptan ya el parámetro obsoleto de la palabra clave bin.Biblioteca: Las clases
SimpleXMLRPCServer
yDocXMLRPCServer
tienen ahora un atributorpc_paths
que restringe las operaciones XML-RPC a un conjunto limitado de rutas URL; por defecto sólo se permiten'/'
y'/RPC2'
. Establecerrpc_paths
comoNone
o una tupla vacía desactiva esta comprobación de rutas.API C: Muchas funciones utilizan ahora
Py_ssize_t
en lugar deint
para permitir el procesamiento de más datos en máquinas de 64 bits. Es posible que el código de las extensiones tenga que hacer el mismo cambio para evitar advertencias y soportar máquinas de 64 bits. Véase la sección anterior PEP 353: Uso de ssize_t como tipo de índice para una discusión de este cambio.C API: Los cambios en obmalloc significan que debe tener cuidado de no mezclar el uso de las familias de funciones
PyMem_*()
yPyObject_*()
. La memoria asignada con la función*_Malloc()
de una familia debe ser liberada con la función*_Free()
de la familia correspondiente.
Agradecimientos¶
El autor desea agradecer a las siguientes personas sus sugerencias, correcciones y ayuda en varios borradores de este artículo: Georg Brandl, Nick Coghlan, Phillip J. Eby, Lars Gustäbel, Raymond Hettinger, Ralf W. Grosse-Kunstleve, Kent Johnson, Iain Lowe, Martin von Löwis, Fredrik Lundh, Andrew McNamara, Skip Montanaro, Gustavo Niemeyer, Paul Prescod, James Pryor, Mike Rovner, Scott Weikart, Barry Warsaw, Thomas Wouters.