Python Language
Oförenlighet med att flytta från Python 2 till Python 3
Sök…
Introduktion
Till skillnad från de flesta språk stöder Python två huvudversioner. Sedan 2008 när Python 3 släpptes har många gjort övergången, medan många inte har gjort det. För att förstå båda täcker detta avsnitt de viktiga skillnaderna mellan Python 2 och Python 3.
Anmärkningar
Det finns för närvarande två versioner av Python som stöds: 2.7 (Python 2) och 3.6 (Python 3). Dessutom får versionerna 3.3 och 3.4 säkerhetsuppdateringar i källformat.
Python 2.7 är bakåtkompatibel med de flesta tidigare versioner av Python och kan köra Python-kod från de flesta 1.x- och 2.x-versioner av Python oförändrade. Det är allmänt tillgängligt med en omfattande samling paket. Det anses också vara avskrivet av CPython-utvecklarna och får endast säkerhets- och bug-fix-utveckling. CPython-utvecklarna avser att överge denna version av språket 2020 .
Enligt Python Enhancement-förslag 373 finns det inga planerade framtida utgivningar av Python 2 efter den 25 juni 2016, men bugfixar och säkerhetsuppdateringar stöds fram till 2020. (Det anger inte vilket exakta datum 2020 som ska vara solnedgången för Python 2.)
Python 3 bröt avsiktligt bakåtkompatibilitet, för att ta itu med de problem som språkutvecklarna hade med kärnan i språket. Python 3 får ny utveckling och nya funktioner. Det är versionen av språket som språkutvecklarna tänker gå vidare med.
Under tiden mellan den första utgåvan av Python 3.0 och den aktuella versionen, backades vissa funktioner i Python 3 tillbaka till Python 2.6, och andra delar av Python 3 utvidgades för att ha syntax kompatibel med Python 2. Därför är det möjligt att skriva Python som fungerar på både Python 2 och Python 3 genom att använda framtida import och specialmoduler (som sex ).
Framtida import måste vara i början av din modul:
from __future__ import print_function
# other imports and instructions go after __future__
print('Hello world')
För mer information om __future__
modulen, se relevant sida i Python-dokumentationen .
Verktyget 2to3 är ett Python-program som konverterar Python 2.x-kod till Python 3.x-kod, se även Python-dokumentationen .
Paketet sex ger verktyg för Python 2/3-kompatibilitet:
- enhetlig åtkomst till döpt namn på bibliotek
- variabler för sträng- / unicodtyper
- funktioner för metod som har tagits bort eller har bytt namn
En referens för skillnader mellan Python 2 och Python 3 kan hittas här .
Skriv ut uttalande kontra utskriftsfunktion
I Python 2 är print
ett uttalande:
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)"
I Python 3 är print()
en funktion med sökordargument för vanliga användningar:
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)"
Utskriftsfunktionen har följande parametrar:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
sep
är det som skiljer de objekt du skickar för att skriva ut. Till exempel:
print('foo', 'bar', sep='~') # out: foo~bar
print('foo', 'bar', sep='.') # out: foo.bar
end
är vad slutet på utskriften sägs av. Till exempel:
print('foo', 'bar', end='!') # out: foo bar!
Skriva ut igen efter en utskrift som inte slutar skriva ut på samma linje kommer att skrivas ut på samma rad:
print('foo', end='~')
print('bar')
# out: foo~bar
Obs! För framtida kompatibilitet, print
är en funktion även i Python 2.6 och framåt; men det kan inte användas om tolkning av print
uttalande är inaktiverad med
from __future__ import print_function
Denna funktion har exakt samma format som Python 3: er, förutom att den saknar flush
.
Se PEP 3105 för motivering.
Strängar: Bytes kontra Unicode
I Python 2 finns det två varianter av strängar: de som är gjorda av byte med typ ( str
) och de som är gjorda av text med typ ( unicode
).
I Python 2 är ett objekt av typen str
alltid en bytesekvens, men används vanligtvis för både text och binär data.
En strängbokstavlig tolkas som en bytsträng.
s = 'Cafe' # type(s) == str
Det finns två undantag: Du kan definiera en Unicode-bokstav (text) uttryckligen genom att prefixera den bokstavliga med u
:
s = u'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == str
Alternativt kan du ange att en hel moduls strängbokstäver ska skapa Unicode (text) bokstäver:
from __future__ import unicode_literals
s = 'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == unicode
För att kontrollera om din variabel är en sträng (antingen Unicode eller en byte-sträng) kan du använda:
isinstance(s, basestring)
I Python 3 är str
typen en Unicode-texttyp.
s = 'Cafe' # type(s) == str
s = 'Café' # type(s) == str (note the accented trailing e)
Dessutom har Python 3 lagt till ett bytes
, lämpligt för binära "klumpar" eller skrivning till kodningsoberoende filer. För att skapa ett byteobjekt kan du prefix b
till en strängbokstav eller kalla strängens encode
:
# Or, if you really need a byte string:
s = b'Cafe' # type(s) == bytes
s = 'Café'.encode() # type(s) == bytes
För att testa om ett värde är en sträng använder du:
isinstance(s, str)
Det är också möjligt att prefixera strängbokstäver med ett u
prefix för att underlätta kompatibiliteten mellan kodbaserna Python 2 och Python 3. Eftersom, i Python 3, alla strängar är Unicode som standard, förbereda en sträng bokstavlig med u
har ingen effekt:
u'Cafe' == 'Cafe'
Python 2: s råa Unicode-strängprefix ur
stöds dock inte:
>>> ur'Café'
File "<stdin>", line 1
ur'Café'
^
SyntaxError: invalid syntax
Observera att du måste encode
ett Python 3-textobjekt ( str
) för att konvertera det till en bytes
av den texten. Standardkodningen för denna metod är UTF-8 .
Du kan använda decode
att fråga ett bytes
för vilken Unicode-text den representerar:
>>> b.decode()
'Café'
Medan bytes
finns i både Python 2 och 3, existerar unicode
bara i Python 2. För att använda Python 3: s implicita Unicode-strängar i Python 2, lägg till följande till toppen av din kodfil:
from __future__ import unicode_literals
print(repr("hi"))
# u'hi'
En annan viktig skillnad är att indexering av byte i Python 3 resulterar i en int
utgång som så:
b"abc"[0] == 97
Medan skivning i en storlek resulterar i ett längd 1 byte-objekt:
b"abc"[0:1] == b"a"
Dessutom fixar Python 3 något ovanligt beteende med unicode, dvs att byta bytsträngar i Python 2. Till exempel löses följande problem :
# -*- 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
Heltalsuppdelning
Standard division symbol ( /
) arbetar på olika sätt i Python 3 och Python 2 när den appliceras till heltal.
När du delar ett heltal med ett annat heltal i Python 3, representerar delningsoperationen x / y
en sann uppdelning (använder metoden __truediv__
) och ger ett resultat med flytande punkter. Samtidigt representerar samma operation i Python 2 en klassisk uppdelning som avrunder resultatet ned mot negativ oändlighet (även känd som att ta ordet ).
Till exempel:
Koda | Python 2-utgång | Python 3-utgång |
---|---|---|
3 / 2 | 1 | 1,5 |
2 / 3 | 0 | ,6666666666666666 |
-3 / 2 | -2 | -1,5 |
Uppförandet av avrundningen mot noll avskrivs i Python 2.2 , men förblir i Python 2.7 för bakåtkompatibilitet och togs bort i Python 3.
Obs: För att få ett flottörresultat i Python 2 (utan golvrundning) kan vi ange en av operanderna med decimalpunkten. Ovanstående exempel på 2/3
som ger 0
i Python 2 ska användas som 2 / 3.0
eller 2.0 / 3
eller 2.0/3.0
att få 0.6666666666666666
Koda | Python 2-utgång | Python 3-utgång |
---|---|---|
3.0 / 2.0 | 1,5 | 1,5 |
2 / 3.0 | ,6666666666666666 | ,6666666666666666 |
-3.0 / 2 | -1,5 | -1,5 |
Det finns också golvdelningsoperatören ( //
), som fungerar på samma sätt i båda versionerna: den avrundas till närmaste heltal. (även om en flottör returneras när den används med flottörer) I båda versionerna kartlägger //
operatören till __floordiv__
.
Koda | Python 2-utgång | Python 3-utgång |
---|---|---|
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 |
Man kan uttryckligen verkställa verklig division eller golvdelning med hjälp av inbyggda funktioner i operator
:
from operator import truediv, floordiv
assert truediv(10, 8) == 1.25 # equivalent to `/` in Python 3
assert floordiv(10, 8) == 1 # equivalent to `//`
Även om det är tydligt och tydligt kan det vara tråkigt att använda operatörsfunktioner för varje division. Att ändra beteendet hos /
operatören föredras ofta. En vanlig praxis är att eliminera typiskt uppdelningsbeteende genom att lägga till from __future__ import division
som det första uttalandet i varje modul:
# needs to be the first statement in a module
from __future__ import division
Koda | Python 2-utgång | Python 3-utgång |
---|---|---|
3 / 2 | 1,5 | 1,5 |
2 / 3 | ,6666666666666666 | ,6666666666666666 |
-3 / 2 | -1,5 | -1,5 |
from __future__ import division
garanterar att /
operatören representerar verklig division och endast inom modulerna som innehåller __future__
import, så det finns inga tvingande skäl för att inte aktivera den i alla nya moduler.
Obs : Vissa andra programmeringsspråk använder avrundning mot noll (trunkering) snarare än avrundning mot negativ oändlighet som Python gör (dvs. på dessa språk -3 / 2 == -1
). Detta beteende kan skapa förvirring vid porting eller jämförelse av kod.
Obs om flottöroperander : Som ett alternativ till from __future__ import division
kan man använda den vanliga divisionssymbolen /
och se till att åtminstone en av operandema är en flottör: 3 / 2.0 == 1.5
. Detta kan dock betraktas som dålig praxis. Det är alldeles för enkelt att skriva average = sum(items) / len(items)
och glömma att kasta ett av argumenten att flyta. Dessutom kan sådana fall ofta undvika meddelande under testning, t.ex. om du testar på en matris som innehåller float
men får en mängd int
under produktion. Om samma kod används i Python 3 fungerar dessutom program som förväntar sig att 3/2 3 / 2 == 1
är sant inte korrekt.
Se PEP 238 för mer detaljerade skäl till varför divisionsoperatören byttes i Python 3 och varför division i gammal stil bör undvikas.
Se ämnet Simple Math för mer om uppdelning.
Minska är inte längre en inbyggd
I Python 2 finns reduce
tillgänglig antingen som en inbyggd funktion eller från functools
(version 2.6 och framåt), medan i Python 3 reduce
finns tillgänglig från functools
. Men syntaxen för reduce
i både Python2 och Python3 är densamma och reduce(function_to_reduce, list_to_reduce)
.
Låt oss som exempel överväga att reducera en lista till ett enda värde genom att dela vart och ett av de angränsande siffrorna. Här använder vi truediv
funktion från operator
.
I Python 2.x är det så enkelt som:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator
>>> reduce(operator.truediv, my_list)
0.008333333333333333
I Python 3.x blir exemplet lite mer komplicerat:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator, functools
>>> functools.reduce(operator.truediv, my_list)
0.008333333333333333
Vi kan också använda from functools import reduce
att undvika att ringa reduce
med namnområdet.
Skillnader mellan intervall- och xrange-funktioner
I Python 2, range
returnerar funktionen en lista medan xrange
skapar en speciell xrange
objekt, vilket är en oföränderlig sekvens, som till skillnad från andra inbyggda sekvenstyper, inte stödskivning och har varken index
eller count
metoder:
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
I Python 3 xrange
till range
, vilket nu skapar ett range
. Det finns ingen xrange
typ:
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
Dessutom, eftersom Python 3.2 range
stöder också skivning, index
och 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
Fördelen med att använda en speciell sekvenstyp istället för en lista är att tolkaren inte behöver tilldela minne för en lista och fylla i den:
# range(10000000000000000)
# The output would be:
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# MemoryError
print(xrange(100000000000000000))
# Out: xrange(100000000000000000)
Eftersom det senare beteendet i allmänhet är önskvärt, togs det förstnämnda bort i Python 3. Om du fortfarande vill ha en lista i Python 3 kan du helt enkelt använda list()
-konstruktören på ett range
:
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Kompatibilitet
För att bibehålla kompatibiliteten mellan både Python 2.x och Python 3.x versioner kan du använda builtins
modulen från det externa paketets future
att uppnå både framåtkompatibilitet och bakåtkompatibilitet :
#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
range
i future
bibliotek stöder skärning, index
och count
i alla Python-versioner, precis som den inbyggda metoden på Python 3.2+.
Packa upp Iterables
I Python 3 kan du packa upp en iterable utan att veta det exakta antalet objekt i det, och till och med ha en variabel som håller slutet på iterable. För detta tillhandahåller du en variabel som kan samla en lista med värden. Detta görs genom att placera en asterisk före namnet. Till exempel, packa upp en 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
Obs! När du använder syntaxen *variable
-variabel är variable
alltid en lista, även om originaltypen inte var en lista. Det kan innehålla noll eller fler element beroende på antalet element i originallistan.
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
På liknande sätt packa upp en str
:
begin, *tail = "Hello"
print(begin)
# Out: 'H'
print(tail)
# Out: ['e', 'l', 'l', 'o']
Exempel på att packa upp ett date
; _
Används i detta exempel som en slit och släng variabel (vi är intresserade endast i year
värde):
person = ('John', 'Doe', (10, 16, 2016))
*_, (*_, year_of_birth) = person
print(year_of_birth)
# Out: 2016
Det är värt att nämna att eftersom *
äter upp ett variabelt antal objekt kan du inte ha två *
s för samma iterable i ett uppdrag - det skulle inte veta hur många element som går in i den första uppackningen och hur många i den andra :
*head, *tail = [1, 2]
# Out: SyntaxError: two starred expressions in assignment
Hittills har vi diskuterat uppackning i uppdrag. *
och **
förlängdes i Python 3.5 . Det är nu möjligt att ha flera uppackningsoperationer i ett uttryck:
{*range(4), 4, *(5, 6, 7)}
# Out: {0, 1, 2, 3, 4, 5, 6, 7}
Det är också möjligt att packa upp en iterable till funktionsargument:
iterable = [1, 2, 3, 4, 5]
print(iterable)
# Out: [1, 2, 3, 4, 5]
print(*iterable)
# Out: 1 2 3 4 5
Uppackning av en ordlista använder två angränsande stjärnor **
( PEP 448 ):
tail = {'y': 2, 'z': 3}
{'x': 1, **tail}
# Out: {'x': 1, 'y': 2, 'z': 3}
Detta möjliggör både åsidosättande av gamla värden och sammanslagning av ordböcker.
dict1 = {'x': 1, 'y': 1}
dict2 = {'y': 2, 'z': 3}
{**dict1, **dict2}
# Out: {'x': 1, 'y': 2, 'z': 3}
Python 3 har tagit bort tupeluppackning i funktioner. Följaktligen fungerar inte följande i 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
Se PEP 3113 för detaljerad motivering.
Att höja och hantera undantag
Detta är Python 2-syntaxen, notera kommatecken ,
på raise
och except
linjer:
try:
raise IOError, "input/output error"
except IOError, exc:
print exc
I Python 3, den ,
är syntaxen tappas och ersattes med parentes och as
nyckelord:
try:
raise IOError("input/output error")
except IOError as exc:
print(exc)
För bakåtkompatibilitet är Python 3-syntaxen också tillgänglig i Python 2.6 och framåt, så den bör användas för all ny kod som inte behöver vara kompatibel med tidigare versioner.
Python 3 lägger också till undantagskedjor , där du kan signalera att något annat undantag var orsaken till detta undantag. Till exempel
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from e
Undantaget som tas upp i except
är av typen DatabaseError
, men det ursprungliga undantaget markeras som attributet __cause__
för det undantaget. När spårningen visas kommer det ursprungliga undantaget också att visas i spårningen:
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')
Om du kastar in ett except
utan uttrycklig kedja:
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}')
Traceback är
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')
Ingen av dem stöds i Python 2.x; det ursprungliga undantaget och dess spårning kommer att förloras om ett annat undantag tas upp i undantagsblocket. Följande kod kan användas för kompatibilitet:
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")
För att "glömma" det tidigare kastade undantaget använder du raise from None
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from None
Nu skulle spårningen helt enkelt vara
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
Eller för att göra den kompatibel med både Python 2 och 3 kan du använda sex paket så här:
import six
try:
file = open('database.db')
except FileNotFoundError as e:
six.raise_from(DatabaseError('Cannot open {}'), None)
.nästa () -metod på iteratorer som bytt namn
I Python 2 kan en iterator korsas genom att använda en metod som kallas next
på själva iteratorn:
g = (i for i in range(0, 3))
g.next() # Yields 0
g.next() # Yields 1
g.next() # Yields 2
I Python 3 har .next
metoden bytt namn till .__next__
, vilket bekräftar dess ”magiska” roll, så att ringa .next
kommer att höja ett AttributeError
. Det rätta sättet att komma åt denna funktionalitet i både Python 2 och Python 3 är att ringa next
funktion med iteratorn som ett argument.
g = (i for i in range(0, 3))
next(g) # Yields 0
next(g) # Yields 1
next(g) # Yields 2
Den här koden är bärbar mellan versioner från 2.6 till nuvarande utgåvor.
Jämförelse av olika typer
Objekt av olika typer kan jämföras. Resultaten är godtyckliga, men konsekventa. De beställs så att None
är mindre än något annat, numeriska typer är mindre än icke-numeriska typer, och allt annat beställs leksikografiskt efter typ. Således är en int
mindre än en str
och en tuple
är större än en 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
Detta gjordes ursprungligen så att en lista med blandade typer kunde sorteras och objekt skulle grupperas tillsammans efter typ:
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)]
Ett undantag tas upp när man jämför olika (icke-numeriska) typer:
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()
För att sortera blandade listor i Python 3 efter typer och för att uppnå kompatibilitet mellan versioner måste du ange en nyckel till den sorterade funktionen:
>>> 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}]
str
använder str
som key
konverteras varje objekt till en sträng endast för att jämföra. Därefter ser strängrepresentationen börja med antingen [
, '
, {
eller 0-9
och den kan sortera dessa (och alla följande tecken).
Användarinmatning
I Python 2 accepteras raw_input
funktionen raw_input
,
user_input = raw_input()
I Python 3 accepteras användarinmatning med hjälp av input
.
user_input = input()
I Python 2, den input
kommer funktionen att acceptera input och tolka den. Även om detta kan vara användbart, har det flera säkerhetshänsyn och togs bort i Python 3. För att få tillgång till samma funktionalitet kan eval(input())
användas.
För att hålla ett skript bärbart över de två versionerna kan du sätta koden nedan nära toppen av ditt Python-skript:
try:
input = raw_input
except NameError:
pass
Ordboksmetod ändras
I Python 3 är många av ordboksmetoderna helt annorlunda i beteende än Python 2, och många har också tagits bort: has_key
, iter*
och view*
är borta. I stället för d.has_key(key)
, som länge hade försvunnit, måste man nu använda key in d
.
I Python 2, ordlista metoder keys
, values
och items
returnerar listor. I Python 3 returnerar de visningsobjekt istället; utsiktsobjekten är inte iteratorer, och de skiljer sig från dem på två sätt, nämligen:
- de har storlek (man kan använda
len
funktionen på dem) - de kan upprepas under många gånger
Dessutom, liksom med iteratorer, återspeglas förändringarna i ordboken i visningsobjekten.
Python 2.7 har backporterat dessa metoder från Python 3; de är tillgängliga som viewkeys
, viewvalues
och viewitems
. För att omvandla Python 2-kod till Python 3-kod är motsvarande former:
-
d.keys()
,d.values()
ochd.items()
i Python 2 bör ändras tilllist(d.keys())
,list(d.values())
ochlist(d.items())
-
d.iterkeys()
,d.itervalues()
ochd.iteritems()
bör ändras tilliter(d.keys())
, eller ännu bättre,iter(d)
;iter(d.values())
respektiveiter(d.items())
- och slutligen Python 2.7-metoden kallar
d.viewkeys()
,d.viewvalues()
ochd.viewitems()
kan ersättas medd.keys()
,d.values()
ochd.items()
.
Porting av Python 2-kod som iterates över ordbordsnycklar, värden eller objekt medan du muterar den är ibland svår. Överväga:
d = {'a': 0, 'b': 1, 'c': 2, '!': 3}
for key in d.keys():
if key.isalpha():
del d[key]
Koden ser ut som om det skulle fungera på samma sätt i Python 3, men där keys
metoden returnerar en vy objekt, inte en lista, och om ordboken ändrar storlek samtidigt som upprepas över kommer Python 3-koden krasch med RuntimeError: dictionary changed size during iteration
. Lösningen är naturligtvis att skriva ordentligt for key in list(d)
.
På liknande sätt uppträder visningsobjekt på ett annorlunda sätt än iteratorer: man kan inte använda next()
på dem och man kan inte återuppta iterationen; det skulle istället starta om; om Python 2-koden skickar returvärdet för d.iterkeys()
, d.itervalues()
eller d.iteritems()
till en metod som förväntar sig en iterator istället för en iterable , bör det vara iter(d)
, iter(d.values())
eller iter(d.items())
i Python 3.
exec-uttalande är en funktion i Python 3
I Python 2 är exec
ett uttalande med speciell syntax: exec code [in globals[, locals]].
I Python 3 är exec
nu en funktion: exec(code, [, globals[, locals]])
, och Python 2-syntaxen kommer att höja en SyntaxError
.
När print
ändrades från uttalande till en funktion, lades också en __future__
import till. Det finns dock inget from __future__ import exec_function
, eftersom det inte behövs: exec-uttalandet i Python 2 kan också användas med syntax som ser exakt ut som exec
funktionen kallas i Python 3. Således kan du ändra påståenden
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars
till former
exec('code')
exec('code', global_vars)
exec('code', global_vars, local_vars)
och de senare formerna garanteras att fungera identiskt i både Python 2 och Python 3.
hasattr-funktionsfel i Python 2
I Python 2, när en egenskap tar upp ett fel, kommer hasattr
att ignorera den här egenskapen och returnera 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
Det här felet fixas i Python3. Så om du använder Python 2, använd
try:
a.get
except AttributeError:
print("no get property!")
eller använd getattr
istället
p = getattr(a, "get", None)
if p is not None:
print(p)
else:
print("no get property!")
Byt namn på moduler
Några moduler i standardbiblioteket har fått nytt namn:
Gammalt namn | Nytt namn |
---|---|
_winreg | winreg |
ConfigParser | configparser |
copy_reg | copyreg |
Kö | kö |
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 |
Vissa moduler har till och med konverterats från filer till bibliotek. Ta tkinter och urllib ovanifrån som ett exempel.
Kompatibilitet
När du bibehåller kompatibiliteten mellan både Python 2.x- och 3.x-versionerna kan du använda det future
externa paketet för att möjliggöra import av högsta standardbibliotekspaket med Python 3.x-namn i Python 2.x-versionerna.
Octal Constants
I Python 2 kan en oktal literal definieras som
>>> 0755 # only Python 2
Använd för att säkerställa tvärkompatibilitet
0o755 # both Python 2 and Python 3
Alla klasser är "klasser i ny stil" i Python 3.
I Python 3.x
alla klasser i nya stilklasser ; när man definierar en ny klasspython implicit gör det arv från object
. Som sådana, som specificerar object
i en class
definition är en helt valfri:
class X: pass
class Y(object): pass
Båda dessa klasser innehåller nu object
i sin mro
( mro
):
>>> X.__mro__
(__main__.X, object)
>>> Y.__mro__
(__main__.Y, object)
I Python 2.x
klasser som standard gamla klasser; de ärver inte implicit från object
. Detta medför semantiken av klasser att variera beroende på om vi lägger uttryckligen object
som bas class
:
class X: pass
class Y(object): pass
I det här fallet, om vi försöker skriva ut __mro__
för Y
, kommer en liknande utgång som i Python 3.x
fallet att visas:
>>> Y.__mro__
(<class '__main__.Y'>, <type 'object'>)
Detta händer eftersom vi uttryckligen fick Y
ärva från objektet när vi definierade det: class Y(object): pass
. För klass X
som inte ärver från objektet finns inte __mro__
attributet, försöker komma åt det resulterar i ett AttributeError
.
För att säkerställa kompatibilitet mellan båda versionerna av Python kan klasser definieras med object
som en basklass:
class mycls(object):
"""I am fully compatible with Python 2/3"""
Alternativt, om variabeln __metaclass__
är inställd på type
i global omfattning, är alla efterföljande definierade klasser i en given modul implicit nystil utan att behöva uttryckligen ärva från object
:
__metaclass__ = type
class mycls:
"""I am also fully compatible with Python 2/3"""
Borttagna operatörer <> och ``, synonymt med! = Och repr ()
I Python 2 är <>
en synonym för !=
; På samma sätt är `foo`
en synonym för 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
kodning / avkodning till hex är inte längre tillgänglig
"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'
Som föreslagits av felmeddelandet kan du dock använda codecs
modulen för att uppnå samma resultat:
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'
Observera att codecs.encode
returnerar ett bytes
. För att få ett str
objekt decode
bara till ASCII:
codecs.encode(b'\x1d\xea\xdb\xee\xff', 'hex').decode('ascii')
# Out: '1deadbeeff'
cmp-funktion tas bort i Python 3
I Python 3 cmp
inbyggda cmp
-funktionen ut tillsammans med __cmp__
specialmetod.
Från dokumentationen:
cmp()
ska behandlas som försvunnen och__cmp__()
specialmetoden stöds inte längre. Använd__lt__()
för sortering,__eq__()
med__hash__()
och andra rika jämförelser efter behov. (Om du verkligen behövercmp()
-funktionen kan du använda uttrycket(a > b) - (a < b)
som ekvivalent förcmp(a, b)
.)
Dessutom accepterar alla inbyggda funktioner som accepterade cmp
parametern nu bara parametern key
nyckelord endast.
I functools
modulen finns också användbar cmp_to_key(func)
funktion cmp_to_key(func)
som låter dig konvertera från en cmp
stil-funktion till en key
stil-funktion:
Förvandla en gammal stil jämförelsefunktion till en nyckelfunktion. Används med verktyg som accepterar nyckelfunktioner (som
sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
). Denna funktion används främst som ett övergångsverktyg för program som konverteras från Python 2 som stöder användningen av jämförelsefunktioner.
Läckta variabler i listförståelse
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!'
Som framgår av exemplet, i Python 2 läckte värdet på x
: det maskerade hello world!
och tryckte U
, eftersom detta var det sista värdet på x
när slingan slutade.
I Python 3 x
skrivs emellertid den ursprungligen definierade hello world!
, eftersom den lokala variabeln från listförståelsen inte maskerar variabler från det omgivande omfånget.
Dessutom läcker varken generatoruttryck (tillgängliga i Python sedan 2,5) eller ordböcker eller uppsättningsförståelser (som backporterades till Python 2.7 från Python 3) variabler i Python 2.
Observera att i både Python 2 och Python 3 kommer variabler att läcka ut i det omgivande omfånget när du använder en for loop:
x = 'hello world!'
vowels = []
for x in 'AEIOU':
vowels.append(x)
print(x)
# Out: 'U'
Karta()
map()
är en inbyggd som är användbar för att tillämpa en funktion på delar av en iterable. I Python 2 returnerar map
en lista. I Python 3, map
returnerar ett kartobjekt, som är en generator.
# 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']
I Python 2 kan du passera None
att fungera som en identitetsfunktion. Detta fungerar inte längre i 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
Dessutom, när du passerar mer än en iterable som argument i Python 2, map
de kortare iterablesna med None
(liknande itertools.izip_longest
). I Python 3 slutar iterationen efter den kortaste iterbara.
I 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)]
I 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)]
Obs : istället för map
överväga att använda listförståelser, som är Python 2/3 kompatibla. Byt ut map(str, [1, 2, 3, 4, 5])
:
>>> [str(i) for i in [1, 2, 3, 4, 5]]
['1', '2', '3', '4', '5']
filter (), karta () och zip () returnerar iteratorer istället för sekvenser
I Python 2- filter
map
och zip
inbyggda funktioner en sekvens. map
och zip
returnerar alltid en lista medan med filter
är returtypen beroende på typen av given parameter:
>>> 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)]
I Python 3- filter
returnerar iterator för map
och zip
returer istället:
>>> 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)]
Sedan Python 2 itertools.izip
är ekvivalent med Python 3 zip
izip
har tagits bort på Python 3.
Absolut / relativ import
I Python 3 ändrar PEP 404 hur import fungerar från Python 2. Implicit relativ import är inte längre tillåten i paket och from ... import *
import är endast tillåtet i modulnivåkod.
För att uppnå Python 3-beteende i Python 2:
- funktionen för absolutimport kan aktiveras med
from __future__ import absolute_import
- uttrycklig relativ import uppmuntras i stället för implicit relativimport
För förtydligande kan en modul i Python 2 importera innehållet i en annan modul som finns i samma katalog enligt följande:
import foo
Observera att foo
platsen är tvetydig endast från importmeddelandet. Denna typ av implicit relativimport avskräckas således till förmån för uttrycklig relativimport , som ser ut enligt följande:
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
Punkten .
tillåter en uttrycklig deklaration av modulplatsen i katalogträdet.
Mer om relativ import
Tänk på något användardefinierat paket som kallas shapes
. Katalogstrukturen är som följer:
shapes
├── __init__.py
|
├── circle.py
|
├── square.py
|
└── triangle.py
circle.py
, square.py
och triangle.py
all import util.py
som modul. Hur hänvisar de till en modul på samma nivå?
from . import util # use util.PI, util.sq(x), etc
ELLER
from .util import * #use PI, sq(x), etc to call functions
Den .
används för relativ import på samma nivå.
Tänk nu på en alternativ layout för shapes
:
shapes
├── __init__.py
|
├── circle
│ ├── __init__.py
│ └── circle.py
|
├── square
│ ├── __init__.py
│ └── square.py
|
├── triangle
│ ├── __init__.py
│ ├── triangle.py
|
└── util.py
Nu, hur kommer dessa tre klasser att hänvisa till util.py?
from .. import util # use util.PI, util.sq(x), etc
ELLER
from ..util import * # use PI, sq(x), etc to call functions
Det ..
används för relativa import förälder-nivå. Lägg till mer .
s med antal nivåer mellan förälder och barn.
Fil I / O
file
är inte längre ett inbyggt namn i 3.x ( open
fungerar fortfarande).
Interna detaljer för fil I / O har flyttats till standardbibliotekets io
modul, som också är det nya hemmet för 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'
Filläget (text kontra binärt) bestämmer nu vilken typ av data som produceras genom att läsa en fil (och vilken typ som krävs för att skriva):
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
Kodningen för textfiler går som standard tillbaka till locale.getpreferredencoding(False)
. För att specificera en kodning uttryckligen använder du encoding
:
with open('old_japanese_poetry.txt', 'shift_jis') as text:
haiku = text.read()
Den runda () -funktionen slips- och returtyp
rund () slips
I Python 2 kommer att använda round()
på ett nummer lika nära två heltal att returnera det som är längst från 0. Till exempel:
round(1.5) # Out: 2.0
round(0.5) # Out: 1.0
round(-0.5) # Out: -1.0
round(-1.5) # Out: -2.0
I Python 3 kommer round()
att returnera det jämna heltalet (även bankers avrundning ). Till exempel:
round(1.5) # Out: 2
round(0.5) # Out: 0
round(-0.5) # Out: 0
round(-1.5) # Out: -2
Funktionen runda () följer halv till jämn rundningsstrategi som kommer att runda halvvägsnummer till närmaste jämna heltal (till exempel ger round(2.5)
nu 2 istället för 3.0).
Enligt referens på Wikipedia är detta också känt som opartisk avrundning , konvergent avrundning , statistikens avrundning , holländsk avrundning , Gaussisk avrundning eller udda jämn avrundning .
Halva till jämna avrundning är en del av IEEE 754- standarden och det är också standardavrundningsläget i Microsofts .NET.
Denna avrundningsstrategi tenderar att minska det totala avrundningsfelet. Eftersom antalet nummer som avrundas i genomsnitt är detsamma som antalet som avrundas avbryter avrundningsfel. Andra avrundningsmetoder tenderar istället att ha en uppåt eller nedåt förspänning i det genomsnittliga felet.
round () returtyp
Funktionen round()
returnerar en float
i Python 2.7
round(4.8)
# 5.0
Från Python 3.0, om det andra argumentet (antal siffror) utelämnas, returnerar det ett int
.
round(4.8)
# 5
Det är sant, falskt och inget
I Python 2 är True
, False
och None
inbyggda konstanter. Vilket innebär att det är möjligt att tilldela dem igen.
True, False = False, True
True # False
False # True
Du kan inte göra detta med None
sedan Python 2.4.
None = None # SyntaxError: cannot assign to None
I Python 3 är True
, False
och None
nu nyckelord.
True, False = False, True # SyntaxError: can't assign to keyword
None = None # SyntaxError: can't assign to keyword
Returnera värde när du skriver till ett filobjekt
I Python 2 returnerar skrivning direkt till ett filhandtag None
:
hi = sys.stdout.write('hello world\n')
# Out: hello world
type(hi)
# Out: <type 'NoneType'>
I Python 3 kommer att skriva till ett handtag att returnera antalet tecken skrivna när du skriver text och antalet byte skrivna när du skriver 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
lång kontra int
I Python 2 skulle alla heltal som är större än en C- ssize_t
omvandlas till den long
datatypen, indikerat med en L
suffix på bokstaven. Till exempel på en 32-bitars byggnad av Python:
>>> 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
I Python 3 togs dock den long
datatypen bort; oavsett hur stort heltalet är, kommer det att vara ett int
.
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>
Booleskt värde
Om du vill definiera ett booleskt värde i Python 2 måste du implementera metoden __nonzero__
din klass. Värdet är sant som standard.
class MyClass:
def __nonzero__(self):
return False
my_instance = MyClass()
print bool(MyClass) # True
print bool(my_instance) # False
I Python 3 används __bool__
istället för __nonzero__
class MyClass:
def __bool__(self):
return False
my_instance = MyClass()
print(bool(MyClass)) # True
print(bool(my_instance)) # False