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:

Python 2.x 2.7
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:

Python 3.x 3.0
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

Python 2.x 2.7

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)
Python 3.x 3.0

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)
Python 3.x 3.3

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é'
Python 2.x 2.6

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'
Python 3.x 3.0

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:

Python 2.x 2.3
>>> 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:

Python 3.x 3.0
>>> 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 :

Python 2.x 2.3
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 :

Python 3.x 3.0
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:

Python 2.x 2.3
# 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 :

Python 3.x 3.0
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 :

Python 2.x 2.0
#forward-compatible
from builtins import range

for i in range(10**8):
    pass
Python 3.x 3.0
#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

Python 3.x 3.0

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
Python 3.x 3.5

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}
Python 2.x 2.0

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
Python 3.x 3.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.x 3.0

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 :

Python 2.x 2.3
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.x 3.0

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')
Python 2.x 2.0

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")
Python 3.x 3.3

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:

Python 2.x 2.3
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.

Python 3.x 3.0
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

Python 2.x 2.3

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)]
Python 3.x 3.0

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 ,

Python 2.x 2.3
user_input = raw_input()

Mientras que en Python 3, la entrada del usuario se acepta usando la función de input .

Python 3.x 3.0
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() y d.items() de Python 2 deben cambiarse a list(d.keys()) , list(d.values()) y list(d.items())
  • d.iterkeys() , d.itervalues() y d.iteritems() deben cambiarse a iter(d.keys()) , o incluso mejor, iter(d) ; iter(d.values()) e iter(d.items()) respectivamente
  • y, finalmente, las llamadas al método Python 2.7 d.viewkeys() , d.viewvalues() y d.viewitems() se pueden reemplazar por d.keys() , d.values() y d.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

Python 2.x 2.3
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars

a las formas

Python 3.x 3.0
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:

Python 3.x 3.0
class X: pass
class Y(object): pass

Ambas de estas clases ahora contienen object en su mro (orden de resolución de métodos):

Python 3.x 3.0
>>> 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:

Python 2.x 2.3
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 :

Python 2.x 2.3
>>> 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) .

Python 2.x 2.7
>>> 1 <> 2
True
>>> 1 <> 1
False
>>> foo = 'hello world'
>>> repr(foo)
"'hello world'"
>>> `foo`
"'hello world'"
Python 3.x 3.0
>>> 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

Python 2.x 2.7
"1deadbeef3".decode('hex')
# Out: '\x1d\xea\xdb\xee\xf3'
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Out: 1deadbeef3
Python 3.x 3.0
"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 funcionalidad cmp() , puede usar la expresión (a > b) - (a < b) como equivalente para cmp(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.

Python 2.x 2.3
x = 'hello world!'
vowels = [x for x in 'AEIOU'] 

print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'U'   
Python 3.x 3.0
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.

Python 2.x 2.3
>>> map(None, [0, 1, 2, 3, 0, 4])
[0, 1, 2, 3, 0, 4]
Python 3.x 3.0
>>> 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:

Python 2.x 2.3
>>> 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:

Python 3.x 3.0
>>> 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

Python 2.x 2.7

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)]
Python 3.x 3.0

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:

Python 2.x 2.7
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:

Python 3.x 3.0
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

Python 2.x 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 .

Python 3.x 3.0
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.

Python 2.x 2.0
True, False = False, True
True   # False
False  # True

No puedes hacer esto con None desde Python 2.4.

Python 2.x 2.4
None = None  # SyntaxError: cannot assign to None

En Python 3, True , False y None ahora son palabras clave.

Python 3.x 3.0
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 :

Python 2.x 2.3
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:

Python 3.x 3.0
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:

Python 2.x 2.7
>>> 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 .

Python 3.x 3.0
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>

Valor booleano de clase

Python 2.x 2.7

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
Python 3.x 3.0

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


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow