Python Language
Incompatibilità che si spostano da Python 2 a Python 3
Ricerca…
introduzione
A differenza della maggior parte delle lingue, Python supporta due versioni principali. Dal 2008, quando è stato rilasciato Python 3, molti hanno fatto la transizione, mentre molti non l'hanno fatto. Per comprendere entrambi, questa sezione copre le importanti differenze tra Python 2 e Python 3.
Osservazioni
Ci sono attualmente due versioni supportate di Python: 2.7 (Python 2) e 3.6 (Python 3). Inoltre, le versioni 3.3 e 3.4 ricevono aggiornamenti di sicurezza in formato sorgente.
Python 2.7 è retrocompatibile con la maggior parte delle versioni precedenti di Python e può eseguire il codice Python dalla maggior parte delle versioni 1.xe 2.x di Python invariato. È ampiamente disponibile, con una vasta collezione di pacchetti. Viene anche considerato deprecato dagli sviluppatori CPython e riceve solo sicurezza e sviluppo di correzioni di errori. Gli sviluppatori CPython intendono abbandonare questa versione della lingua nel 2020 .
Secondo Python Enhancement Proposal 373 non sono previste versioni future di Python 2 dopo il 25 giugno 2016, ma correzioni di bug e aggiornamenti di sicurezza saranno supportati fino al 2020. (Non specifica quale data esatta nel 2020 sarà la data di tramonto di Python 2.)
Python 3 ha intenzionalmente rotto la compatibilità all'indietro, per affrontare le preoccupazioni che gli sviluppatori linguistici avevano del nucleo della lingua. Python 3 riceve nuovo sviluppo e nuove funzionalità. È la versione della lingua che gli sviluppatori di lingue intendono portare avanti.
Nel tempo intercorso tra la versione iniziale di Python 3.0 e la versione corrente, alcune funzionalità di Python 3 sono state sottoposte a back-port in Python 2.6 e altre parti di Python 3 sono state estese per avere la sintassi compatibile con Python 2. Pertanto è possibile scrivere Python che funzionerà sia su Python 2 che su Python 3, usando future importazioni e moduli speciali (come sei ).
Le importazioni future devono essere all'inizio del modulo:
from __future__ import print_function
# other imports and instructions go after __future__
print('Hello world')
Per ulteriori informazioni sul modulo __future__
, consultare la pagina pertinente nella documentazione di Python .
Lo strumento 2to3 è un programma Python che converte il codice Python 2.x in codice Python 3.x, vedi anche la documentazione di Python .
Il pacchetto six fornisce utility per la compatibilità con Python 2/3:
- accesso unificato alle librerie rinominate
- variabili per tipi string / unicode
- funzioni per il metodo rimosso o rinominato
Un riferimento per le differenze tra Python 2 e Python 3 può essere trovato qui .
Stampa dichiarazione vs. funzione di stampa
In Python 2, la print
è una dichiarazione:
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)"
In Python 3, print()
è una funzione, con argomenti parola chiave per usi comuni:
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 funzione di stampa ha i seguenti parametri:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
sep
è ciò che separa gli oggetti che passi per stampare. Per esempio:
print('foo', 'bar', sep='~') # out: foo~bar
print('foo', 'bar', sep='.') # out: foo.bar
end
è ciò a cui è seguita la fine della dichiarazione di stampa. Per esempio:
print('foo', 'bar', end='!') # out: foo bar!
La stampa successiva a una stampa di fine non nuova riga verrà stampata sulla stessa riga:
print('foo', end='~')
print('bar')
# out: foo~bar
Nota: per compatibilità futura, la funzione di print
è disponibile anche in Python 2.6; tuttavia non può essere utilizzato a meno che l'analisi dell'istruzione di print
non sia disabilitata con
from __future__ import print_function
Questa funzione ha esattamente lo stesso formato di Python 3, tranne per il fatto che manca il parametro flush
.
Vedere PEP 3105 per la logica.
Stringhe: byte contro Unicode
In Python 2 ci sono due varianti di stringa: quelle fatte di byte con tipo ( str
) e quelle fatte di testo con tipo ( unicode
).
In Python 2, un oggetto di tipo str
è sempre una sequenza di byte, ma è comunemente usato sia per i dati di testo che per quelli binari.
Una stringa letterale viene interpretata come una stringa di byte.
s = 'Cafe' # type(s) == str
Ci sono due eccezioni: puoi definire un letterale Unicode (testo) esplicitamente prefiggendo il letterale con u
:
s = u'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == str
In alternativa, è possibile specificare che i valori letterali stringa di un intero modulo devono creare valori letterali Unicode (testo):
from __future__ import unicode_literals
s = 'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == unicode
Per verificare se la variabile è una stringa (Unicode o una stringa di byte), puoi utilizzare:
isinstance(s, basestring)
In Python 3, il tipo str
è un tipo di testo Unicode.
s = 'Cafe' # type(s) == str
s = 'Café' # type(s) == str (note the accented trailing e)
Inoltre, Python 3 ha aggiunto un oggetto bytes
, adatto per "blob" binari o per scrivere in file indipendenti dalla codifica. Per creare un oggetto bytes, puoi anteporre b
a un letterale stringa o chiamare il metodo encode
della stringa:
# Or, if you really need a byte string:
s = b'Cafe' # type(s) == bytes
s = 'Café'.encode() # type(s) == bytes
Per verificare se un valore è una stringa, utilizzare:
isinstance(s, str)
È anche possibile prefissare i letterali stringa con un prefisso u
per facilitare la compatibilità tra le basi di codice Python 2 e Python 3. Poiché, in Python 3, tutte le stringhe sono Unicode per impostazione predefinita, la preposizione di una stringa letterale con u
non ha alcun effetto:
u'Cafe' == 'Cafe'
Il prefisso di stringa Unicode non ur
Python 2 non è supportato, tuttavia:
>>> ur'Café'
File "<stdin>", line 1
ur'Café'
^
SyntaxError: invalid syntax
Nota che devi encode
un oggetto testo ( str
) Python 3 per convertirlo in una rappresentazione in bytes
di quel testo. La codifica predefinita di questo metodo è UTF-8 .
Puoi utilizzare la decode
per chiedere a un oggetto bytes
quale testo Unicode rappresenta:
>>> b.decode()
'Café'
Mentre il tipo di bytes
esiste sia in Python 2 che in 3, il tipo unicode
esiste solo in Python 2. Per usare le stringhe Unicode implicite di Python 3 in Python 2, aggiungi quanto segue all'inizio del tuo file di codice:
from __future__ import unicode_literals
print(repr("hi"))
# u'hi'
Un'altra importante differenza è che l'indicizzazione dei byte in Python 3 ha come risultato un output int
simile:
b"abc"[0] == 97
Mentre l'affettatura in una dimensione di un risultato in un oggetto di lunghezza 1 byte:
b"abc"[0:1] == b"a"
Inoltre, Python 3 corregge alcuni comportamenti insoliti con unicode, ovvero invertendo le stringhe di byte in Python 2. Ad esempio, il seguente problema è stato risolto:
# -*- 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
Divisione intera
Il simbolo di divisione standard ( /
) opera in modo diverso in Python 3 e Python 2 quando applicato a numeri interi.
Quando si divide un intero di un altro intero in Python 3, l'operazione di divisione x / y
rappresenta una divisione vera (utilizza il metodo __truediv__
) e produce un risultato in virgola mobile. Nel frattempo, la stessa operazione in Python 2 rappresenta una divisione classica che arrotonda il risultato verso l'infinito negativo (noto anche come prendere la parola ).
Per esempio:
Codice | Uscita Python 2 | Uscita Python 3 |
---|---|---|
3 / 2 | 1 | 1.5 |
2 / 3 | 0 | ,6666666666666666 |
-3 / 2 | -2 | -1.5 |
Il comportamento di arrotondamento verso lo zero era deprecato in Python 2.2 , ma rimane in Python 2.7 per motivi di compatibilità con le versioni precedenti ed è stato rimosso in Python 3.
Nota: per ottenere un risultato float in Python 2 (senza arrotondamento del pavimento) possiamo specificare uno degli operandi con il punto decimale. L'esempio precedente di 2/3
che dà 0
in Python 2 deve essere usato come 2 / 3.0
o 2.0 / 3
o 2.0/3.0
per ottenere 0.6666666666666666
Codice | Uscita Python 2 | Uscita Python 3 |
---|---|---|
3.0 / 2.0 | 1.5 | 1.5 |
2 / 3.0 | ,6666666666666666 | ,6666666666666666 |
-3.0 / 2 | -1.5 | -1.5 |
Esiste anche l' operatore della divisione floor ( //
), che funziona allo stesso modo in entrambe le versioni: si arrotonda al numero intero più vicino. (anche se un float viene restituito quando viene utilizzato con float) In entrambe le versioni l'operatore //
associa a __floordiv__
.
Codice | Uscita Python 2 | Uscita 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 |
Si può forzare esplicitamente la vera divisione o divisione del piano usando le funzioni native nel modulo operator
:
from operator import truediv, floordiv
assert truediv(10, 8) == 1.25 # equivalent to `/` in Python 3
assert floordiv(10, 8) == 1 # equivalent to `//`
Mentre è chiaro ed esplicito, usare le funzioni dell'operatore per ogni divisione può essere noioso. Spesso si preferisce modificare il comportamento dell'operatore /
. Una pratica comune consiste nell'eliminare il tipico comportamento di divisione aggiungendo from __future__ import division
come prima affermazione in ogni modulo:
# needs to be the first statement in a module
from __future__ import division
Codice | Uscita Python 2 | Uscita Python 3 |
---|---|---|
3 / 2 | 1.5 | 1.5 |
2 / 3 | ,6666666666666666 | ,6666666666666666 |
-3 / 2 | -1.5 | -1.5 |
from __future__ import division
garantisce che l'operatore /
rappresenta la vera divisione e solo all'interno dei moduli che contengono l'importazione __future__
, quindi non ci sono motivi validi per non abilitarlo in tutti i nuovi moduli.
Nota : alcuni altri linguaggi di programmazione utilizzano l' arrotondamento verso lo zero (troncamento) anziché l' arrotondamento verso il basso negativo come fa Python (cioè in quei linguaggi -3 / 2 == -1
). Questo comportamento può creare confusione durante il porting o il confronto del codice.
Nota sugli operandi float : in alternativa alla from __future__ import division
, si potrebbe usare il consueto simbolo di divisione /
e assicurarsi che almeno uno degli operandi sia float: 3 / 2.0 == 1.5
. Tuttavia, questo può essere considerato una cattiva pratica. È troppo facile scrivere average = sum(items) / len(items)
e dimenticare di lanciare uno degli argomenti per renderlo mobile. Inoltre, tali casi possono spesso eludere la notifica durante il test, ad esempio, se si prova su un array contenente float
s ma si riceve una matrice di int
s in produzione. Inoltre, se in Python 3 viene utilizzato lo stesso codice, i programmi che prevedono che 3/2 3 / 2 == 1
siano True non funzioneranno correttamente.
Vedi PEP 238 per ragioni più dettagliate sul perché l'operatore di divisione è stato modificato in Python 3 e perché la divisione vecchio stile dovrebbe essere evitata.
Vedi l' argomento Simple Math per ulteriori informazioni sulla divisione.
Ridurre non è più un built-in
In Python 2, reduce
è disponibile sia come funzione integrata o dal pacchetto functools
(versione 2.6 in poi), mentre in Python 3 la reduce
è disponibile solo da functools
. Tuttavia la sintassi per la reduce
sia in Python2 che in Python3 è la stessa ed è reduce(function_to_reduce, list_to_reduce)
.
Ad esempio, consideriamo la possibilità di ridurre un elenco a un singolo valore dividendo ciascuno dei numeri adiacenti. Qui usiamo la funzione truediv
dalla libreria operator
.
In Python 2.x è semplice come:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator
>>> reduce(operator.truediv, my_list)
0.008333333333333333
In Python 3.x l'esempio diventa un po 'più complicato:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator, functools
>>> functools.reduce(operator.truediv, my_list)
0.008333333333333333
Possiamo anche usare from functools import reduce
per evitare di chiamare reduce
con il nome del namespace.
Differenze tra le funzioni range e xrange
In Python 2, la funzione range
restituisce un elenco mentre xrange
crea un oggetto xrange
speciale, che è una sequenza immutabile, che a differenza di altri tipi di sequenza incorporati, non supporta l'slicing e non ha né index
né metodi di count
:
print(range(1, 10))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(isinstance(range(1, 10), list))
# Out: True
print(xrange(1, 10))
# Out: xrange(1, 10)
print(isinstance(xrange(1, 10), xrange))
# Out: True
In Python 3, xrange
stato espanso alla sequenza di range
, che ora crea un oggetto range
. Non esiste un tipo xrange
:
print(range(1, 10))
# Out: range(1, 10)
print(isinstance(range(1, 10), range))
# Out: True
# print(xrange(1, 10))
# The output will be:
#Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#NameError: name 'xrange' is not defined
Inoltre, dal momento che Python 3.2, range
supporta anche affettare, index
e 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
Il vantaggio di usare un tipo di sequenza speciale invece di una lista è che l'interprete non deve allocare memoria per un elenco e popolarlo:
# range(10000000000000000)
# The output would be:
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# MemoryError
print(xrange(100000000000000000))
# Out: xrange(100000000000000000)
Poiché il secondo comportamento è generalmente desiderato, il primo è stato rimosso in Python 3. Se vuoi comunque avere un elenco in Python 3, puoi semplicemente usare il costruttore di list()
su un oggetto range
:
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Compatibilità
Per mantenere la compatibilità tra le versioni di Python 2.xe di Python 3.x, è possibile utilizzare il modulo builtins
dal pacchetto esterno future
per ottenere sia compatibilità builtins
compatibilità all'indietro :
#forward-compatible
from builtins import range
for i in range(10**8):
pass
#backward-compatible
from past.builtins import xrange
for i in xrange(10**8):
pass
L' range
nella future
libreria supporta slicing, index
e count
in tutte le versioni di Python, proprio come il metodo built-in su Python 3.2+.
Disimballare Iterables
In Python 3, puoi decomprimere un iterabile senza conoscere il numero esatto di elementi in esso contenuti e persino avere una variabile che tenga la fine del iterabile. Per questo, si fornisce una variabile che può raccogliere un elenco di valori. Questo viene fatto mettendo un asterisco prima del nome. Ad esempio, decomprimere un 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 : quando si utilizza la sintassi *variable
, la variable
sarà sempre un elenco, anche se il tipo originale non era un elenco. Può contenere zero o più elementi a seconda del numero di elementi nell'elenco originale.
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
Allo stesso modo, scompattando un str
:
begin, *tail = "Hello"
print(begin)
# Out: 'H'
print(tail)
# Out: ['e', 'l', 'l', 'o']
Esempio di disimballaggio di una date
; _
è usato in questo esempio come variabile throwaway (ci interessa solo il valore year
):
person = ('John', 'Doe', (10, 16, 2016))
*_, (*_, year_of_birth) = person
print(year_of_birth)
# Out: 2016
Vale la pena ricordare che, dal momento che *
mangia un numero variabile di elementi, non è possibile avere due *
s per lo stesso iterabile in un compito - non saprebbe quanti elementi vanno nel primo disimballaggio, e quanti nel secondo :
*head, *tail = [1, 2]
# Out: SyntaxError: two starred expressions in assignment
Finora abbiamo discusso di disfare i compiti. *
e **
sono stati estesi in Python 3.5 . Ora è possibile avere diverse operazioni di spacchettamento in un'unica espressione:
{*range(4), 4, *(5, 6, 7)}
# Out: {0, 1, 2, 3, 4, 5, 6, 7}
È anche possibile decomprimere un argomento iterabile in funzione:
iterable = [1, 2, 3, 4, 5]
print(iterable)
# Out: [1, 2, 3, 4, 5]
print(*iterable)
# Out: 1 2 3 4 5
La decompressione di un dizionario utilizza due stelle adiacenti **
( PEP 448 ):
tail = {'y': 2, 'z': 3}
{'x': 1, **tail}
# Out: {'x': 1, 'y': 2, 'z': 3}
Ciò consente sia la sovrascrittura dei vecchi valori sia la fusione dei dizionari.
dict1 = {'x': 1, 'y': 1}
dict2 = {'y': 2, 'z': 3}
{**dict1, **dict2}
# Out: {'x': 1, 'y': 2, 'z': 3}
Python 3 ha rimosso la disimballaggio tuple nelle funzioni. Quindi quanto segue non funziona in 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
Vedi PEP 3113 per informazioni dettagliate.
Sollevamento e gestione delle eccezioni
Questa è la sintassi di Python 2, nota le virgole ,
raise
e except
linee:
try:
raise IOError, "input/output error"
except IOError, exc:
print exc
In Python 3, la sintassi ,
viene eliminata e sostituita da parentesi e la parola chiave as
:
try:
raise IOError("input/output error")
except IOError as exc:
print(exc)
Per compatibilità con le versioni precedenti, la sintassi di Python 3 è disponibile anche in Python 2.6, quindi dovrebbe essere utilizzata per tutti i nuovi codici che non devono essere compatibili con le versioni precedenti.
Python 3 aggiunge anche il concatenamento delle eccezioni , in cui è possibile segnalare che qualche altra eccezione è stata la causa di questa eccezione. Per esempio
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from e
L'eccezione sollevata __cause__
except
è di tipo DatabaseError
, ma l'eccezione originale è contrassegnata come l'attributo __cause__
di tale eccezione. Quando viene visualizzato il traceback, l'eccezione originale verrà visualizzata anche nel traceback:
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')
Se lanci un blocco except
senza concatenamento esplicito:
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}')
Il traceback è
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')
Nessuno dei due è supportato in Python 2.x; l'eccezione originale e il suo traceback saranno persi se viene sollevata un'altra eccezione nel blocco eccetto. Il seguente codice può essere utilizzato per la compatibilità:
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")
Per "dimenticare" l'eccezione precedentemente generata, usa raise from None
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from None
Ora il traceback sarebbe semplicemente
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
Oppure per renderlo compatibile con entrambi i Python 2 e 3 è possibile utilizzare il pacchetto sei in questo modo:
import six
try:
file = open('database.db')
except FileNotFoundError as e:
six.raise_from(DatabaseError('Cannot open {}'), None)
.next () metodo sugli iteratori rinominato
In Python 2, un iteratore può essere attraversato usando un metodo chiamato next
sull'iteratore stesso:
g = (i for i in range(0, 3))
g.next() # Yields 0
g.next() # Yields 1
g.next() # Yields 2
In Python 3 il metodo .next
è stato rinominato in .__next__
, riconoscendo il suo ruolo "magico", quindi chiamando .next
genererà un AttributeError
. Il modo corretto per accedere a questa funzionalità sia in Python 2 che in Python 3 è chiamare la funzione next
con l'iteratore come argomento.
g = (i for i in range(0, 3))
next(g) # Yields 0
next(g) # Yields 1
next(g) # Yields 2
Questo codice è portatile tra le versioni dalla 2.6 alla versione corrente.
Confronto tra diversi tipi
Oggetti di diverso tipo possono essere confrontati. I risultati sono arbitrari, ma coerenti. Sono ordinati in modo tale che None
sia inferiore a qualsiasi altra cosa, i tipi numerici sono più piccoli dei tipi non numerici e tutto il resto è ordinato lessicograficamente per tipo. Quindi, un int
è minore di un str
e una tuple
è maggiore di 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
Inizialmente era stato fatto in modo da poter ordinare un elenco di tipi misti e raggruppare gli oggetti per 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)]
Viene sollevata un'eccezione quando si confrontano diversi tipi (non numerici):
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()
Per ordinare gli elenchi misti in Python 3 in base ai tipi e per ottenere la compatibilità tra le versioni, è necessario fornire una chiave per la funzione ordinata:
>>> 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}]
L'utilizzo di str
come funzione key
converte temporaneamente ciascun elemento in una stringa solo ai fini del confronto. Quindi vede la rappresentazione della stringa che inizia con [
, '
, {
o 0-9
ed è in grado di ordinare quelli (e tutti i seguenti caratteri).
Input dell'utente
In Python 2, l'input dell'utente è accettato usando la funzione raw_input
,
user_input = raw_input()
Mentre in Python 3 l'input dell'utente è accettato usando la funzione di input
.
user_input = input()
In Python 2, l' input
funzione accetta input e interpretarlo. Anche se questo può essere utile, ha diverse considerazioni sulla sicurezza ed è stato rimosso in Python 3. Per accedere alla stessa funzionalità, è possibile utilizzare eval(input())
.
Per mantenere uno script portatile tra le due versioni, puoi inserire il codice sotto la parte superiore del tuo script Python:
try:
input = raw_input
except NameError:
pass
Modifiche al metodo dei dizionari
In Python 3, molti dei metodi del dizionario sono molto diversi nel comportamento di Python 2, e molti sono stati rimossi: has_key
, iter*
e view*
sono spariti. Invece di d.has_key(key)
, che era stato a lungo deprecato, è necessario utilizzare la key in d
.
In Python 2, le keys
metodi del dizionario, i values
e gli items
restituiscono gli elenchi. In Python 3 restituiscono invece gli oggetti vista ; gli oggetti vista non sono iteratori e differiscono da essi in due modi:
- hanno dimensioni (si può usare la funzione
len
su di loro) - possono essere ripetuti più volte
Inoltre, come con gli iteratori, le modifiche nel dizionario si riflettono negli oggetti vista.
Python 2.7 ha eseguito il backport di questi metodi da Python 3; sono disponibili come viewkeys
, viewvalues
e viewitems
. Per trasformare il codice Python 2 in codice Python 3, i moduli corrispondenti sono:
-
d.keys()
,d.values()
ed.items()
di Python 2 dovrebbero essere cambiati inlist(d.keys())
,list(d.values())
edlist(d.items())
-
d.iterkeys()
,d.itervalues()
ed.iteritems()
dovrebbero essere modificati initer(d.keys())
, o anche meglioiter(d)
;iter(d.values())
eiter(d.items())
rispettivamente - e infine il metodo Python 2.7 chiama
d.viewkeys()
,d.viewvalues()
ed.viewitems()
può essere sostituito cond.keys()
,d.values()
ed.items()
.
Porting Python 2 codice che itera su chiavi, valori o voci del dizionario, mentre la sua mutazione è a volte difficile. Tenere conto:
d = {'a': 0, 'b': 1, 'c': 2, '!': 3}
for key in d.keys():
if key.isalpha():
del d[key]
Il codice sembra funzionare in modo simile in Python 3, ma il metodo keys
restituisce un oggetto vista, non una lista, e se il dizionario cambia dimensione mentre viene iterato, il codice Python 3 si bloccherà con RuntimeError: dictionary changed size during iteration
. La soluzione è ovviamente quella di scrivere correttamente for key in list(d)
.
Allo stesso modo, gli oggetti vista si comportano diversamente dagli iteratori: non si può usare next()
su di essi, e non si può riprendere l' iterazione; sarebbe invece ricominciare; se il codice Python 2 supera il valore restituito da d.iterkeys()
, d.itervalues()
o d.iteritems()
a un metodo che si aspetta un iteratore invece di un iterabile , allora dovrebbe essere iter(d)
, iter(d.values())
o iter(d.items())
in Python 3.
la dichiarazione exec è una funzione in Python 3
In Python 2, exec
è un'istruzione, con una sintassi speciale: exec code [in globals[, locals]].
In Python 3 exec
è ora una funzione: exec(code, [, globals[, locals]])
, e la sintassi Python 2 solleverà un SyntaxError
.
Poiché la print
stata modificata da una funzione in una funzione, è stata aggiunta un'importazione __future__
. Tuttavia, non esiste from __future__ import exec_function
, poiché non è necessario: l'istruzione exec in Python 2 può anche essere utilizzata con una sintassi che assomiglia esattamente alla exec
funzione exec
in Python 3. In questo modo è possibile modificare le istruzioni
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars
alle forme
exec('code')
exec('code', global_vars)
exec('code', global_vars, local_vars)
e queste ultime sono garantite per funzionare in modo identico sia in Python 2 che in Python 3.
hasattr bug di funzionalità in Python 2
In Python 2, quando una proprietà hasattr
un errore, hasattr
ignorerà questa proprietà, restituendo 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
Questo bug è stato risolto in Python3. Quindi se usi Python 2, usa
try:
a.get
except AttributeError:
print("no get property!")
o usa invece getattr
p = getattr(a, "get", None)
if p is not None:
print(p)
else:
print("no get property!")
Moduli rinominati
Alcuni moduli nella libreria standard sono stati rinominati:
Vecchio nome | Nuovo nome |
---|---|
_winreg | winreg |
ConfigParser | ConfigParser |
copy_reg | copyreg |
Coda | coda |
SocketServer | SocketServer |
_markupbase | markupbase |
repr | reprlib |
test.test_support | test.support |
Tkinter | Tkinter |
tkFileDialog | tkinter.filedialog |
urllib / urllib2 | urllib, urllib.parse, urllib.error, urllib.response, urllib.request, urllib.robotparser |
Alcuni moduli sono stati addirittura convertiti da file in librerie. Prendi tkinter e urllib dall'alto come esempio.
Compatibilità
Quando si mantiene la compatibilità tra entrambe le versioni di Python 2.xe 3.x, è possibile utilizzare il future
pacchetto esterno per abilitare l'importazione di pacchetti di libreria standard di livello superiore con nomi Python 3.x nelle versioni di Python 2.x.
Costanti ottali
In Python 2, un letterale ottale potrebbe essere definito come
>>> 0755 # only Python 2
Per garantire la compatibilità incrociata, utilizzare
0o755 # both Python 2 and Python 3
Tutte le classi sono "classi di nuovo stile" in Python 3.
In Python 3.x
tutte le classi sono classi di nuovo stile ; quando la definizione di una nuova classe python la rende implicitamente ereditata object
. In quanto tale, specificare l' object
in una definizione di class
è completamente facoltativo:
class X: pass
class Y(object): pass
Entrambe queste classi ora contengono object
nel loro mro
(ordine di risoluzione dei metodi):
>>> X.__mro__
(__main__.X, object)
>>> Y.__mro__
(__main__.Y, object)
In Python 2.x
classi sono, di default, classi vecchio stile; non ereditano implicitamente object
. Questo fa sì che la semantica delle classi differisca a seconda se aggiungiamo esplicitamente l' object
come una class
base:
class X: pass
class Y(object): pass
In questo caso, se proviamo a stampare il __mro__
di Y
, __mro__
un output simile a quello nel caso Python 3.x
:
>>> Y.__mro__
(<class '__main__.Y'>, <type 'object'>)
Questo accade perché abbiamo esplicitamente fatto ereditare Y
dall'oggetto quando lo definiamo: class Y(object): pass
. Per la classe X
che non eredita da un oggetto, l'attributo __mro__
non esiste, il tentativo di accedervi produce un AttributeError
.
Per garantire la compatibilità tra entrambe le versioni di Python, le classi possono essere definite con object
come classe base:
class mycls(object):
"""I am fully compatible with Python 2/3"""
In alternativa, se la variabile __metaclass__
è impostata su type
at global scope, tutte le classi definite successivamente in un dato modulo sono implicitamente di nuovo stile senza bisogno di ereditare esplicitamente da object
:
__metaclass__ = type
class mycls:
"""I am also fully compatible with Python 2/3"""
Operatori rimossi <> e ``, sinonimi di! = E repr ()
In Python 2, <>
è un sinonimo di !=
; allo stesso modo, `foo`
è un sinonimo di repr(foo)
.
>>> 1 <> 2
True
>>> 1 <> 1
False
>>> foo = 'hello world'
>>> repr(foo)
"'hello world'"
>>> `foo`
"'hello world'"
>>> 1 <> 2
File "<stdin>", line 1
1 <> 2
^
SyntaxError: invalid syntax
>>> `foo`
File "<stdin>", line 1
`foo`
^
SyntaxError: invalid syntax
codifica / decodifica in esadecimale non più disponibile
"1deadbeef3".decode('hex')
# Out: '\x1d\xea\xdb\xee\xf3'
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Out: 1deadbeef3
"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'str' object has no attribute 'decode'
b"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.decode() to handle arbitrary codecs
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
b'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'bytes' object has no attribute 'encode'
Tuttavia, come suggerito dal messaggio di errore, è possibile utilizzare il modulo codecs
per ottenere lo stesso risultato:
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'
Si noti che codecs.encode
restituisce un oggetto bytes
. Per ottenere un oggetto str
basta decode
in ASCII:
codecs.encode(b'\x1d\xea\xdb\xee\xff', 'hex').decode('ascii')
# Out: '1deadbeeff'
funzione cmp rimossa in Python 3
In Python 3 la funzione integrata di cmp
stata rimossa, insieme al metodo speciale __cmp__
.
Dalla documentazione:
La funzione
cmp()
dovrebbe essere considerata come andata, e il metodo speciale__cmp__()
non è più supportato. Utilizzare__lt__()
per l'ordinamento,__eq__()
con__hash__()
e altri confronti ricchi secondo necessità. (Se hai davvero bisogno della funzionalitàcmp()
, potresti usare l'espressione(a > b) - (a < b)
come equivalente percmp(a, b)
.)
Inoltre tutte le funzioni built-in che hanno accettato il parametro cmp
ora accettano solo il parametro key
keyword only.
Nel modulo functools
è anche utile la funzione cmp_to_key(func)
che consente di convertire da una funzione stile cmp
a una funzione stile- key
:
Trasforma una funzione di confronto vecchio stile in una funzione chiave. Utilizzato con strumenti che accettano funzioni chiave (come
sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
). Questa funzione viene principalmente utilizzata come strumento di transizione per i programmi in fase di conversione da Python 2 che supporta l'utilizzo di funzioni di confronto.
Variabili trapelate nella comprensione delle liste
x = 'hello world!'
vowels = [x for x in 'AEIOU']
print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'U'
x = 'hello world!'
vowels = [x for x in 'AEIOU']
print (vowels)
# Out: ['A', 'E', 'I', 'O', 'U']
print(x)
# Out: 'hello world!'
Come si può vedere dall'esempio, in Python 2 è stato trapelato il valore di x
: è mascherato hello world!
e stampato U
, poiché questo era l'ultimo valore di x
quando il ciclo terminava.
Tuttavia, in Python 3 x
stampato il hello world!
originariamente definito hello world!
, poiché la variabile locale dalla comprensione della lista non maschera le variabili dall'ambito circostante.
Inoltre, né le espressioni del generatore (disponibili in Python dal 2.5) né le definizioni del dizionario o dell'insieme (che sono state trasferite a Python 2.7 da Python 3) perdono variabili in Python 2.
Nota che sia in Python 2 che in Python 3, le variabili penetreranno nell'ambiente circostante quando si utilizza un ciclo for:
x = 'hello world!'
vowels = []
for x in 'AEIOU':
vowels.append(x)
print(x)
# Out: 'U'
carta geografica()
map()
è un builtin utile per applicare una funzione agli elementi di un iterabile. In Python 2, la map
restituisce una lista. In Python 3, map
restituisce un oggetto map , che è un generatore.
# 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']
In Python 2, è possibile passare None
per fungere da funzione di identità. Questo non funziona più in Python 3.
>>> map(None, [0, 1, 2, 3, 0, 4])
[0, 1, 2, 3, 0, 4]
>>> list(map(None, [0, 1, 2, 3, 0, 5]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
Inoltre, quando si passa più di un iterable come argomento in Python 2, map
esegue il pad dei file itertools.izip_longest
più brevi con None
(simile a itertools.izip_longest
). In Python 3, l'iterazione si interrompe dopo il più breve iterabile.
In Python 2:
>>> map(None, [1, 2, 3], [1, 2], [1, 2, 3, 4, 5])
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]
In Python 3:
>>> list(map(lambda x, y, z: (x, y, z), [1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2)]
# to obtain the same padding as in Python 2 use zip_longest from itertools
>>> import itertools
>>> list(itertools.zip_longest([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]))
[(1, 1, 1), (2, 2, 2), (3, None, 3), (None, None, 4), (None, None, 5)]
Nota : al posto della map
considera l'utilizzo delle list comprehensions, che sono compatibili con Python 2/3. Sostituzione map(str, [1, 2, 3, 4, 5])
:
>>> [str(i) for i in [1, 2, 3, 4, 5]]
['1', '2', '3', '4', '5']
filter (), map () e zip () restituiscono gli iteratori anziché le sequenze
Nel filter
Python 2, le funzioni incorporate di map
e zip
restituiscono una sequenza. map
e zip
restituiscono sempre una lista mentre con filter
il tipo restituito dipende dal tipo di parametro dato:
>>> 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)]
Nel filter
Python 3, map
e zip
restituiscono invece iterator:
>>> 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)]
Poiché Python 2 itertools.izip
è equivalente a Python 3 zip
izip
è stato rimosso su Python 3.
Importazioni assolute / relative
In Python 3, PEP 404 cambia il modo in cui le importazioni funzionano da Python 2. Le importazioni relative implicite non sono più consentite nei pacchetti e from ... import *
import sono consentite solo nel codice a livello di modulo.
Per ottenere il comportamento di Python 3 in Python 2:
- la funzione di importazione assoluta può essere abilitata con
from __future__ import absolute_import
- le importazioni relative esplicite sono incoraggiate al posto delle importazioni relative implicite
Per chiarimenti, in Python 2, un modulo può importare il contenuto di un altro modulo situato nella stessa directory come segue:
import foo
Si noti che la posizione di foo
è ambigua dalla sola dichiarazione di importazione. Questo tipo di importazione relativa implicita è quindi scoraggiato a favore delle importazioni relative esplicite , che assomigliano alle seguenti:
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
Il punto .
consente una dichiarazione esplicita della posizione del modulo all'interno dell'albero delle directory.
Maggiori informazioni sulle importazioni relative
Prendi in considerazione un pacchetto definito dall'utente chiamato shapes
. La struttura della directory è la seguente:
shapes
├── __init__.py
|
├── circle.py
|
├── square.py
|
└── triangle.py
circle.py
, square.py
e triangle.py
importano util.py
come modulo. Come faranno riferimento a un modulo nello stesso livello?
from . import util # use util.PI, util.sq(x), etc
O
from .util import * #use PI, sq(x), etc to call functions
Il .
è usato per importazioni relative allo stesso livello.
Ora, considera un layout alternativo del modulo shapes
:
shapes
├── __init__.py
|
├── circle
│ ├── __init__.py
│ └── circle.py
|
├── square
│ ├── __init__.py
│ └── square.py
|
├── triangle
│ ├── __init__.py
│ ├── triangle.py
|
└── util.py
Ora, in che modo queste 3 classi si riferiscono 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
Il ..
è usato per importazioni relative a livello di genitore. Aggiungi altro .
s con il numero di livelli tra genitore e figlio.
File I / O
file
non è più un nome incorporato in 3.x ( open
funziona ancora).
I dettagli interni del file I / O sono stati spostati nel modulo io
libreria standard, che è anche la nuova casa di 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'
La modalità file (testo vs binario) ora determina il tipo di dati prodotti dalla lettura di un file (e il tipo richiesto per la scrittura):
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 codifica per i file di testo ha come valore predefinito quello che viene restituito da locale.getpreferredencoding(False)
. Per specificare esplicitamente una codifica, utilizzare il parametro della parola chiave encoding
:
with open('old_japanese_poetry.txt', 'shift_jis') as text:
haiku = text.read()
La funzione round () tie-break e return
round () tie break
In Python 2, l'uso di round()
su un numero uguale a due numeri interi restituirà quello più lontano da 0. Ad esempio:
round(1.5) # Out: 2.0
round(0.5) # Out: 1.0
round(-0.5) # Out: -1.0
round(-1.5) # Out: -2.0
In Python 3 tuttavia, round()
restituirà l'intero pari (ovvero l'arrotondamento dei banchieri ). Per esempio:
round(1.5) # Out: 2
round(0.5) # Out: 0
round(-0.5) # Out: 0
round(-1.5) # Out: -2
La funzione round () segue la strategia di arrotondamento da mezzo a arrotondamento che arrotonderà i numeri a metà fino al numero intero pari più vicino (ad esempio, round(2.5)
restituisce 2 anziché 3.0).
Come riferimento in Wikipedia , questo è anche conosciuto come arrotondamento imparziale , arrotondamento convergente , arrotondamento di uno statistico, arrotondamento olandese , arrotondamento gaussiano o arrotondamento dispari-pari .
La metà dell'arrotondamento è parte dello standard IEEE 754 ed è anche la modalità di arrotondamento predefinita in .NET di Microsoft.
Questa strategia di arrotondamento tende a ridurre l'errore di arrotondamento totale. Poiché in media la quantità di numeri arrotondati è uguale alla quantità di numeri arrotondati, gli errori di arrotondamento vengono annullati. Altri metodi di arrotondamento tendono invece ad avere una tendenza verso l'alto o verso il basso nell'errore medio.
round () tipo di ritorno
La funzione round()
restituisce un tipo float
in Python 2.7
round(4.8)
# 5.0
A partire da Python 3.0, se il secondo argomento (numero di cifre) viene omesso, restituisce un int
.
round(4.8)
# 5
Vero, Falso e Nessuno
In Python 2, True
, False
e None
sono costanti incorporate. Il che significa che è possibile riassegnarli.
True, False = False, True
True # False
False # True
Non puoi farlo con None
da Python 2.4.
None = None # SyntaxError: cannot assign to None
In Python 3, True
, False
e None
ora sono le parole chiave.
True, False = False, True # SyntaxError: can't assign to keyword
None = None # SyntaxError: can't assign to keyword
Restituisce valore quando si scrive su un oggetto file
In Python 2, scrivere direttamente su un handle di file restituisce None
:
hi = sys.stdout.write('hello world\n')
# Out: hello world
type(hi)
# Out: <type 'NoneType'>
In Python 3, la scrittura su un handle restituirà il numero di caratteri scritti durante la scrittura del testo e il numero di byte scritti durante la scrittura di byte:
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
long vs. int
In Python 2, qualsiasi intero più grande di un C ssize_t
verrebbe convertito nel tipo di dati long
, indicato da un suffisso L
sul letterale. Ad esempio, su una build di Python a 32 bit:
>>> 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
Tuttavia, in Python 3, il long
tipo di dati è stato rimosso; non importa quanto sia grande il numero intero, sarà un int
.
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>
Classe Valore booleano
In Python 2, se si desidera definire un valore booleano della classe da soli, è necessario implementare il metodo __nonzero__
sulla classe. Il valore è True per impostazione predefinita.
class MyClass:
def __nonzero__(self):
return False
my_instance = MyClass()
print bool(MyClass) # True
print bool(my_instance) # False
In Python 3, __bool__
è usato al posto di __nonzero__
class MyClass:
def __bool__(self):
return False
my_instance = MyClass()
print(bool(MyClass)) # True
print(bool(my_instance)) # False