Qué hay de nuevo en Python 2.4¶
- Autor:
A.M. Kuchling
Este artículo explica las nuevas funcionalidades en Python 2.4.1 lanzadas el 30 de marzo de 2005.
Python 2.4 es un lanzamiento de término medio. Esto significa que no se han introducido grandes cambios como en la versión 2.2 de Python pero si son más significativas que la versión 2.3. Lo más relevante de estas nuevas funcionalidades son los decoradores y generadores de expresiones, la mayor parte del resto de los cambios son a la librería estándar.
De acuerdo al registro de cambios CVS , han sido aplicados 481 parches y 502 bugs han sido corregidos entre las versiones 2.3 y 2.4 de Python. Es posible que ambas cifras no concuerden con la realidad, podrían estar subestimadas.
Este artículo no pretende proveer una especificación completa y detallada de cada funcionalidad nueva, en vez de esto, se provee una breve descripción de las nuevas características. Para obtener más información se debe consultar la documentación oficial de Python 2.4, tal como la librería de referencia de Python y el manual de referencia de Python. Otra fuente de información es PEP (guía de estilo-mejoras de python) para buscar información sobre la implementación y fundamentación del diseño.
PEP 218: Objetos conjunto integrados¶
Python 2.3 introdujo el módulo sets
, implementaciones del lenguaje C de tipos de datos han sido agregados al core de Python como dos nuevos tipos integrados. set (iterable)
y frozenset (iterable)
. Ellos proveen operaciones de alto rendimiento para pruebas de pertenencia, eliminar datos duplicados de una secuencia y operaciones matemáticas como: uniones, intersecciones, diferencias y diferencias simétricas.
>>> a = set('abracadabra') # form a set from a string
>>> 'z' in a # fast membership testing
False
>>> a # unique letters in a
set(['a', 'r', 'b', 'c', 'd'])
>>> ''.join(a) # convert back into a string
'arbcd'
>>> b = set('alacazam') # form a second set
>>> a - b # letters in a but not in b
set(['r', 'd', 'b'])
>>> a | b # letters in either a or b
set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
>>> a & b # letters in both a and b
set(['a', 'c'])
>>> a ^ b # letters in a or b but not both
set(['r', 'd', 'b', 'm', 'z', 'l'])
>>> a.add('z') # add a new element
>>> a.update('wxy') # add multiple new elements
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z'])
>>> a.remove('x') # take one element out
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z'])
La función de conjuntos integrados frozenset()
es una versión inmutable de set()
. Como es inmutable y hashable (su valor no cambia), se puede usar como una llave de diccionario o como parte de otro set.
El módulo set sets
se encuentra en la librería estándar y puede ser útil si se desea usar una subclase de Set
o ImmutableSet
No existen planes de deprecación del módulo.
Ver también
- PEP 218 - Agregando tipo de objeto integrado set
Originalmente propuesto por Greg Wilson e implementado finalmente por Raymond Hettinger.
PEP 237: Unificando enteros largos y enteros¶
El prolongado proceso de transición para este PEP que comenzó en Python 2.2 ha dado un paso más adelante en Python 2.4. En la versión 2.3 ciertas operaciones de enteros podían comportarse diferente después de lanzar la unificación del tipo de dato int-long entregando alertas FutureWarning
y retornando valores limitados a 32 o 64 bits dependiendo de su plataforma. En la versión 2.4 estas expresiones ya no producen alertas y en vez de eso entrega un resultado diferente que suele ser un entero largo.
Las expresiones problemáticas son principalmente desplazamientos a la izquierda y constantes largas de hexadecimales y octales. Por ejemplo, 2 << 32
entrega una alerta en la versión 2.3 y evalúa 0 en plataformas 32-bit. Ahora en Python 2.4 la expresión retorna la respuesta correcta, 8589934592.
Ver también
- PEP 237 - Unificando enteros largos y enteros
PEP original escrito por Moshe Zadka y GvR. Los cambios a la versión 2.4 fueron implementados por Kalle Svensson.
PEP 289: Expresiones generadoras¶
La función de iterador introducida en Python 2.2 y el módulo itertools
facilitan la escritura de programas que recorren grandes conjuntos de datos sin tener todo el conjunto de datos en la memoria al mismo tiempo. Las listas de comprensión no encajan muy bien en esta imagen porque producen un objeto de lista de Python que contiene todos los elementos. Esto inevitablemente lleva todos los objetos a la memoria, lo que puede ser un problema si su conjunto de datos es muy grande. Al tratar de escribir un programa de estilo funcional, sería natural escribir algo como:
links = [link for link in get_all_links() if not link.followed]
for link in links:
...
en vez de
for link in get_all_links():
if link.followed:
continue
...
La primera forma es mas concisa y quizás mas legible pero en caso de trabajar con un gran número largo de objetos podría ser necesario el escribir una segunda línea para evitar tener los objetos enlazados en memoria al mismo tiempo.
Las expresiones generadoras trabajan de forma similar a las listas por comprensión pero no materializan la lista completa, en vez de eso se crea un generador que retornará los elementos uno a uno. El siguiente ejemplo podría ser escrito como:
links = (link for link in get_all_links() if not link.followed)
for link in links:
...
Los generadores de expresiones siempre tienen que ser escritos dentro de paréntesis como en el ejemplo descrito arriba. Los paréntesis señalan una llamada a la función que también se puede contar, entonces si se necesita crear un iterador que inmediatamente pasara a una función se podría escribir:
print sum(obj.count for obj in list_all_objects())
Las expresiones generadoras difieren de las listas de comprensión por pequeñas diferencias. La mas notable es que la variable del loop (obj en el ejemplo de arriba) no es accesible fuera de la expresión generadora. Las listas de comprensión dejan la variable asignada a su último valor, en versiones futuras de Python esto será cambiado en lo que respecta a hacer que las listas de comprensión coincidan con las expresiones de los generadores.
Ver también
- PEP 289 - Expresiones generadoras
Propuesto por Raymond Hettinger e implementada por Jiwon Seo con los primeros esfuerzos dirigidos por Hye-Shik Chang.
PEP 292: Sustituciones simples de cadenas de caracteres¶
Algunas nuevas clases en la librería estándar proveen un mecanismo alternativo para sustituir variables dentro de cadenas de caracteres, este estilo de sustituciones puede ser mejor por aplicaciones donde usuarios sin experiencia necesitan editar plantillas.
La manera usual de sustituir variables por el nombre es con el operador %
:
>>> '%(page)i: %(title)s' % {'page':2, 'title': 'The Best of Times'}
'2: The Best of Times'
Cuando se escriben plantillas con cadenas de caracteres puede ser muy fácil olvidar el uso de i
or s
después de cerrar paréntesis. Esto no es un problema grande si se está dentro de un módulo de Python pues al correr el código se lanza el siguiente mensaje de error «Unsupported format character» ValueError
y el problema se resuelve. Sin embargo, tengamos en cuenta una aplicación como Mailman donde una plantilla de caracteres o traducciones son editadas por usuarios que no están familiarizados con Python. La sintaxis de como formatear las cadenas de caracteres es complicada de explicar para ciertos usuarios y si ellos cometen un error es una dificultad el entregar retroalimentación y ayuda.
PEP 292 agrega una clase Template
al módulo string
al módulo que usa $
para indicar una sustitución:
>>> import string
>>> t = string.Template('$page: $title')
>>> t.substitute({'page':2, 'title': 'The Best of Times'})
'2: The Best of Times'
Si una llave falta en el diccionario, el método substitute()
lanzará una KeyError
. También el método safe_substitute()
que ignora las llaves faltantes:
>>> t = string.Template('$page: $title')
>>> t.safe_substitute({'page':3})
'3: $title'
Ver también
- PEP 292 - Sustituciones simples de cadenas de caracteres
Escrito e implementado por Barry Warsaw.
PEP 318: Decoradores para funciones y métodos¶
Python 2.2 extendió el modelo de objeto de Python añadiendo métodos estáticos y métodos de clase pero no se extendió la sintaxis de Python para proveer alguna nueva forma de definir métodos estáticos o de clase. En vez de eso se tenía que escribir la palabra clave def
de manera usual y pasar el método resultante a la staticmethod()
o a la classmethod()
que podía agrupar la función como método de un nuevo tipo. El código podría verse como esto:
class C:
def meth (cls):
...
meth = classmethod(meth) # Rebind name to wrapped-up class method
Si el método era muy largo, era muy probable el perder o olvidar la invocación classmethod()
dentro del cuerpo de la función.
La intención era siempre agregar alguna sintaxis que hicieran las definiciones mas entendibles pero al tiempo del lanzamiento de la versión 2.2 una buena sintaxis no era clara. Al día de hoy una buena sintaxis aun no es clara pero los usuarios están preguntando por formas más fáciles de acceder a las características, entonces una nueva funcionalidad sintáctica ha sido añadida para satisfacer esta necesidad.
La nueva característica es llamada decoradores de funciones. El nombre proviene de la idea de que classmethod()
, staticmethod()
son amigos y guardan información adicional en un objeto de una función. ellos están decorando funciones con mas detalles.
La notación proviene de Java y usa el '@'
símbolo arroba como un indicador. Usando la nueva sintaxis el ejemplo descrito arriba podría ser escrito de la siguiente forma:
class C:
@classmethod
def meth (cls):
...
El @classmethod
es un atajo para meth=classmethod(meth)
. De forma general si se tiene lo siguiente:
@A
@B
@C
def f ():
...
Es el equivalente para el siguiente código de pre decorador:
def f(): ...
f = A(B(C(f)))
Los decoradores deben agregarse en una línea antes de la definición de la función, un decorador por línea y no puede estar en la misma línea donde se usa la palabra def para comenzar una función, por ejemplo @A def f(): ...
es incorrecto. Solo se puede decorar una definición de función tanto al nivel de módulo o dentro de una clase pero no puedes decorar definiciones de clase.
Un decorador es simplemente una función que toma la función a ser decorada como un argumento y retorna tanto la misma función o un nuevo objeto. El valor de retorno del decorador no necesita ser llamado (como típicamente se cree) si no que los decoradores podrán ser aplicados al resultado. Es fácil escribir sus propios decoradores. El siguiente ejemplo agrega un atributo a la función objetiva:
>>> def deco(func):
... func.attr = 'decorated'
... return func
...
>>> @deco
... def f(): pass
...
>>> f
<function f at 0x402ef0d4>
>>> f.attr
'decorated'
>>>
Como un ejemplo un poco mas realista, el siguiente decorador revisa si el argumento entregado es un entero:
def require_int (func):
def wrapper (arg):
assert isinstance(arg, int)
return func(arg)
return wrapper
@require_int
def p1 (arg):
print arg
@require_int
def p2(arg):
print arg*2
Un ejemplo en PEP 318 contiene una versión mas elegante de esta idea donde deja que usted elija específicamente el tipo y revisa el tipo de retorno.
Los decoradores de funciones pueden tomar argumentos. Si los argumentos son provistos, el decorador de la función es llamado con solo esos argumentos y retorna un nuevo decorador de función, esta función debe tomar una función sola y retorna una función como previamente se ha descrito. En otras palabras @A @B @C(args)
comienza:
def f(): ...
_deco = C(args)
f = A(B(_deco(f)))
Conseguir que esto resulte correcto puede ser un acertijo pero tampoco es muy dificultoso.
A small related change makes the func_name
attribute of functions
writable. This attribute is used to display function names in tracebacks, so
decorators should change the name of any new function that’s constructed and
returned.
Ver también
- PEP 318 Decoradores para funciones, métodos y clases
Escrito por Kevin D.Smith, Jim Jewett y Skip Montanaro. Varias personas escribieron parches sobre la implementación de los decoradores de funciones, pero el único que fue chequeado fue #979728 por Mark Russell.
- https://wiki.python.org/moin/PythonDecoratorLibrary
Esta pagina de wiki contiene múltiples ejemplos de decoradores.
PEP 322: Iteración inversa¶
Una nueva función de conjuntos integrados, reversed(seq)
toma una secuencia y retorna un iterador que recorre los elementos de la secuencia en orden inverso.:
>>> for i in reversed(xrange(1,4)):
... print i
...
3
2
1
Comparado con el uso tradicional de la segmentación tal como range(1,4)[::-1]
la función reversed()
es fácil de leer, se ejecuta mas rápido y usa sustancialmente menos memoria.
Señalar que la función reversed()
solo acepta secuencias, no iteradores arbitrarios. Si se quiere revertir un iterador, primero se debe convertir a una lista usando la función list()
.:
>>> input = open('/etc/passwd', 'r')
>>> for line in reversed(list(input)):
... print line
...
root:*:0:0:System Administrator:/var/root:/bin/tcsh
...
Ver también
- PEP 322 - Iteración inversa
Escrita e implementada por Raymond Hettinger.
PEP 324: Nuevo módulo de subproceso¶
The standard library provides a number of ways to execute a subprocess, offering
different features and different levels of complexity.
os.system(command)
is easy to use, but slow (it runs a shell process
which executes the command) and dangerous (you have to be careful about escaping
the shell’s metacharacters). The popen2
module offers classes that can
capture standard output and standard error from the subprocess, but the naming
is confusing. The subprocess
module cleans this up, providing a unified
interface that offers all the features you might need.
Instead of popen2
’s collection of classes, subprocess
contains a
single class called subprocess.Popen
whose constructor supports a number of
different keyword arguments.
class Popen(args, bufsize=0, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=False, shell=False,
cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0):
args es comúnmente una secuencia de cadenas de caracteres que podrán ser los argumentos del programa ejecutado como un subproceso. (Si el argumento shell es verdadero, args puede ser una cadena de caracteres que serán pasados directamente a la shell para su interpretación, tal como os.system()
lo hace.)
stdin, stdout, y stderr especifican que flujos de entrada, salida y error serán utilizados. Se puede proceder un objeto de archivo o un archivo de descripción o se puede usar la constante subprocess.PIPE
para crear un enlace entre el subproceso y el proceso principal.
El constructor tiene un número de opciones útiles:
close_fds requiere que todos los descriptores de archivos sean cerrados antes de correr el subproceso.
cwd especifica el directorio operativo donde el subproceso será ejecutado (por defecto, cualquiera que sea el directorio principal)
env es un diccionario donde se especifican las variables de entorno.
preexec_fn es una función que es llamada antes de que el proceso hijo sea llamado.
universal_newlines abre el flujo de entrada y salida del hijo usando la característica de Python universal newlines .
Una vez que se ha creado la instancia de la Popen
se puede llamar al método wait()
para poner en pausa hasta que el subproceso ha terminado, el método poll()
comprueba si se ha salido sin pausar o el uso de communicate(data)
envía la cadena de caracteres data a la entrada estándar del subproceso. Y el uso de communicate(data)
que lee cualquier dato que el subproceso ha enviado a la salida estándar, retornando una tupla (stdout_data, stderr_data)
.
call()
es un atajo que pasa estos argumentos a lo largo del constructor de la clase Popen
, espera por el comando para completar la secuencia y retorna el código de estatus del subproceso. Esto puede servir como un análogo mas seguro de os.system()
:
sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb'])
if sts == 0:
# Success
...
else:
# dpkg returned an error
...
El comando es invocado sin el uso del interprete de comandos. Si se desea usar el intérprete se puede agregar shell=True
como un argumento de palabra clave y proveer una cadena de caracteres en vez de una secuencia:
sts = subprocess.call('dpkg -i /tmp/new-package.deb', shell=True)
La guía de estilo de Python toma varios ejemplos de línea de comandos y código python y muestra como estos son traducidos en el código python subprocess
. Leer esta sección de la guía de estilo es altamente recomendado.
Ver también
- PEP 324 - subprocess - Nuevo módulo de procesos
Escrito e implementado por Peter Åstrand, con asistencia de Frederik Lundh y otros.
PEP 327: Tipo de dato decimal¶
Python siempre ha soportado números de punto flotante (FP), basados en el tipo subyacente C double, como un tipo de datos. Sin embargo, aunque la mayoría de los lenguajes de programación proporcionan un tipo de punto flotante, muchas personas (incluso los programadores) no saben que los números de punto flotante no representan ciertas fracciones decimales con precisión. El nuevo tipo Decimal
puede representar estas fracciones con precisión, hasta un límite de precisión especificado por el usuario.
¿Por qué se necesita Decimal?¶
Las limitaciones surgen de la representación usada para los números de punto flotante. Los números de punto flotante están hechos de tres componentes:
El signo, el cual es positivo o negativo.
El significando o mantisa el cual es el un dígito binario seguido de su parte fraccional. Por ejemplo,
1.01
en notación base 2 es1 + 0/2 + 1/4
o 1.25 en notación decimal.El exponente, que indica dónde se encuentra el punto decimal en el número representado.
Por ejemplo, el número 1.25 tiene un signo positivo, una mantisa de valor 1.01 (en binario) y un exponente de 0 (el punto decimal no necesita ser desplazado. El números 5 tiene el mismo signo y significando pero, el exponente es 2 porque el significando es multiplicado por 4 (2 elevado a la potencia del exponente 2), 1.25 * 4 es igual a 5.
Los sistemas modernos generalmente brindan soporte de coma flotante que se ajusta a un estándar llamado IEEE 754. El tipo double de C generalmente se implementa como un número IEEE 754 de 64 bits, que usa 52 bits de espacio para la mantisa. Esto significa que los números solo se pueden especificar con 52 bits de precisión. Si está tratando de representar números cuya expansión se repite sin cesar, la expansión se corta después de 52 bits. Desafortunadamente, la mayoría del software necesita producir resultados en base 10, y las fracciones comunes en base 10 a menudo son decimales repetidos en binario. Por ejemplo, 1.1 decimal es binario 1.0001100110011 ...
; .1 = 1/16 + 1/32 + 1/256 más un número infinito de términos adicionales. IEEE 754 tiene que cortar ese decimal repetido infinitamente después de 52 dígitos, por lo que la representación es un poco inexacta.
Algunas veces se puede ver esta inexactitud cuando el número es impreso por pantalla:
>>> 1.1
1.1000000000000001
La inexactitud no siempre es visible cuando se imprime el número porque el punto flotante a decimal y conversión a cadena de texto es entregada por la librería C y la mayoría de las librerías C tratan de producir una salida sensible. Incluso si no es mostrado, la inexactitud sigue ahí y las operaciones subsecuentes pueden agrandar el error.
Para muchas aplicaciones esto no importa. Si estoy trazando puntos y mostrándolos en el monitor la diferencia entre 1.1 y 1.1000000000000001 es muy pequeña para ser visible. Los reportes a menudo limitan la salida de un cierto número de decimales y si se redondea el número a dos o tres e incluso a 8 decimales, el error nunca aparece. Sin embargo, para las aplicaciones donde esto importa, es una cantidad de trabajo importante el personalizar los cálculos aritméticos.
Es por eso que el tipo de clase Decimal
fue creada.
El tipo de clase Decimal
¶
Un nuevo módulo, decimal
, fue añadido a la librería estándar de Python. Esta contiene dos clases, Decimal
y Context
. Las instancias de la clase decimal Decimal
representan números y la instancia de la Context
son usadas para condensar varios ajustes como la precisión y el modo de redondeo por defecto.
Las instancias de la clase Decimal
son inmutables como los números enteros y números de punto flotante en Python, una vez han sido creadas no se puede cambiar el valor de lo que la instancia representa. Las instancias de la Decimal
pueden ser creados desde números enteros o cadenas de texto:
>>> import decimal
>>> decimal.Decimal(1972)
Decimal("1972")
>>> decimal.Decimal("1.1")
Decimal("1.1")
También se pueden proveer tuplas que contentan el signo, la mantisa representada como una tupla de números decimales y el exponente:
>>> decimal.Decimal((1, (1, 4, 7, 5), -2))
Decimal("-14.75")
Precaución: El signo bit es un valor booleano entonces 0 es positivo y 1 es negativo.
Convertir desde números de punto flotante posee un pequeño problema, el punto flotante representa 1.1 y se convierte en número decimal como 1.1 o por 1.1 mas cualquier inexactitud que se introduzca? La decisión fue evitar el problema y dejar tal conversión fuera de la API. En su lugar se debe convertir el número de punto flotante en una cadena con la precisión deseada y pasar la cadena al constructor Decimal
:
>>> f = 1.1
>>> decimal.Decimal(str(f))
Decimal("1.1")
>>> decimal.Decimal('%.12f' % f)
Decimal("1.100000000000")
Una vez que se tiene la instancia de la clase Decimal
se pueden realizar las operaciones matemáticas de rigor. Una limitación, la exponenciación requiere un exponente expresado en tipo de dato entero:
>>> a = decimal.Decimal('35.72')
>>> b = decimal.Decimal('1.73')
>>> a+b
Decimal("37.45")
>>> a-b
Decimal("33.99")
>>> a*b
Decimal("61.7956")
>>> a/b
Decimal("20.64739884393063583815028902")
>>> a ** 2
Decimal("1275.9184")
>>> a**b
Traceback (most recent call last):
...
decimal.InvalidOperation: x ** (non-integer)
Se puede combinar la instancia de la clase Decimal
con enteros pero no con números de punto flotante:
>>> a + 4
Decimal("39.72")
>>> a + 4.5
Traceback (most recent call last):
...
TypeError: You can interact Decimal only with int, long or Decimal data types.
>>>
Los números en la clase Decimal
pueden ser usados con los módulos math
y cmath
pero es preciso aclarar que ellos serán inmediatamente convertidos a números de punto flotante antes de realizar la operación, resultando en una posible perdida de precisión y exactitud. También obtendrá un número de punto flotante y no una clase Decimal
:
>>> import math, cmath
>>> d = decimal.Decimal('123456789012.345')
>>> math.sqrt(d)
351364.18288201344
>>> cmath.sqrt(-d)
351364.18288201344j
Las instancias de la clase Decimal
poseen un método sqrt()
que retorna una clase Decimal
pero si se necesita otro tipo de cosas como funciones trigonométricas se tendrían que implementar:
>>> d.sqrt()
Decimal("351364.1828820134592177245001")
El tipo de clase Context
¶
Las instancias de la Context
encapsulan varios ajustes para operaciones con decimales:
atributo
prec
es la precisión del número de decimales.El atributo
rounding
especifica el modo de redondeo. El módulodecimal
tiene constantes para varias posibilidades,ROUND_DOWN
,ROUND_CEILING
,ROUND_HALF_EVEN
y varias otras.El atributo
traps
es un diccionario que especifica lo que sucede al encontrar ciertas condiciones de error: Ya sea una excepción lanzada o un valor es retornado. algunos ejemplos de errores son las divisiones por cero, perdida de precisión o desbordamiento.
Hay un contexto predeterminado local de subprocesos disponible llamando a la función getcontext()
, se puede cambiar las propiedades de este contexto para alterar la precisión por defecto, redondear o manejar trampas. el siguiente ejemplo muestra el efecto de cambiar la precisión del contexto por defecto:
>>> decimal.getcontext().prec
28
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.1428571428571428571428571429")
>>> decimal.getcontext().prec = 9
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.142857143")
Las acciones por defecto para condiciones de error se puede seleccionar, ya sea que el módulo pueda retornar un valor especial como un infinito o un valor no numérico NaN o se pueden lanzar excepciones:
>>> decimal.Decimal(1) / decimal.Decimal(0)
Traceback (most recent call last):
...
decimal.DivisionByZero: x / 0
>>> decimal.getcontext().traps[decimal.DivisionByZero] = False
>>> decimal.Decimal(1) / decimal.Decimal(0)
Decimal("Infinity")
>>>
La instancia de la clase Context
también tiene varios métodos para formatear números tales como to_eng_string()
y to_sci_string()
.
Para mas información, revisar la documentación para el módulo decimal
el cual incluye un tutoría de inicio rápido y una referencia.
Ver también
- PEP 327 - Tipo de dato decimal
Escrito por Facundo Batista e implementado por Facundo Batista, Eric Price, Raymond Hettinger, Aahz y Tim Peters.
- http://www.lahey.com/float.htm
El articulo usa código Fortran para ilustrar varios de los problemas que la inexactitud de los puntos flotantes pueden causar.
- http://speleotrove.com/decimal/
Una descripción de una representación basada en decimales. Esta representación ha sido propuesta como un estándar y subyace al nuevo tipo de dato decimal en Python. La mayor parte de este material fue escrita por Mike Cowlishaw, diseñador del lenguaje Rexx.
PEP 328: Importaciones multilínea¶
Un pequeño cambio en el lenguaje ha sido una modificación a una sintaxis confusa que ha sido cambiada para hacer mas fácil el agregar varios nombres en un módulo. En una declaración from module import names
, names es una secuencia de nombres separados por comas. Si la sentencia es muy larga, se puede ya sea escribir múltiples sentencias import desde el mismo módulo o se pueden usar barras invertidas para escapar de los términos de línea como esto:
from SimpleXMLRPCServer import SimpleXMLRPCServer,\
SimpleXMLRPCRequestHandler,\
CGIXMLRPCRequestHandler,\
resolve_dotted_attribute
La sintaxis cambió en Python 2.4 y es simplemente el permitir poner los nombres dentro de paréntesis. Python ignora nuevas líneas dentro de una expresión entre paréntesis por lo que las barras invertidas ya no se necesitan:
from SimpleXMLRPCServer import (SimpleXMLRPCServer,
SimpleXMLRPCRequestHandler,
CGIXMLRPCRequestHandler,
resolve_dotted_attribute)
La convención de estilo también propone que todas las declaraciones usando import
son importaciones absolutas, con el siguiente carácter .
indica una importación relativa. Esta parte de la convención de estilo no fue implementada para Python 2.4 pero fue completada para la versión 2.5.
Ver también
- PEP 328 - Importaciones multi línea y absolutas/relativas
Escrita por Aahz. Importaciones multi línea fueron implementadas por Dima Dorfman.
PEP 331: Conversiones locales-independientes números flotantes/cadenas de texto¶
Los módulos locale
deja que el software de Python seleccione varias conversiones y despliegue convenciones que están localizadas en un país particular o lenguaje. Sin embargo, el módulo es cuidadoso en no cambiar el local numérico porque la implementación de Python requería que la configuración regional numérica permaneciera establecida en la configuración regional 'C'
. A menudo, esto se debía a que el código utilizaba la función atof()
de la biblioteca C.
No configurar la configuración regional numérica causaba problemas para las extensiones que usaban librerías externas de C, sin embargo, porque no configuraban la correcta configuración. El ejemplo mas patente fue GTK+, cuya interfaz de usuario no mostraba números en la ubicación actual.
La solución descrita en la convención de estilo es añadir tres nuevas funciones a la API de python que ejecuta solo conversiones a ASCII, ignorando las configuraciones locales:
PyOS_ascii_strtod(str, ptr)
yPyOS_ascii_atof(str, ptr)
convierten una cadena en C double.PyOS_ascii_formatd(buffer, buf_len, format, d)
convierte un double en una cadena ASCII.
The code for these functions came from the GLib library
(https://developer-old.gnome.org/glib/2.26/), whose developers kindly
relicensed the relevant functions and donated them to the Python Software
Foundation. The locale
module can now change the numeric locale,
letting extensions such as GTK+ produce the correct results.
Ver también
- PEP 331 Conversiones Local-Independiente flotante/cadena de texto
Escrito por Christian R. Reis, e implementado por Gustavo Carneiro.
Otros cambios en el lenguaje¶
Aquí están todos los cambios que Python 2.4 ha hecho al core del lenguaje Python.
Fueron añadidos decoraciones para funciones (PEP 318).
Funciones de conjuntos integrados
set()
yfrozenset()
fueron añadidas (PEP 218). Otras nuevas funciones de conjuntos integrados incluyen la funciónreversed(seq)
(PEP 322).Generador de expresiones fueron añadidas (PEP 289).
Algunas expresiones numéricas ya no retornan valores restringidos a 32 o 64 bits (PEP 237).
Se puede poner entre paréntesis una lista de nombres en la declaración
from module import names
(PEP 328).El método
dict.update()
ahora acepta el mismo argumento que el constructor de ladict
. Esto incluye cualquier tipo de mapeo, iterable pares de clave/valor y argumentos de palabra clave. (Contribución de Raymond Hettinger)Los métodos de cadena de caracteres
ljust()
,rjust()
ycenter()
ahora toman un argumento de tipo opcional para especificar un carácter de relleno que no sea un espacio. (Contribución de Raymond Hettinger).Cadenas de caracteres también han ganado un método
rsplit()
que funciona como el métodosplit()
pero divide desde el final de la cadena de caracteres. (Contribución de Sean Reifschneider)>>> 'www.python.org'.split('.', 1) ['www', 'python.org'] 'www.python.org'.rsplit('.', 1) ['www.python', 'org']
Tres parámetros de argumentos de palabra clave cmp, key y reverse fueron añadidos al método de listas
sort()
. Estos parámetros hacen algunos usos comunes del métodosort()
mas simple. Todos estos parámetros son opcionales.Para el parámetro cmp el valor debe ser una función comparativa que toma dos parámetros y retorna -1, 0 o + 1 dependiendo de como compare los parámetros. Esta función será usada para ordenar la lista. Previamente esto era el único parámetro que podía ser entregado al
sort()
.key debe ser una función con un solo parámetro que toma un elemento de la lista y retorna una llave de comparación para el elemento. Entonces la lista es ordenado usando las claves de comparación. El siguiente ejemplo ordena una lista sin distinción de mayúsculas ni minúsculas:
>>> L = ['A', 'b', 'c', 'D'] >>> L.sort() # Case-sensitive sort >>> L ['A', 'D', 'b', 'c'] >>> # Using 'key' parameter to sort list >>> L.sort(key=lambda x: x.lower()) >>> L ['A', 'b', 'c', 'D'] >>> # Old-fashioned way >>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower())) >>> L ['A', 'b', 'c', 'D']
El ultimo ejemplo el cual usa el parámetro cmp es la antigua forma de ejecutar el orden sin distinción de mayúsculas y minúsculas. Funciona pero es mas lento en vez de usar el parámetro key. El uso de key llama al método
lower()
una vez para cada elemento de la lista mientras el uso de cmp lo llamara dos veces para cada comparación, entonces al usar * key * se guardan las llamadas del métodolower()
.Para funciones de clave sencillas y comparativas es a menudo posible el obviar la palabra clave
lambda
usando un método sin ligar en reemplazo. El siguiente ejemplo de orden sin importar mayúsculas ni minúsculas es mejor escrito como se muestra:>>> L.sort(key=str.lower) >>> L ['A', 'b', 'c', 'D']
Finalmente el parámetro reverse toma un valor de tipo booleano. Si el valor es verdadero la lista será ordenada de forma inversa. En vez de
L.sort(); L.reverse()
ahora se puede escribirL.sort(reverse=True)
.Los resultados del ordenamiento ahora están garantizados que son estables. Esto significa que dos entradas con iguales claves serán retiradas en el mismo orden en que fueron ingresadas. Por ejemplo se puede ordenar una lista de personas por el nombre y entonces ordenarla por edad, resultando en una lista ordenada donde las personas con la misma edad están en el mismo orden por nombre.
(Todos los cambios al método
sort()
fueron realizados por Raymond Hettinger.)Se tiene una nueva función incorporada
sorted(iterable)
que trabaja como el método in situlist.sort()
que se puede usar en expresiones. Las diferencias son:el dato de entrada puede ser algún iterable;
se ordena una copia recién formada, manteniendo el original intacto y
la expresión retorna una nueva copia ordenada
>>> L = [9,7,8,3,2,4,1,6,5] >>> [10+i for i in sorted(L)] # usable in a list comprehension [11, 12, 13, 14, 15, 16, 17, 18, 19] >>> L # original is left unchanged [9,7,8,3,2,4,1,6,5] >>> sorted('Monty Python') # any iterable may be an input [' ', 'M', 'P', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y', 'y'] >>> # List the contents of a dict sorted by key values >>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5) >>> for k, v in sorted(colormap.iteritems()): ... print k, v ... black 4 blue 2 green 3 red 1 yellow 5
(Contribución de Raymond Hettinger.)
Operaciones de números enteros no lanzaran una excepción
OverflowWarning
. La advertencia sobreOverflowWarning
desaparecerá en Python 2.5.Se añadió al interprete una nueva opción de cambio
-m
la cual toma un nombre, busca el módulo correspondiente ensys.path
y corre el módulo como script. Ahora por ejemplo se puede correr el perfilador de Python conpython -m profile
. (Contribución de Nick Coghlan)La expresión
eval(expr, globals, locals)
la funciónexecfile(filename, globals, locals)
y la sentenciaexec
ahora aceptan cualquier tipo de mapeo para parámetros locales. Previamente esto era parte de un diccionario de Python. (Contribución de Raymond Hettinger.)La función incorporada
zip()
y la funciónitertools.izip()
ahora retornan una lista hacia si se llama sin argumentos. Previamente estos lanzaban una excepción de tipoTypeError
. Esto lo hace mas apropiado de usar con listas de argumentos de longitud variable:>>> def transpose(array): ... return zip(*array) ... >>> transpose([(1,2,3), (4,5,6)]) [(1, 4), (2, 5), (3, 6)] >>> transpose([]) []
(Contribución de Raymond Hettinger.)
Encontrar un error al importar un módulo ya no deja un objeto de módulo parcialmente inicializado en
sys.modules
. El objeto de módulo incompleto que se deja atrás engañaría a las importaciones posteriores del mismo módulo para que tuvieran éxito, lo que generaría errores confusos. (Reparado por Tim Peters.)None`es ahora una constante, el código que une un nuevo valor con el nombre :const:`None
es ahora un error de sintaxis (Contribución de Raymond Hettinger)
Optimizaciones¶
Los bucles internos para separar listas y tuplas fueron optimizados y ahora corren un tercio mas rápido. Los bucles internos para diccionarios también fueron optimizados resultando en una mejora en el rendimiento para
keys()
,values()
,items()
,iterkeys()
,itervalues()
, yiteritems()
. (Contribución de Raymond Hettinger)El mecanismo para mejorar y contraer listas fue optimizada para efectos de velocidad y eficiencia en la utilización de recursos. Anexar y quitar elementos de una lista es ahora mas rápido debido al código mas eficiente y al menos frecuente uso de la función subyacente
realloc()
. Las listas por comprensión también son beneficiadas, el métodolist.extend()
fue también optimizado y ya no convierte mas el argumento en una lista temporal antes de extender la lista base. (Contribución de Raymond Hettinger)Las funciones
list()
,tuple()
,map()
,filter()
yzip()
ahora corren mucho mas rápido con argumentos no secuenciales que ahora suministra el método__len__()
. (Contribución Raymond Hettinger.)Los métodos
list.__getitem__()
,dict.__getitem__()
ydict.__contains__()
ahora son implementados como objetos de la clasemethod_descriptor
en vez de los objetos de la clasewrapper_descriptor
. Este acceso dobla el rendimiento y hace que sea mas apropiado para ser usado como argumentos de:map(mydict.__getitem__, keylist)
. (Contribución de Raymond Hettinger)Adicionalmente se ha agregado a un nuevo código de operación
LIST_APPEND
esto simplifica la generación de código a nivel de byte para las listas por comprensión y las agiliza en aproximadamente un tercio.El optimizador de código a nivel de byte ha sido mejorado para producir código a nivel de byte mas corto y rápido. Esto resulta en código mas legible. (Contribución de Raymond Hettinger)
La concatenación de cadenas de texto en la declaración de
s = s + "abc"
ands += "abc"
ahora son ejecutadas de forma mas eficiente en ciertas circunstancias. Esta optimizaciones no serán mostradas en otras implementaciones de Python tales como Python, entonces no se debe utilizar, es mejor seguir utilizando el métodojoin()
de cadenas de caracteres si se quiere mantener la eficiencia de concatenar un largo número de cadenas de caracteres. (Contribución de Armin Rigo.)
El resultado de las optimizaciones de la versión 2.4 es que tomando Python 2.4 como punto de referencia corre alrededor de un 5% mas rápido que Python 2.3 y un 35% mas rápido que Python 2.2 (pystone no es particularmente un buen punto de referencia pero es el mas usado para medir rendimiento en Python. Sus propias aplicaciones pueden mostrar beneficios mas grandes o mínimos desde Python 2.4)
Módulos nuevos, mejorados y obsoletos¶
Como es usual, la librería estándar de Python recibió un número de mejoras y corrección de errores. Aquí hay una lista parcial de los cambios mas notables, ordenados alfabéticamente por nombre de módulo. Consulte el archivo Misc/NEWS
en la estructura del directorio para una completa lista de los cambios o se puede buscar a través del registro CVS para obtener todos los detalles.
El módulo
asyncore
y la funciónloop()
ahora tiene un parámetro count que permite ejecutar un limitado número de pases mediante el bucle. El valor predeterminado sigue siendo el bucle para siempre.El módulo
base64
ahora tiene un soporte mas completo RFC 3548 para Base64, Base32 y Base16 para codificación y descodificación, incluyendo procesos de convertir caracteres a minúsculas y alfabetos alternativos. (Contribución de Barry Warsaw)El módulo
bisect
ahora tiene una implementación C subyacente para mejorar el rendimiento. (Contribuido por Dmitry Vasiliev.)Las colecciones CJKCodecs de códecs de Asia oriental, mantenidas por Hye-Shik Chang, se integraron en 2.4. Las nuevas codificaciones son:
Chino (PRC): gb2312, gbk, gb18030, big5hkscs, hz
Chino (República de China): big5, cp950
- Japonés: cp932, euc-jis-2004, euc-jp, euc-jisx0213, iso-2022-jp,
iso-2022-jp-1, iso-2022-jp-2, iso-2022-jp-3, iso-2022-jp-ext, iso-2022-jp-2004, shift-jis, shift-jisx0213, shift- jis-2004
Coreano: cp949, euc-kr, johab, iso-2022-kr
Se agregaron algunas otras codificaciones nuevas: HP Roman8, ISO_8859-11, ISO_8859-16, PCTP-154 y TIS-620.
Los códecs UTF-8 y UTF-16 ahora se adaptan mejor a la recepción de entradas parciales. Anteriormente, la clase
StreamReader
intentaba leer más datos, lo que hacía imposible reanudar la decodificación desde el flujo. El métodoread()
ahora devolverá tantos datos como pueda y las llamadas futuras reanudarán la decodificación donde lo dejaron las anteriores. (Implementado por Walter Dörwald.)Hay un nuevo módulo
collections
para varios tipos de datos de recopilación especializados. Actualmente contiene solo un tipo,deque
, una cola de dos extremos que admite la adición y eliminación de elementos de manera eficiente desde cualquier extremo:>>> from collections import deque >>> d = deque('ghi') # make a new deque with three items >>> d.append('j') # add a new entry to the right side >>> d.appendleft('f') # add a new entry to the left side >>> d # show the representation of the deque deque(['f', 'g', 'h', 'i', 'j']) >>> d.pop() # return and remove the rightmost item 'j' >>> d.popleft() # return and remove the leftmost item 'f' >>> list(d) # list the contents of the deque ['g', 'h', 'i'] >>> 'h' in d # search the deque True
Varios módulos, como los módulos
Queue
ythreading
, ahora aprovechancollections.deque
para mejorar el rendimiento. (Contribuido por Raymond Hettinger.)The
ConfigParser
classes have been enhanced slightly. Theread()
method now returns a list of the files that were successfully parsed, and theset()
method raisesTypeError
if passed a value argument that isn’t a string. (Contributed by John Belmonte and David Goodger.)El módulo
curses
ahora admite la extensión ncursesuse_default_colors()
. En plataformas donde el terminal admite transparencia, esto permite utilizar un fondo transparente. (Contribución de Jörg Lehmann.)El módulo
difflib
ahora incluye una claseHtmlDiff
que crea una tabla HTML que muestra una comparación lado a lado de dos versiones de un texto. (Contribuido por Dan Gass.)El paquete
email
se actualizó a la versión 3.0, que eliminó varias API obsoletas y elimina la compatibilidad con versiones de Python anteriores a la 2.3. La versión 3.0 del paquete usa un nuevo analizador incremental para mensajes MIME, disponible en el móduloemail.FeedParser
. El nuevo analizador no requiere leer todo el mensaje en la memoria y no genera excepciones si un mensaje tiene un formato incorrecto; en su lugar, registra cualquier problema en el atributodefect
del mensaje. (Desarrollado por Anthony Baxter, Barry Warsaw, Thomas Wouters y otros).El módulo
heapq
se ha convertido a C. La mejora de diez veces resultante en la velocidad hace que el módulo sea adecuado para manejar grandes volúmenes de datos. Además, el módulo tiene dos funciones nuevasnlargest()
ynsmallest()
que usan montones para encontrar los N valores más grandes o más pequeños en un conjunto de datos sin el gasto de una clasificación completa. (Contribuido por Raymond Hettinger.)The
httplib
module now contains constants for HTTP status codes defined in various HTTP-related RFC documents. Constants have names such asOK
,CREATED
,CONTINUE
, andMOVED_PERMANENTLY
; use pydoc to get a full list. (Contributed by Andrew Eland.)El módulo
imaplib
ahora es compatible con el comando THREAD de IMAP (aportado por Yves Dionne) y los nuevos métodosdeleteacl()
ymyrights()
(aportado por Arnaud Mazin).El módulo
itertools
ganó una funcióngroupby(iterable[, *func*])
. El parámetro iterable is something that can be iterated over to return a stream of elements, and the optional func es una función que toma un elemento y devuelve un valor clave; si se omite, la clave es simplemente el elemento en sí.groupby()
luego agrupa los elementos en subsecuencias que tienen valores coincidentes de la clave y devuelve una serie de 2 tuplas que contienen el valor de la clave y un iterador sobre la subsecuencia.Aquí hay un ejemplo para aclarar esto. La función key simplemente devuelve si un número es par o impar, por lo que el resultado de
groupby()
es devolver series consecutivas de números pares o impares.>>> import itertools >>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14] >>> for key_val, it in itertools.groupby(L, lambda x: x % 2): ... print key_val, list(it) ... 0 [2, 4, 6] 1 [7] 0 [8] 1 [9, 11] 0 [12, 14] >>>
groupby()
se utiliza normalmente con entrada ordenada. La lógica paragroupby()
es similar al filtro Unixuniq
, lo que lo hace útil para eliminar, contar o identificar elementos duplicados:>>> word = 'abracadabra' >>> letters = sorted(word) # Turn string into a sorted list of letters >>> letters ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r'] >>> for k, g in itertools.groupby(letters): ... print k, list(g) ... a ['a', 'a', 'a', 'a', 'a'] b ['b', 'b'] c ['c'] d ['d'] r ['r', 'r'] >>> # List unique letters >>> [k for k, g in groupby(letters)] ['a', 'b', 'c', 'd', 'r'] >>> # Count letter occurrences >>> [(k, len(list(g))) for k, g in groupby(letters)] [('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]
(Contribuido por Hye-Shik Chang.)
itertools
también obtuvo una función denominadatee(iterator, N)
que devuelve N independent iterators that replicate iterator. If N se omite, el valor predeterminado es 2.>>> L = [1,2,3] >>> i1, i2 = itertools.tee(L) >>> i1,i2 (<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>) >>> list(i1) # Run the first iterator to exhaustion [1, 2, 3] >>> list(i2) # Run the second iterator to exhaustion [1, 2, 3]
Tenga en cuenta que
tee()
debe mantener copias de los valores devueltos por el iterador; en el peor de los casos, es posible que deba conservarlos todos. Por lo tanto, esto debe usarse con cuidado si el iterador principal puede ejecutarse muy por delante del iterador final en un flujo largo de entradas. Si la separación es grande, entonces también podría usarlist()
en su lugar. Cuando los iteradores se siguen de cerca entre sí,tee()
es ideal. Las posibles aplicaciones incluyen marcadores, ventanas o iteradores de anticipación. (Contribuido por Raymond Hettinger.)A number of functions were added to the
locale
module, such asbind_textdomain_codeset()
to specify a particular encoding and a family ofl*gettext()
functions that return messages in the chosen encoding. (Contributed by Gustavo Niemeyer.)Se agregaron algunos argumentos de palabras clave a la función
basicConfig()
del paquetelogging
para simplificar la configuración del registro. El comportamiento predeterminado es registrar mensajes con error estándar, pero se pueden especificar varios argumentos de palabras clave para registrar en un archivo en particular, cambiar el formato de registro o establecer el nivel de registro. Por ejemplo:import logging logging.basicConfig(filename='/var/log/application.log', level=0, # Log all messages format='%(levelname):%(process):%(thread):%(message)')
Otras adiciones al paquete
logging
incluyen un método de conveniencialog(level, msg)
, así como una claseTimedRotatingFileHandler
que rota sus archivos de registro en un intervalo cronometrado. El módulo ya teníaRotatingFileHandler
, que rotaba los registros una vez que el archivo excedía un cierto tamaño. Ambas clases derivan de una nueva claseBaseRotatingHandler
que se puede utilizar para implementar otros controladores rotativos.(Cambios implementados por Vinay Sajip.)
El módulo
marshal
ahora comparte cadenas internas al desempaquetar una estructura de datos. Esto puede reducir el tamaño de ciertas cadenas de pickle, pero el efecto principal es hacer que los archivos.pyc
sean significativamente más pequeños. (Contribución de Martin von Löwis.)La clase
NNTP
del módulonntplib
obtuvo los métodosdescription()
ydescriptions()
para recuperar descripciones de grupos de noticias para un solo grupo o para un rango de grupos. (Contribución de Jürgen A. Erhard.)Se agregaron dos nuevas funciones al módulo
operator
,attrgetter(attr)
yitemgetter(index)
. Ambas funciones devuelven invocables que toman un solo argumento y devuelven el atributo o elemento correspondiente; estos llamables son excelentes extractores de datos cuando se utilizan conmap()
osorted()
. Por ejemplo:>>> L = [('c', 2), ('d', 1), ('a', 4), ('b', 3)] >>> map(operator.itemgetter(0), L) ['c', 'd', 'a', 'b'] >>> map(operator.itemgetter(1), L) [2, 1, 4, 3] >>> sorted(L, key=operator.itemgetter(1)) # Sort list by second tuple item [('d', 1), ('c', 2), ('b', 3), ('a', 4)]
(Contribución de Raymond Hettinger.)
El módulo
optparse
se actualizó de varias formas. El módulo ahora pasa sus mensajes a través degettext.gettext()
, lo que permite internacionalizar los mensajes de error y ayuda de Optik. Los mensajes de ayuda para las opciones ahora pueden incluir la cadena'%default'
, que será reemplazada por el valor predeterminado de la opción. (Contribuido por Greg Ward.)The long-term plan is to deprecate the
rfc822
module in some future Python release in favor of theemail
package. To this end, theemail.Utils.formatdate
function has been changed to make it usable as a replacement forrfc822.formatdate()
. You may want to write new e-mail processing code with this in mind. (Change implemented by Anthony Baxter.)Se agregó una nueva función
urandom(n)
al móduloos
, que devuelve una cadena que contiene n bytes de datos aleatorios. Esta función proporciona acceso a fuentes de aleatoriedad específicas de la plataforma, como/dev/urandom
en Linux o Windows CryptoAPI. (Contribuido por Trevor Perrin.)Otra función nueva:
os.path.lexists(path)
devuelve verdadero si el archivo especificado por path exists, whether or not it’s a symbolic link. This differs from the existing ASDF01 function, which returns false if path es un enlace simbólico que apunta a un destino que no existe. (Contribuido por Beni Cherniavsky.)Se agregó una nueva función
getsid()
al móduloposix
que subyace al móduloos
. (Contribuido por J. Raynor.)El módulo
poplib
ahora admite POP sobre SSL. (Contribuido por Héctor Urtubia.)El módulo
profile
ahora puede perfilar funciones de extensión C. (Contribuido por Nick Bastin.)El módulo
random
tiene un nuevo método llamadogetrandbits(N)
que devuelve un entero largo N bits de longitud. El métodorandrange()
existente ahora usagetrandbits()
cuando corresponde, lo que hace que la generación de números aleatorios arbitrariamente grandes sea más eficiente. (Contribuido por Raymond Hettinger.)El lenguaje de expresiones regulares aceptado por el módulo
re
se amplió con expresiones condicionales simples, escritas como(?(group)A|B)
. En su lugar, se utilizará group is either a numeric group ID or a group name defined with ASDF02 earlier in the expression. If the specified group matched, the regular expression pattern A will be tested against the string; if the group didn’t match, the pattern B. (Contribución de Gustavo Niemeyer.)El módulo
re
ya no es recursivo, gracias a la enorme cantidad de trabajo de Gustavo Niemeyer. En un motor de expresión regular recursivo, ciertos patrones dan como resultado que se consuma una gran cantidad de espacio de pila de C y es posible desbordar la pila. Por ejemplo, si comparó una cadena de 30000 bytes de caracteresa
con la expresión(a|b)+
, se consumió un marco de pila por carácter. Python 2.3 intentó verificar el desbordamiento de la pila y generar una excepciónRuntimeError
, pero ciertos patrones podrían eludir la verificación y, si no tuvo suerte, Python podría segregar. El motor de expresiones regulares de Python 2.4 puede coincidir con este patrón sin problemas.El módulo
signal
ahora realiza una verificación de errores más estricta en los parámetros de la funciónsignal.signal()
. Por ejemplo, no puede establecer un controlador en la señalSIGKILL
; las versiones anteriores de Python aceptarían silenciosamente esto, pero 2.4 lanzará una excepciónRuntimeError
.Se agregaron dos nuevas funciones al módulo
socket
.socketpair()
devuelve un par de sockets conectados ygetservbyport(port)
busca el nombre del servicio para un número de puerto determinado. (Contribuido por Dave Cole y Barry Warsaw.)La función
sys.exitfunc()
ha quedado obsoleta. El código debe usar el móduloatexit
existente, que maneja correctamente la llamada a múltiples funciones de salida. Finalmente,sys.exitfunc()
se convertirá en una interfaz puramente interna, a la que solo accederáatexit
.El módulo
tarfile
ahora genera archivos tar en formato GNU de forma predeterminada. (Contribución de Lars Gustäbel.)El módulo
threading
ahora tiene una forma elegante y sencilla de admitir datos locales de subprocesos. El módulo contiene una claselocal
cuyos valores de atributo son locales para diferentes subprocesos.import threading data = threading.local() data.number = 42 data.url = ('www.python.org', 80)
Otros subprocesos pueden asignar y recuperar sus propios valores para los atributos
number
yurl
. Puede crear una subclase delocal
para inicializar atributos o agregar métodos. (Contribuido por Jim Fulton.)El módulo
timeit
ahora deshabilita automáticamente la recolección de basura periódica durante el ciclo de temporización. Este cambio hace que los tiempos consecutivos sean más comparables. (Contribuido por Raymond Hettinger.)El módulo
weakref
ahora admite una variedad más amplia de objetos, incluidas funciones de Python, instancias de clases, conjuntos, frozensets, deques, matrices, archivos, sockets y objetos de patrones de expresión regular. (Contribuido por Raymond Hettinger.)The
xmlrpclib
module now supports a multi-call extension for transmitting multiple XML-RPC calls in a single HTTP operation. (Contributed by Brian Quinlan.)Se han eliminado los módulos
mpz
,rotor
yxreadlines
.
doctest¶
El módulo doctest
se sometió a una refactorización considerable gracias a Edward Loper y Tim Peters. Las pruebas pueden ser tan simples como ejecutar doctest.testmod()
, pero las refactorizaciones permiten personalizar el funcionamiento del módulo de varias formas.
La nueva clase DocTestFinder
extrae las pruebas de las cadenas de documentos de un objeto dado:
def f (x, y):
""">>> f(2,2)
4
>>> f(3,2)
6
"""
return x*y
finder = doctest.DocTestFinder()
# Get list of DocTest instances
tests = finder.find(f)
La nueva clase DocTestRunner
luego ejecuta pruebas individuales y puede producir un resumen de los resultados:
runner = doctest.DocTestRunner()
for t in tests:
tried, failed = runner.run(t)
runner.summarize(verbose=1)
El ejemplo anterior produce la siguiente salida:
1 items passed all tests:
2 tests in f
2 tests in 1 items.
2 passed and 0 failed.
Test passed.
DocTestRunner
usa una instancia de la clase OutputChecker
para comparar la salida esperada con la salida real. Esta clase toma varios indicadores diferentes que personalizan su comportamiento; Los usuarios ambiciosos también pueden escribir una subclase completamente nueva de OutputChecker
.
El comprobador de salida predeterminado proporciona una serie de funciones útiles. Por ejemplo, con el indicador de opción doctest.ELLIPSIS
, una elipsis (...
) en la salida esperada coincide con cualquier subcadena, lo que facilita la adaptación de salidas que varían en formas menores:
def o (n):
""">>> o(1)
<__main__.C instance at 0x...>
>>>
"""
Otra cadena especial, <BLANKLINE>
, coincide con una línea en blanco:
def p (n):
""">>> p(1)
<BLANKLINE>
>>>
"""
Otra nueva capacidad es producir una visualización de estilo diff de la salida especificando doctest.REPORT_UDIFF
(diferencias unificadas), doctest.REPORT_CDIFF
(diferencias de contexto), o doctest.REPORT_NDIFF
Indicadores de opción (estilo delta). Por ejemplo:
def g (n):
""">>> g(4)
here
is
a
lengthy
>>>"""
L = 'here is a rather lengthy list of words'.split()
for word in L[:n]:
print word
Al ejecutar las pruebas de la función anterior con doctest.REPORT_UDIFF
especificado, obtiene el siguiente resultado:
**********************************************************************
File "t.py", line 15, in g
Failed example:
g(4)
Differences (unified diff with -expected +actual):
@@ -2,3 +2,3 @@
is
a
-lengthy
+rather
**********************************************************************
Cambios en la API de Build y C¶
Algunos de los cambios en el proceso de compilación de Python y en la API de C son:
Se agregaron tres nuevas macros de conveniencia para valores de retorno comunes de funciones de extensión:
Py_RETURN_NONE
,Py_RETURN_TRUE
, yPy_RETURN_FALSE
. (Contribuido por Brett Cannon.)Otra macro nueva,
Py_CLEAR
, reduce el recuento de referencias de obj y establece obj en el puntero nulo. (Aportado por Jim Fulton.)Una nueva función,
PyTuple_Pack(N, obj1, obj2, ..., objN)
, construye tuplas a partir de una lista de argumentos de longitud variable de objetos Python. (Contribuido por Raymond Hettinger.)Una nueva función,
PyDict_Contains(d, k)
, implementa búsquedas rápidas de diccionarios sin enmascarar las excepciones que surgen durante el proceso de búsqueda. (Contribuido por Raymond Hettinger.)La macro Py_IS_NAN(X) retorna 1 si su argumento flotante o doble X es un NaN. (Aportado por Tim Peters.)
C code can avoid unnecessary locking by using the new
PyEval_ThreadsInitialized()
function to tell if any thread operations have been performed. If this function returns false, no lock operations are needed. (Contributed by Nick Coghlan.)Una nueva función,
PyArg_VaParseTupleAndKeywords()
, es la misma quePyArg_ParseTupleAndKeywords()
pero toma unva_list
en lugar de varios argumentos. (Contribuido por Greg Chapman.)A new method flag,
METH_COEXIST
, allows a function defined in slots to co-exist with aPyCFunction
having the same name. This can halve the access time for a method such asset.__contains__()
. (Contributed by Raymond Hettinger.)Python ahora se puede construir con perfiles adicionales para el intérprete en sí, con la intención de ayudar a las personas que desarrollan el núcleo de Python. Proporcionar
- enable-profiling
al configure script le permitirá perfilar el intérprete con gprof, y proporcionar el- with-tsc
switch permite la creación de perfiles utilizando el registro de contador de marcas de tiempo del Pentium. Tenga en cuenta que el conmutador- with-tsc
tiene un nombre ligeramente incorrecto, porque la función de creación de perfiles también funciona en la plataforma PowerPC, aunque la arquitectura del procesador no llama a ese registro» el registro TSC «. (Contribuido por Jeremy Hylton.)The
tracebackobject
type has been renamed toPyTracebackObject
.
Cambios específicos del puerto¶
El puerto de Windows ahora se construye bajo MSVC ++ 7.1 y también con la versión 6. (Contribuido por Martin von Löwis).
Portar a Python 2.4¶
Esta sección enumera los cambios descritos anteriormente que pueden requerir cambios en su código:
Los desplazamientos a la izquierda y las constantes hexadecimales / octales que son demasiado grandes ya no activan un
FutureWarning
y devuelven un valor limitado a 32 o 64 bits; en su lugar, devuelven un entero largo.Operaciones de números enteros no lanzaran una excepción
OverflowWarning
. La advertencia sobreOverflowWarning
desaparecerá en Python 2.5.La función de conjunto integrado
zip()
y laitertools.izip()
ahora retornan una lista hacia en vez de lanzar una excepción de tipoTypeError
si son llamados sin argumentos.Ya no puede comparar las instancias
date
ydatetime
proporcionadas por el módulodatetime
. Dos instancias de clases diferentes ahora siempre serán desiguales, y las comparaciones relativas (<
,>
) lanzarán unTypeError
.dircache.listdir()
now passes exceptions to the caller instead of returning empty lists.LexicalHandler.startDTD()
solía recibir los identificadores públicos y del sistema en el orden incorrecto. Esto ha sido corregido; las aplicaciones que se basan en el orden incorrecto deben corregirse.fcntl.ioctl()
ahora advierte si el argumento mutate se omite y es relevante.El módulo
tarfile
ahora genera archivos de GNU tar-formato por defecto.Encontrar un error al importar un módulo ya no deja un objeto de módulo parcialmente inicializado en
sys.modules
.None
ahora es una constante; El código que une un nuevo valor al nombreNone
ahora es un error de sintaxis.La función
signals.signal()
ahora genera una excepciónRuntimeError
para ciertos valores ilegales; anteriormente estos errores pasaban silenciosamente. Por ejemplo, ya no puede configurar un controlador en la señalSIGKILL
.
Agradecimientos¶
El autor desea agradecer a las siguientes personas por ofrecer sugerencias, correcciones y ayuda con varios borradores de este artículo: Koray Can, Hye-Shik Chang, Michael Dyck, Raymond Hettinger, Brian Hurt, Hamish Lawson, Fredrik Lundh, Sean Reifschneider, Sadruddin Rejeb.