Python Language
Niezgodności przechodzące z Python 2 do Python 3
Szukaj…
Wprowadzenie
W przeciwieństwie do większości języków, Python obsługuje dwie główne wersje. Od 2008 roku, kiedy wydano Python 3, wielu dokonało tego przejścia, a wielu nie. Aby zrozumieć oba, w tej sekcji omówiono ważne różnice między Python 2 i Python 3.
Uwagi
Obecnie obsługiwane są dwie wersje Pythona: 2.7 (Python 2) i 3.6 (Python 3). Dodatkowo wersje 3.3 i 3.4 otrzymują aktualizacje zabezpieczeń w formacie źródłowym.
Python 2.7 jest wstecznie kompatybilny z większością wcześniejszych wersji Pythona i może uruchamiać kod Pythona z większości wersji Python 1.x i 2.x bez zmian. Jest szeroko dostępny, z obszerną kolekcją pakietów. Jest również uważany za przestarzały przez programistów CPython i otrzymuje tylko rozwój bezpieczeństwa i poprawiania błędów. Programiści CPython zamierzają porzucić tę wersję języka w 2020 roku .
Zgodnie z propozycją 373 dotyczącą ulepszenia Pythona nie ma planowanych przyszłych wersji Python 2 po 25 czerwca 2016 r., Ale poprawki błędów i aktualizacje zabezpieczeń będą obsługiwane do 2020 r. (Nie określa dokładnej daty w Pythonie w 2020 r. 2.)
Python 3 celowo zerwał z kompatybilnością wsteczną, aby uwzględnić obawy, które programiści mieli z rdzeniem języka. Python 3 otrzymuje nowe oprogramowanie i nowe funkcje. Jest to wersja języka, z którą programiści zamierzają się rozwijać.
W okresie między początkową wersją Pythona 3.0 a bieżącą wersją niektóre funkcje Pythona 3 zostały przeniesione z powrotem do Pythona 2.6, a inne części Pythona 3 zostały rozszerzone, aby mieć składnię zgodną z Pythonem 2. Dlatego możliwe jest pisanie Python, który będzie działał zarówno na Python 2, jak i Python 3, wykorzystując przyszłe importy i specjalne moduły (jak sześć ).
Przyszłe importowanie musi odbywać się na początku modułu:
from __future__ import print_function
# other imports and instructions go after __future__
print('Hello world')
Aby uzyskać więcej informacji na temat modułu __future__
, zobacz odpowiednią stronę w dokumentacji Pythona .
Narzędzie 2to3 to program w języku Python, który konwertuje kod Python 2.x na kod Python 3.x, zobacz także dokumentację Python .
Pakiet szósty zawiera narzędzia do kompatybilności z Python 2/3:
- ujednolicony dostęp do bibliotek o zmienionych nazwach
- zmienne dla typów łańcuchowych / Unicode
- funkcje dla metody, która została usunięta lub której nazwa została zmieniona
Odniesienie do różnic między Python 2 i Python 3 można znaleźć tutaj .
Instrukcja drukowania a funkcja drukowania
W Pythonie 2 print
jest instrukcją:
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)"
W Pythonie 3 print()
jest funkcją z argumentami słów kluczowych do typowych zastosowań:
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)"
Funkcja drukowania ma następujące parametry:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
sep
jest tym, co oddziela obiekty, które przekazujesz do wydrukowania. Na przykład:
print('foo', 'bar', sep='~') # out: foo~bar
print('foo', 'bar', sep='.') # out: foo.bar
end
jest końcem instrukcji print. Na przykład:
print('foo', 'bar', end='!') # out: foo bar!
Ponowne drukowanie po wyciągu nie kończącym nowego wiersza zostanie wydrukowane w tym samym wierszu:
print('foo', end='~')
print('bar')
# out: foo~bar
Uwaga: Dla przyszłej kompatybilności funkcja print
jest również dostępna w Pythonie 2.6 i nowszych; jednak nie mogą być wykorzystywane, dopóki parsowanie do print
oświadczenia jest wyłączona z
from __future__ import print_function
Ta funkcja ma dokładnie taki sam format jak Python 3, z tą różnicą, że brakuje jej parametru flush
.
Uzasadnienie znajduje się w PEP 3105 .
Ciągi: Bajty kontra Unicode
W Pythonie 2 istnieją dwa warianty ciągów znaków: te wykonane z bajtów typu type ( str
) i te wykonane z tekstu typu type ( unicode
).
W Pythonie 2 obiekt typu str
jest zawsze sekwencją bajtów, ale jest powszechnie używany zarówno w przypadku tekstu, jak i danych binarnych.
Dosłowny ciąg znaków jest interpretowany jako ciąg bajtów.
s = 'Cafe' # type(s) == str
Istnieją dwa wyjątki: Możesz zdefiniować literał Unicode (tekst) jawnie, poprzedzając literał u
:
s = u'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == str
Alternatywnie możesz określić, że literały łańcuchowe całego modułu powinny tworzyć literały Unicode (tekstowe):
from __future__ import unicode_literals
s = 'Café' # type(s) == unicode
b = 'Lorem ipsum' # type(b) == unicode
Aby sprawdzić, czy zmienna jest ciągiem (Unicode lub ciągiem bajtów), możesz użyć:
isinstance(s, basestring)
W Pythonie 3 typem str
jest typ tekstowy Unicode.
s = 'Cafe' # type(s) == str
s = 'Café' # type(s) == str (note the accented trailing e)
Ponadto Python 3 dodał obiekt bytes
, odpowiedni do binarnych „obiektów blob” lub zapisu do plików niezależnych od kodowania. Aby utworzyć obiekt bajtów, możesz poprzedzić literę b
literałem ciągu lub wywołać metodę encode
ciągu:
# Or, if you really need a byte string:
s = b'Cafe' # type(s) == bytes
s = 'Café'.encode() # type(s) == bytes
Aby sprawdzić, czy wartość jest łańcuchem, użyj:
isinstance(s, str)
Możliwe jest także prefiksowanie literałów łańcuchowych za pomocą prefiksu u
aby ułatwić kompatybilność między bazami kodu Python 2 i Python 3. Ponieważ w Pythonie 3 wszystkie ciągi znaków są domyślnie Unicode, poprzedzanie literału ciągów u
nie ma wpływu:
u'Cafe' == 'Cafe'
Python 2 za surowy ciąg Unicode przedrostek ur
nie jest obsługiwany, jednak:
>>> ur'Café'
File "<stdin>", line 1
ur'Café'
^
SyntaxError: invalid syntax
Zauważ, że musisz encode
obiekt tekstowy ( str
) Python 3, aby przekonwertować go na bytes
reprezentację tego tekstu. Domyślne kodowanie tej metody to UTF-8 .
Możesz użyć decode
aby zapytać obiekt bytes
o reprezentowany przez niego tekst Unicode:
>>> b.decode()
'Café'
Podczas gdy typ bytes
istnieje zarówno w Pythonie 2, jak i 3, typ unicode
istnieje tylko w Pythonie 2. Aby użyć ukrytych ciągów Unicode w Pythonie 3 w Pythonie 2, dodaj następujący tekst na górze pliku kodu:
from __future__ import unicode_literals
print(repr("hi"))
# u'hi'
Inną ważną różnicą jest to, że indeksowanie bajtów w Pythonie 3 daje w wyniku wynik int
taki:
b"abc"[0] == 97
Podczas krojenia w rozmiar jednego obiektu powstaje obiekt o długości 1 bajtu:
b"abc"[0:1] == b"a"
Ponadto Python 3 naprawia niektóre nietypowe zachowania w Unicode, tj. Odwracanie ciągów bajtów w Pythonie 2. Na przykład rozwiązano następujący 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
Division Integer
Standardowy symbol podziału ( /
) działa inaczej w Pythonie 3 i Pythonie 2, gdy jest stosowany do liczb całkowitych.
Podczas dzielenia liczby całkowitej przez inną liczbę całkowitą w Pythonie 3 operacja dzielenia x / y
reprezentuje prawdziwy podział (używa metody __truediv__
) i daje wynik zmiennoprzecinkowy. Tymczasem ta sama operacja w Pythonie 2 reprezentuje klasyczny podział, który zaokrągla wynik w kierunku ujemnej nieskończoności (znanej również jako zabieranie głosu ).
Na przykład:
Kod | Dane wyjściowe w języku Python 2 | Dane wyjściowe w języku Python 3 |
---|---|---|
3 / 2 | 1 | 1.5 |
2 / 3 | 0 | 0,66666666666666666 |
-3 / 2 | -2 | -1,5 |
Zachowanie zaokrąglania do zera było przestarzałe w Pythonie 2.2 , ale pozostaje w Pythonie 2.7 ze względu na wsteczną kompatybilność i zostało usunięte w Pythonie 3.
Uwaga: Aby uzyskać wynik zmiennoprzecinkowy w Pythonie 2 (bez zaokrąglania podłogi), możemy podać jeden z operandów z kropką dziesiętną. Powyższy przykład 2/3
który daje 0
w Pythonie 2, będzie użyty jako 2 / 3.0
lub 2.0 / 3
lub 2.0/3.0
aby otrzymać 0.6666666666666666
Kod | Dane wyjściowe w języku Python 2 | Dane wyjściowe w języku Python 3 |
---|---|---|
3.0 / 2.0 | 1.5 | 1.5 |
2 / 3.0 | 0,66666666666666666 | 0,66666666666666666 |
-3.0 / 2 | -1,5 | -1,5 |
Istnieje również operator podziału podłogi ( //
), który działa w ten sam sposób w obu wersjach: zaokrągla w dół do najbliższej liczby całkowitej. (chociaż liczba zmiennoprzecinkowa jest zwracana, gdy jest używana z __floordiv__
) W obu wersjach operator //
odwzorowuje na __floordiv__
.
Kod | Dane wyjściowe w języku Python 2 | Dane wyjściowe w języku 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 |
Można jawnie wymusić prawdziwy podział lub podział podłogi za pomocą rodzimych funkcji w module operator
:
from operator import truediv, floordiv
assert truediv(10, 8) == 1.25 # equivalent to `/` in Python 3
assert floordiv(10, 8) == 1 # equivalent to `//`
Jasne i jednoznaczne użycie funkcji operatora dla każdego działu może być uciążliwe. Często preferowana jest zmiana zachowania operatora /
. Powszechną praktyką jest eliminowanie typowego zachowania podziału poprzez dodanie from __future__ import division
jako pierwszej instrukcji w każdym module:
# needs to be the first statement in a module
from __future__ import division
Kod | Dane wyjściowe w języku Python 2 | Dane wyjściowe w języku Python 3 |
---|---|---|
3 / 2 | 1.5 | 1.5 |
2 / 3 | 0,66666666666666666 | 0,66666666666666666 |
-3 / 2 | -1,5 | -1,5 |
from __future__ import division
gwarantuje, że operator /
reprezentuje prawdziwy podział i tylko w modułach zawierających import __future__
, więc nie ma istotnych powodów, aby nie włączać go we wszystkich nowych modułach.
Uwaga : Niektóre inne języki programowania używają zaokrąglania w kierunku zera (obcięcia) zamiast zaokrąglania w dół w kierunku ujemnej nieskończoności, tak jak robi to Python (tj. W tych językach -3 / 2 == -1
). Takie zachowanie może powodować zamieszanie podczas przenoszenia lub porównywania kodu.
Uwaga na argumenty zmiennoprzecinkowe : Zamiast alternatywy from __future__ import division
, można użyć zwykłego symbolu podziału /
i upewnić się, że co najmniej jeden z argumentów jest zmiennoprzecinkowy: 3 / 2.0 == 1.5
. Można to jednak uznać za złą praktykę. Po prostu zbyt łatwo jest napisać average = sum(items) / len(items)
i zapomnieć rzucić jeden z argumentów na zmienną wartość. Co więcej, takie przypadki mogą często unikać powiadomienia podczas testowania, np. Jeśli testujesz na tablicy zawierającej float
ale otrzymujesz tablicę int
w produkcji. Dodatkowo, jeśli ten sam kod jest używany w Pythonie 3, programy, które oczekują, że 3 / 2 == 1
będzie Prawdą, nie będą działać poprawnie.
Zobacz PEP 238, aby uzyskać bardziej szczegółowe uzasadnienie, dlaczego operator podziału został zmieniony w Pythonie 3 i dlaczego należy unikać podziału w starym stylu.
Więcej informacji na temat podziału można znaleźć w temacie Prosta matematyka .
Redukcja nie jest już wbudowana
W Python 2 reduce
jest dostępna albo jako funkcja wbudowana, albo z pakietu functools
(wersja 2.6 i nowsze), podczas gdy w Pythonie 3 reduce
jest dostępna tylko z functools
. Jednak składnia reduce
zarówno w Python2, jak i Python3 jest taka sama i jest reduce(function_to_reduce, list_to_reduce)
.
Jako przykład rozważmy zmniejszenie listy do jednej wartości przez podzielenie każdej z sąsiednich liczb. Tutaj używamy funkcji truediv
z biblioteki operator
.
W Pythonie 2.x jest to tak proste, jak:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator
>>> reduce(operator.truediv, my_list)
0.008333333333333333
W Pythonie 3.x przykład staje się nieco bardziej skomplikowany:
>>> my_list = [1, 2, 3, 4, 5]
>>> import operator, functools
>>> functools.reduce(operator.truediv, my_list)
0.008333333333333333
Możemy również użyć from functools import reduce
aby uniknąć wywoływania reduce
z nazwą przestrzeni nazw.
Różnice między funkcjami zakresu i Xrange
W Pythonie 2 funkcja range
zwraca listę, podczas gdy xrange
tworzy specjalny obiekt xrange
, który jest niezmienną sekwencją, która w przeciwieństwie do innych wbudowanych typów sekwencji, nie obsługuje krojenia i nie ma metod index
ani 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
W Pythonie 3 xrange
został rozszerzony do sekwencji range
, która w ten sposób tworzy teraz obiekt range
. Nie ma typu 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
Ponadto od wersji Python 3.2 range
obsługuje również krojenie, index
i 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
Zaletą używania specjalnego typu sekwencji zamiast listy jest to, że interpreter nie musi przydzielać pamięci dla listy i zapełniać jej:
# range(10000000000000000)
# The output would be:
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# MemoryError
print(xrange(100000000000000000))
# Out: xrange(100000000000000000)
Ponieważ to drugie zachowanie jest ogólnie pożądane, pierwsze zostało usunięte w Pythonie 3. Jeśli nadal chcesz mieć listę w Pythonie 3, możesz po prostu użyć konstruktora list()
na obiekcie range
:
print(list(range(1, 10)))
# Out: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Zgodność
Aby zachować zgodność między wersjami Python 2.xi Python 3.x, możesz użyć builtins
modułu z zewnętrznego pakietu w future
aby osiągnąć zgodność zarówno w przód, jak i wstecz :
#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
w future
bibliotece obsługuje krojenie, index
i count
we wszystkich wersjach Pythona, podobnie jak wbudowana metoda Python 3.2+.
Rozpakowywanie Iterables
W Pythonie 3 możesz rozpakować iterowalny plik, nie znając dokładnej liczby elementów, a nawet mieć zmienną, która zatrzyma jego koniec. W tym celu podajesz zmienną, która może gromadzić listę wartości. Odbywa się to poprzez umieszczenie gwiazdki przed nazwą. Na przykład rozpakowywanie 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
Uwaga: Przy użyciu *variable
składni The variable
zawsze będzie lista, nawet jeśli oryginalny typ nie była lista. Może zawierać zero lub więcej elementów w zależności od liczby elementów na oryginalnej liście.
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
Podobnie rozpakowywanie str
:
begin, *tail = "Hello"
print(begin)
# Out: 'H'
print(tail)
# Out: ['e', 'l', 'l', 'o']
Przykład rozpakowywania date
; _
jest użyty w tym przykładzie jako zmienna jednorazowa (interesuje nas tylko wartość year
):
person = ('John', 'Doe', (10, 16, 2016))
*_, (*_, year_of_birth) = person
print(year_of_birth)
# Out: 2016
Warto wspomnieć, że skoro *
zjada zmienną liczbę przedmiotów, nie możesz mieć dwóch *
tych samych iteracji w zadaniu - nie wiedziałoby, ile elementów trafi do pierwszego rozpakowania, a ile w drugim :
*head, *tail = [1, 2]
# Out: SyntaxError: two starred expressions in assignment
Do tej pory omawialiśmy rozpakowywanie zadań. *
i **
zostały rozszerzone w Pythonie 3.5 . Można teraz mieć kilka operacji rozpakowywania w jednym wyrażeniu:
{*range(4), 4, *(5, 6, 7)}
# Out: {0, 1, 2, 3, 4, 5, 6, 7}
Możliwe jest również rozpakowanie iterowalnego argumentu funkcji:
iterable = [1, 2, 3, 4, 5]
print(iterable)
# Out: [1, 2, 3, 4, 5]
print(*iterable)
# Out: 1 2 3 4 5
Rozpakowanie słownika wykorzystuje dwie sąsiednie gwiazdki **
( PEP 448 ):
tail = {'y': 2, 'z': 3}
{'x': 1, **tail}
# Out: {'x': 1, 'y': 2, 'z': 3}
Umożliwia to zarówno nadpisywanie starych wartości, jak i łączenie słowników.
dict1 = {'x': 1, 'y': 1}
dict2 = {'y': 2, 'z': 3}
{**dict1, **dict2}
# Out: {'x': 1, 'y': 2, 'z': 3}
Python 3 usunął rozpakowywanie krotek w funkcjach. Dlatego poniższe funkcje nie działają w Pythonie 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
Szczegółowe uzasadnienie znajduje się w PEP 3113 .
Zgłaszanie wyjątków i postępowanie z nimi
Oto składnia Python 2, zwróć uwagę na przecinki ,
na linii raise
i except
linii:
try:
raise IOError, "input/output error"
except IOError, exc:
print exc
W Pythonie 3, ,
składnia jest odrzucany i zastąpione przez nawias i as
słowa kluczowego:
try:
raise IOError("input/output error")
except IOError as exc:
print(exc)
W celu zapewnienia kompatybilności wstecznej składnia Python 3 jest również dostępna w Python 2.6 i nowszych wersjach, dlatego należy jej używać do całego nowego kodu, który nie musi być zgodny z poprzednimi wersjami.
Python 3 dodaje również łańcuchy wyjątków , w których można zasygnalizować, że przyczyną tego wyjątku był jakiś inny wyjątek. Na przykład
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from e
Wyjątkiem podniesione w except
oświadczenia jest typu DatabaseError
, ale oryginalny wyjątek jest oznaczony jako __cause__
atrybutem tego wyjątku. Gdy zostanie wyświetlone śledzenie, oryginalny wyjątek zostanie również wyświetlony w śledzeniu:
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')
Jeśli wrzucisz blok except
bez wyraźnego łączenia:
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}')
Tracenie jest
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')
Żadne z nich nie jest obsługiwane w Pythonie 2.x; oryginalny wyjątek i jego śledzenie zostaną utracone, jeśli w bloku wyjątków zostanie zgłoszony inny wyjątek. Do kompatybilności można użyć następującego kodu:
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")
Aby „zapomnieć” wcześniej zgłoszony wyjątek, użyj raise from None
try:
file = open('database.db')
except FileNotFoundError as e:
raise DatabaseError('Cannot open {}') from None
Teraz ślad po prostu byłby
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
DatabaseError('Cannot open database.db')
Lub w celu zapewnienia zgodności zarówno z Pythonem 2, jak i 3, możesz użyć sześciu pakietów w następujący sposób:
import six
try:
file = open('database.db')
except FileNotFoundError as e:
six.raise_from(DatabaseError('Cannot open {}'), None)
Nazwa metody .next () w iteratorach została zmieniona
W Pythonie 2 do iteratora można przechodzić przy użyciu metody o nazwie next
na samym iteratorze:
g = (i for i in range(0, 3))
g.next() # Yields 0
g.next() # Yields 1
g.next() # Yields 2
W Pythonie 3 zmieniono nazwę metody .next
na .__next__
, uznając jej rolę „magiczną”, dlatego wywołanie .next
wywoła błąd AttributeError
. Prawidłowym sposobem uzyskania dostępu do tej funkcji zarówno w Pythonie 2, jak i Pythonie 3 jest wywołanie next
funkcji z iteratorem jako argumentem.
g = (i for i in range(0, 3))
next(g) # Yields 0
next(g) # Yields 1
next(g) # Yields 2
Ten kod jest przenośny w wersjach od 2.6 do aktualnych wydań.
Porównanie różnych typów
Obiekty różnych typów można porównywać. Wyniki są arbitralne, ale spójne. Są one uporządkowane w taki sposób, że None
jest mniejsza niż cokolwiek innego, typy numeryczne są mniejsze niż typy nienumeryczne, a wszystko inne jest uporządkowane leksykograficznie według typu. Zatem liczba int
jest mniejsza niż str
a tuple
jest większa niż 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
Zrobiono to pierwotnie, aby można było sortować listę typów mieszanych, a obiekty grupować według typu:
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)]
Pojawia się wyjątek podczas porównywania różnych (nienumerycznych) typów:
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()
Aby posortować listy mieszane w Pythonie 3 według typów i osiągnąć zgodność między wersjami, musisz podać klucz do posortowanej funkcji:
>>> 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}]
Użycie str
jako funkcji key
tymczasowo konwertuje każdy element na ciąg tylko dla celów porównania. Następnie widzi ciąg znaków rozpoczynający się od [
, '
, {
lub 0-9
i jest w stanie posortować te (i wszystkie następujące znaki).
Wprowadzane przez użytkownika
W Pythonie 2 dane wejściowe użytkownika są akceptowane przy użyciu funkcji raw_input
,
user_input = raw_input()
Podczas gdy w Pythonie 3 dane wejściowe użytkownika są akceptowane przy użyciu funkcji input
.
user_input = input()
W Pythonie 2, input
funkcja zaakceptuje wejście i zinterpretować. Chociaż może to być przydatne, ma kilka względów bezpieczeństwa i zostało usunięte w Pythonie 3. Aby uzyskać dostęp do tej samej funkcjonalności, można użyć eval(input())
.
Aby skrypt był przenośny w obu wersjach, możesz umieścić kod poniżej w górnej części skryptu Python:
try:
input = raw_input
except NameError:
pass
Zmiany metody słownikowej
W Pythonie 3 wiele metod słownikowych różni się zachowaniem od Pythona 2, a wiele też zostało usuniętych: has_key
, iter*
i view*
zniknęły. Zamiast d.has_key(key)
, który był od dawna przestarzały, należy teraz użyć key in d
.
W Pythonie 2 keys
metod słownikowych, values
i items
zwracają listy. W Pythonie 3 zwracają obiekty widoku ; obiekty widoku nie są iteratorami i różnią się od nich na dwa sposoby, a mianowicie:
- mają rozmiar (można na nich użyć funkcji
len
) - można je powtarzać wiele razy
Dodatkowo, podobnie jak w iteratorach, zmiany w słowniku są odzwierciedlane w obiektach widoku.
Python 2.7 przeportował te metody z Python 3; są dostępne jako viewkeys
, wartości viewvalues
i viewitems
. Aby przekształcić kod Python 2 na kod Python 3, odpowiednie formularze to:
-
d.keys()
,d.values()
id.items()
w Pythonie 2 należy zmienić nalist(d.keys())
,list(d.values())
ilist(d.items())
-
d.iterkeys()
,d.itervalues()
id.iteritems()
należy zmienić naiter(d.keys())
lub nawet lepiej,iter(d)
;iter(d.values())
iiter(d.items())
odpowiednio - i wreszcie metoda Python 2.7 wywołuje
d.viewkeys()
,d.viewvalues()
id.viewitems()
można zastąpićd.keys()
,d.values()
id.items()
.
Przenoszenie kodu w języku Python 2, który iteruje klucze, wartości lub elementy słownika podczas mutowania, jest czasem trudne. Rozważać:
d = {'a': 0, 'b': 1, 'c': 2, '!': 3}
for key in d.keys():
if key.isalpha():
del d[key]
Kod wygląda tak, jakby działał podobnie w Pythonie 3, ale tam metoda keys
zwraca obiekt widoku, a nie listę, a jeśli słownik zmienia rozmiar podczas iteracji, kod Python 3 RuntimeError: dictionary changed size during iteration
awarii z RuntimeError: dictionary changed size during iteration
. Rozwiązaniem jest oczywiście prawidłowe wpisanie for key in list(d)
.
Podobnie obiekty widoku zachowują się inaczej niż iteratory: nie można na nich używać funkcji next()
i nie można wznowić iteracji; zamiast tego uruchomiłby się ponownie; Jeżeli kod Pythona 2 przechodzi przez wartość powrotną d.iterkeys()
, d.itervalues()
lub d.iteritems()
sposobu wymagającej iterację zamiast iterowalny, to powinny być iter(d)
, iter(d.values())
lub iter(d.items())
w Pythonie 3.
Instrukcja exec jest funkcją w Pythonie 3
W Pythonie 2 exec
jest instrukcją ze specjalną składnią: exec code [in globals[, locals]].
W Python 3 exec
jest teraz funkcją: exec(code, [, globals[, locals]])
, a składnia Python 2 wywoła błąd SyntaxError
.
Ponieważ zmieniono print
z instrukcji na funkcję, dodano również import __future__
. Nie istnieje jednak from __future__ import exec_function
, ponieważ nie jest potrzebna: instrukcja exec w Pythonie 2 może być również używana ze składnią, która wygląda dokładnie tak, jak wywołanie funkcji exec
w Pythonie 3. W ten sposób można zmienić instrukcje
exec 'code'
exec 'code' in global_vars
exec 'code' in global_vars, local_vars
do form
exec('code')
exec('code', global_vars)
exec('code', global_vars, local_vars)
a te ostatnie formy gwarantują identyczne działanie zarówno w Pythonie 2, jak i Pythonie 3.
błąd funkcji hasattr w Pythonie 2
W Pythonie 2, gdy właściwość zgłosi błąd, hasattr
zignoruje tę właściwość, zwracając wartość 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
Ten błąd został naprawiony w Python3. Więc jeśli używasz Python 2, użyj
try:
a.get
except AttributeError:
print("no get property!")
lub zamiast tego użyj getattr
p = getattr(a, "get", None)
if p is not None:
print(p)
else:
print("no get property!")
Zmieniono nazwy modułów
Zmieniono nazwę kilku modułów w bibliotece standardowej:
Stara nazwa | Nowe imie |
---|---|
_winreg | winreg |
ConfigParser | configparser |
copy_reg | copyreg |
Kolejka | kolejka |
SocketServer | serwer gniazd |
_markupbase | znaczniki |
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 |
Niektóre moduły zostały nawet przekonwertowane z plików do bibliotek. Jako przykład weź tkinter i urllib z góry.
Zgodność
Zachowując zgodność między wersjami Python 2.xi 3.x, można użyć future
pakietu zewnętrznego, aby umożliwić importowanie standardowych pakietów bibliotek najwyższego poziomu z nazwami Python 3.x w wersjach Python 2.x.
Stałe ósemkowe
W Python 2 literał ósemkowy można zdefiniować jako
>>> 0755 # only Python 2
Aby zapewnić zgodność krzyżową, użyj
0o755 # both Python 2 and Python 3
Wszystkie klasy są „klasami w nowym stylu” w Pythonie 3.
W Pythonie 3.x
wszystkie klasy są klasami w nowym stylu ; podczas definiowania nowego klasy python domyślnie powoduje, że dziedziczy on po object
. Jako takie, określenie object
w definicji class
jest całkowicie opcjonalne:
class X: pass
class Y(object): pass
Obie te klasy zawierają teraz object
w swoim mro
(kolejność rozwiązywania metod):
>>> X.__mro__
(__main__.X, object)
>>> Y.__mro__
(__main__.Y, object)
W Python 2.x
klasy są domyślnie klasami w starym stylu; nie dziedziczą domyślnie po object
. Powoduje to, że semantyka klas różni się w zależności od tego, czy jawnie dodamy object
jako class
bazową:
class X: pass
class Y(object): pass
W takim przypadku, jeśli spróbujemy wydrukować __mro__
Y
, __mro__
podobne dane wyjściowe jak w przypadku Python 3.x
:
>>> Y.__mro__
(<class '__main__.Y'>, <type 'object'>)
Dzieje się tak, ponieważ podczas definiowania go jawnie dziedziczyliśmy Y
po obiekcie: class Y(object): pass
. W przypadku klasy X
która nie dziedziczy po obiekcie, atrybut __mro__
nie istnieje, próba uzyskania do niego dostępu powoduje błąd AttributeError
.
Aby zapewnić zgodność między obiema wersjami Pythona, klasy można zdefiniować z object
jako klasą podstawową:
class mycls(object):
"""I am fully compatible with Python 2/3"""
Alternatywnie, jeśli zmienna __metaclass__
jest ustawiona na type
w zakresie globalnym, wszystkie później zdefiniowane klasy w danym module mają domyślnie nowy styl bez potrzeby jawnego dziedziczenia po object
:
__metaclass__ = type
class mycls:
"""I am also fully compatible with Python 2/3"""
Usunięto operatory <> i ``, równoznaczne z! = I repr ()
W Pythonie 2 <>
jest synonimem !=
; podobnie, `foo`
jest synonimem 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
kodowanie / dekodowanie na hex nie jest już dostępne
"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'
Jednak, jak sugeruje komunikat o błędzie, możesz użyć modułu codecs
, aby osiągnąć ten sam wynik:
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'
Zauważ, że codecs.encode
zwraca obiekt bytes
. Aby uzyskać obiekt str
po prostu decode
do ASCII:
codecs.encode(b'\x1d\xea\xdb\xee\xff', 'hex').decode('ascii')
# Out: '1deadbeeff'
usunięta funkcja cmp w Pythonie 3
W Pythonie 3 wbudowana funkcja cmp
została usunięta wraz ze specjalną metodą __cmp__
.
Z dokumentacji:
Funkcję
cmp()
należy traktować jako__cmp__()
, a specjalna metoda__cmp__()
nie jest już obsługiwana. Użyj__lt__()
do sortowania,__eq__()
z__hash__()
i innymi szczegółowymi porównaniami w razie potrzeby. (Jeśli naprawdę potrzebujesz funkcjicmp()
, możesz użyć wyrażenia(a > b) - (a < b)
jako odpowiednikacmp(a, b)
.)
Ponadto wszystkie funkcje wbudowane, które przyjęły cmp
parametr teraz akceptować tylko key
słowa kluczowego tylko parametr.
W module functools
znajduje się również przydatna funkcja cmp_to_key(func)
która pozwala przekonwertować funkcję cmp
styl key
:
Przekształć funkcję porównania w starym stylu w funkcję kluczową. Używany z narzędziami, które akceptują kluczowe funkcje (takie jak
sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
). Ta funkcja jest używana przede wszystkim jako narzędzie przejściowe dla programów konwertowanych z Python 2, które wspierały użycie funkcji porównawczych.
Nieszczelne zmienne w rozumieniu listy
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!'
Jak widać z przykładu, w Pythonie 2 wyciekła wartość x
: zamaskowała ona hello world!
i wydrukował U
, ponieważ była to ostatnia wartość x
po zakończeniu pętli.
Jednak w Pythonie 3 x
drukuje pierwotnie zdefiniowany hello world!
, ponieważ zmienna lokalna ze zrozumienia listy nie maskuje zmiennych z otaczającego zakresu.
Dodatkowo, ani wyrażenia generatora (dostępne w Pythonie od wersji 2.5), ani słownik, ani zestaw wyrażeń (które zostały przeniesione do Pythona 2.7 z Pythona 3) nie wyciekają zmiennych w Pythonie 2.
Zauważ, że zarówno w Pythonie 2, jak i Pythonie 3, zmienne będą przeciekać do otaczającego zakresu, gdy używa się pętli for:
x = 'hello world!'
vowels = []
for x in 'AEIOU':
vowels.append(x)
print(x)
# Out: 'U'
mapa()
map()
jest wbudowanym narzędziem, które jest przydatne do zastosowania funkcji do elementów iterowalnych. W Pythonie 2 map
zwraca listę. W Pythonie 3 map
zwraca obiekt mapy , który jest generatorem.
# 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']
W Pythonie 2 możesz przekazać None
aby służył jako funkcja tożsamości. To już nie działa w Pythonie 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
Ponadto, przy przejściu więcej niż jeden iterable jako argument w Pythonie 2, map
tarcze krótsze iterables z None
(podobny do itertools.izip_longest
). W Pythonie 3 iteracja zatrzymuje się po najkrótszej iteracji.
W 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)]
W 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)]
Uwaga : zamiast map
rozważ użycie list, które są zgodne z Python 2/3. Zamiana map(str, [1, 2, 3, 4, 5])
:
>>> [str(i) for i in [1, 2, 3, 4, 5]]
['1', '2', '3', '4', '5']
filter (), map () i zip () zwracają iteratory zamiast sekwencji
W filter
Python 2 wbudowane funkcje map
i zip
zwracają sekwencję. map
i zip
zawsze zwracają listę, podczas gdy z filter
typ zwrotu zależy od typu danego parametru:
>>> 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)]
W filter
Python 3 iterator map
i zip
zwraca zamiast tego:
>>> 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)]
Ponieważ Python 2 itertools.izip
jest odpowiednikiem Python 3 zip
izip
został usunięty z Python 3.
Import bezwzględny / względny
W Pythonie 3 PEP 404 zmienia sposób importowania z Pythona 2. Implikowany import względny nie jest już dozwolony w pakietach, a from ... import *
jest dozwolony tylko w kodzie poziomu modułu.
Aby osiągnąć zachowanie Python 3 w Python 2:
- funkcję importu bezwzględnego można włączyć za pomocą opcji
from __future__ import absolute_import
- zachęca się do wyraźnego względnego importu zamiast domyślnego importu względnego
Dla wyjaśnienia, w Pythonie 2 moduł może importować zawartość innego modułu znajdującego się w tym samym katalogu w następujący sposób:
import foo
Zauważ, że lokalizacja foo
jest niejednoznaczna na podstawie samej instrukcji importu. Ten rodzaj niejawnego importu względnego jest zatem odradzany na rzecz jawnego importu względnego , który wygląda następująco:
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
Kropka .
pozwala na jednoznaczne zadeklarowanie lokalizacji modułu w drzewie katalogów.
Więcej na temat importu względnego
Zastanów się nad pakietem zdefiniowanym przez użytkownika o nazwie shapes
. Struktura katalogów jest następująca:
shapes
├── __init__.py
|
├── circle.py
|
├── square.py
|
└── triangle.py
circle.py
, square.py
i triangle.py
wszystkie importują util.py
jako moduł. Jak będą odnosić się do modułu na tym samym poziomie?
from . import util # use util.PI, util.sq(x), etc
LUB
from .util import * #use PI, sq(x), etc to call functions
The .
służy do importu względnego na tym samym poziomie.
Teraz rozważ alternatywny układ modułu shapes
:
shapes
├── __init__.py
|
├── circle
│ ├── __init__.py
│ └── circle.py
|
├── square
│ ├── __init__.py
│ └── square.py
|
├── triangle
│ ├── __init__.py
│ ├── triangle.py
|
└── util.py
Jak te 3 klasy będą odnosić się do util.py?
from .. import util # use util.PI, util.sq(x), etc
LUB
from ..util import * # use PI, sq(x), etc to call functions
..
służy do importu względnego na poziomie nadrzędnym. Dodaj więcej .
s z liczbą poziomów między rodzicem a dzieckiem.
Plik I / O
file
nie jest już wbudowaną nazwą w wersji 3.x ( open
nadal działa).
Wewnętrzne szczegóły pliku I / O zostały przeniesione do standardowego modułu biblioteki io
, który jest także nowym domem 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'
Tryb pliku (tekst kontra plik binarny) określa teraz typ danych generowanych przez odczyt pliku (i typ wymagany do zapisu):
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
Domyślnie kodowanie plików tekstowych jest zwracane przez locale.getpreferredencoding(False)
. Aby jawnie określić kodowanie, użyj parametru słowa kluczowego encoding
:
with open('old_japanese_poetry.txt', 'shift_jis') as text:
haiku = text.read()
Funkcja round () przerywa remis i zwraca typ
remis w rundzie ()
W Pythonie 2 użycie round()
na liczbie równej dwóm liczbom całkowitym zwróci wartość najdalszą od 0. Na przykład:
round(1.5) # Out: 2.0
round(0.5) # Out: 1.0
round(-0.5) # Out: -1.0
round(-1.5) # Out: -2.0
Jednak w Pythonie 3 round()
zwróci parzystą liczbę całkowitą (aka zaokrąglenia bankowców ). Na przykład:
round(1.5) # Out: 2
round(0.5) # Out: 0
round(-0.5) # Out: 0
round(-1.5) # Out: -2
Funkcja round () jest zgodna ze strategią zaokrąglania od połowy do parzystości, która zaokrągla liczby w połowie do najbliższej parzystej liczby całkowitej (na przykład, round(2.5)
zwraca teraz 2 zamiast 3,0).
Zgodnie z odniesieniem w Wikipedii , jest to również znane jako zaokrąglanie bezstronne, zaokrąglanie zbieżne, zaokrąglanie statystyki , holenderskie, zaokrąglanie Gaussa lub zaokrąglanie nieparzyste .
Zaokrąglanie od połowy do nawet jest częścią standardu IEEE 754, a także jest domyślnym trybem zaokrąglania w Microsoft .NET.
Ta strategia zaokrąglania ma tendencję do zmniejszania całkowitego błędu zaokrąglania. Ponieważ średnio liczba zaokrąglonych w górę jest równa liczbie zaokrąglonych w dół, błędy zaokrąglania są anulowane. Inne metody zaokrąglania mają tendencję do odchylenia w górę lub w dół w średnim błędzie.
typ zwrotu round ()
Funkcja round()
zwraca typ float
w Pythonie 2.7
round(4.8)
# 5.0
Począwszy od Pythona 3.0, jeśli drugi argument (ilość cyfr) jest pominięty, zwraca int
.
round(4.8)
# 5
Prawda, fałsz i brak
W Python 2 True
, False
i None
są wbudowanymi stałymi. Co oznacza, że można je ponownie przypisać.
True, False = False, True
True # False
False # True
Nie można tego zrobić z None
od wersji Python 2.4.
None = None # SyntaxError: cannot assign to None
W Pythonie 3 True
, False
i None
są teraz słowami kluczowymi.
True, False = False, True # SyntaxError: can't assign to keyword
None = None # SyntaxError: can't assign to keyword
Zwraca wartość podczas zapisu do obiektu pliku
W Pythonie 2 pisanie bezpośrednio do uchwytu pliku zwraca None
:
hi = sys.stdout.write('hello world\n')
# Out: hello world
type(hi)
# Out: <type 'NoneType'>
W Pythonie 3 pisanie do uchwytu zwróci liczbę znaków zapisanych podczas pisania tekstu oraz liczbę bajtów zapisanych podczas pisania bajtów:
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
W Pythonie 2 każda liczba całkowita większa niż C ssize_t
byłaby konwertowana na long
typ danych, oznaczony sufiksem L
na literale. Na przykład w 32-bitowej wersji Pythona:
>>> 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
Jednak w Pythonie 3 long
typ danych został usunięty; bez względu na to, jak duży jest liczbą całkowitą, to będzie int
.
2**1024
# Output: 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
print(-(2**1024))
# Output: -179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
type(2**1024)
# Output: <class 'int'>
Klasa Wartość logiczna
W Pythonie 2, jeśli chcesz samodzielnie zdefiniować wartość logiczną klasy, musisz zaimplementować metodę __nonzero__
w swojej klasie. Wartość domyślna to True.
class MyClass:
def __nonzero__(self):
return False
my_instance = MyClass()
print bool(MyClass) # True
print bool(my_instance) # False
W Pythonie 3 zamiast __bool__
jest używane __nonzero__
class MyClass:
def __bool__(self):
return False
my_instance = MyClass()
print(bool(MyClass)) # True
print(bool(my_instance)) # False