Python Language
Incompatibilidades que se mueven de Python 2 a Python 3
Buscar..
Introducción
A diferencia de la mayoría de los idiomas, Python admite dos versiones principales. Desde 2008, cuando se lanzó Python 3, muchos han hecho la transición, mientras que muchos no lo han hecho. Para entender ambos, esta sección cubre las diferencias importantes entre Python 2 y Python 3.
Observaciones
Actualmente hay dos versiones compatibles de Python: 2.7 (Python 2) y 3.6 (Python 3). Además, las versiones 3.3 y 3.4 reciben actualizaciones de seguridad en formato de origen.
Python 2.7 es compatible con versiones anteriores de la mayoría de las versiones anteriores de Python, y puede ejecutar el código de Python desde la mayoría de las versiones 1.xy 2.x de Python sin cambios. Está ampliamente disponible, con una extensa colección de paquetes. También es considerado obsoleto por los desarrolladores de CPython, y recibe solo seguridad y desarrollo de corrección de errores. Los desarrolladores de CPython tienen la intención de abandonar esta versión del lenguaje en 2020 .
De acuerdo con la Propuesta 373 de mejora de Python, no hay lanzamientos futuros planeados de Python 2 después del 25 de junio de 2016, pero las correcciones de errores y las actualizaciones de seguridad serán compatibles hasta 2020. (No especifica cuál será la fecha exacta en 2020 para la fecha de caducidad de Python 2.)
Python 3 rompió intencionalmente la compatibilidad con versiones anteriores, para abordar las preocupaciones que los desarrolladores de idiomas tenían con el núcleo del lenguaje. Python 3 recibe nuevos desarrollos y nuevas características. Es la versión del lenguaje con la que los desarrolladores del lenguaje pretenden avanzar.
Durante el tiempo entre la versión inicial de Python 3.0 y la versión actual, algunas características de Python 3 se portaron en Python 2.6, y otras partes de Python 3 se ampliaron para tener una sintaxis compatible con Python 2. Por lo tanto, es posible escribir Python que funcionará tanto en Python 2 como en Python 3, mediante el uso de futuras importaciones y módulos especiales (como seis ).
Las importaciones futuras deben estar al comienzo de su módulo:
from __future__ import print_function
# other imports and instructions go after __future__
print('Hello world')
Para obtener más información sobre el módulo __future__
, consulte la página correspondiente en la documentación de Python .
La herramienta 2to3 es un programa de Python que convierte el código de Python 2.x en el código de Python 3.x; consulte también la documentación de Python .
El paquete seis proporciona utilidades para la compatibilidad con Python 2/3:
- Acceso unificado a bibliotecas renombradas
- variables para los tipos de cadena / Unicode
- Funciones para el método que se eliminó o se ha renombrado.
Una referencia para las diferencias entre Python 2 y Python 3 se puede encontrar aquí .
Declaración de impresión vs. función de impresión
En Python 2, print
es una declaración:
print "Hello World"
print # print a newline
print "No newline", # add trailing comma to remove newline
print >>sys.stderr, "Error" # print to stderr
print("hello") # print "hello", since ("hello") == "hello"
print() # print an empty tuple "()"
print 1, 2, 3 # print space-separated arguments: "1 2 3"
print(1, 2, 3) # print tuple "(1, 2, 3)"
En Python 3, print()
es una función, con argumentos de palabras clave para usos comunes:
print "Hello World" # SyntaxError
print("Hello World")
print() # print a newline (must use parentheses)
print("No newline", end="") # end specifies what to append (defaults to newline)
print("Error", file=sys.stderr) # file specifies the output buffer
print("Comma", "separated", "output", sep=",") # sep specifies the separator
print("A", "B", "C", sep="") # null string for sep: prints as ABC
print("Flush this", flush=True) # flush the output buffer, added in Python 3.3
print(1, 2, 3) # print space-separated arguments: "1 2 3"
print((1, 2, 3)) # print tuple "(1, 2, 3)"
La función de impresión tiene los siguientes parámetros:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
sep
es lo que separa los objetos que pasas para imprimir. Por ejemplo:
print('foo', 'bar', sep='~') # out: foo~bar
print('foo', 'bar', sep='.') # out: foo.bar
end
es lo que sigue el final de la declaración de impresión. Por ejemplo:
print('foo', 'bar', end='!') # out: foo bar!
La impresión de nuevo después de una declaración de impresión final que no sea de nueva línea se imprimirá en la misma línea:
print('foo', end='~')
print('bar')
# out: foo~bar
Nota: Para compatibilidad futura, print
función de print
también está disponible en Python 2.6 en adelante; sin embargo, no se puede utilizar a menos que el análisis de la declaración de print
se deshabilite con
from __future__ import print_function
Esta función tiene exactamente el mismo formato que Python 3, excepto que carece del parámetro de flush
.
Ver PEP 3105 para la justificación.
Cuerdas: Bytes contra Unicode
En Python 2 hay dos variantes de cadena: las de bytes con tipo ( str
) y las de texto con tipo ( unicode
).
En Python 2, un objeto de tipo str
es siempre una secuencia de bytes, pero se usa comúnmente tanto para texto como para datos binarios.
Un literal de cadena se interpreta como una cadena de bytes.
s = 'Cafe' # type(s) == str
Hay dos excepciones: Puedes definir un literal de Unicode (texto) explícitamente prefijando el literal con u
:
s = u'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == str
Alternativamente, puede especificar que los literales de cadena de un módulo completo deberían crear literales Unicode (texto):
from __future__ import unicode_literals
s = 'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == unicode
Para verificar si su variable es una cadena (ya sea Unicode o una cadena de bytes), puede usar:
isinstance(s, basestring)
En Python 3, el tipo str
es un tipo de texto Unicode.
s = 'Cafe' # type(s) == str
s = 'Café' # type(s) == str (note the accented trailing e)
Además, Python 3 agregó un objeto de bytes
, adecuado para "blobs" binarios o escrito en archivos independientes de la codificación. Para crear un objeto de bytes, puede prefijar b
a un literal de cadena o llamar al método de encode
la cadena:
# Or, if you really need a byte string:
s = b'Cafe' # type(s) == bytes
s = 'Café'.encode() # type(s) == bytes
Para probar si un valor es una cadena, use:
isinstance(s, str)
También es posible prefijar literales de cadena con un prefijo u
para facilitar la compatibilidad entre las bases de código de Python 2 y Python 3. Dado que, en Python 3, todas las cadenas son Unicode de forma predeterminada, el antepuesto de una cadena literal con u
no tiene ningún efecto:
u'Cafe' == 'Cafe'
Sin embargo, el prefijo ur
cadena Unicode sin procesar de Python 2 no es compatible:
>>> ur'Café'
File "<stdin>", line 1
ur'Café'
^
SyntaxError: invalid syntax
Tenga en cuenta que debe encode
un objeto de texto ( str
) de Python 3 para convertirlo en una representación de bytes
de ese texto. La codificación predeterminada de este método es UTF-8 .
Puede usar decode
para pedir a un objeto de bytes
texto Unicode que representa:
>>> b.decode()
'Café'
Mientras que el tipo de bytes
existe tanto en Python 2 como en 3, el tipo unicode
solo existe en Python 2. Para usar las cadenas de Unicode implícitas de Python 3 en Python 2, agregue lo siguiente en la parte superior de su archivo de código:
from __future__ import unicode_literals
print(repr("hi"))
# u'hi'
Otra diferencia importante es que la indexación de bytes en Python 3 da como resultado una salida int
como:
b"abc"[0] == 97
Mientras se corta en un tamaño de uno, se obtiene un objeto de longitud de 1 bytes:
b"abc"[0:1] == b"a"
Además, Python 3 corrige algunos comportamientos inusuales con Unicode, es decir, invierte cadenas de bytes en Python 2. Por ejemplo, se resuelve el siguiente problema :
# -*- coding: utf8 -*-
print("Hi, my name is Łukasz Langa.")
print(u"Hi, my name is Łukasz Langa."[::-1])
print("Hi, my name is Łukasz Langa."[::-1])
# Output in Python 2
# Hi, my name is Łukasz Langa.
# .agnaL zsakuŁ si eman ym ,iH
# .agnaL zsaku�� si eman ym ,iH
# Output in Python 3
# Hi, my name is Łukasz Langa.
# .agnaL zsakuŁ si eman ym ,iH
# .agnaL zsakuŁ si eman ym ,iH
División entera
El símbolo de división estándar ( /
) funciona de manera diferente en Python 3 y Python 2 cuando se aplica a enteros.
Cuando se divide un entero por otro entero en Python 3, la operación de división x / y
representa una verdadera división (usa el método __truediv__
) y produce un resultado de punto flotante. Mientras tanto, la misma operación en Python 2 representa una división clásica que redondea el resultado hacia el infinito negativo (también conocido como tomar el piso ).
Por ejemplo:
Código | Salida Python 2 | Salida Python 3 |
---|---|---|
3 / 2 | 1 | 1.5 |
2 / 3 | 0 | 0.6666666666666666 |
-3 / 2 | -2 | -1.5 |
El comportamiento de redondeo hacia cero fue obsoleto en Python 2.2 , pero permanece en Python 2.7 por motivos de compatibilidad con versiones anteriores y se eliminó en Python 3.
Nota: para obtener un resultado flotante en Python 2 (sin redondear el piso) podemos especificar uno de los operandos con el punto decimal. El ejemplo anterior de 2/3
que da 0
en Python 2 se usará como 2 / 3.0
o 2.0 / 3
o 2.0/3.0
para obtener 0.6666666666666666
Código | Salida Python 2 | Salida Python 3 |
---|---|---|
3.0 / 2.0 | 1.5 | 1.5 |
2 / 3.0 | 0.6666666666666666 | 0.6666666666666666 |
-3.0 / 2 | -1.5 | -1.5 |
También está el operador de división de piso ( //
), que funciona de la misma manera en ambas versiones: se redondea al entero más cercano. (aunque se devuelve un flotador cuando se usa con flotadores) En ambas versiones, el operador //
asigna a __floordiv__
.
Código | Salida Python 2 | Salida Python 3 |
---|---|---|
3 // 2 | 1 | 1 |
2 // 3 | 0 | 0 |
-3 // 2 | -2 | -2 |
3.0 // 2.0 | 1.0 | 1.0 |
2.0 // 3 | 0.0 | 0.0 |
-3 // 2.0 | -2.0 | -2.0 |
Uno puede imponer explícitamente la división verdadera o la división de piso usando funciones nativas en el módulo del operator
:
from operator import truediv, floordiv
assert truediv(10, 8) == 1.25 # equivalent to `/` in Python 3
assert floordiv(10, 8) == 1 # equivalent to `//`
Si bien es claro y explícito, el uso de funciones de operador para cada división puede ser tedioso. Cambiar el comportamiento del operador /
a menudo será preferido. Una práctica común es eliminar el comportamiento de división típico agregando la from __future__ import division
como la primera declaración en cada módulo:
# needs to be the first statement in a module
from __future__ import division
Código | Salida Python 2 | Salida Python 3 |
---|---|---|
3 / 2 | 1.5 | 1.5 |
2 / 3 | 0.6666666666666666 | 0.6666666666666666 |
-3 / 2 | -1.5 | -1.5 |
from __future__ import division
garantiza que el operador /
representa la división verdadera y solo dentro de los módulos que contienen la importación __future__
, por lo que no hay razones de peso para no habilitarla en todos los módulos nuevos.
Nota : Algunos otros lenguajes de programación utilizan el redondeo hacia cero (truncamiento) en lugar de redondear hacia el infinito negativo como Python (es decir, en esos idiomas -3 / 2 == -1
). Este comportamiento puede crear confusión al portar o comparar código.
Nota sobre los operandos de flotación : Como alternativa a la from __future__ import division
, se podría usar el símbolo de división habitual /
y asegurarse de que al menos uno de los operandos es una flotación: 3 / 2.0 == 1.5
. Sin embargo, esto puede considerarse una mala práctica. Es demasiado fácil escribir el average = sum(items) / len(items)
y olvidarse de lanzar uno de los argumentos para flotar. Además, estos casos pueden evadir con frecuencia el aviso durante las pruebas, por ejemplo, si realiza pruebas en una matriz que contiene float
pero recibe una matriz de int
s en producción. Además, si se usa el mismo código en Python 3, los programas que esperan que 3/2 3 / 2 == 1
sea Verdadero no funcionarán correctamente.
Vea PEP 238 para una explicación más detallada de por qué se cambió el operador de la división en Python 3 y por qué se debe evitar la división de estilo antiguo.
Vea el tema de Matemáticas simples para más información sobre la división.
Reducir ya no es una función incorporada.
En Python 2, reduce
está disponible como una función incorporada o desde el paquete functools
(versión 2.6 en adelante), mientras que en Python 3, reduce
está disponible solo desde functools
. Sin embargo, la sintaxis para reduce
tanto en Python2 como en Python3 es la misma y es reduce(function_to_reduce, list_to_reduce)
.
Como ejemplo, consideremos reducir una lista a un solo valor al dividir cada uno de los números adyacentes. Aquí usamos la función truediv
de la biblioteca del operator
.
En Python 2.x es tan simple como:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator
>>> reduce(operator.truediv, my_list)
0.008333333333333333
En Python 3.x el ejemplo se vuelve un poco más complicado:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator, functools
>>> functools.reduce(operator.truediv, my_list)
0.008333333333333333
También podemos utilizar from functools import reduce
para evitar reduce
llamadas con el nombre del espacio de nombres.
Diferencias entre las funciones de rango y rango
En Python 2, la función de range
devuelve una lista, mientras que xrange
crea un objeto de xrange
especial, que es una secuencia inmutable, que a diferencia de otros tipos de secuencia incorporados, no admite el corte y no tiene métodos de index
ni de count
:
print(range(1, 10))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(isinstance(range(1, 10), list))
# Out: True
print(xrange(1, 10))
# Out: xrange(1, 10)
print(isinstance(xrange(1, 10), xrange))
# Out: True
En Python 3, xrange
se expandió a la secuencia de range
, que ahora crea un objeto de range
. No hay tipo xrange
:
print(range(1, 10))
# Out: range(1, 10)
print(isinstance(range(1, 10), range))
# Out: True
# print(xrange(1, 10))
# The output will be:
#Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#NameError: name 'xrange' is not defined
Además, dado que Python 3.2, el range
también admite el corte, index
y count
:
print(range(1, 10)[3:7])
# Out: range(3, 7)
print(range(1, 10).count(5))
# Out: 1
print(range(1, 10).index(7))
# Out: 6
La ventaja de usar un tipo de secuencia especial en lugar de una lista es que el intérprete no tiene que asignar memoria para una lista y llenarla:
# range(10000000000000000)
# The output would be:
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# MemoryError
print(xrange(100000000000000000))
# Out: xrange(100000000000000000)
Como generalmente se desea el último comportamiento, el primero se eliminó en Python 3. Si aún desea tener una lista en Python 3, simplemente puede usar el constructor list()
en un objeto de range
:
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Compatibilidad
Para mantener la compatibilidad entre las versiones de Python 2.xy Python 3.x, puede usar el módulo builtins
del future
paquete externo para lograr tanto compatibilidad con versiones anteriores como compatibilidad con versiones anteriores :
#forward-compatible
from builtins import range
for i in range(10**8):
pass
#backward-compatible
from past.builtins import xrange
for i in xrange(10**8):
pass
El range
en la biblioteca future
admite la segmentación, el index
y el count
en todas las versiones de Python, al igual que el método incorporado en Python 3.2+.
Desembalaje Iterables
En Python 3, puedes descomprimir un iterable sin saber la cantidad exacta de elementos que contiene, e incluso tener una variable que mantenga el final del iterable. Para eso, proporciona una variable que puede recopilar una lista de valores. Esto se hace colocando un asterisco antes del nombre. Por ejemplo, desempaquetar una list
:
first, second, *tail, last = [1, 2, 3, 4, 5]
print(first)
# Out: 1
print(second)
# Out: 2
print(tail)
# Out: [3, 4]
print(last)
# Out: 5
Nota : Al usar la sintaxis de la *variable
, la variable
siempre será una lista, incluso si el tipo original no era una lista. Puede contener cero o más elementos dependiendo del número de elementos en la lista original.
first, second, *tail, last = [1, 2, 3, 4]
print(tail)
# Out: [3]
first, second, *tail, last = [1, 2, 3]
print(tail)
# Out: []
print(last)
# Out: 3
Del mismo modo, desempaquetando un str
:
begin, *tail = "Hello"
print(begin)
# Out: 'H'
print(tail)
# Out: ['e', 'l', 'l', 'o']
Ejemplo de desempaquetar una date
; _
se utiliza en este ejemplo como una variable desechable (solo nos interesa el valor del year
):
person = ('John', 'Doe', (10, 16, 2016))
*_, (*_, year_of_birth) = person
print(year_of_birth)
# Out: 2016
Vale la pena mencionar que, dado que *
consume una cantidad variable de elementos, no puede tener dos *
s para el mismo iterable en una asignación; no sabría cuántos elementos entran en el primer desempaquetado y cuántos en el segundo :
*head, *tail = [1, 2]
# Out: SyntaxError: two starred expressions in assignment
Hasta ahora hemos discutido el desempaquetado en las tareas. *
y **
se extendieron en Python 3.5 . Ahora es posible tener varias operaciones de desempaquetado en una expresión:
{*range(4), 4, *(5, 6, 7)}
# Out: {0, 1, 2, 3, 4, 5, 6, 7}
También es posible descomprimir un iterable en argumentos de función:
iterable = [1, 2, 3, 4, 5]
print(iterable)
# Out: [1, 2, 3, 4, 5]
print(*iterable)
# Out: 1 2 3 4 5
Desembalar un diccionario usa dos estrellas adyacentes **
( PEP 448 ):
tail = {'y': 2, 'z': 3}
{'x': 1, **tail}
# Out: {'x': 1, 'y': 2, 'z': 3}
Esto permite anular valores antiguos y fusionar diccionarios.
dict1 = {'x': 1, 'y': 1}
dict2 = {'y': 2, 'z': 3}
{**dict1, **dict2}
# Out: {'x': 1, 'y': 2, 'z': 3}
Python 3 eliminó el desempaquetado de tuplas en las funciones. Por lo tanto lo siguiente no funciona en Python 3
# Works in Python 2, but syntax error in Python 3:
map(lambda (x, y): x + y, zip(range(5), range(5)))
# Same is true for non-lambdas:
def example((x, y)):
pass
# Works in both Python 2 and Python 3:
map(lambda x: x[0] + x[1], zip(range(5), range(5)))
# And non-lambdas, too:
def working_example(x_y):
x, y = x_y
pass
Ver PEP 3113 para una explicación detallada.
Levantando y manejando excepciones
Esta es la sintaxis de Python 2, tenga en cuenta las comas ,
en las líneas de raise
y except
:
try:
raise IOError, "input/output error"
except IOError, exc:
print exc
En Python 3, el ,
la sintaxis se deja caer y se sustituye por el paréntesis y as
palabra clave:
try:
raise IOError("input/output error")
except IOError as exc:
print(exc)
Para la compatibilidad con versiones anteriores, la sintaxis de Python 3 también está disponible en Python 2.6 en adelante, por lo que debe usarse para todo el código nuevo que no necesita ser compatible con versiones anteriores.
Python 3 también agrega el encadenamiento de excepciones , en el que puede indicar que alguna otra excepción fue la causa de esta excepción. Por ejemplo
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from e
La excepción generada en la declaración de except
es de tipo DatabaseError
, pero la excepción original está marcada como el atributo __cause__
de esa excepción. Cuando se muestra el rastreo, la excepción original también se mostrará en el rastreo:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
FileNotFoundError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
Si lanza un bloque de except
sin encadenamiento explícito:
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}')
La traza es
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
FileNotFoundError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
Ninguno de los dos está soportado en Python 2.x; la excepción original y su rastreo se perderán si se genera otra excepción en el bloque de excepción. El siguiente código puede ser usado para compatibilidad:
import sys
import traceback
try:
funcWithError()
except:
sys_vers = getattr(sys, 'version_info', (0,))
if sys_vers < (3, 0):
traceback.print_exc()
raise Exception("new exception")
Para "olvidar" la excepción lanzada anteriormente, use raise from None
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from None
Ahora el rastreo sería simplemente
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
O para que sea compatible con Python 2 y 3 puede usar el paquete seis así:
import six
try:
file = open('database.db')
except FileNotFoundError as e:
six.raise_from(DatabaseError('Cannot open {}'), None)
.next () método en los iteradores renombrados
En Python 2, se puede recorrer un iterador usando un método llamado next
en el mismo iterador:
g = (i for i in range(0, 3))
g.next() # Yields 0
g.next() # Yields 1
g.next() # Yields 2
En Python 3, el método .next
ha sido renombrado a .__next__
, reconociendo su función "mágica", por lo que llamar a .next
generará un AttributeError
. La forma correcta de acceder a esta funcionalidad tanto en Python 2 como en Python 3 es llamar a la next
función con el iterador como argumento.
g = (i for i in range(0, 3))
next(g) # Yields 0
next(g) # Yields 1
next(g) # Yields 2
Este código es portátil en las versiones desde 2.6 hasta las versiones actuales.
Comparación de diferentes tipos
Se pueden comparar objetos de diferentes tipos. Los resultados son arbitrarios, pero consistentes. Están ordenados de modo que None
es menor que cualquier otra cosa, los tipos numéricos son más pequeños que los tipos no numéricos y todo lo demás está ordenado lexicográficamente por tipo. Por lo tanto, un int
es menor que un str
y una tuple
es mayor que una list
:
[1, 2] > 'foo'
# Out: False
(1, 2) > 'foo'
# Out: True
[1, 2] > (1, 2)
# Out: False
100 < [1, 'x'] < 'xyz' < (1, 'x')
# Out: True
Esto se hizo originalmente para poder ordenar una lista de tipos mixtos y los objetos se agruparían por tipo:
l = [7, 'x', (1, 2), [5, 6], 5, 8.0, 'y', 1.2, [7, 8], 'z']
sorted(l)
# Out: [1.2, 5, 7, 8.0, [5, 6], [7, 8], 'x', 'y', 'z', (1, 2)]
Se produce una excepción al comparar diferentes tipos (no numéricos):
1 < 1.5
# Out: True
[1, 2] > 'foo'
# TypeError: unorderable types: list() > str()
(1, 2) > 'foo'
# TypeError: unorderable types: tuple() > str()
[1, 2] > (1, 2)
# TypeError: unorderable types: list() > tuple()
Para ordenar las listas mixtas en Python 3 por tipos y para lograr la compatibilidad entre versiones, debe proporcionar una clave para la función ordenada:
>>> list = [1, 'hello', [3, 4], {'python': 2}, 'stackoverflow', 8, {'python': 3}, [5, 6]]
>>> sorted(list, key=str)
# Out: [1, 8, [3, 4], [5, 6], 'hello', 'stackoverflow', {'python': 2}, {'python': 3}]
El uso de str
como la función de key
convierte temporalmente cada elemento en una cadena solo para fines de comparación. Luego ve la representación de la cadena comenzando con [
, '
, {
o 0-9
y es capaz de ordenarlas (y todos los siguientes caracteres).
Entrada del usuario
En Python 2, la entrada del usuario se acepta utilizando la función raw_input
,
user_input = raw_input()
Mientras que en Python 3, la entrada del usuario se acepta usando la función de input
.
user_input = input()
En Python 2, la input
la función aceptará la entrada e interpretarla. Si bien esto puede ser útil, tiene varias consideraciones de seguridad y se eliminó en Python 3. Para acceder a la misma funcionalidad, se puede usar eval(input())
.
Para mantener un script portátil en las dos versiones, puede colocar el código a continuación cerca de la parte superior de su script de Python:
try:
input = raw_input
except NameError:
pass
Cambios en el método del diccionario
En Python 3, muchos de los métodos del diccionario tienen un comportamiento bastante diferente al de Python 2, y muchos también fueron eliminados: has_key
, iter*
y view*
se han ido. En lugar de d.has_key(key)
, que había estado en desuso durante mucho tiempo, ahora se debe usar la key in d
.
En Python 2, las keys
métodos de diccionario, values
y items
devuelven listas. En Python 3 devuelven los objetos de vista en su lugar; los objetos de vista no son iteradores, y se diferencian de ellos de dos maneras, a saber:
- tienen tamaño (uno puede usar la función
len
en ellos) - Se pueden iterar varias veces.
Además, como con los iteradores, los cambios en el diccionario se reflejan en los objetos de vista.
Python 2.7 ha respaldado estos métodos desde Python 3; están disponibles como viewkeys
, viewvalues
y elementos de viewitems
. Para transformar el código de Python 2 en el código de Python 3, los formularios correspondientes son:
-
d.keys()
,d.values()
yd.items()
de Python 2 deben cambiarse alist(d.keys())
,list(d.values())
ylist(d.items())
-
d.iterkeys()
,d.itervalues()
yd.iteritems()
deben cambiarse aiter(d.keys())
, o incluso mejor,iter(d)
;iter(d.values())
eiter(d.items())
respectivamente - y, finalmente, las llamadas al método Python 2.7
d.viewkeys()
,d.viewvalues()
yd.viewitems()
se pueden reemplazar pord.keys()
,d.values()
yd.items()
.
Portar el código de Python 2 que itera sobre las claves del diccionario, los valores o los elementos mientras se muta a veces es complicado. Considerar:
d = {'a': 0, 'b': 1, 'c': 2, '!': 3}
for key in d.keys():
if key.isalpha():
del d[key]
El código parece que funcionaría de manera similar en Python 3, pero allí el método de las keys
devuelve un objeto de vista, no una lista, y si el diccionario cambia de tamaño mientras se repite, el código de Python 3 se bloqueará con RuntimeError: dictionary changed size during iteration
. La solución es, por supuesto, escribir correctamente for key in list(d)
.
De manera similar, los objetos de vista se comportan de manera diferente a los iteradores: uno no puede usar next()
en ellos, y uno no puede reanudar la iteración; en su lugar se reiniciaría; Si el código de Python 2 pasa el valor de retorno de d.iterkeys()
, d.itervalues()
o d.iteritems()
a un método que espera un iterador en lugar de un iterable , entonces debería ser iter(d)
, iter(d.values())
o iter(d.items())
en Python 3.
La sentencia exec es una función en Python 3
En Python 2, exec
es una declaración, con una sintaxis especial: exec code [in globals[, locals]].
En Python 3, exec
ahora es una función: exec(code, [, globals[, locals]])
, y la sintaxis de Python 2 generará un SyntaxError
.
A medida que se cambió la print
de una declaración a una función, también se agregó una importación __future__
. Sin embargo, no hay from __future__ import exec_function
, ya que no es necesario: la declaración exec en Python 2 también se puede usar con una sintaxis que se ve exactamente como la invocación de la función exec
en Python 3. Por lo tanto, puede cambiar las declaraciones
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars
a las formas
exec('code')
exec('code', global_vars)
exec('code', global_vars, local_vars)
y se garantiza que las últimas formas funcionarán de manera idéntica tanto en Python 2 como en Python 3.
Error de la función hasattr en Python 2
En Python 2, cuando una propiedad hasattr
un error, hasattr
ignorará esta propiedad y devolverá False
.
class A(object):
@property
def get(self):
raise IOError
class B(object):
@property
def get(self):
return 'get in b'
a = A()
b = B()
print 'a hasattr get: ', hasattr(a, 'get')
# output False in Python 2 (fixed, True in Python 3)
print 'b hasattr get', hasattr(b, 'get')
# output True in Python 2 and Python 3
Este error se corrige en Python3. Así que si usas Python 2, usa
try:
a.get
except AttributeError:
print("no get property!")
o use getattr
en getattr
lugar
p = getattr(a, "get", None)
if p is not None:
print(p)
else:
print("no get property!")
Módulos renombrados
Algunos módulos en la biblioteca estándar han sido renombrados:
Viejo nombre | Nuevo nombre |
---|---|
_winreg | Winreg |
ConfigParser | configparser |
copy_reg | copyreg |
Cola | cola |
SocketServer | socketserver |
_markupbase | markupbase |
reprimir | reprender |
test.test_support | test.support |
Tkinter | tkinter |
tkFileDialog | tkinter.filedialog |
urllib / urllib2 | urllib, urllib.parse, urllib.error, urllib.response, urllib.request, urllib.robotparser |
Algunos módulos incluso se han convertido de archivos a bibliotecas. Tome tkinter y urllib desde arriba como ejemplo.
Compatibilidad
Al mantener la compatibilidad entre las versiones de Python 2.xy 3.x, puede usar el paquete externo future
para habilitar la importación de paquetes de biblioteca de nivel superior con nombres de Python 3.x en las versiones de Python 2.x.
Constantes octales
En Python 2, un literal octal podría definirse como
>>> 0755 # only Python 2
Para asegurar la compatibilidad cruzada, use
0o755 # both Python 2 and Python 3
Todas las clases son "clases de nuevo estilo" en Python 3.
En Python 3.x
todas las clases son clases de nuevo estilo ; Al definir una nueva clase, Python implícitamente la hace heredar de un object
. Como tal, especificar un object
en una definición de class
es completamente opcional:
class X: pass
class Y(object): pass
Ambas de estas clases ahora contienen object
en su mro
(orden de resolución de métodos):
>>> X.__mro__
(__main__.X, object)
>>> Y.__mro__
(__main__.Y, object)
En Python 2.x
clases son, por defecto, las clases de estilo antiguo; no heredan implícitamente del object
. Esto hace que la semántica de las clases difiera dependiendo de si agregamos explícitamente el object
como una class
base:
class X: pass
class Y(object): pass
En este caso, si intentamos imprimir el __mro__
de Y
, __mro__
una salida similar a la del caso Python 3.x
:
>>> Y.__mro__
(<class '__main__.Y'>, <type 'object'>)
Esto sucede porque hicimos que Y
heredara explícitamente de un objeto al definirlo: class Y(object): pass
. Para la clase X
que no hereda del objeto, el atributo __mro__
no existe, al intentar acceder a él se obtiene un AttributeError
.
Para garantizar la compatibilidad entre ambas versiones de Python, las clases se pueden definir con el object
como una clase base:
class mycls(object):
"""I am fully compatible with Python 2/3"""
Alternativamente, si la variable __metaclass__
está configurada para type
en el ámbito global, todas las clases definidas posteriormente en un módulo dado son implícitamente un estilo nuevo sin la necesidad de heredar explícitamente del object
:
__metaclass__ = type
class mycls:
"""I am also fully compatible with Python 2/3"""
Se eliminaron los operadores <> y ``, sinónimo de! = Y repr ()
En Python 2, <>
es un sinónimo para !=
; Del mismo modo, `foo`
es un sinónimo de repr(foo)
.
>>> 1 <> 2
True
>>> 1 <> 1
False
>>> foo = 'hello world'
>>> repr(foo)
"'hello world'"
>>> `foo`
"'hello world'"
>>> 1 <> 2
File "<stdin>", line 1
1 <> 2
^
SyntaxError: invalid syntax
>>> `foo`
File "<stdin>", line 1
`foo`
^
SyntaxError: invalid syntax
codificar / decodificar a hex ya no está disponible
"1deadbeef3".decode('hex')
# Out: '\x1d\xea\xdb\xee\xf3'
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Out: 1deadbeef3
"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'str' object has no attribute 'decode'
b"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.decode() to handle arbitrary codecs
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
b'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'bytes' object has no attribute 'encode'
Sin embargo, como lo sugiere el mensaje de error, puede usar el módulo de codecs
para lograr el mismo resultado:
import codecs
codecs.decode('1deadbeef4', 'hex')
# Out: b'\x1d\xea\xdb\xee\xf4'
codecs.encode(b'\x1d\xea\xdb\xee\xf4', 'hex')
# Out: b'1deadbeef4'
Tenga en cuenta que codecs.encode
devuelve un objeto de bytes
. Para obtener un objeto str
simplemente decode
a ASCII:
codecs.encode(b'\x1d\xea\xdb\xee\xff', 'hex').decode('ascii')
# Out: '1deadbeeff'
Función cmp eliminada en Python 3
En Python 3 se eliminó la función incorporada de cmp
, junto con el método especial __cmp__
.
De la documentación:
La función
cmp()
debe tratar como pasada, y el método especial__cmp__()
ya no se admite. Use__lt__()
para clasificar,__eq__()
con__hash__()
, y otras comparaciones ricas según sea necesario. (Si realmente necesita la funcionalidadcmp()
, puede usar la expresión(a > b) - (a < b)
como equivalente paracmp(a, b)
.
Además, todas las funciones incorporadas que aceptaron el parámetro cmp
ahora solo aceptan el parámetro de key
clave única.
En el módulo functools
también hay una función útil cmp_to_key(func)
que le permite convertir de una función de estilo cmp
a una key
estilo de key
:
Transformar una función de comparación de estilo antiguo en una función clave. Se usa con herramientas que aceptan funciones clave (como
sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
). Esta función se utiliza principalmente como una herramienta de transición para los programas que se convierten desde Python 2 que admite el uso de funciones de comparación.
Variables filtradas en la lista de comprensión.
x = 'hello world!'
vowels = [x for x in 'AEIOU']
print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'U'
x = 'hello world!'
vowels = [x for x in 'AEIOU']
print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'hello world!'
Como se puede ver en el ejemplo, en Python 2 se filtró el valor de x
: ¡enmascaró a hello world!
e imprimió U
, ya que este fue el último valor de x
cuando finalizó el bucle.
Sin embargo, en Python 3 x
imprime el hello world!
originalmente definido hello world!
, ya que la variable local de la lista de comprensión no enmascara las variables del ámbito circundante.
Además, ni las expresiones generadoras (disponibles en Python desde la versión 2.5) ni las comprensiones de diccionario o conjunto (que fueron respaldadas a Python 2.7 desde Python 3) filtran las variables en Python 2.
Tenga en cuenta que tanto en Python 2 como en Python 3, las variables se filtrarán en el ámbito circundante cuando se use un bucle for:
x = 'hello world!'
vowels = []
for x in 'AEIOU':
vowels.append(x)
print(x)
# Out: 'U'
mapa()
map()
es un componente que es útil para aplicar una función a elementos de un iterable. En Python 2, el map
devuelve una lista. En Python 3, map
devuelve un objeto map , que es un generador.
# Python 2.X
>>> map(str, [1, 2, 3, 4, 5])
['1', '2', '3', '4', '5']
>>> type(_)
>>> <class 'list'>
# Python 3.X
>>> map(str, [1, 2, 3, 4, 5])
<map object at 0x*>
>>> type(_)
<class 'map'>
# We need to apply map again because we "consumed" the previous map....
>>> map(str, [1, 2, 3, 4, 5])
>>> list(_)
['1', '2', '3', '4', '5']
En Python 2, puede pasar None
para que funcione como una función de identidad. Esto ya no funciona en Python 3.
>>> map(None, [0, 1, 2, 3, 0, 4])
[0, 1, 2, 3, 0, 4]
>>> list(map(None, [0, 1, 2, 3, 0, 5]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
Además, al pasar más de un iterable como argumento en Python 2, el map
rellena los iterables más cortos con None
(similar a itertools.izip_longest
). En Python 3, la iteración se detiene después de la iteración más corta.
En Python 2:
>>> map(None, [1, 2, 3], [1, 2], [1, 2, 3, 4, 5])
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]
En Python 3:
>>> list(map(lambda x, y, z: (x, y, z), [1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2)]
# to obtain the same padding as in Python 2 use zip_longest from itertools
>>> import itertools
>>> list(itertools.zip_longest([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]
Nota : en lugar de un map
considere utilizar listas de comprensión, que son compatibles con Python 2/3. Reemplazo del map(str, [1, 2, 3, 4, 5])
:
>>> [str(i) for i in [1, 2, 3, 4, 5]]
['1', '2', '3', '4', '5']
filter (), map () y zip () devuelven iteradores en lugar de secuencias
En el filter
Python 2, las funciones incorporadas de map
y zip
devuelven una secuencia. map
y zip
siempre devuelven una lista, mientras que con el filter
el tipo de retorno depende del tipo de parámetro dado:
>>> s = filter(lambda x: x.isalpha(), 'a1b2c3')
>>> s
'abc'
>>> s = map(lambda x: x * x, [0, 1, 2])
>>> s
[0, 1, 4]
>>> s = zip([0, 1, 2], [3, 4, 5])
>>> s
[(0, 3), (1, 4), (2, 5)]
En el filter
Python 3, el map
y el zip
iterador de retorno en su lugar:
>>> it = filter(lambda x: x.isalpha(), 'a1b2c3')
>>> it
<filter object at 0x00000098A55C2518>
>>> ''.join(it)
'abc'
>>> it = map(lambda x: x * x, [0, 1, 2])
>>> it
<map object at 0x000000E0763C2D30>
>>> list(it)
[0, 1, 4]
>>> it = zip([0, 1, 2], [3, 4, 5])
>>> it
<zip object at 0x000000E0763C52C8>
>>> list(it)
[(0, 3), (1, 4), (2, 5)]
Desde Python 2, itertools.izip
es equivalente a Python 3 zip
izip
se ha eliminado en Python 3.
Importaciones absolutas / relativas
En Python 3, PEP 404 cambia la forma en que funcionan las importaciones desde Python 2. Ya no se permiten las importaciones relativas implícitas en los paquetes y from ... import *
solo se permiten en el código de nivel de módulo.
Para lograr el comportamiento de Python 3 en Python 2:
- la característica de importaciones absolutas se puede habilitar
from __future__ import absolute_import
- Se alientan las importaciones relativas explícitas en lugar de las importaciones relativas implícitas
Para aclarar, en Python 2, un módulo puede importar el contenido de otro módulo ubicado en el mismo directorio de la siguiente manera:
import foo
Observe que la ubicación de foo
es ambigua desde la declaración de importación solo. Este tipo de importación relativa implícita se desaconseja, por tanto, a favor de las importaciones relativas explícitas , que se parecen a las siguientes:
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
from ...package import bar
from ...sys import path
El punto .
Permite una declaración explícita de la ubicación del módulo dentro del árbol de directorios.
Más sobre Importaciones Relativas
Considere algún paquete definido por el usuario llamado shapes
. La estructura del directorio es la siguiente:
shapes
├── __init__.py
|
├── circle.py
|
├── square.py
|
└── triangle.py
circle.py
, square.py
y triangle.py
importan util.py
como un módulo. ¿Cómo se referirán a un módulo en el mismo nivel?
from . import util # use util.PI, util.sq(x), etc
O
from .util import * #use PI, sq(x), etc to call functions
El .
Se utiliza para importaciones relativas del mismo nivel.
Ahora, considere un diseño alternativo del módulo de shapes
:
shapes
├── __init__.py
|
├── circle
│ ├── __init__.py
│ └── circle.py
|
├── square
│ ├── __init__.py
│ └── square.py
|
├── triangle
│ ├── __init__.py
│ ├── triangle.py
|
└── util.py
Ahora, ¿cómo se referirán estas 3 clases a util.py?
from .. import util # use util.PI, util.sq(x), etc
O
from ..util import * # use PI, sq(x), etc to call functions
El ..
se utiliza para las importaciones relativas de nivel padre. Añadir más .
s con número de niveles entre el padre y el niño.
Archivo I / O
file
ya no es un nombre incorporado en 3.x ( open
aún funciona).
Los detalles internos del archivo de E / S se han trasladado al módulo de la biblioteca estándar io
, que también es el nuevo hogar de StringIO
:
import io
assert io.open is open # the builtin is an alias
buffer = io.StringIO()
buffer.write('hello, ') # returns number of characters written
buffer.write('world!\n')
buffer.getvalue() # 'hello, world!\n'
El modo de archivo (texto frente a binario) ahora determina el tipo de datos producidos al leer un archivo (y el tipo requerido para escribir):
with open('data.txt') as f:
first_line = next(f)
assert type(first_line) is str
with open('data.bin', 'rb') as f:
first_kb = f.read(1024)
assert type(first_kb) is bytes
La codificación de los archivos de texto se establece de forma predeterminada en locale.getpreferredencoding(False)
. Para especificar una codificación explícitamente, use el parámetro de palabra clave de encoding
:
with open('old_japanese_poetry.txt', 'shift_jis') as text:
haiku = text.read()
La función round () rompe el empate y devuelve el tipo
rotura de corbata redonda ()
En Python 2, usar round()
en un número igualmente cercano a dos enteros devolverá el más alejado de 0. Por ejemplo:
round(1.5) # Out: 2.0
round(0.5) # Out: 1.0
round(-0.5) # Out: -1.0
round(-1.5) # Out: -2.0
Sin embargo, en Python 3, round()
devolverá el entero par (también conocido como redondeo de banqueros ). Por ejemplo:
round(1.5) # Out: 2
round(0.5) # Out: 0
round(-0.5) # Out: 0
round(-1.5) # Out: -2
La función round () sigue la mitad de la estrategia de redondeo uniforme que redondeará los números a mitad de camino al entero par más cercano (por ejemplo, round(2.5)
ahora devuelve 2 en lugar de 3.0).
Según la referencia en Wikipedia , esto también se conoce como redondeo imparcial , redondeo convergente , redondeo estadístico, redondeo holandés , redondeo gaussiano o redondeo impar .
La mitad del redondeo uniforme es parte del estándar IEEE 754 y también es el modo de redondeo predeterminado en .NET de Microsoft.
Esta estrategia de redondeo tiende a reducir el error de redondeo total. Como en promedio, la cantidad de números que se redondean es la misma que la cantidad de números que se redondean hacia abajo, los errores de redondeo se cancelan. En cambio, otros métodos de redondeo tienden a tener un sesgo hacia arriba o hacia abajo en el error promedio.
round () tipo de retorno
La función round()
devuelve un tipo float
en Python 2.7
round(4.8)
# 5.0
A partir de Python 3.0, si se omite el segundo argumento (número de dígitos), devuelve un int
.
round(4.8)
# 5
Verdadero, Falso y Ninguno
En Python 2, True
, False
y None
son constantes integradas. Lo que significa que es posible reasignarlos.
True, False = False, True
True # False
False # True
No puedes hacer esto con None
desde Python 2.4.
None = None # SyntaxError: cannot assign to None
En Python 3, True
, False
y None
ahora son palabras clave.
True, False = False, True # SyntaxError: can't assign to keyword
None = None # SyntaxError: can't assign to keyword
Devolver valor al escribir en un objeto de archivo
En Python 2, escribir directamente en un identificador de archivo devuelve None
:
hi = sys.stdout.write('hello world\n')
# Out: hello world
type(hi)
# Out: <type 'NoneType'>
En Python 3, escribir en un identificador devolverá el número de caracteres escritos al escribir texto, y el número de bytes escritos al escribir bytes:
import sys
char_count = sys.stdout.write('hello world 🐍\n')
# Out: hello world 🐍
char_count
# Out: 14
byte_count = sys.stdout.buffer.write(b'hello world \xf0\x9f\x90\x8d\n')
# Out: hello world 🐍
byte_count
# Out: 17
largo vs. int
En Python 2, cualquier entero mayor que un C ssize_t
se convertiría en el tipo de datos long
, indicado por un sufijo L
en el literal. Por ejemplo, en una compilación de Python de 32 bits:
>>> 2**31
2147483648L
>>> type(2**31)
<type 'long'>
>>> 2**30
1073741824
>>> type(2**30)
<type 'int'>
>>> 2**31 - 1 # 2**31 is long and long - int is long
2147483647L
Sin embargo, en Python 3, el tipo de datos long
fue eliminado; no importa qué tan grande sea el número entero, será un int
.
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>
Valor booleano de clase
En Python 2, si desea definir un valor booleano de clase por sí mismo, debe implementar el método __nonzero__
en su clase. El valor es True por defecto.
class MyClass:
def __nonzero__(self):
return False
my_instance = MyClass()
print bool(MyClass) # True
print bool(my_instance) # False
En Python 3, __bool__
se usa en lugar de __nonzero__
class MyClass:
def __bool__(self):
return False
my_instance = MyClass()
print(bool(MyClass)) # True
print(bool(my_instance)) # False