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