Indice

Porting da Python 2 a Python 3

Differenze con impatto maggiore

Python nell'evoluzione dalla versione 2 alla versione 3 ha radicalmente cambiato molte parti del linguaggio.
Fra le modifiche con un impatto piú rilevante troviamo:

  • la scrittura su console print
  • Sollevare e Gestire eccezioni
  • la divisione intera
  • Unicode
  • xrange

Nelle seguenti sezioni vedremo come scrivere codice che sia compatibile su entrambe le versioni.

print

Print è ora una funzione e per tanto vuole le parentesi tonde.

# python 2.x
print "Ciao"
 
# python 3.x
print("Ciao")

Per una semplice print, potete mettere le parentesi anche su Python 2 ed il risultato sarà identico.
Varia invece se usate una print con parti concatenate da virgola

# python 2.x
print "Ciao", " Come stati?"
>> Ciao Come stai?
 
# python 3.x
print ("Ciao", " Come stati?")
>> Ciao Come stai?

In questo caso, aggingendo le parentesi se python 2 otteniamo un risultato che è quello desiderato

# python 2.x
print ("Ciao", " Come stati?")
>> ("Ciao", "Come stai?")

Per ovviare a questo spiacevole risultato, ci viene in aiuto il modulo __future__

# python 2.x
from __future__ import print_function
 
print ("Ciao", " Come stati?")
>> Ciao Come stai?

Divisione Intera

Questa modifica è particolarmente pericolosa poiché può spesso passare inosservata (non genera un SyntaxError). Quindi si consiglia l'importazione del modulo __future__ in tutti gli script Python 2 ove sia prevista una divisione).

Python 2

print 'Python', python_version()
print '3 / 2 =', 3 / 2
print '3 // 2 =', 3 // 2
print '3 / 2.0 =', 3 / 2.0
print '3 // 2.0 =', 3 // 2.0
>> Python 2.7.6
3 / 2 = 1
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0

Python 3

print('Python', python_version())
print('3 / 2 =', 3 / 2)
print('3 // 2 =', 3 // 2)
print('3 / 2.0 =', 3 / 2.0)
print('3 // 2.0 =', 3 // 2.0)
>> Python 3.4.1
3 / 2 = 1.5
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0

Python 2 e 3

# Python 2 and 3
from __future__ import division
 
assert 3 / 2 == 1.5

Long integers

In Python 3, il tipo int corrisponde come implementazione al vecchio tipo long, quindi int e long diventano equivalenti.

Python 2

bigint = 1L
 
if isinstance(bigint, (int, long)):
    ...    

Python 3

bigint = 1
 
if isinstance(bigint, int):
    ...    

Python 2 e 3

ATTENZIONE: A Python 3 da fastidio la 'L' quindi in Python 2 sarà necessario modificare il codice come mostrato di seguito.

from builtins import int
bigint = int(1)
 
if isinstance(bigint, int):             # matches both int and long on Py2
    ...

Octal constants

0644     # Python 2 only
0o644    # Python 2 and 3

Backtick repr

`x`      # Python 2 only
 
repr(x)  # Python 2 and 3

Unicode (text) string literals e Byte-string literals

In Python 2 esistono due diversi tipi stringa:

  • ASCII str()
  • UNICODE unicode()

Ma non esiste la stringa di byte.
Ora, in Python 3, tutte le stringhe sono Unicode (utf-8), in aggiunta abbiamo due nuove classi: byte e bytearrays.

Python 2

print 'Python', python_version()
 
>> Python 2.7.6
 
print type(unicode('Questa è come una stringa di Python3'))
 
>> <type 'unicode'>
 
print type(b'il tipo byte non esiste')
 
>> <type 'str'>
 
print 'Queste due stringe sono' + b' dello stesso tipo'
 
>> Queste due stringe sono dello stesso tipo
 
print type(bytearray(b'Stranamente però esiste il bytearray'))
 
>> <type 'bytearray'>

Python 3

print('Python', python_version())
print('ora le stringhe sono utf-8 \u03BCnico\u0394é!')
 
>> Python 3.7.3
   strings are now utf-8 μnicoΔé!
 
print('Python', python_version(), end="")
print(' ha', type(b' il tipo bytes'))
 
>> Python 3.7.3 ha <class 'bytes'>
 
print('e Python', python_version(), end="")
print(' ha anche ', type(bytearray(b'bytearrays')))
 
>> e Python 3.7.3 ha anche <class 'bytearray'>
 
'Ora cercare di sommare una stringa' + b' ed un bytes provoca errore.'
 
>> Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    'Ora cercare di sommare una stringa' + b' ed un bytes provoca errore.'
TypeError: can only concatenate str (not "bytes") to str

Python 2 e 3

# Byte-String
# Python 2 and 3: byte-strings as strings.
from builtins import str
a = u'abc'
b = b'def'
c = b.decode()
assert isinstance(a, str) and isinstance(c, str)
# ...
 
# Unicode: Alternative 1
# Python 2 and 3
s1 = u'The Zen of Python'
s2 = u'きたないのよりきれいな方がいい\n'
 
# Unicode: Alternative 2
# Python 2 and 3
from __future__ import unicode_literals    # rende tutte le stringhe unicode
 
s1 = 'The Zen of Python'
s2 = 'きたないのよりきれいな方がいい\n'

xrange

Poichè xrange() è generalmente più veloce di range(), in Python 3 range() è implementata come xrange() mentre quest'ultima è stata rimossa.
Questo lo rende efficientissimo su iterazioni 1-time, mentre su iterazioni multiple perde un po' di efficienza perchè, ogni volta, la generazione viene rifatta da zero.
In Python 3, la chiamata alla funzione xrange() genera un NameError.

Sollevare Eccezioni

Mentre Python 2 accetta sia la sintassi “vecchia” che la “nuova”, Python 3 genera un SyntaxError se non l'argomento non viene messo tra parentesi.

Python 2

raise IOError, "file error"
 
>> Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    raise IOError, "file Error"
IOError: file Error
 
raise IOError("file error")
 
>> Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    raise IOError("file Error")
IOError: file Error

Python 3

raise IOError, "file error"
 
>> SyntaxError: invalid syntax
 
raise IOError("file error")
 
>> Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    raise IOError("file error")
OSError: file error

Python 2 e 3

Poichè Python 2 supporta la sintassi con le parentesi è buona cosa scrivere le raise con tale sintassi anche in Python 2.

Sollevare Eccezioni (TraceBack)

Python 2

traceback = sys.exc_info()[2]
raise ValueError, "dodgy value", traceback

Python 3

raise ValueError("dodgy value").with_traceback()

Python 2 e 3

# Python 2 e 3: Alternativa 1
from future.utils import raise_
 
traceback = sys.exc_info()[2]
raise_(ValueError, "dodgy value", traceback)
 
#...
#...
 
# Python 2 e 3: Alternativa 2
from future.utils import raise_with_traceback
 
raise_with_traceback(ValueError("dodgy value"))

Gestire Eccezioni

In Python 3 ora è obbligatoria la keyword as.

Python 2

try:
    ...
except ValueError, e:
    ...

Python 3

try:
    ...
except ValueError as e:
    ...

Python 2 e 3

Python 2 supporta la sintassi di Python 3.

try:
    ...
except ValueError as e:
    ...

La funzione next() ed il metodo .next()

Mentre in Python 2.7 per ottenere l'elemento successivo di un generatore è possibile usare sia la funzione next() che il metodo .next(), il Python 3 è presente solo la funzione ed un eventuale chiamata al metodo genera un'eccezione di tipo AttributeError.

Python 2

my_generator = (letter for letter in 'abcdefg')
 
next(my_generator)
>> 'a'
 
my_generator.next()
>> 'b'

Python 3

my_generator = (letter for letter in 'abcdefg')
 
next(my_generator)
>> 'a'
 
my_generator.next()
>> Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    my_generator.next()
AttributeError: 'generator' object has no attribute 'next'

Python 2 e 3

La soluzione è utilizzare sempre la funzione next().

Variabili For-loop e perdita del namespace globale

In Python 3 non avviene più la perdita del namespace globale.

Python 2

i = 1
print 'before: i =', i
 
>> before: i = 1
 
print 'comprehension: ', [i for i in range(5)]
 
>> comprehension:  [0, 1, 2, 3, 4]
 
print 'after: i =', i
 
>> after: i = 4

Python 3

i = 1
print('before: i =', i)
 
>> before: i = 1
 
print('comprehension:', [i for i in range(5)])
 
>> comprehension:  [0, 1, 2, 3, 4]
 
print('after: i =', i)
 
>> after: i = 1

Comparazione fra tipi unorderable

InPython 3 il tentativo di comparare due entità non ordinabili restituisce un TypeError.

Python 2

print "[1, 2] > 'foo' = ", [1, 2] > 'foo'
 
>> [1, 2] > 'foo' =  False
 
print "(1, 2) > 'foo' = ", (1, 2) > 'foo'
 
>> (1, 2) > 'foo' =  True
 
print "[1, 2] > (1, 2) = ", [1, 2] > (1, 2)
 
>> [1, 2] > (1, 2) =  False

Python 3

print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
 
>> Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
TypeError: '>' not supported between instances of 'list' and 'str'
 
print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
 
>> Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
TypeError: '>' not supported between instances of 'tuple' and 'str'
 
print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))
 
>> Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))
TypeError: '>' not supported between instances of 'list' and 'tuple'

Analisi degli input dell'utente tramite input()

In Python 2 la funzione input() cercava di determinare il tipo dell'input inserito (a volte causando problemi perchè gestiva la stringa di input come se fosse codice Python).
In Python 3 questo comportamento è stato corretto ed ora input() restituisce sempre una stringa.
Per lo stesso comportamento in Python 2 è necessario chiamare la funzione raw_input().

Python 2

my_input = input('enter a number: ')
 
>> enter a number: 123
 
type(my_input)
 
>> <type 'int'>
 
my_input = raw_input('enter a number: ')
 
>> enter a number: 123
 
type(my_input)
>> <type 'str'>

Python 3

my_input = input('enter a number: ')
 
>> enter a number: 123
 
type(my_input)
>> <class 'str'>

Restituire Oggetti Iterabili al posto si Liste

Come abbiamo già visto nella sezione xrange, alcune funzioni e metodi restituiscono oggetti iterabili in Python 3, anziché liste come in Python 2.
Poichè solitamente vengono ciclati una sola volta, questo cambiamento consente di salvare memoria.
Tuttavia, con una perdita di efficienza, è anche possibile, a differenza dei generatori, scorrere più volte se necessario.
E per quei casi in cui abbiamo davvero bisogno degli oggetti list, possiamo semplicemente convertire l'oggetto iterabile in una lista tramite la funzione list().

Python 2

print range(3)
 
>> [0, 1, 2]
 
print type(range(3))
 
>> <type 'list'>

Python 3

print(range(3))
 
>> range(0, 3)
 
print(type(range(3)))
 
>> <class 'range'>
 
print(list(range(3)))
 
>> [0, 1, 2]

Funzioni e metodi comunemente usati che non restituiscono più elenchi in Python 3:

  • zip()
  • map()
  • filter()
  • Metodo .keys() dei dizionari
  • Metodo .values() dei dizionari
  • Metodo .items() dei dizionari

Variazione del comportamento della funzione Round

Python 3 ha adottato il modo ormai standard di arrotondare i decimali quando si ottiene un pareggio (.5) alle ultime cifre significative.
Ora, in Python 3, i decimali vengono arrotondati al numero pari più vicino.
Purtroppo questo comportamento non è workaround-abile … il che significa che bisogna tenerne conto.

Python 2

round(15.5)
 
>> 16.0
 
round(16.5)
 
>> 17.0

Python 3

round(15.5)
 
>> 16
 
round(16.5)
 
>> 16

Custom class behaviour

Dictionaries

heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}

Scorrere le chiavi / i valori / gli elementi di un dizionario

Le chiavi

Python 2
for key in heights.iterkeys():
    ...
Python 2 e 3
for key in heights:
    ...

I Valori

Python 2
for value in heights.itervalues():
    ...
Python 2 e 3
#Opzione 0: Sconsigliata
for value in heights.values():    # Maggiore consumo di memoria in Py2
    ...
# Opzione 1
from builtins import dict
 
heights = dict(Fred=175, Anne=166, Joe=192)
for key in heights.values():    # efficiente in Py2 e Py3
# Opzione 2
from builtins import itervalues
 
for key in itervalues(heights):
    ...

Gli Elementi

Python 2
for (key, value) in heights.iteritems():
    ...
Python 2 e 3
# Opzione 1
for (key, value) in heights.items():    # inefficiente in Py2
    ...
# Opzione 2
from future.utils import viewitems
 
for (key, value) in viewitems(heights):   # si compporta come un set
    ...
# Opzione 3
from future.utils import iteritems
 
for (key, value) in iteritems(heights):
    ...

Chiavi/Valori/Elementi di un Dizionario come Lista

Chiavi

Python 2
keylist = heights.keys()
assert isinstance(keylist, list)
Python 2 e 3
keylist = list(heights)
assert isinstance(keylist, list)

Valori

Python 2
heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}
valuelist = heights.values()
assert isinstance(valuelist, list)
Python 2 e 3
# Opzione 1
valuelist = list(heights.values())    # inefficiente in Py2
# Opzione 2
from builtins import dict
 
heights = dict(Fred=175, Anne=166, Joe=192)
valuelist = list(heights.values())
# Opzione 3
from future.utils import listvalues
 
valuelist = listvalues(heights)
# Opzione 4
from future.utils import itervalues
 
valuelist = list(itervalues(heights))

Elementi

Python 2 e 3
# Opzione 1
itemlist = list(heights.items())    # inefficiente in Py2
# Opzione 2
from future.utils import listitems
 
itemlist = listitems(heights)
# Opzione 3
from future.utils import iteritems
 
itemlist = list(iteritems(heights))

Imports relativi ad un package

supponiamo che il package abbia struttura:

mypackage/
    __init__.py
    submodule1.py
    submodule2.py

dove il modulo submodule1.py contenga il seguente codice:

# Python 2 only:
import submodule2
 
# Python 2 and 3:
from . import submodule2
 
# Python 2 and 3:
# To make Py2 code safer (more like Py3) by preventing
# implicit relative imports, you can also add this to the top:
from __future__ import absolute_import

Altre variazioni ai builtins

File IO con open()

# Python 2 only
f = open('myfile.txt')
data = f.read()              # as a byte string
text = data.decode('utf-8')
 
# Python 2 and 3: alternative 1
from io import open
f = open('myfile.txt', 'rb')
data = f.read()              # as bytes
text = data.decode('utf-8')  # unicode, not bytes
 
# Python 2 and 3: alternative 2
from io import open
f = open('myfile.txt', encoding='utf-8')
text = f.read()    # unicode, not bytes

reduce()

# Python 2 only:
assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5
 
 
# Python 2 and 3:
from functools import reduce
 
assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5

file()

# Python 2 only:
f = file(pathname)
# Python 2 and 3:
f = open(pathname)
 
# But preferably, use this:
from io import open
f = open(pathname, 'rb')   # if f.read() should return bytes
# or
f = open(pathname, 'rt')   # if f.read() should return unicode text

exec

# Python 2 only:
exec 'x = 10'
 
# Python 2 and 3:
exec('x = 10')
# Python 2 only:
g = globals()
exec 'x = 10' in g
 
# Python 2 and 3:
g = globals()
exec('x = 10', g)
# Python 2 only:
l = locals()
exec 'x = 10' in g, l
 
# Python 2 and 3:
exec('x = 10', g, l)

execfile()

# Python 2 only:
execfile('myfile.py')
 
 
# Python 2 and 3: alternative 1
from past.builtins import execfile
 
execfile('myfile.py')
 
 
# Python 2 and 3: alternative 2
exec(compile(open('myfile.py').read()))
 
 
# This can sometimes cause this:
#     SyntaxError: function ... uses import * and bare exec ...
# See https://github.com/PythonCharmers/python-future/issues/37

unichr()

# Python 2 only:
assert unichr(8364) == '€'
 
# Python 3 only:
assert chr(8364) == '€'
 
# Python 2 and 3:
from builtins import chr
assert chr(8364) == '€'

intern()

# Python 2 only:
intern('mystring')
 
 
# Python 3 only:
from sys import intern
intern('mystring')
 
 
# Python 2 and 3: alternative 1
from past.builtins import intern
intern('mystring')
 
 
# Python 2 and 3: alternative 2
from six.moves import intern
intern('mystring')
 
 
# Python 2 and 3: alternative 3
from future.standard_library import install_aliases
install_aliases()
from sys import intern
intern('mystring')
 
 
# Python 2 and 3: alternative 4
try:
    from sys import intern
except ImportError:
    pass
intern('mystring')

apply()

args = ('a', 'b')
kwargs = {'kwarg1': True}
 
 
# Python 2 only:
apply(f, args, kwargs)
 
 
# Python 2 and 3: alternative 1
f(*args, **kwargs)
 
 
# Python 2 and 3: alternative 2
from past.builtins import apply
apply(f, args, kwargs)

chr()

# Python 2 only:
assert chr(64) == b'@'
assert chr(200) == b'\xc8'
 
 
# Python 3 only: option 1
assert chr(64).encode('latin-1') == b'@'
assert chr(0xc8).encode('latin-1') == b'\xc8'
 
 
# Python 2 and 3: option 1
from builtins import chr
 
assert chr(64).encode('latin-1') == b'@'
assert chr(0xc8).encode('latin-1') == b'\xc8'
 
 
# Python 3 only: option 2
assert bytes([64]) == b'@'
assert bytes([0xc8]) == b'\xc8'
 
 
# Python 2 and 3: option 2
from builtins import bytes
 
assert bytes([64]) == b'@'
assert bytes([0xc8]) == b'\xc8'

cmp()

# Python 2 only:
assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
 
 
# Python 2 and 3: alternative 1
from past.builtins import cmp
assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0
 
 
# Python 2 and 3: alternative 2
cmp = lambda(x, y): (x > y) - (x < y)
assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0

reload()

# Python 2 only:
reload(mymodule)
 
 
# Python 2 and 3
from imp import reload
reload(mymodule)

Standard library

dbm modules

# Python 2 only
import anydbm
import whichdb
import dbm
import dumbdbm
import gdbm
 
# Python 2 and 3: alternative 1
from future import standard_library
standard_library.install_aliases()
 
import dbm
import dbm.ndbm
import dbm.dumb
import dbm.gnu
 
# Python 2 and 3: alternative 2
from future.moves import dbm
from future.moves.dbm import dumb
from future.moves.dbm import ndbm
from future.moves.dbm import gnu
 
# Python 2 and 3: alternative 3
from six.moves import dbm_gnu
# (others not supported)

commands / subprocess modules

# Python 2 only
from commands import getoutput, getstatusoutput
 
# Python 2 and 3
from future import standard_library
standard_library.install_aliases()
 
from subprocess import getoutput, getstatusoutput

subprocess.check_output()

# Python 2.7 and above
from subprocess import check_output
 
# Python 2.6 and above: alternative 1
from future.moves.subprocess import check_output
 
# Python 2.6 and above: alternative 2
from future import standard_library
standard_library.install_aliases()
 
from subprocess import check_output

Collections: Counter and OrderedDict

# Python 2.7 and above
from collections import Counter, OrderedDict
 
# Python 2.6 and above: alternative 1
from future.moves.collections import Counter, OrderedDict
 
# Python 2.6 and above: alternative 2
from future import standard_library
standard_library.install_aliases()
 
from collections import Counter, OrderedDict

StringIO module

# Python 2 only
from StringIO import StringIO
from cStringIO import StringIO
 
# Python 2 and 3
from io import BytesIO
# and refactor StringIO() calls to BytesIO() if passing byte-strings

http module

# Python 2 only:
import httplib
import Cookie
import cookielib
import BaseHTTPServer
import SimpleHTTPServer
import CGIHttpServer
 
# Python 2 and 3 (after ``pip install future``):
import http.client
import http.cookies
import http.cookiejar
import http.server

xmlrpc module

# Python 2 only:
import DocXMLRPCServer
import SimpleXMLRPCServer
 
# Python 2 and 3 (after ``pip install future``):
import xmlrpc.server
# Python 2 only:
import xmlrpclib
 
# Python 2 and 3 (after ``pip install future``):
import xmlrpc.client

html escaping and entities

# Python 2 and 3:
from cgi import escape
 
# Safer (Python 2 and 3, after ``pip install future``):
from html import escape
 
# Python 2 only:
from htmlentitydefs import codepoint2name, entitydefs, name2codepoint
 
# Python 2 and 3 (after ``pip install future``):
from html.entities import codepoint2name, entitydefs, name2codepoint

html parsing

# Python 2 only:
from HTMLParser import HTMLParser
 
# Python 2 and 3 (after ``pip install future``)
from html.parser import HTMLParser
 
# Python 2 and 3 (alternative 2):
from future.moves.html.parser import HTMLParser

urllib module

urllib è uno dei moduli più complessi da usare in compatibilità fra 2 e 3.

# Python 2 only:
from urlparse import urlparse
from urllib import urlencode
from urllib2 import urlopen, Request, HTTPError
# Python 3 only:
from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError
# Python 2 and 3: easiest option
from future.standard_library import install_aliases
install_aliases()
 
from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError
# Python 2 and 3: alternative 2
from future.standard_library import hooks
 
with hooks():
    from urllib.parse import urlparse, urlencode
    from urllib.request import urlopen, Request
    from urllib.error import HTTPError
# Python 2 and 3: alternative 3
from future.moves.urllib.parse import urlparse, urlencode
from future.moves.urllib.request import urlopen, Request
from future.moves.urllib.error import HTTPError
# Python 2 and 3: alternative 4
try:
    from urllib.parse import urlparse, urlencode
    from urllib.request import urlopen, Request
    from urllib.error import HTTPError
except ImportError:
    from urlparse import urlparse
    from urllib import urlencode
    from urllib2 import urlopen, Request, HTTPError

Tkinter

# Python 2 only:
import Tkinter
import Dialog
import FileDialog
import ScrolledText
import SimpleDialog
import Tix
import Tkconstants
import Tkdnd
import tkColorChooser
import tkCommonDialog
import tkFileDialog
import tkFont
import tkMessageBox
import tkSimpleDialog
import ttk
 
# Python 2 and 3 (after ``pip install future``):
import tkinter
import tkinter.dialog
import tkinter.filedialog
import tkinter.scrolledtext
import tkinter.simpledialog
import tkinter.tix
import tkinter.constants
import tkinter.dnd
import tkinter.colorchooser
import tkinter.commondialog
import tkinter.filedialog
import tkinter.font
import tkinter.messagebox
import tkinter.simpledialog
import tkinter.ttk

socketserver

# Python 2 only:
import SocketServer
 
# Python 2 and 3 (after ``pip install future``):
import socketserver

copy_reg, copyreg

# Python 2 only:
import copy_reg
 
# Python 2 and 3 (after ``pip install future``):
import copyreg

configparser

# Python 2 only:
from ConfigParser import ConfigParser
 
# Python 2 and 3 (after ``pip install configparser``):
from configparser import ConfigParser

queue

# Python 2 only:
from Queue import Queue, heapq, deque
 
# Python 2 and 3 (after ``pip install future``):
from queue import Queue, heapq, deque

repr, reprlib

# Python 2 only:
from repr import aRepr, repr
 
# Python 2 and 3 (after ``pip install future``):
from reprlib import aRepr, repr

UserDict, UserList, UserString

# Python 2 only:
from UserDict import UserDict
from UserList import UserList
from UserString import UserString
 
 
# Python 3 only:
from collections import UserDict, UserList, UserString
 
 
# Python 2 and 3: alternative 1
from future.moves.collections import UserDict, UserList, UserString
 
 
# Python 2 and 3: alternative 2
from six.moves import UserDict, UserList, UserString
 
 
# Python 2 and 3: alternative 3
from future.standard_library import install_aliases
install_aliases()
from collections import UserDict, UserList, UserString

itertools: filterfalse, zip_longest

# Python 2 only:
from itertools import ifilterfalse, izip_longest
 
# Python 3 only:
from itertools import filterfalse, zip_longest
 
# Python 2 and 3: alternative 1
from future.moves.itertools import filterfalse, zip_longest
 
# Python 2 and 3: alternative 2
from six.moves import filterfalse, zip_longest
 
# Python 2 and 3: alternative 3
from future.standard_library import install_aliases
install_aliases()
from itertools import filterfalse, zip_longest

Python-Modernize

Scopo del progetto

Questa libreria è un wrapper attorno a lib2to3 che serve a rendere il codice Python 2 più moderno in ottica di portarlo su Python 3.

Il comando python-modernize funziona come 2to3. Ecco come riscrivere un singolo file:

python-modernize -w example.py

Il sito Web del progetto è disponibile su GitHub e il nome del progetto PyPI è modernize

Una nota sulla gestione delle stringhe

  • Di default modernize non cambia le stringhe Unicode.
    Questa è l'opzione più semplice se vuoi supportare Python 3.x e versioni successive insieme a Python 2.
  • In alternativa, c'è il flag –six-unicode che avvolgerà le stringhe Unicode con la funzione helper six.u() usando il fixer contenuto in libmodernize.fixes.fix_unicode.
    Ciò è utile se si desidera supportare Python 3.1 e Python 3.2 senza grandi cambiamenti.
  • L'ultima alternativa è il flag –future-unicode che importa gli unicode_literals dal modulo __future__ usando il fixer contenuto in libmodernize.fixes.fix_unicode_future.
    Ciò richiede Python 2.6 e versioni successive e richiederà di contrassegnare le bytestring con b e le stringhe native in str() o qualcosa di simile che sopravviva alla trasformazione.

Preparazione

Dal prompt dei comandi lanciare

pip --install modernize

Al termine dell'installazione avrete a disposizione l'eseguibile python-modernize

Batch di conversione

set mydatetime=%date:~-4%%date:~-7,2%%date:~-10,2%_%time:~0,2%%time:~3,2%%time:~6,2%
set logpath=.\Logs
set logfile=%logpath%\Migrate_%Application%_2to3_%mydatetime%.log
set RepoPath=path\to\your \web2py\applications
set Application=Your_Folder_App_Name
 
IF NOT EXIST %logpath% (
  MKDIR %logpath%
)
 
(FOR /f "delims=" %%a IN ('DIR %RepoPath%\%Application%\*.pyc /b /s') do (del %%a))
(FOR /f "delims=" %%a IN ('DIR %RepoPath%\%Application%\*.py /b /s') do (python-modernize -w %%a >> %LogFile%))
(FOR /f "delims=" %%a IN ('DIR %RepoPath%\%Application%\*.bak /b /s') do (del %%a))

PyCharm e Cross-compatibilità

Fonti

python/porting_python_2_to_pyton_3.txt · Ultima modifica: 2020/01/22 18:01 da apressato
Torna su
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0