Nivel de dificultad:5 sobre 5
Han cambiado tantas cosas entre Python 2 y Python 3 que son pocos los programas que funcionan con ambos sin modificaciones. ¡Pero no te desalientes! Para ayudar con la transición, Python 3 incorpora una herramienta denominada 2to3, que analiza el código fuente en Python 2 y lo convierte en Python 3 tanto como puede. El capítulo 15, se describe como ejecutar 2to3, y muestra algunas cosas que este no puede resolver de forma automática. Este apéndice documenta aquello que sí puede convertir de forma automática.
En Python 2, print era una sentencia. Lo que quisieras imprimir iba detrás de ella. En Python 3, print() es una función. Lo quieras imprimir debe pasarse como parámetro, igual que en cualquier otra función.
Línea | Python 2 | Python 3 |
1 | print() | |
2 | print 1 | print(1) |
3 | print 1, 2 | print(1, 2) |
4 | print »sys.stderr, 1, 2, 3 | print(1, 2, 3, file=sys.stderr) |
Python 2 tiene dos tipos de cadenas de caracteres: Unicode y no Unicode. Python 3 solo tiene un tipo: Unicode.
Línea | Python 2 | Python 3 |
1 | u'PapayaWhip' | 'PapayaWhip' |
2 | ur'PapayaWhip\foo' | r'PapayaWhip\foo' |
Python 2 dispone de dos funciones globales para convertir objetos a cadenas de caracteres: unicode() para convertirlas en cadenas Unicode, y str() para convertirlas en cadenas no Unicode. Python 3 solamente tiene un tipo de cadenas de caracteres, Unicode, por lo que solamente existe la función str(). La función unicode() no existe.
Línea | Python 2 | Python 3 |
unicode(cualquier_objeto) | str(cualquier_objeto) |
Python 2 tiene dos tipos de datos para números enteros: int y long. Un int no puede ser mayor que sys.maxint, que es diferente según la plataforma. El tipo long se define añadiendo una 'L' al final del número, y puede ser, bueno, más grande que un int.
En Python 3, solamente existe un tipo de números enteros, denominado int, que se comporta como el tipo long de Python 2. Puesto que no existen dos tipos, no hay necesidad de una sintaxis especial para distinguirlos.
Para profundizar, se puede leer el documento PEP 237: unificando los enteros long e int.
Línea | Python 2 | Python 3 |
1 | x = 1000000000000L | x = 1000000000000 |
2 | x = 0xFFFFFFFFFFFFL | x = 0xFFFFFFFFFFFF |
3 | long(x) | int(x) |
4 | type(x) is long | type(x) is int |
5 | isinstance(x, long) | isinstance(x, int) |
Python 2 soporta <> como sinónimo de !=, el operador de comparación de desigualdad. Python 3 tiene este operador, pero <> deja de existir.
Línea | Python 2 | Python 3 |
1 | if x <> y: | if x != y: |
2 | if x <> y <> z: | if x != y != z: |
En Python 2, los diccionarios tienen un método has_key() para comprobar si el diccionario contiene una determinada clave. En Python 3, este método no existe. En su lugar, debes utilizar el operador in.
Línea | Python 2 | Python 3 |
1 | un_diccionario.has_key('PapayaWhip') | 'PapayaWhip' in un_diccionario |
2 | 10cmun_diccionario.has_key(x) or
un_diccionario.has_key(y) |
10cmx in un_diccionario or
y in un_diccionario |
3 | un_diccionario.has_key(x or y) | (x or y) in un_diccionario |
4 | un_diccionario.has_key(x + y) | (x + y) in un_diccionario |
5 | x + un_diccionario.has_key(y) | x + (y in un_diccionario) |
En Python 2, muchos métodos de diccionario devuelven listas. Los métodos más usados, como: keys(), items(), y values(). En Python 3, todos estos métodos devuelven vistas dinámicas. En algunos contextos, esto no es problema. Por ejemplo, si el valor de retorno de uno de estos métodos se pasa inmediatamente a otra función que itera a través de la secuencia completa, no hay diferencia visible si el tipo real es una lista o una vista. En otros contextos, sí tiene mucha importancia. Si estabas esperando una lista completa con elementos direccionables individualmente, el código fallará, ya que las vistas no soportan el indexado.
Línea | Python 2 | Python 3 |
1 | mi_diccionario.keys() | list(mi_diccionario.keys()) |
2 | mi_diccionario.items() | list(mi_diccionario.items()) |
3 | mi_diccionario.iterkeys() | iter(mi_diccionario.keys()) |
4 | [i for i in mi_diccionario.iterkeys()] | [i for i in mi_diccionario.keys()] |
5 | min(mi_diccionario.keys()) | no cambia |
Se han renombrado varios módulos de la Librería Estándar de Python. Otros relacionados se han combinado o reorganizado para darles una asociación más lógica.
En Python 3, se han combinado en un único paquete, http, varios módulos relacionados con HTTP.
Línea | Python 2 | Python 3 |
1 | import httplib | import http.client |
2 | import Cookie | import http.cookies |
3 | import cookielib | import http.cookiejar |
4 | 10cmimport BaseHTTPServer
import SimpleHTTPServer import CGIHttpServer |
import http.server |
Python 2 tiene un nido de ratas de módulos solapados para procesar, codificar y recuperar URLs. En Python 3, se han refactorizado y combinado en un único paquete, urllib.
Línea | Python 2 | Python 3 |
1 | import urllib | 10cm
import urllib.request, urllib.parse,
urllib.error |
2 | import urllib2 | import urllib.request, urllib.error |
3 | import urlparse | import urllib.parse |
4 | import robotparse | import urllib.robotparse |
5 | 10cmfrom urllib import FancyURLopener
from urllib import urlencode |
10cmfrom urllib.request
import FancyURLopener from urllib.parse urlencode |
6 | 10cmfrom urllib2 import Request
from urllib2 import HTTPError |
10cmfrom urllib.request import Request
from urllib.error HTTPError |
¿He mencionado que 2to3 reescribirá todas las llamadas a estas funciones? Por ejemplo, si tu código Python 2 importa el módulo urllib y llama a urllib.urlopen() para obtener datos, 2to3 arreglará arreglará ambas: la sentencia de importación y la llamada a la función.
Línea | Python 2 | Python 3 |
import urllib | 10cm
import urllib.request, urllib.parse,
urllib.error |
|
10cmprint urllib.urlopen(
'http://diveintopython3.org').read() |
10cmprint urllib.request.urlopen(
'http://diveintopython3.org').read() |
Los diversos clones de DBM se encuentran ahora en un único paquete, dbm. Si necesitas una variante específica, como GNU DBM, puedes importar el módulo apropiado de este paquete.
Línea | Python 2 | Python 3 |
import dbm | import dbm.ndbm | |
import gdbm | import dbm.gnu | |
import dbhash | import dbm.bsd | |
import dumbdbm | import dbm.dumb | |
10cmimport anydbm
import whichdb |
import dbm |
XML-RPC es un método ligero de hacer llamadas RPC sobre HTTP. La librería cliente XML-RPC y varias implementaciones de servidores XML-RPC se han combinado en un único paquete, xmlrpc.
Línea | Python 2 | Python 3 |
import xmlrpclib | import xmlrpc.client | |
10cmimport DocXMLRPCServer
import SimpleXMLRPCServer |
import xmlrpc.server |
Línea | Python 2 | Python 3 |
1 | try: | import io |
import cStringIO as StringIO | ||
except ImportError: | ||
import StringIO | ||
2 | try: | import pickle |
import cPickle as pickle | ||
except ImportError: | ||
import pickle | ||
3 | import __builtin__ | import builtins |
4 | import copy_reg | import copyreg |
5 | import Queue | import queue |
6 | import SocketServer | import socketserver |
7 | import ConfigParser | import configparser |
8 | import repr | import reprlib |
9 | import commands | import subprocess |
Un paquete es un grupo de módulos relacionados que funcionan como una única entidad. En Python 2, cuando los módulos de un paquete necesitaban referenciarse entre sí, podías utilizar import foo o from foo import Bar. El interprete de Python 2 primero buscaba en el paquete actual el fichero foo.py, y luego se movía a los demás directorios del camino de búsqueda (sys.path). Python 3 funciona diferente. En lugar de buscar en el paquete actual, va directamente al camino de búsqueda. Si quieres que un módulo de un paquete importe a otro módulo en el mismo paquete, necesitas proporcionar explícitamente el camino relativo entre estos dos módulos.
Supón que tenías el siguiente paquete con múltiples ficheros en el mismo directorio:
chardet/
|
+-__init__.py
|
+-constants.py
|
+-mbcharsetprober.py
|
+-universaldetector.py
Ahora supón que el fichero universaldetector.py necesita importar el contenido completo del fichero constants.py y una clase del fichero mbcharsetprober.py. ¿Cómo lo harías?
Línea | Python 2 | Python 3 |
1 | import constants | from . import constants |
2 | 10cmfrom mbcharsetprober import
MultiByteCharSetProber |
10cmfrom .mbcharsetprober import
MultiByteCharsetProber |
En Python 2, los iteradores tienen el método next() que devuelve el siguiente elemento de la secuencia. Esto sigue siendo cierto en Python 3, pero ahora hay también una función global next() que toma un iterador como parámetro.
Línea | Python 2 | Python 3 |
1 | unIterador.next() | next(unIterador) |
2 | función_q_retorna_iterador().next() | next(función_q_retorna_iterador()) |
3 | class A: | class A: |
def next(self): | def __next__(self): | |
pass | pass | |
4 | class A: | |
def next(self, x, y): | no cambia | |
pass |
En Python 2, la función filter() devolvía una lista, el resultado de filtrar una secuencia a través de una función que devolviera True o False para cada elemento de la secuencia. En Python 3, la función filter() devuelve un iterador, no una lista.
Línea | Python 2 | Python 3 |
1 | filter(función, secuencia) | list(filter(función, secuencia)) |
2 | list(filter(función, secuencia)) | no cambia |
3 | filter(None, secuencia) | [i for i in secuencia if i] |
4 | for i in filter(None, secuencia): | no cambia |
5 | [i for i in filter(función, secuencia)] | no cambia |
De forma parecida a como se comporta filter(), la función map() ahora devuelve un iterador (En Python 2, devolvía una lista).
Línea | Python 2 | Python 3 |
1 | map(función, 'PapayaWhip') | list(map(función, 'PapayaWhip')) |
2 | map(None, 'PapayaWhip') | list('PapayaWhip') |
2 | map(lambda x: x+1, range(42)) | [x+1 for x in range(42)] |
4 | for i in map(None, secuencia): | no cambia |
5 | [i for i in map(función, secuencia)] | no cambia |
En Python 3, se ha suprimido la función reduce() del espacio de nombres global, y se ha colocado en el módulo functools.
Línea | Python 2 | Python 3 |
reduce(a, b, c) | from functools import reduce | |
reduce(a, b, c) |
Python 2 tiene una función global denominada apply(), que toma una función f y una lista [a, b, c] y devuelve f(a, b, c). Puedes conseguir el mismo resultado mediante la llamada directa a la función pasándole la lista de parámetros precedida de un asterisco. En Python 3, la función apply() ha dejado de existir; debes usar obligatoriamente la notación asterisco.
Línea | Python 2 | Python 3 |
1 | apply(funcion, listaParametros) | funcion(*listaParametros) |
2 | apply(funcion, listaParametros, | funcion(*listaParametros, |
dicParamNombre) | **dicParamNombre) | |
3 | apply(funcion, listaParametros + z) | funcion(listaParametros + z) |
4 | apply(modulo.funcion, listaParam) | modulo.funcion(listaParam) |
En Python 2, se puede llamar a la función intern() sobre una cadena de caracteres para internalizarla con el fin de optimizar su rendimiento. En Python 3, la función intern() se ha movido al módulo sys.
Línea | Python 2 | Python 3 |
intern(a, b, c) | sys.intern(a, b, c) |
Igual que se ha convertido la sentencia print en función en Python 3, se ha hecho lo mismo con la sentencia exec. La función exec() toma una cadena de caracteres que contiene cualquier código Python y lo ejecuta como si fuese una sentencia o expresión. exec() es como eval(), pero aún más poderoso y maligno. La función eval() solo puede evaluar una única expresión, pero exec() puede ejecutar múltiples sentencias, importar paquetes, declarar funciones --esencialmente, ejecutar un programa Python entero, escrito en una cadena de caracteres.
Línea | Python 2 | Python 3 |
1 | exec cadenaEjecutable | exec(cadenaEjecutable) |
2 | exec cadenaEjec in espNombresGlobal | exec(cadenaEjec, espNombresGlobal) |
3 | exec cadenaEjec in espNombresGlobal, | exec(cadenaEjec, espNombresGlobal, |
espacioNombresLocal | espacioNombresLocal) |
Como la anterior sentencia exec, la sentencia execfile sirve ejecuta el código escrito, esta vez, en un fichero. En Python 3 esta sentencia se ha eliminado. Si realmente necesitas leer un fichero Python y ejecutarlo (pero no deseas, simplemente, importarlo), puedes conseguirlo abriendo el fichero, leyendo su contenido, llamando a la función global compile() para forzar al interprete de Python a compilar el código, y luego llamar a la nueva función exec().
Línea | Python 2 | Python 3 |
execfile('nombre_fichero') | exec(compile(open('nombre_fichero').read(), | |
'nombre_fichero2', 'exec')) |
En Python 2, existe una sintaxis especial para envolver cualquier objeto en comillas invertidas (como `x`) para obtener una representación del objeto. En Python 3, no puedes utilizarlas; en su lugar, debes usar la función global repr().
Línea | Python 2 | Python 3 |
1 | `x` | repr(x) |
2 | `'PapayaWhip' + `2`` | repr('PapayaWhip' + repr(2)) |
La sintaxis para capturar excepciones ha cambiado algo entre Python 2 y 3.
Línea | Python 2 | Python 3 |
1 | try: | try: |
import mymodule | import mymodule | |
except ImportError, e | except ImportError as e: | |
pass | pass | |
2 | try: | try: |
import mymodule | import mymodule | |
except (RuntimeError, | except (RuntimeError | |
ImportError), e | ImportError) as e: | |
pass | pass | |
3 | try: | |
import mymodule | no cambia | |
except ImportError: | ||
pass | ||
4 | try: | |
import mymodule | no cambia | |
except: | ||
pass |
Nunca deberías utilizar la captura por defecto de todos los tipos de excepción cuando importes módulos (o en la mayoría de otras ocasiones). Al hacer esto, capturarás cosas como KeyboardInterrupt (que se dispara si el usuario pulsa Ctrl-C para interrumpir el programa) y que puede hacer más difícil depurar los errores.
La sintaxis para elevar tus propias excepciones ha cambiado también ligeramente.
Línea | Python 2 | Python 3 |
1 | raise miExcepcion | no cambia |
2 | raise miExcepcion, 'mensaje de error' | raise miExcepcion('mensaje de error') |
3 | raise miExcepcion, 'mensaje de error', | raise miExcepcion('mensaje de error'). |
traza) | with_traceback(traza) | |
4 | raise 'mensaje de error' | no soportado |
En Python 2, los generadores disponen de un método throw(): al llamar a este método se eleva una excepción en el punto en el que el generador estuviera pausado, luego se devuelve el siguiente valor disponible (en yield). En Python 3, esta funcionalidad sigue existiendo con pequeños cambios.
Línea | Python 2 | Python 3 |
1 | unGenerador.throw(miExcepcion) | no cambia |
2 | unGenerador.throw(miExcepcion, | unGenerador.throw( |
'mensaje de error') | miExcepcion('mensaje de error')) | |
3 | unGenerador.throw('mensaje de error') | no soportado |
En Python 2, había dos formas de obtener un rango de números: range(), que retornaba una lista; y xrange(), que retornaba un iterador. En Python 3, range() retorna un iterador, y xrange() no existe.
Línea | Python 2 | Python 3 |
1 | xrange(10) | range(10) |
2 | lista = range(10) | lista = list(range(10)) |
3 | [i for i in xrange(10)] | [i for i in range(10)] |
4 | for i in range(10): | no cambia |
5 | sum(range(10)) | no cambia |
Python 2 tiene dos funciones globales para pedir al usuario que introduzca datos en la línea de comandos. La primera se denomina input(), y espera que el usuario introduzca una expresión Python (y devuelve el resultado). La segunda, denominada raw_input(), simplemente retorna lo que el usuario ha tecleado. Esto es confuso para principiantes. Python 3 redenomina raw_input() a input(), para que funcione como todo el mundo imagina que debería.
Línea | Python 2 | Python 3 |
1 | raw_input() | input() |
2 | raw_input('prompt:') | input('prompt:') |
3 | input() | eval(input()) |
En Python 2, el código dentro de las funcionas puede acceder a atributos de la propia función. En Python 3, estos atributos especiales se han redenominado por consistencia con otros atributos.
Línea | Python 2 | Python 3 |
1 | unaFuncion.func_name | unaFuncion.__name__ |
2 | unaFuncion.func_doc | unaFuncion.__doc__ |
3 | unaFuncion.func_defaults | unaFuncion.__defaults__ |
4 | unaFuncion.func_dict | unaFuncion.__dict__ |
5 | unaFuncion.func_closure | unaFuncion.__closure__ |
6 | unaFuncion.func_globals | unaFuncion.__globals__ |
7 | unaFuncion.func_code | unaFuncion.__code__ |
En Python 2, los objetos fichero tenían un método xreadlines() que devolvía un iterador que leía una línea cada vez. Era útil en bucles for, entre otros lugares. En realidad, era tan útil, que posteriores versiones añadieron esta capacidad de forma nativa a los propios objetos fichero.
En Python 3, la función xreadlines() ya no existe. 2to3 puede arreglar los casos más simples, pero otros requieren de intervención manual.
Línea | Python 2 | Python 3 |
1 | for linea in fich.xreadlines(): | for linea in fich: |
2 | for linea in fich.xreadlines(5): | no cambia (roto) |
En Python 2, podías definir una función lambda anónima que tomara varios parámetros definiendo la función para que recibiera una tupla con un número específico de elementos. Python 2 ``desempaqueta'' la tupla en los parámetros con nombre, que luego puedes referenciar (por nombre) en la propia función lambda. En Python 3, aún puedes pasar una tupla a una función lambda, pero el interprete de Python no desempaquetará los parámetros. En su lugar, necesitas referenciar cada uno de ellos mediante su posición en la tupla.
Línea | Python 2 | Python 3 |
1 | lambda (x,): x + f(x) | lambda x1: x1[0] + f(x1[0]) |
2 | lambda (x, y): x + f(y) | lambda x_y: x_y[0] + f(x_y[1]) |
3 | lambda (x, (y,z)): x + y + z | lambda x_y_z: x_y_z[0] + |
x_y_z[1][0] + x_y_z[1][1] | ||
4 | lambda x, y, z: x + y + z | no cambia |
En Python 2, los métodos de las clases pueden referenciar al objeto clase en el que están definidos, así como el objeto método en sí mismo. im_self es el objeto instancia de la clase; im_func es el objeto función (el propio método); im_class es la clase de im_self. En Python 3, estos atributos especiales de método se han redenominado para seguir las convenciones de otros atributos.
Python 2 | Python 3 |
instDeClase.MétDeClase.im_func | instDeClase.MétDeClase.__func__ |
---|---|
instDeClase.MétDeClase.im_self | instDeClase.MétDeClase.__self__ |
instDeClase.MétDeClase.im_class | instDeClase.MétDeClase.__self__.__class__ |
En Python 2, podrías construir tus propias clases que podían utilizarse en contextos booleanos. Por ejemplo, podrías instanciar un objeto de la clase y luego usar esta instancia como condición en una sentencia if. Para hacer esto debías definir un método especial __nonzero__() que debía devolver True o False, y que Python llamaba siempre que un objeto se utilizara en un contexto booleano. En Python 3, se ha cambiado el nombre del método a __bool__().
Línea | Python 2 | Python 3 |
1 | class A: | class A: |
def __nonzero__(self): | def __bool__(self): | |
pass | pass | |
2 | class A: | |
def __nonzero__(self, x, y): | no cambia | |
pass |
Ha cambiado ligeramente:
Línea | Python 2 | Python 3 |
x = 0755 | x = 0o755 |
Debido a que los tipos long e int se integran en uno solo, la constante sys.maxint deja de ser precisa. Por ello se ha redenominado a sys.maxsize.
Línea | Python 2 | Python 3 |
1 | from sys import maxint | from sys import maxsize |
2 | unaFunción(sys.maxint) | unaFunción(sys.maxsize) |
En Python 2, podías comprobar con la función callable() si un objeto se podía ``llamar'' (como una función). En Python 3, esta función global se ha eliminado. Para comprobar si un objeto se puede llamar hay que comprobar la existencia del método especial __call__().
Línea | Python 2 | Python 3 |
1 | callable(cualquierObjeto) | hasattr(cualquierObjeto, '__call__') |
En Python 2, la función global zip() tomaba cualquier número de secuencias y devolvía una lista de tuplas. La primera tupla contenía el primer elemento de cada una de las secuencias que había recibido como parámetros; la segunda tupla, los segundos elementos de cada secuencia, y así sucesivamente. En Python 3, zip() devuelve un iterador en lugar de una lista.
Línea | Python 2 | Python 3 |
1 | zip(a, b, c) | list(zip(a, b, c)) |
2 | d.join(zip(a, b, c)) | no cambia |
En Python 2, StandardError era la clase base de todas las excepciones internas salvo StopIteration, GeneratorExit, KeyboardInterrupt, y SystemExit. En Python 3, StandardError ha sido eliminada; en su lugar se debe usar Exception.
Línea | Python 2 | Python 3 |
x = StandardError() | x = Exception() | |
x = StandardError(a, b, c) | x = Exception(a, b, c) |
El módulo types contiene una variedad de constantes destinadas a ayudar a encontrar el tipo de un objeto. En Python 2, contenía constantes para todos los tipos primitivos como dict e int. En Python 3, se han eliminado estas constantes; basta con usar el propio nombre de los tipos.
Línea | Python 2 | Python 3 |
types.UnicodeType | str | |
types.StringType | bytes | |
types.DictType | dict | |
types.IntType | int | |
types.LongType | int | |
types.ListType | list | |
types.NoneType | type(None) | |
types.BooleanType | bool | |
types.BufferType | memoryview | |
types.ClassType | type | |
types.ComplexType | complex | |
types.EllipsisType | type(Ellipsis) | |
types.FloatType | float | |
types.ObjectType | object | |
types.NotImplementedType | type(NotImplemented) | |
types.SliceType | slice | |
types.TupleType | tuple | |
types.TypeType | type | |
types.XRangeType | range |
types.StringType se mapea a bytes en lugar de a str porque en Python 2 ``string'' (no Unicode) realmente es una secuencia de bytes en una codificación de caracteres determinada.
La función insinstance() comprueba si un objeto es una instancia de una clase o tipo particular. En Python 2, puedes pasar una tupla de tipos: isinstance() devolverá True si el objeto es de alguno de los tipos de la tupla. En Python 3, aún puedes hacerlo, pero pasar el mismo tipo dos veces está deprecado.
Línea | Python 2 | Python 3 |
isinstance(x (int, float, int)) | isinstance(x, (int, float)) |
Python 2 tenía dos tipos de cadenas de caracteres: Unicode y no Unicode. Pero había también otro tipo: basestring. Era un tipo de datos abstracto, una superclase para ambos tipos: str y unicode. No se podía instanciar directamente, pero sí se podía pasar a la función global isinstance(). En Python 3, solamente existe un tipo de datos de cadenas de caracteres, por lo que basestring no tiene razón de existir.
Línea | Python 2 | Python 3 |
isinstance(x, basestring) | isinstance(x, str) |
Python 2.3 introdujo el módulo itertools, que definía variantes de las funciones zip(), map(), y filter() que devolvían iteradores en lugar de listas. En Python 3, las funciones originales ya devuelven iteradores, por lo que estas funciones se han eliminado del módulo.
Línea | Python 2 | Python 3 |
1 | itertools.izip(a, b) | zip(a, b) |
2 | itertools.imap(a, b) | map(a, b) |
3 | itertools.ifilter(a, b) | filter(a, b) |
4 | from itertools import imap, izip, foo | from itertools import foo |
Python 2 tiene tres variables en el módulo sys que puedes acceder mientras se está manejando una excepción: sys.exc_type, sys.exc_value, sys.exc_traceback (En realidad, se remontan a Python 1). Estas variables están deprecadas desde Python 1.5, en favor del uso de sys.exc_info(), que es una función que retorna una tupla que contiene los tres valores. En Python 3, estas variables individuales por fin desaparecen; debes usar obligatoriamente la función.
Línea | Python 2 | Python 3 |
sys.exc_type | sys.exc_info()[0] | |
sys.exc_value | sys.exc_info()[1] | |
sys.exc_traceback | sys.exc_info()[2] |
En Python 2, si quieres codificar una lista por comprensión que a partir de una tupla, no necesitas poner paréntesis sobre los valores de la tupla. En Python 3, es necesario explicitarlos.
Línea | Python 2 | Python 3 |
[i for i in 1, 2] | [i for i in (1, 2)] |
Python 2 tiene una función denominada os.getcwd(), que devuelve el directorio de trabajo actual como una cadena de caracteres (no Unicode). Puesto que los sistemas de ficheros modernos pueden manejar nombres en cualquier codificación de caracteres, Python 2.3 introdujo la función os.getcwdu() que devuelve el directorio de trabajo actual codificado en una cadena de caracteres Unicode. En Python 3, solamente existe un tipo de cadena de caracteres (es Unicode), por eso solamente existe os.getcwd().
Línea | Python 2 | Python 3 |
os.getcwdu() | os.getcwd() |
En Python 2, podías crear metaclases, bien definiendo el parámetros metaclass en la declaración de la clase, o bien, definiendo un atributo especial de clase __metaclass__. En Python 3, el atributo de clase ha sido eliminado.
Línea | Python 2 | Python 3 |
1 | class C(metaclass=PapayaMeta): | no cambia |
pass | ||
2 | class Whip: | class Whip(metaclass=PapayaMeta): |
__metaclass__ | pass | |
3 | class C(Whipper, Beater): | class C(Whipper, Beater, |
__metaclass__ = PapayaMeta | metaclass=PapayaMeta): | |
pass |
El resto de los ``arreglos'' listados aquí, realmente no lo son. Son cosas que 2to3 cambia como mejora de estilo. Funcionan igual ambas soluciones tanto en Python 2 como en Python 3, pero los desarrolladores tienen interés en que el código fuente de Python sea lo más homogéneo posible en cuanto a estilo. Por ello, existe una
hrefhttp://www.python.org/dev/peps/pep-0008/Guía oficial de estilo de Python que describe --con todo lujo de detalles-- toda clase de reglas de escritura que, seguramente, no te interesan.
En Python 2, la única forma de definir un conjunto con literales en el código es llamar a set(unaSecuencia). Esto sigue funcionando en Python 3, pero una forma más clara de hacerlo es utilizar la nueva notación de literal de conjuntos: las llaves. Esto sirve para todos los conjuntos, excepto para los vacíos, ya que los diccionarios también utilizan las llaves, y {} es el conjunto vacío.
2to3, por defecto, no arregla literales set(). Para activar esta modificación, debes especificar -f set_literal en la línea de comando de 2to3.
Línea | Python 2 | Python 3 |
set([1, 2, 3]) | {1, 2, 3} | |
set((1, 2, 3)) | {1, 2, 3} | |
[i for i in unaSecuencia] | {i for in in unaSecuencia} |
Los objetos Python implementados en C pueden exportar un ``interfaz de buffer'', que permite al código Python leer y escribir directamente en los bloques de memoria del objeto. En Python 3, buffer() se ha redenominado a memoryview() (Es más complicado que esto, pero puedes ignorar las diferencias).
Para que 2to3 aplique este cambio hay que especificar el parámetro -f buffer en la línea de comando.
Línea | Python 2 | Python 3 |
x = buffer(y) | x = memoryview(y) |