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 è 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-unicodeche avvolgerà le stringhe Unicode con la funzione helper six.u() usando il fixer contenuto inlibmodernize.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-unicodeche importa gliunicode_literalsdal modulo __future__ usando il fixer contenuto inlibmodernize.fixes.fix_unicode_future.
Ciò richiede Python 2.6 e versioni successive e richiederà di contrassegnare le bytestring con be 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))


