Qué hay de nuevo en Python 2.2¶
- Autor:
A.M. Kuchling
Introducción¶
Este artículo explica las nuevas características en Python 2.2.2, publicado el 14 de octubre de 2002. Python 2.2.2 es una versión de corrección de errores de Python 2.2, lanzada originalmente el 21 de diciembre de 2001.
Python 2.2 se puede considerar como la «versión de limpieza». Hay algunas características como los generadores e iteradores que son completamente nuevas, pero la mayoría de los cambios, aunque sean significativos y de gran alcance, tienen como objetivo limpiar las irregularidades y los rincones oscuros del diseño del lenguaje.
Este artículo no procura proporcionar una especificación completa de las nuevas características, pero en su lugar proporciona una descripción general conveniente. Para más detalles, deberías consultar la documentación de Python 2.2, como Python Library Reference y Python Reference Manual. Si quieres comprender la justificación completa de la implementación y el diseño de un cambio, consultar la PEP para conocer una característica nueva en particular.
PEPs 252 y 253: Cambios de tipo y clase¶
Los cambios más grandes y de mayor alcance en Python 2.2 son el modelo de objetos y clases de Python. Los cambios deben ser compatibles con versiones anteriores, por lo que es probable que tu código continuará ejecutándose sin cambios, pero los cambios proporcionan algunas capacidades nuevas increíbles. Antes de comenzar esta, la sección más larga y complicada de este artículo, brindaré una descripción general de los cambios y ofreceré algunos comentarios.
A long time ago I wrote a web page listing flaws in Python’s design. One of the
most significant flaws was that it’s impossible to subclass Python types
implemented in C. In particular, it’s not possible to subclass built-in types,
so you can’t just subclass, say, lists in order to add a single useful method to
them. The UserList
module provides a class that supports all of the
methods of lists and that can be subclassed further, but there’s lots of C code
that expects a regular Python list and won’t accept a UserList
instance.
Python 2.2 corrige esto y, en el proceso, agrega algunas capacidades nuevas interesantes. Un breve resumen:
Puedes subclasificar tipos incorporados como listas e incluso enteros, y tus subclases deberían funcionar en todos los lugares que requieran el tipo original.
Ahora es posible definir métodos estáticos y de clase, además de los métodos de instancia disponibles en versiones anteriores de Python.
It’s also possible to automatically call methods on accessing or setting an instance attribute by using a new mechanism called properties. Many uses of
__getattr__()
can be rewritten to use properties instead, making the resulting code simpler and faster. As a small side benefit, attributes can now have docstrings, too.La lista de atributos legales para una instancia se puede limitar a un conjunto particular usando slots, lo que hace posible protegerse contra errores tipográficos y quizás hacer posibles más optimizaciones en versiones futuras de Python.
Algunos usuarios han expresado preocupación por todos estos cambios. Claro, dicen, las nuevas características son ordenadas y se prestan a todo tipo de trucos que no eran posibles en versiones anteriores de Python, pero también hacen que el lenguaje sea más complicado. Algunas personas han dicho que siempre han recomendado Python por su simplicidad, y sienten que su simplicidad se está perdiendo.
Personalmente. pienso que no hay que preocuparse. Muchas de las nuevas características son bastante esotéricas, y puedes escribir mucho código de Python sin tener que estar al tanto de ellas. Escribir una clase simple no es más difícil de lo que nunca fue, así que no necesitas molestarte en aprender o enseñarlos a menos que realmente sean necesarios. Algunas tareas muy complicadas que antes solo eran posibles desde C ahora serán posibles en Python puro, y en mi opinión, esto es todo para mejor.
No voy a intentar cubrir todas los casos de las esquinas y los pequeños cambios que fueron necesarios para hacer que las nuevas características funcionen. En su lugar, esta sección pintará solo a grandes rasgos. Consultar la sección Enlaces relacionados, «Enlaces relacionados», para más fuentes de información sobre el nuevo modelo de objetos de Python 2.2.
Clases antiguas y nuevas¶
Primero, debes saber que realmente Python 2.2 tiene dos tipos de clases: clases clásicas o de estilo antiguo y clases de estilo nuevo. El modelo de clase de estilo antiguo exactamente es el mismo que el modelo de clase en versiones anteriores de Python. Todas las nuevas características descritas en esta sección se aplican solo a las clases de estilo nuevo. Esta divergencia no está destinada a durar para siempre; eventualmente las clases de estilo antiguo se eliminarán, posiblemente en Python 3.0.
Entonces, ¿cómo defines una clase de estilo nuevo? Lo haces subclasificando una clases de estilo nuevo existente. La mayoría de los tipos integrados de Python, como enteros, listas, diccionarios e incluso archivos, ahora son clases de estilo nuevo. También se agregó una clase de estilo nuevo llamada object
, la clase base para todos los tipos integrados, por lo que si ningún tipo integrado es apropiado, puedes solo subclasificar object
:
class C(object):
def __init__ (self):
...
...
This means that class
statements that don’t have any base classes are
always classic classes in Python 2.2. (Actually you can also change this by
setting a module-level variable named __metaclass__
— see PEP 253
for the details — but it’s easier to just subclass object
.)
Los objetos de tipo para los tipos integrados están disponibles como incorporados, nombrados mediante un truco inteligente. Python siempre ha tenido funciones incorporadas llamadas int()
, float()
y str()
. En la versión 2.2, ya no son funciones, sino objetos de tipo que se comportan como fábricas cuando se les llaman.
>>> int
<type 'int'>
>>> int('123')
123
To make the set of types complete, new type objects such as dict()
and
file()
have been added. Here’s a more interesting example, adding a
lock()
method to file objects:
class LockableFile(file):
def lock (self, operation, length=0, start=0, whence=0):
import fcntl
return fcntl.lockf(self.fileno(), operation,
length, start, whence)
The now-obsolete posixfile
module contained a class that emulated all of
a file object’s methods and also added a lock()
method, but this class
couldn’t be passed to internal functions that expected a built-in file,
something which is possible with our new LockableFile
.
Descriptores¶
In previous versions of Python, there was no consistent way to discover what
attributes and methods were supported by an object. There were some informal
conventions, such as defining __members__
and __methods__
attributes that were lists of names, but often the author of an extension type
or a class wouldn’t bother to define them. You could fall back on inspecting
the __dict__
of an object, but when class inheritance or an arbitrary
__getattr__()
hook were in use this could still be inaccurate.
La única gran idea que subyace al nuevo modelo de clases es que se ha formalizado una API para describir los atributos de un objeto usando descriptors. Los descriptores especifican el valor de un atributo, indicando si es un método o un campo. Con la API de un descriptor, los métodos estáticos y de clase se vuelven posibles, así como constructos más exóticos.
Los descriptores de atributos son objetos que viven dentro de los objetos de clase y tienen algunos atributos propios:
__name__
es el nombre del atributo.__doc__
is the attribute’s docstring.__get__(object)
es un método que recupera el valor del atributo de object.__set__(object, value)
establece el atributo de object en value.__delete__(object, value)
elimina el atributo value de object.
Por ejemplo, cuando escribes obj.x
, los pasos que realmente Python realiza son:
descriptor = obj.__class__.x
descriptor.__get__(obj)
For methods, descriptor.__get__()
returns a temporary object that’s
callable, and wraps up the instance and the method to be called on it. This is
also why static methods and class methods are now possible; they have
descriptors that wrap up just the method, or the method and the class. As a
brief explanation of these new kinds of methods, static methods aren’t passed
the instance, and therefore resemble regular functions. Class methods are
passed the class of the object, but not the object itself. Static and class
methods are defined like this:
class C(object):
def f(arg1, arg2):
...
f = staticmethod(f)
def g(cls, arg1, arg2):
...
g = classmethod(g)
The staticmethod()
function takes the function f()
, and returns it
wrapped up in a descriptor so it can be stored in the class object. You might
expect there to be special syntax for creating such methods (def static f
,
defstatic f()
, or something like that) but no such syntax has been defined
yet; that’s been left for future versions of Python.
También se implementan más características nuevas, como ranuras y propiedades, como nuevos tipos de descriptores, y no es difícil escribir una clase de descriptor que haga algo nuevo. Por ejemplo, sería posible escribir una clase de descriptor que hiciera posible escribir condiciones previas al estilo Eiffel y posteriores para un método. Una clase que usó esta característica podría definirse así:
from eiffel import eiffelmethod
class C(object):
def f(self, arg1, arg2):
# The actual function
...
def pre_f(self):
# Check preconditions
...
def post_f(self):
# Check postconditions
...
f = eiffelmethod(f, pre_f, post_f)
Note that a person using the new eiffelmethod()
doesn’t have to understand
anything about descriptors. This is why I think the new features don’t increase
the basic complexity of the language. There will be a few wizards who need to
know about it in order to write eiffelmethod()
or the ZODB or whatever,
but most users will just write code on top of the resulting libraries and ignore
the implementation details.
Herencia múltiple: la regla del diamante¶
La herencia múltiple también se ha hecho más útil al cambiar las reglas bajo las cuales se resuelven los nombres. Considera este conjunto de clases (diagrama tomado de PEP 253 de Guido van Rossum):
class A:
^ ^ def save(self): ...
/ \
/ \
/ \
/ \
class B class C:
^ ^ def save(self): ...
\ /
\ /
\ /
\ /
class D
The lookup rule for classic classes is simple but not very smart; the base
classes are searched depth-first, going from left to right. A reference to
D.save()
will search the classes D
, B
, and then
A
, where save()
would be found and returned. C.save()
would never be found at all. This is bad, because if C
’s save()
method is saving some internal state specific to C
, not calling it will
result in that state never getting saved.
Las clases de estilo nuevo siguen un algoritmo diferente que es más complicado de explicar, pero hace lo correcto en esta situación. (Toma en cuenta que Python 2.3 cambia este algoritmo a uno que produce los mismos resultados en la mayoría de los casos, pero produce resultados más útiles para gráficos de herencia realmente complicados.)
List all the base classes, following the classic lookup rule and include a class multiple times if it’s visited repeatedly. In the above example, the list of visited classes is [
D
,B
,A
,C
,A
].Scan the list for duplicated classes. If any are found, remove all but one occurrence, leaving the last one in the list. In the above example, the list becomes [
D
,B
,C
,A
] after dropping duplicates.
Following this rule, referring to D.save()
will return C.save()
,
which is the behaviour we’re after. This lookup rule is the same as the one
followed by Common Lisp. A new built-in function, super()
, provides a way
to get at a class’s superclasses without having to reimplement Python’s
algorithm. The most commonly used form will be super(class, obj)
, which
returns a bound superclass object (not the actual class object). This form
will be used in methods to call a method in the superclass; for example,
D
’s save()
method would look like this:
class D (B,C):
def save (self):
# Call superclass .save()
super(D, self).save()
# Save D's private information here
...
También super()
puede retornar objetos de superclase no vinculados cuando se llama como super(class)
o super(class1, class2)
, pero probablemente esto no sea útil a menudo.
Acceso a atributos¶
A fair number of sophisticated Python classes define hooks for attribute access
using __getattr__()
; most commonly this is done for convenience, to make
code more readable by automatically mapping an attribute access such as
obj.parent
into a method call such as obj.get_parent
. Python 2.2 adds
some new ways of controlling attribute access.
Primero, __getattr__(attr_name)
aún es compatible con las clases de nuevo estilo, y nada al respecto ha cambiado. Como antes, se llamará cuando se intente acceder a obj.foo
y no se encuentre ningún atributo llamado foo
en el diccionario de la instancia.
New-style classes also support a new method,
__getattribute__(attr_name)
. The difference between the two methods is
that __getattribute__()
is always called whenever any attribute is
accessed, while the old __getattr__()
is only called if foo
isn’t
found in the instance’s dictionary.
However, Python 2.2’s support for properties will often be a simpler way
to trap attribute references. Writing a __getattr__()
method is
complicated because to avoid recursion you can’t use regular attribute accesses
inside them, and instead have to mess around with the contents of
__dict__
. __getattr__()
methods also end up being called by Python
when it checks for other methods such as __repr__()
or __coerce__()
,
and so have to be written with this in mind. Finally, calling a function on
every attribute access results in a sizable performance loss.
property
is a new built-in type that packages up three functions that
get, set, or delete an attribute, and a docstring. For example, if you want to
define a size
attribute that’s computed, but also settable, you could
write:
class C(object):
def get_size (self):
result = ... computation ...
return result
def set_size (self, size):
... compute something based on the size
and set internal state appropriately ...
# Define a property. The 'delete this attribute'
# method is defined as None, so the attribute
# can't be deleted.
size = property(get_size, set_size,
None,
"Storage size of this instance")
That is certainly clearer and easier to write than a pair of
__getattr__()
/__setattr__()
methods that check for the size
attribute and handle it specially while retrieving all other attributes from the
instance’s __dict__
. Accesses to size
are also the only ones
which have to perform the work of calling a function, so references to other
attributes run at their usual speed.
Finalmente, es posible restringir la lista de atributos que se pueden referenciar en un objeto usando el nuevo atributo de clase __slots__
. Los objetos de Python por lo general son muy dinámicos; en cualquier momento es posible definir un nuevo atributo en una instancia haciendo simplemente obj.new_attr=1
. Una clase de estilo nuevo puede definir un atributo de clase llamado __slots__
para limitar los atributos legales a un conjunto particular de nombres. Un ejemplo hará esto claro:
>>> class C(object):
... __slots__ = ('template', 'name')
...
>>> obj = C()
>>> print obj.template
None
>>> obj.template = 'Test'
>>> print obj.template
Test
>>> obj.newattr = None
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'C' object has no attribute 'newattr'
Toma en cuenta cómo obtienes un AttributeError
en el intento de asignar a un atributo que no aparece en __slots__
.
PEP 234: Iteradores¶
Otra adición significativa a la versión 2.2 es una interfaz de iteración tanto a nivel de C como de Python. Los objetos pueden definir cómo pueden ser iterados por quienes los llaman.
In Python versions up to 2.1, the usual way to make for item in obj
work is
to define a __getitem__()
method that looks something like this:
def __getitem__(self, index):
return <next item>
__getitem__()
is more properly used to define an indexing operation on an
object so that you can write obj[5]
to retrieve the sixth element. It’s a
bit misleading when you’re using this only to support for
loops.
Consider some file-like object that wants to be looped over; the index
parameter is essentially meaningless, as the class probably assumes that a
series of __getitem__()
calls will be made with index incrementing by
one each time. In other words, the presence of the __getitem__()
method
doesn’t mean that using file[5]
to randomly access the sixth element will
work, though it really should.
In Python 2.2, iteration can be implemented separately, and __getitem__()
methods can be limited to classes that really do support random access. The
basic idea of iterators is simple. A new built-in function, iter(obj)
or iter(C, sentinel)
, is used to get an iterator. iter(obj)
returns
an iterator for the object obj, while iter(C, sentinel)
returns an
iterator that will invoke the callable object C until it returns sentinel to
signal that the iterator is done.
Python classes can define an __iter__()
method, which should create and
return a new iterator for the object; if the object is its own iterator, this
method can just return self
. In particular, iterators will usually be their
own iterators. Extension types implemented in C can implement a tp_iter
function in order to return an iterator, and extension types that want to behave
as iterators can define a tp_iternext
function.
Entonces, después de todo esto, ¿qué hacen realmente los iteradores? Tienen un método obligatorio, next()
, que no toma argumentos y retorna el siguiente valor. Cuando no hay más valores que retornar, la llamada a next()
debería lanzar la excepción StopIteration
.
>>> L = [1,2,3]
>>> i = iter(L)
>>> print i
<iterator object at 0x8116870>
>>> i.next()
1
>>> i.next()
2
>>> i.next()
3
>>> i.next()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
StopIteration
>>>
In 2.2, Python’s for
statement no longer expects a sequence; it
expects something for which iter()
will return an iterator. For backward
compatibility and convenience, an iterator is automatically constructed for
sequences that don’t implement __iter__()
or a tp_iter
slot, so
for i in [1,2,3]
will still work. Wherever the Python interpreter loops
over a sequence, it’s been changed to use the iterator protocol. This means you
can do things like this:
>>> L = [1,2,3]
>>> i = iter(L)
>>> a,b,c = i
>>> a,b,c
(1, 2, 3)
Se ha añadido soporte de iteradores a algunos de los tipos básicos de Python. Llamar a iter()
sobre un diccionario retornará un iterador que hace un bucle sobre sus claves:
>>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
... 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
>>> for key in m: print key, m[key]
...
Mar 3
Feb 2
Aug 8
Sep 9
May 5
Jun 6
Jul 7
Jan 1
Apr 4
Nov 11
Dec 12
Oct 10
That’s just the default behaviour. If you want to iterate over keys, values, or
key/value pairs, you can explicitly call the iterkeys()
,
itervalues()
, or iteritems()
methods to get an appropriate iterator.
In a minor related change, the in
operator now works on dictionaries,
so key in dict
is now equivalent to dict.has_key(key)
.
Los archivos también proporcionan un iterador, que llama al método readline()
hasta que no hay más líneas en el archivo. Esto significa que ahora puede leer cada línea de un archivo utilizando un código como este:
for line in file:
# do something for each line
...
Tenga en cuenta que sólo puede avanzar en un iterador; no hay forma de obtener el elemento anterior, reiniciar el iterador o hacer una copia del mismo. Un objeto iterador podría proporcionar estas capacidades adicionales, pero el protocolo iterador sólo requiere un método next()
.
Ver también
- PEP 234 - Iteradores
Escrito por Ka-Ping Yee y GvR; implementado por el equipo de Python Labs, principalmente por GvR y Tim Peters.
PEP 255: Generadores simples¶
Los generadores son otra novedad que interactúa con la introducción de los iteradores.
Sin duda estás familiarizado con cómo funcionan las llamadas a funciones en Python o C. Cuando llamas a una función, ésta obtiene un espacio de nombres privado donde se crean sus variables locales. Cuando la función llega a una declaración return
, las variables locales se destruyen y el valor resultante se retorna a quien la llamó. Una llamada posterior a la misma función obtendrá un nuevo conjunto de variables locales. Pero, ¿qué pasaría si las variables locales no se tiraran al salir de una función? ¿Qué pasaría si pudieras reanudar la función donde la dejaste? Esto es lo que proporcionan los generadores; se puede pensar en ellos como funciones reanudables.
Este es el ejemplo más sencillo de una función generadora:
def generate_ints(N):
for i in range(N):
yield i
Se ha introducido una nueva palabra clave, yield
, para los generadores. Cualquier función que contenga una declaración yield
es una función generadora; esto es detectado por el compilador de código de bits de Python que compila la función especialmente como resultado. Debido a la introducción de una nueva palabra clave, los generadores deben ser explícitamente habilitados en un módulo incluyendo una declaración from __future__ import generators
cerca de la parte superior del código fuente del módulo. En Python 2.3 esta declaración será innecesaria.
Cuando se llama a una función generadora, ésta no retorna un único valor, sino que retorna un objeto generador que soporta el protocolo de los iteradores. Al ejecutar la sentencia yield
, el generador retorna el valor de i
, de forma similar a una sentencia return
. La gran diferencia entre yield
y una sentencia return
es que al llegar a una sentencia yield
se suspende el estado de ejecución del generador y se conservan las variables locales. En la siguiente llamada al método next()
del generador, la función se reanudará la ejecución inmediatamente después de la sentencia yield
. (Por razones complicadas, la sentencia yield
no está permitida dentro del bloque try
de una sentencia try
…`finally
; lea PEP 255 para una explicación completa de la interacción entre yield
y las excepciones)
Here’s a sample usage of the generate_ints()
generator:
>>> gen = generate_ints(3)
>>> gen
<generator object at 0x8117f90>
>>> gen.next()
0
>>> gen.next()
1
>>> gen.next()
2
>>> gen.next()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in generate_ints
StopIteration
También podrías escribir for i in generate_ints(5)
, o a,b,c = generate_ints(3)
.
Dentro de una función generadora, la sentencia return
sólo puede usarse sin un valor, y señala el final de la procesión de valores; después el generador no puede retornar más valores. return
con un valor, como return 5
, es un error de sintaxis dentro de una función generadora. El final de los resultados del generador también puede indicarse levantando manualmente StopIteration
, o simplemente dejando que el flujo de ejecución caiga en el fondo de la función.
Puedes conseguir el efecto de los generadores manualmente escribiendo tu propia clase y almacenando todas las variables locales del generador como variables de instancia. Por ejemplo, la lución de una lista de enteros podría hacerse estableciendo self.count
a 0, y haciendo que el método next()
incremente self.count
y lo retorne. Sin embargo, para un generador medianamente complicado, escribir la clase correspondiente sería mucho más complicado. Lib/test/test_generators.py
contiene varios ejemplos más interesantes. El más sencillo implementa un recorrido en orden de un árbol utilizando generadores de forma recursiva
# A recursive generator that generates Tree leaves in in-order.
def inorder(t):
if t:
for x in inorder(t.left):
yield x
yield t.label
for x in inorder(t.right):
yield x
Otros dos ejemplos en Lib/test/test_generators.py
producen soluciones para el problema de las N reinas (colocar $N$ reinas en un tablero de ajedrez $NxN$ de forma que ninguna reina amenace a otra) y el recorrido del caballero (una ruta que lleva a un caballo a cada casilla de un tablero de ajedrez $NxN$ sin visitar ninguna casilla dos veces).
The idea of generators comes from other programming languages, especially Icon (https://www2.cs.arizona.edu/icon/), where the idea of generators is central. In Icon, every expression and function call behaves like a generator. One example from «An Overview of the Icon Programming Language» at https://www2.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks like:
sentence := "Store it in the neighboring harbor"
if (i := find("or", sentence)) > 5 then write(i)
In Icon the find()
function returns the indexes at which the substring
«or» is found: 3, 23, 33. In the if
statement, i
is first
assigned a value of 3, but 3 is less than 5, so the comparison fails, and Icon
retries it with the second value of 23. 23 is greater than 5, so the comparison
now succeeds, and the code prints the value 23 to the screen.
Python no va tan lejos como Icon en la adopción de generadores como concepto central. Los generadores se consideran una nueva parte del núcleo del lenguaje Python, pero aprenderlos o utilizarlos no es obligatorio; si no resuelven ningún problema que tengas, siéntete libre de ignorarlos. Una característica novedosa de la interfaz de Python en comparación con la de Icon es que el estado de un generador se representa como un objeto concreto (el iterador) que puede pasarse a otras funciones o almacenarse en una estructura de datos.
Ver también
- PEP 255 - Generadores simples
Escrito por Neil Schemenauer, Tim Peters, Magnus Lie Hetland. Implementado principalmente por Neil Schemenauer y Tim Peters, con otras correcciones del equipo de Python Labs.
PEP 237: Unificación de enteros largos y enteros¶
In recent versions, the distinction between regular integers, which are 32-bit
values on most machines, and long integers, which can be of arbitrary size, was
becoming an annoyance. For example, on platforms that support files larger than
2**32
bytes, the tell()
method of file objects has to return a long
integer. However, there were various bits of Python that expected plain integers
and would raise an error if a long integer was provided instead. For example,
in Python 1.5, only regular integers could be used as a slice index, and
'abc'[1L:]
would raise a TypeError
exception with the message “slice
index must be int”.
Python 2.2 cambiará los valores de enteros cortos a enteros largos según sea necesario. El sufijo “L” ya no es necesario para indicar un literal entero largo, ya que ahora el compilador elegirá el tipo apropiado. (El uso del sufijo “L” se desaconsejará en futuras versiones 2.x de Python, provocando una advertencia en Python 2.4, y probablemente se eliminará en Python 3.0) Muchas operaciones que solían lanzar un OverflowError
ahora retornarán un entero largo como resultado. Por ejemplo:
>>> 1234567890123
1234567890123L
>>> 2 ** 64
18446744073709551616L
En la mayoría de los casos, los enteros y los enteros largos se tratarán ahora de forma idéntica. Todavía se pueden distinguir con la función incorporada type()
, pero rara vez se necesita.
Ver también
- PEP 237 - Unificación de enteros largos y enteros
Escrito por Moshe Zadka y Guido van Rossum. Implementado principalmente por Guido van Rossum.
PEP 238: Cambio del operador de división¶
El cambio más controvertido de Python 2.2 anuncia el inicio de un esfuerzo por arreglar un viejo defecto de diseño que ha estado en Python desde el principio. Actualmente, el operador de división de Python, /
, se comporta como el operador de división de C cuando se le presentan dos argumentos enteros: retorna un resultado entero que se trunca cuando hay una parte fraccionaria. Por ejemplo, 3/2
es 1, no 1,5, y (-1)/2
es -1, no -0,5. Esto significa que los resultados de la división pueden variar inesperadamente dependiendo del tipo de los dos operandos y, como Python está tipado dinámicamente, puede ser difícil determinar los posibles tipos de los operandos.
(La controversia se centra en si esto es realmente un defecto de diseño, y si vale la pena romper el código existente para arreglarlo. Ha provocado interminables discusiones en python-dev, y en julio de 2001 estalló una tormenta de publicaciones ácidamente sarcásticas en comp.lang.python. No argumentaré aquí a favor de ninguno de los dos bandos y me limitaré a describir lo que se ha implementado en la 2.2. Lea PEP 238 para un resumen de los argumentos y contra-argumentos)
Debido a que este cambio podría romper el código, se está introduciendo de forma muy gradual. Python 2.2 comienza la transición, pero el cambio no será completo hasta Python 3.0.
En primer lugar, tomaré prestada alguna terminología de PEP 238. La «división verdadera» es la división con la que la mayoría de los no programadores están familiarizados: 3/2 es 1,5, 1/4 es 0,25, y así sucesivamente. La «división por el piso» es lo que hace actualmente el operador /
de Python cuando se le dan operandos enteros; el resultado es el piso del valor retornado por la división verdadera. La «división clásica» es el comportamiento mixto actual de /
; retorna el resultado de la división por el suelo cuando los operandos son enteros, y retorna el resultado de la división verdadera cuando uno de los operandos es un número de punto flotante.
Estos son los cambios que introduce la versión 2.2:
Un nuevo operador,
//
, es el operador de división por el suelo. (Sí, ya sabemos que se parece al símbolo de comentario de C++.)//
siempre realiza la división por el suelo sin importar los tipos de sus operandos, así que1 // 2
es 0 y1.0 // 2.0
también es 0.0.//
está siempre disponible en Python 2.2; no es necesario habilitarlo mediante una sentencia__future__
.Al incluir una declaración
from __future__ import division
en un módulo, el operador/
se cambiará para retornar el resultado de la división verdadera, por lo que1/2
es 0,5. Sin la declaración__future__
,/
sigue significando la división clásica. El significado por defecto de/
no cambiará hasta Python 3.0.Classes can define methods called
__truediv__()
and__floordiv__()
to overload the two division operators. At the C level, there are also slots in thePyNumberMethods
structure so extension types can define the two operators.Python 2.2 admite algunos argumentos de línea de comandos para comprobar si el código funcionará con la semántica de división modificada. Ejecutar python con
-Q warn
hará que se emita una advertencia cada vez que se aplique la división a dos enteros. Puedes usar esto para encontrar el código que está afectado por el cambio y arreglarlo. Por defecto, Python 2.2 simplemente realizará la división clásica sin una advertencia; la advertencia se activará por defecto en Python 2.3.
Ver también
- PEP 238 - Cambio del operador de división
Escrito por Moshe Zadka y Guido van Rossum. Implementado por Guido van Rossum..
Cambios en Unicode¶
El soporte de Unicode de Python se ha mejorado un poco en la versión 2.2. Las cadenas Unicode se almacenan normalmente como UCS-2, como enteros sin signo de 16 bits. Python 2.2 también puede ser compilado para usar UCS-4, enteros sin signo de 32 bits, como su codificación interna suministrando --enable-unicode=ucs4
al script de configuración. (También es posible especificar --disable-unicode
para desactivar completamente el soporte de Unicode)
When built to use UCS-4 (a «wide Python»), the interpreter can natively handle
Unicode characters from U+000000 to U+110000, so the range of legal values for
the unichr()
function is expanded accordingly. Using an interpreter
compiled to use UCS-2 (a «narrow Python»), values greater than 65535 will still
cause unichr()
to raise a ValueError
exception. This is all
described in PEP 261, «Support for “wide” Unicode characters»; consult it for
further details.
Another change is simpler to explain. Since their introduction, Unicode strings
have supported an encode()
method to convert the string to a selected
encoding such as UTF-8 or Latin-1. A symmetric decode([*encoding*])
method has been added to 8-bit strings (though not to Unicode strings) in 2.2.
decode()
assumes that the string is in the specified encoding and decodes
it, returning whatever is returned by the codec.
Gracias a esta nueva función, se han añadido códecs para tareas no relacionadas directamente con Unicode. Por ejemplo, se han añadido códecs para la codificación uu, la codificación base64 de MIME y la compresión con el módulo zlib
:
>>> s = """Here is a lengthy piece of redundant, overly verbose,
... and repetitive text.
... """
>>> data = s.encode('zlib')
>>> data
'x\x9c\r\xc9\xc1\r\x80 \x10\x04\xc0?Ul...'
>>> data.decode('zlib')
'Here is a lengthy piece of redundant, overly verbose,\nand repetitive text.\n'
>>> print s.encode('uu')
begin 666 <data>
M2&5R92!I<R!A(&QE;F=T:'D@<&EE8V4@;V8@<F5D=6YD86YT+"!O=F5R;'D@
>=F5R8F]S92P*86YD(')E<&5T:71I=F4@=&5X="X*
end
>>> "sheesh".encode('rot-13')
'furrfu'
To convert a class instance to Unicode, a __unicode__()
method can be
defined by a class, analogous to __str__()
.
encode()
, decode()
, and __unicode__()
were implemented by
Marc-André Lemburg. The changes to support using UCS-4 internally were
implemented by Fredrik Lundh and Martin von Löwis.
Ver también
- PEP 261 - Soporte para caracteres Unicode “anchos”
Escrito por Paul Prescod.
PEP 227: Ámbitos anidados¶
En Python 2.1, los ámbitos anidados estáticamente se añadieron como una característica opcional, que se activaba mediante una directiva from __future__ import nested_scopes
. En 2.2 los ámbitos anidados ya no necesitan ser habilitados especialmente, y ahora están siempre presentes. El resto de esta sección es una copia de la descripción de los ámbitos anidados de mi documento «What’s New in Python 2.1»; si lo leíste cuando salió la 2.1, puedes saltarte el resto de esta sección.
El mayor cambio introducido en Python 2.1, y completado en 2.2, es el de las reglas de alcance de Python. En Python 2.0, en cualquier momento hay como máximo tres espacios de nombres utilizados para buscar nombres de variables: local, a nivel de módulo y el espacio de nombres incorporado. Esto a menudo sorprendía a la gente porque no coincidía con sus expectativas intuitivas. Por ejemplo, una definición de función recursiva anidada no funciona:
def f():
...
def g(value):
...
return g(value-1) + 1
...
The function g()
will always raise a NameError
exception, because
the binding of the name g
isn’t in either its local namespace or in the
module-level namespace. This isn’t much of a problem in practice (how often do
you recursively define interior functions like this?), but this also made using
the lambda
expression clumsier, and this was a problem in practice.
In code which uses lambda
you can often find local variables being
copied by passing them as the default values of arguments.
def find(self, name):
"Return list of any entries equal to 'name'"
L = filter(lambda x, name=name: x == name,
self.list_attribute)
return L
La legibilidad del código Python escrito en un estilo fuertemente funcional sufre mucho como resultado.
El cambio más significativo de Python 2.2 es que se ha añadido al lenguaje el ámbito estático para solucionar este problema. Como primer efecto, el argumento por defecto name=name
es ahora innecesario en el ejemplo anterior. En pocas palabras, cuando a un nombre de variable dado no se le asigna un valor dentro de una función (mediante una asignación, o las sentencias def
, class
, o import
), las referencias a la variable se buscarán en el espacio de nombres local del ámbito que la rodea. Puede encontrar una explicación más detallada de las reglas y una disección de la implementación en el PEP.
Este cambio puede causar algunos problemas de compatibilidad para el código en el que el mismo nombre de variable se utiliza tanto a nivel de módulo como de variable local dentro de una función que contiene otras definiciones de función. Sin embargo, esto parece bastante improbable, ya que dicho código habría sido bastante confuso de leer en primer lugar.
Un efecto secundario del cambio es que las sentencias from module import *
y exec
se han hecho ilegales dentro del ámbito de una función bajo ciertas condiciones. El manual de referencia de Python ha dicho todo el tiempo que from module import *
sólo es legal en el nivel superior de un módulo, pero el intérprete de CPython nunca ha aplicado esto antes. Como parte de la implementación de los ámbitos anidados, el compilador que convierte el código fuente de Python en bytecodes tiene que generar un código diferente para acceder a las variables de un ámbito contenedor. Los códigos from module import *
y exec
hacen que el compilador no pueda averiguar esto, porque añaden nombres al espacio de nombres local que son desconocidos en tiempo de compilación. Por lo tanto, si una función contiene definiciones de funciones o expresiones lambda
con variables libres, el compilador lo señalará lanzando una excepción SyntaxError
.
Para que la explicación anterior quede un poco más clara, he aquí un ejemplo:
x = 1
def f():
# The next line is a syntax error
exec 'x=2'
def g():
return x
Line 4 containing the exec
statement is a syntax error, since
exec
would define a new local variable named x
whose value should
be accessed by g()
.
Esto no debería ser una gran limitación, ya que exec
rara vez se utiliza en la mayoría del código de Python (y cuando se utiliza, a menudo es un signo de un mal diseño de todos modos).
Ver también
- PEP 227 - Ámbitos anidados estáticamente
Escrito e implementado por Jeremy Hylton.
Módulos nuevos y mejorados¶
The
xmlrpclib
module was contributed to the standard library by Fredrik Lundh, providing support for writing XML-RPC clients. XML-RPC is a simple remote procedure call protocol built on top of HTTP and XML. For example, the following snippet retrieves a list of RSS channels from the O’Reilly Network, and then lists the recent headlines for one channel:import xmlrpclib s = xmlrpclib.Server( 'http://www.oreillynet.com/meerkat/xml-rpc/server.php') channels = s.meerkat.getChannels() # channels is a list of dictionaries, like this: # [{'id': 4, 'title': 'Freshmeat Daily News'} # {'id': 190, 'title': '32Bits Online'}, # {'id': 4549, 'title': '3DGamers'}, ... ] # Get the items for one channel items = s.meerkat.getItems( {'channel': 4} ) # 'items' is another list of dictionaries, like this: # [{'link': 'http://freshmeat.net/releases/52719/', # 'description': 'A utility which converts HTML to XSL FO.', # 'title': 'html2fo 0.3 (Default)'}, ... ]
The
SimpleXMLRPCServer
module makes it easy to create straightforward XML-RPC servers. See http://xmlrpc.scripting.com/ for more information about XML-RPC.El nuevo módulo
hmac
implementa el algoritmo HMAC descrito por RFC 2104. (Contribución de Gerhard Häring)Several functions that originally returned lengthy tuples now return pseudo-sequences that still behave like tuples but also have mnemonic attributes such as
memberst_mtime
ortm_year
. The enhanced functions includestat()
,fstat()
,statvfs()
, andfstatvfs()
in theos
module, andlocaltime()
,gmtime()
, andstrptime()
in thetime
module.Por ejemplo, para obtener el tamaño de un archivo utilizando las antiguas tuplas, se terminaba escribiendo algo como
tamaño_de_archivo = os.stat(nombre_de_archivo)[stat.ST_SIZE]
, pero ahora se puede escribir más claramente comotamaño_de_archivo = os.stat(nombre_de_archivo).st_size
.El parche original para esta función fue aportado por Nick Mathewson.
El perfilador de Python ha sido ampliamente revisado y se han corregido varios errores en su salida. (Contribución de Fred L. Drake, Jr. y Tim Peters)
El módulo
socket
puede ser compilado para soportar IPv6; especifica la opción--enable-ipv6
al script configure de Python. (Contribución de Jun-ichiro «itojun» Hagino)Se agregaron dos nuevos caracteres de formato al módulo
struct
para enteros de 64 bits en plataformas que admiten el tipo C long long.q
es para un entero de 64 bits con signo yQ
es para uno sin firmar. El valor se retorna en el tipo de entero largo de Python. (Aportado por Tim Peters.)En el modo interactivo del intérprete, hay una nueva función incorporada
help()
que utiliza el módulopydoc
introducido en Python 2.1 para proporcionar ayuda interactiva.help()
sin ningún argumento te sitúa en una utilidad de ayuda online, donde puedes introducir los nombres de las funciones, clases o módulos para leer su texto de ayuda. (Contribuido por Guido van Rossum, usando el módulopydoc
de Ka-Ping Yee)Various bugfixes and performance improvements have been made to the SRE engine underlying the
re
module. For example, there.sub()
andre.split()
functions have been rewritten in C. Another contributed patch speeds up certain Unicode character ranges by a factor of two, and a newfinditer()
method that returns an iterator over all the non-overlapping matches in a given string. (SRE is maintained by Fredrik Lundh. The BIGCHARSET patch was contributed by Martin von Löwis.)El módulo
smtplib
soporta ahora RFC 2487, «Secure SMTP over TLS», por lo que ahora es posible cifrar el tráfico SMTP entre un programa Python y el agente de transporte de correo que recibe un mensaje.smtplib
también soporta la autenticación SMTP. (Contribución de Gerhard Häring)El módulo
imaplib
, mantenido por Piers Lauder, tiene soporte para varias extensiones nuevas: la extensión NAMESPACE definida en RFC 2342, SORT, GETACL y SETACL. (Contribución de Anthony Baxter y Michel Pelletier)The
rfc822
module’s parsing of email addresses is now compliant with RFC 2822, an update to RFC 822. (The module’s name is not going to be changed torfc2822
.) A new package,email
, has also been added for parsing and generating e-mail messages. (Contributed by Barry Warsaw, and arising out of his work on Mailman.)The
difflib
module now contains a newDiffer
class for producing human-readable lists of changes (a «delta») between two sequences of lines of text. There are also two generator functions,ndiff()
andrestore()
, which respectively return a delta from two sequences, or one of the original sequences from a delta. (Grunt work contributed by David Goodger, from ndiff.py code by Tim Peters who then did the generatorization.)New constants
ascii_letters
,ascii_lowercase
, andascii_uppercase
were added to thestring
module. There were several modules in the standard library that usedstring.letters
to mean the ranges A-Za-z, but that assumption is incorrect when locales are in use, becausestring.letters
varies depending on the set of legal characters defined by the current locale. The buggy modules have all been fixed to useascii_letters
instead. (Reported by an unknown person; fixed by Fred L. Drake, Jr.)The
mimetypes
module now makes it easier to use alternative MIME-type databases by the addition of aMimeTypes
class, which takes a list of filenames to be parsed. (Contributed by Fred L. Drake, Jr.)A
Timer
class was added to thethreading
module that allows scheduling an activity to happen at some future time. (Contributed by Itamar Shtull-Trauring.)
Cambios y correcciones en el intérprete¶
Algunos de los cambios sólo afectan a la gente que trata con el intérprete de Python a nivel de C porque están escribiendo módulos de extensión de Python, incrustando el intérprete, o simplemente hackeando el propio intérprete. Si sólo escribes código Python, ninguno de los cambios descritos aquí te afectará mucho.
Las funciones de perfilado y rastreo pueden implementarse ahora en C, que puede operar a velocidades mucho mayores que las funciones basadas en Python y debería reducir la sobrecarga de perfilado y rastreo. Esto será de interés para los autores de entornos de desarrollo para Python. Se han añadido dos nuevas funciones en C a la API de Python,
PyEval_SetProfile()
yPyEval_SetTrace()
. Las funcionessys.setprofile()
ysys.settrace()
existentes siguen existiendo, y simplemente se han cambiado para utilizar la nueva interfaz de nivel C. (Contribución de Fred L. Drake, Jr.)Se ha añadido otra API de bajo nivel, principalmente de interés para los implementadores de depuradores y herramientas de desarrollo de Python.
PyInterpreterState_Head()
yPyInterpreterState_Next()
permiten al usuario recorrer todos los objetos intérpretes existentes;PyInterpreterState_ThreadHead()
yPyThreadState_Next()
permiten recorrer todos los estados de los hilos de un intérprete dado. (Contribución de David Beazley)La interfaz a nivel de C para el recolector de basura ha sido cambiada para facilitar la escritura de tipos de extensión que soporten la recolección de basura y para depurar los malos usos de las funciones. Varias funciones tienen una semántica ligeramente diferente, por lo que hubo que cambiar el nombre de un montón de funciones. Las extensiones que utilizan la antigua API seguirán compilando pero no participarán en la recolección de basura, por lo que actualizarlas para la 2.2 debería considerarse de alta prioridad.
Para actualizar un módulo de extensión a la nueva API, realice los siguientes pasos:
Rename
Py_TPFLAGS_GC
toPy_TPFLAGS_HAVE_GC
.- Utilice
PyObject_GC_New()
oPyObject_GC_NewVar()
para asignar objetos, y
PyObject_GC_Del()
para desocuparlos.
- Utilice
Rename
PyObject_GC_Init()
toPyObject_GC_Track()
andPyObject_GC_Fini()
toPyObject_GC_UnTrack()
.Remove
PyGC_HEAD_SIZE
from object size calculations.Remove calls to
PyObject_AS_GC()
andPyObject_FROM_GC()
.Se ha añadido una nueva secuencia de formato
et
aPyArg_ParseTuple()
;et
toma tanto un parámetro como un nombre de codificación, y convierte el parámetro a la codificación dada si el parámetro resulta ser una cadena Unicode, o lo deja solo si es una cadena de 8 bits, asumiendo que ya está en la codificación deseada. Esto difiere del carácter de formatoes
, que asume que las cadenas de 8 bits están en la codificación ASCII por defecto de Python y las convierte a la nueva codificación especificada. (Contribuido por M.-A. Lemburg, y utilizado para el soporte de MBCS en Windows descrito en la siguiente sección)Se ha agregado una función de análisis de argumentos diferente,
PyArg_UnpackTuple()
, que es más simple y presumiblemente más rápida. En lugar de especificar una cadena de formato, la persona que llama simplemente proporciona el número mínimo y máximo de argumentos esperados y un conjunto de punteros a las variables PyObject* que se completarán con los valores de los argumentos.Two new flags
METH_NOARGS
andMETH_O
are available in method definition tables to simplify implementation of methods with no arguments or a single untyped argument. Calling such methods is more efficient than calling a corresponding method that usesMETH_VARARGS
. Also, the oldMETH_OLDARGS
style of writing C methods is now officially deprecated.Two new wrapper functions,
PyOS_snprintf()
andPyOS_vsnprintf()
were added to provide cross-platform implementations for the relatively newsnprintf()
andvsnprintf()
C lib APIs. In contrast to the standardsprintf()
andvsprintf()
functions, the Python versions check the bounds of the buffer used to protect against buffer overruns. (Contributed by M.-A. Lemburg.)La función
_PyTuple_Resize()
ha perdido un parámetro que no se utilizaba, por lo que ahora toma 2 parámetros en lugar de 3. El tercer argumento nunca se utilizaba, y puede descartarse simplemente al portar el código de versiones anteriores a Python 2.2.
Otros cambios y correcciones¶
Como es habitual, hubo un montón de otras mejoras y correcciones de errores repartidas por todo el árbol de fuentes. Una búsqueda en los registros de cambios de CVS revela que se aplicaron 527 parches y se corrigieron 683 errores entre Python 2.1 y 2.2; en 2.2.1 se aplicaron 139 parches y se corrigieron 143 errores; en 2.2.2 se aplicaron 106 parches y se corrigieron 82 errores. Es probable que estas cifras estén subestimadas.
Algunos de los cambios más notables son:
El código del puerto MacOS para Python, mantenido por Jack Jansen, se mantiene ahora en el árbol CVS principal de Python, y se han realizado muchos cambios para soportar MacOS X.
El cambio más significativo es la capacidad de construir Python como un marco de trabajo, que se activa proporcionando la opción
--enable-framework
al script de configuración cuando se compila Python. Según Jack Jansen, «Esto instala una instalación autónoma de Python más el «pegamento» del framework de OS X en/Library/Frameworks/Python.framework
(o en otra ubicación de su elección). Por ahora hay poco beneficio inmediato añadido a esto (en realidad, existe la desventaja de que tienes que cambiar tu PATH para poder encontrar Python), pero es la base para crear una aplicación Python completa, portar el IDE de MacPython, posiblemente usar Python como un lenguaje de scripting estándar de OSA y mucho más.»La mayoría de los módulos de la caja de herramientas de MacPython, que interactúan con las APIs de MacOS como ventanas, QuickTime, scripts, etc. han sido portados a OS X, pero se han dejado comentados en
setup.py
. Las personas que quieran experimentar con estos módulos pueden descomentarlos manualmente.Los argumentos de palabras clave pasados a funciones incorporadas que no los aceptan ahora provocan una excepción
TypeError
, con el mensaje «function no acepta argumentos de palabras clave».Las referencias débiles, añadidas en Python 2.1 como un módulo de extensión, son ahora parte del núcleo porque se utilizan en la implementación de clases de nuevo estilo. Por lo tanto, la excepción
ReferenceError
se ha movido del móduloweakref
para convertirse en una excepción incorporada.Un nuevo script,
Tools/scripts/cleanfuture.py
de Tim Peters, elimina automáticamente las sentencias__future__
obsoletas del código fuente de Python.Se ha añadido un argumento adicional flags a la función incorporada
compile()
, por lo que el comportamiento de las sentencias__future__
puede ahora observarse correctamente en shells simulados, como los presentados por IDLE y otros entornos de desarrollo. Esto se describe en PEP 264. (Contribución de Michael Hudson)La nueva licencia introducida con Python 1.6 no era compatible con la GPL. Esto se ha solucionado con algunos cambios textuales menores en la licencia 2.2, de modo que ahora es legal volver a incrustar Python dentro de un programa con licencia GPL. Tenga en cuenta que Python en sí mismo no es GPL, sino que está bajo una licencia que es esencialmente equivalente a la licencia BSD, igual que siempre. Los cambios en la licencia también se aplicaron a las versiones 2.0.1 y 2.1.1 de Python.
Cuando se presenta un nombre de archivo Unicode en Windows, Python ahora lo convertirá en una cadena codificada en MBCS, como la que utilizan las APIs de archivos de Microsoft. Como las APIs de archivos utilizan explícitamente MBCS, la elección de Python de ASCII como codificación por defecto resulta ser una molestia. En Unix, se utiliza el juego de caracteres de la localización si
locale.nl_langinfo(CODESET)
está disponible. (El soporte de Windows fue contribuido por Mark Hammond con la ayuda de Marc-André Lemburg. El soporte para Unix fue añadido por Martin von Löwis)La compatibilidad con archivos de gran tamaño ya está activada en Windows. (Contribución de Tim Peters.)
El script
Tools/scripts/ftpmirror.py
ahora analiza un archivo.netrc
, si tiene uno. (Contribución de Mike Romberg)Some features of the object returned by the
xrange()
function are now deprecated, and trigger warnings when they’re accessed; they’ll disappear in Python 2.3.xrange
objects tried to pretend they were full sequence types by supporting slicing, sequence multiplication, and thein
operator, but these features were rarely used and therefore buggy. Thetolist()
method and thestart
,stop
, andstep
attributes are also being deprecated. At the C level, the fourth argument to thePyRange_New()
function,repeat
, has also been deprecated.Hubo un montón de parches para la implementación del diccionario, sobre todo para arreglar posibles vertidos del núcleo si un diccionario contiene objetos que cambian furtivamente su valor hash, o mutan el diccionario que contienen. Durante un tiempo python-dev cayó en un suave ritmo de Michael Hudson encontrando un caso que volcaba el núcleo, Tim Peters corrigiendo el error, Michael encontrando otro caso, y así sucesivamente.
En Windows, Python puede ahora compilarse con Borland C gracias a una serie de parches aportados por Stephen Hansen, aunque el resultado aún no es totalmente funcional. (Pero esto es un progreso…)
Otra mejora de Windows: Wise Solutions ofreció generosamente a PythonLabs el uso de su sistema InstallerMaster 8.1. Los anteriores instaladores de PythonLabs para Windows utilizaban Wise 5.0a, que estaba empezando a mostrar su edad. (Empaquetado por Tim Peters)
Los archivos que terminan en
.pyw
pueden importarse ahora en Windows..pyw
es algo exclusivo de Windows, que se utiliza para indicar que un script debe ejecutarse utilizando PYTHONW.EXE en lugar de PYTHON.EXE para evitar que aparezca una consola DOS para mostrar la salida. Este parche hace posible la importación de tales scripts, en caso de que también se puedan utilizar como módulos. (Implementado por David Bolen)En las plataformas en las que Python utiliza la función C
dlopen()
para cargar módulos de extensión, ahora es posible establecer las banderas utilizadas pordlopen()
utilizando las funcionessys.getdlopenflags()
ysys.setdlopenflags()
. (Contribución de Bram Stolk.)La función incorporada
pow()
ya no admite 3 argumentos cuando se suministran números de punto flotante.pow(x, y, z)
retorna(x**y) % z
, pero esto nunca es útil para números de punto flotante, y el resultado final varía de forma impredecible dependiendo de la plataforma. Una llamada comopow(2.0, 8.0, 7.0)
lanzará ahora una excepciónTypeError
.
Agradecimientos¶
El autor desea agradecer a las siguientes personas sus sugerencias, correcciones y ayuda en varios borradores de este artículo: Fred Bremmer, Keith Briggs, Andrew Dalke, Fred L. Drake, Jr, Carel Fellinger, David Goodger, Mark Hammond, Stephen Hansen, Michael Hudson, Jack Jansen, Marc-André Lemburg, Martin von Löwis, Fredrik Lundh, Michael McLay, Nick Mathewson, Paul Moore, Gustavo Niemeyer, Don O’Donnell, Joonas Paalasma, Tim Peters, Jens Quade, Tom Reinhardt, Neil Schemenauer, Guido van Rossum, Greg Ward, Edward Welbourne.