Wielu początkujących użytkowników Pythona zastanawia się, od której wersji Pythona powinni zacząć. Moją odpowiedzią na to pytanie jest zazwyczaj coś w stylu „po prostu idź z wersją, w której został napisany twój ulubiony tutorial i sprawdź różnice później.”
Ale co jeśli zaczynasz nowy projekt i masz wybór? Powiedziałbym, że obecnie nie ma „dobrego” lub „złego” wyboru, o ile Python 2.7.x i Python 3.x obsługują biblioteki, których zamierzasz używać. Warto jednak przyjrzeć się głównym różnicom pomiędzy tymi dwoma najpopularniejszymi wersjami Pythona, aby uniknąć typowych pułapek podczas pisania kodu dla którejś z nich, lub jeśli planujesz przeportować swój projekt.
Sekcje
- Sekcje
- Moduł
__future__
- Funkcja print
- Python 2
- Python 3
- Działanie liczb całkowitych.
- Python 2
- Python 3
- Unicode
- Python 2
- Python 3
- xrange
- Python 2
- Python 3
- The
__contains__
metoda dlarange
obiektów w Pythonie 3- Uwaga o różnicach w szybkości w Pythonie 2 i 3
- Podnoszenie wyjątków
- Python 2
- Python 3
- Obsługiwanie wyjątków
- Python 2
- Python 3
-
- Python 2
- Python 3
- Zmienne pętli for-.pętli i wyciek globalnej przestrzeni nazw
- Python 2
- Python 3
- Porównanie typów nieuporządkowanych
- Python 2
- Python 3
- Porównanie typów nieuporządkowanych
- Python 2
- Python 3
- Python 2
- Python 3
- Python 2
- Python 3
- Python 2
- Python 3
Moduł __future__
Python 3.x wprowadził pewne słowa kluczowe i funkcje niekompatybilne z Pythonem 2, które można zaimportować za pomocą wbudowanego modułu __future__
w Pythonie 2. Zaleca się używanie importu __future__
, jeśli planujesz wsparcie Pythona 3.x dla swojego kodu. Na przykład, jeśli chcemy, aby Python 3.x’s integer division behavior w Pythonie 2, możemy go zaimportować poprzez
from __future__ import division
Więcej funkcji, które można zaimportować z modułu __future__
wymieniono w poniższej tabeli:
feature | optional in | mandatory in | effect |
---|---|---|---|
nested_scopes | 2.1.0b1 | 2.2 | PEP 227:Statically Nested Scopes |
generators | 2.2.0a1 | 2.3 | PEP 255:Simple Generators |
division | 2.2.0a2 | 3.0 | PEP 238:Changing the Division Operator |
absolute_import | 2.5.0a1 | 3.0 | PEP 328:Imports: Multi-Line and Absolute/Relative |
with_statement | 2.5.0a1 | 2.6 | PEP 343:The „with” Statement |
print_function | 2.6.0a2 | 3.0 | PEP 3105:Make print a function |
unicode_literals | 2.6.0a2 | 3.0 | PEP 3112:Bytes literals in Python 3000 |
from platform import python_version
Funkcja print
Bardzo trywialna, a zmiana w składni print jest prawdopodobnie najbardziej znaną zmianą, ale mimo to warto o niej wspomnieć: Instrukcja print w Pythonie 2 została zastąpiona funkcją print()
, co oznacza, że musimy zawinąć obiekt, który chcemy wydrukować w parantele.
Python 2 nie ma problemu z dodatkowymi nawiasami, ale w przeciwieństwie do niego Python 3 podniósłby SyntaxError
, gdybyśmy wywołali funkcję print w Pythonie 2 bez nawiasów.
Python 2
print 'Python', python_version()print 'Hello, World!'print('Hello, World!')print "text", ; print 'print more text on the same line'
Python 2.7.6Hello, World!Hello, World!text print more text on the same line
Python 3
print('Python', python_version())print('Hello, World!')print("some text,", end="")print(' print more text on the same line')
Python 3.4.1Hello, World!some text, print more text on the same line
print 'Hello, World!'
File "<ipython-input-3-139a7c5835bd>", line 1 print 'Hello, World!' ^SyntaxError: invalid syntax
Uwaga:
Wydrukowanie „Hello, World” powyżej za pomocą Pythona 2 wyglądało całkiem „normalnie”. Jednakże, jeśli mamy wiele obiektów wewnątrz paranteli, utworzymy tuple, ponieważ print
jest „oświadczeniem” w Pythonie 2, a nie wywołaniem funkcji.
print 'Python', python_version()print('a', 'b')print 'a', 'b'
Python 2.7.7('a', 'b')a b
Działanie liczb całkowitych
Ta zmiana jest szczególnie niebezpieczna, jeśli portujesz kod, lub jeśli wykonujesz kod Pythona 3 w Pythonie 2, ponieważ zmiana w zachowaniu dzielenia liczb całkowitych może często pozostać niezauważona (nie powoduje wyświetlenia komunikatu SyntaxError
).
Więc nadal mam tendencję do używania float(3)/2
lub 3/2.0
zamiast 3/2
w moich skryptach Pythona 3, aby zaoszczędzić chłopakom z Pythona 2 trochę kłopotów (i vice versa, Polecam from __future__ import division
w twoich skryptach Pythona 2).
Python 2
print 'Python', python_version()print '3 / 2 =', 3 / 2print '3 // 2 =', 3 // 2print '3 / 2.0 =', 3 / 2.0print '3 // 2.0 =', 3 // 2.0
Python 2.7.63 / 2 = 13 // 2 = 13 / 2.0 = 1.53 // 2.0 = 1.0
Python 3
print('Python', python_version())print('3 / 2 =', 3 / 2)print('3 // 2 =', 3 // 2)print('3 / 2.0 =', 3 / 2.0)print('3 // 2.0 =', 3 // 2.0)
Python 3.4.13 / 2 = 1.53 // 2 = 13 / 2.0 = 1.53 // 2.0 = 1.0
Unicode
Python 2 posiada typy ASCII str()
, oddzielne typy unicode()
, ale nie ma typu byte
.
Teraz, w Pythonie 3, mamy wreszcie Unicode (utf-8) str
ings, i 2 klasy bajtów: byte
i bytearray
s.
Python 2
print 'Python', python_version()
Python 2.7.6
print type(unicode('this is like a python3 str type'))
<type 'unicode'>
print type(b'byte type does not exist')
<type 'str'>
print 'they are really' + b' the same'
they are really the same
print type(bytearray(b'bytearray oddly does exist though'))
<type 'bytearray'>
Python 3
print('Python', python_version())print('strings are now utf-8 \u03BCnico\u0394é!')
Python 3.4.1strings are now utf-8 μnicoΔé!
print('Python', python_version(), end="")print(' has', type(b' bytes for storing data'))
Python 3.4.1 has <class 'bytes'>
print('and Python', python_version(), end="")print(' also has', type(bytearray(b'bytearrays')))
and Python 3.4.1 also has <class 'bytearray'>
'note that we cannot add a string' + b'bytes for data'
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-13-d3e8942ccf81> in <module>()----> 1 'note that we cannot add a string' + b'bytes for data'TypeError: Can't convert 'bytes' object to str implicitly
xrange
Użycie xrange()
jest bardzo popularne w Pythonie 2.x do tworzenia obiektu iterowalnego, np, w pętli for lub list/set-dictionary-comprehension.
Zachowanie było dość podobne do generatora (tj, „lazy evaluation”), ale w tym przypadku xrange-iterable nie jest wyczerpywalny – co oznacza, że można nad nim iterować w nieskończoność.
Dzięki „lazy-evaluation”, zaletą zwykłego range()
jest to, że xrange()
jest generalnie szybszy, jeśli trzeba nad nim iterować tylko raz (np. w pętli for). Jednak w przeciwieństwie do iteracji 1-krotnych, nie jest to zalecane, jeśli powtarzasz iterację wiele razy, ponieważ generowanie odbywa się za każdym razem od zera!
W Pythonie 3, funkcja range()
została zaimplementowana jak funkcja xrange()
, dzięki czemu dedykowana funkcja xrange()
już nie istnieje (xrange()
podnosi NameError
w Pythonie 3).
import timeitn = 10000def test_range(n): return for i in range(n): passdef test_xrange(n): for i in xrange(n): pass
Python 2
print 'Python', python_version()print '\ntiming range()'%timeit test_range(n)print '\n\ntiming xrange()'%timeit test_xrange(n)
Python 2.7.6timing range()1000 loops, best of 3: 433 µs per looptiming xrange()1000 loops, best of 3: 350 µs per loop
Python 3
print('Python', python_version())print('\ntiming range()')%timeit test_range(n)
Python 3.4.1timing range()1000 loops, best of 3: 520 µs per loop
print(xrange(10))
---------------------------------------------------------------------------NameError Traceback (most recent call last)<ipython-input-5-5d8f9b79ea70> in <module>()----> 1 print(xrange(10))NameError: name 'xrange' is not defined
Metoda __contains__ dla obiektów zakresu w Pythonie 3
Inną rzeczą, o której warto wspomnieć jest to, że range
dostał „nową” __contains__
metodę w Pythonie 3.x (dzięki Yuchen Ying, który zwrócił na to uwagę). Metoda __contains__
może przyspieszyć „look-ups” w Pythonie 3.x range
znacznie dla typów całkowitych i Boolean.
x = 10000000
def val_in_range(x, val): return val in range(x)
def val_in_xrange(x, val): return val in xrange(x)
print('Python', python_version())assert(val_in_range(x, x/2) == True)assert(val_in_range(x, x//2) == True)%timeit val_in_range(x, x/2)%timeit val_in_range(x, x//2)
Python 3.4.11 loops, best of 3: 742 ms per loop1000000 loops, best of 3: 1.19 µs per loop
Na podstawie timeit
wyników powyżej, widać, że wykonanie dla „look up” było o około 60 000 szybsze, gdy był to typ integer, a nie float. Jednakże, ponieważ Python 2.x’s range
lub xrange
nie ma metody __contains__
, „prędkość wyszukiwania” nie byłaby tak bardzo różna dla liczb całkowitych lub pływaków:
print 'Python', python_version()assert(val_in_xrange(x, x/2.0) == True)assert(val_in_xrange(x, x/2) == True)assert(val_in_range(x, x/2) == True)assert(val_in_range(x, x//2) == True)%timeit val_in_xrange(x, x/2.0)%timeit val_in_xrange(x, x/2)%timeit val_in_range(x, x/2.0)%timeit val_in_range(x, x/2)
Python 2.7.71 loops, best of 3: 285 ms per loop1 loops, best of 3: 179 ms per loop1 loops, best of 3: 658 ms per loop1 loops, best of 3: 556 ms per loop
Poniżej „dowody”, że metoda __contain__
nie została dodana do Pythona 2.x jeszcze:
print('Python', python_version())range.__contains__
Python 3.4.1<slot wrapper '__contains__' of 'range' objects>
print 'Python', python_version()range.__contains__
Python 2.7.7---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-7-05327350dafb> in <module>() 1 print 'Python', python_version()----> 2 range.__contains__AttributeError: 'builtin_function_or_method' object has no attribute '__contains__'
print 'Python', python_version()xrange.__contains__
print 'Python', python_version()xrange.__contains__
Python 2.7.7---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-8-7d1a71bfee8e> in <module>() 1 print 'Python', python_version()----> 2 xrange.__contains__AttributeError: type object 'xrange' has no attribute '__contains__'
Uwaga na temat różnic prędkości w Pythonie 2 i 3
Niektórzy zwrócili uwagę na różnicę prędkości między Pythonem 3’s range()
i Pythonem2’s xrange()
. Ponieważ są one zaimplementowane w ten sam sposób, można by się spodziewać tej samej prędkości. Jednak różnica tutaj po prostu pochodzi z faktu, że Python 3 ogólnie ma tendencję do działania wolniej niż Python 2.
def test_while(): i = 0 while i < 20000: i += 1 return
print('Python', python_version())%timeit test_while()
Python 3.4.1100 loops, best of 3: 2.68 ms per loop
print 'Python', python_version()%timeit test_while()
Python 2.7.61000 loops, best of 3: 1.72 ms per loop
Raising exceptions
Gdzie Python 2 akceptuje obie notacje, starą” i „nową” składnię, Python 3 dławi się (i podnosi z kolei SyntaxError
), jeśli nie zawrzemy argumentu wyjątku w nawiasach:
Python 2
print 'Python', python_version()
Python 2.7.6
raise IOError, "file error"
---------------------------------------------------------------------------IOError Traceback (most recent call last)<ipython-input-8-25f049caebb0> in <module>()----> 1 raise IOError, "file error"IOError: file error
raise IOError("file error")
---------------------------------------------------------------------------IOError Traceback (most recent call last)<ipython-input-9-6f1c43f525b2> in <module>()----> 1 raise IOError("file error")IOError: file error
Python 3
print('Python', python_version())
Python 3.4.1
raise IOError, "file error"
File "<ipython-input-10-25f049caebb0>", line 1 raise IOError, "file error" ^SyntaxError: invalid syntax
Prawidłowy sposób zgłaszania wyjątków w Pythonie 3:
print('Python', python_version())raise IOError("file error")
Python 3.4.1---------------------------------------------------------------------------OSError Traceback (most recent call last)<ipython-input-11-c350544d15da> in <module>() 1 print('Python', python_version())----> 2 raise IOError("file error")OSError: file error
Obsługa wyjątków
W Pythonie 3 zmieniła się również nieco obsługa wyjątków. W Pythonie 3 musimy teraz używać słowa kluczowego „as
„
Python 2
print 'Python', python_version()try: let_us_cause_a_NameErrorexcept NameError, err: print err, '--> our error message'
Python 2.7.6name 'let_us_cause_a_NameError' is not defined --> our error message
Python 3
print('Python', python_version())try: let_us_cause_a_NameErrorexcept NameError as err: print(err, '--> our error message')
Python 3.4.1name 'let_us_cause_a_NameError' is not defined --> our error message
Ponieważ next()
.next()
) jest tak powszechnie używaną funkcją (metodą), jest to kolejna zmiana składni (a raczej zmiana w implementacji), o której warto wspomnieć: gdzie można używać zarówno składni funkcji, jak i metody w Pythonie 2.7.5, funkcja next()
jest wszystkim, co pozostało w Pythonie 3 (wywołanie metody .next()
podnosi AttributeError
).
Python 2
print 'Python', python_version()my_generator = (letter for letter in 'abcdefg')next(my_generator)my_generator.next()
Python 2.7.6'b'
Python 3
print('Python', python_version())my_generator = (letter for letter in 'abcdefg')next(my_generator)
Python 3.4.1'a'
my_generator.next()
---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-14-125f388bb61b> in <module>()----> 1 my_generator.next()AttributeError: 'generator' object has no attribute 'next'
For-…loop variables and the global namespace leak
Dobra wiadomość to: W Pythonie 3.x zmienne for-loop nie wyciekają już do globalnej przestrzeni nazw!
Wraca to do zmiany, która została wprowadzona w Pythonie 3.x i jest opisana w What’s New In Python 3.0 w następujący sposób:
„List comprehensions nie obsługują już formy składniowej . Zamiast tego należy użyć
. Zauważ też, że list comprehensions mają inną semantykę: są bliższe syntaktycznemu cukrowi dla wyrażenia generatora wewnątrz konstruktora
list()
, a w szczególności zmienne kontrolne pętli nie są już wyciekane do otaczającego zakresu.”
Python 2
print 'Python', python_version()i = 1print 'before: i =', iprint 'comprehension: ', print 'after: i =', i
Python 2.7.6before: i = 1comprehension: after: i = 4
Python 3
print('Python', python_version())i = 1print('before: i =', i)print('comprehension:', )print('after: i =', i)
Python 3.4.1before: i = 1comprehension: after: i = 1
Porównywanie typów nieuporządkowanych
Kolejną miłą zmianą w Pythonie 3 jest to, że TypeError
jest podnoszony jako ostrzeżenie, jeśli próbujemy porównać typy nieuporządkowane.
Python 2
print 'Python', python_version()print " > 'foo' = ", > 'foo'print "(1, 2) > 'foo' = ", (1, 2) > 'foo'print " > (1, 2) = ", > (1, 2)
Python 2.7.6 > 'foo' = False(1, 2) > 'foo' = True > (1, 2) = False
Python 3
print('Python', python_version())print(" > 'foo' = ", > 'foo')print("(1, 2) > 'foo' = ", (1, 2) > 'foo')print(" > (1, 2) = ", > (1, 2))
Python 3.4.1---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-16-a9031729f4a0> in <module>() 1 print('Python', python_version())----> 2 print(" > 'foo' = ", > 'foo') 3 print("(1, 2) > 'foo' = ", (1, 2) > 'foo') 4 print(" > (1, 2) = ", > (1, 2))TypeError: unorderable types: list() > str()
Parsing user inputs via input()
Na szczęście, funkcja input()
została naprawiona w Pythonie 3 tak, że zawsze przechowuje dane wejściowe użytkownika jako obiekty str
. Aby uniknąć niebezpiecznego zachowania w Pythonie 2, polegającego na wczytywaniu innych typów niż strings
, musimy zamiast tego użyć raw_input()
.
Python 2
Python 2.7.6 na darwinType "help", "copyright", "credits" lub "license", aby uzyskać więcej informacji.>>> my_input = input('wpisz liczbę: ')wpisz liczbę: 123>>> type(my_input)<type. 'int'>>>> my_input = raw_input('wprowadź liczbę: ')enter a number: 123>>> type(my_input)<type 'str'>
Python 3
Python 3.4.1 na darwinType "help", "copyright", "credits" lub "license", aby uzyskać więcej informacji.>>> my_input = input('wpisz liczbę: ')wpisz liczbę: 123>>> type(my_input)<class 'str'>
Wracanie obiektów iterowalnych zamiast list
Jak już widzieliśmy w sekcji xrange
, niektóre funkcje i metody zwracają teraz obiekty iterowalne w Pythonie 3 – zamiast list w Pythonie 2.
Ponieważ zazwyczaj i tak iterujemy po nich tylko raz, myślę, że ta zmiana ma sens, aby zaoszczędzić pamięć. Jednakże, jest również możliwe – w przeciwieństwie do generatorów – wielokrotne iterowanie nad nimi w razie potrzeby, tylko nie jest to tak wydajne.
A dla tych przypadków, gdy naprawdę potrzebujemy obiektów list
, możemy po prostu przekonwertować obiekt iterowalny na list
poprzez funkcję list()
.
Python 2
print 'Python', python_version()print range(3)print type(range(3))
Python 2.7.6<type 'list'>
Python 3
print('Python', python_version())print(range(3))print(type(range(3)))print(list(range(3)))
Python 3.4.1range(0, 3)<class 'range'>
Kilka częściej używanych funkcji i metod, które nie zwracają już list w Pythonie 3:
-
zip()
-
map()
-
filter()
-
metoda słownika
.keys()
-
metoda słownika
.values()
method -
dictionary’s
.items()
method
Banker’s Rounding
Python 3 zaadoptował obecnie standardowy sposób zaokrąglania wartości dziesiętnych, gdy skutkuje to remisem (.5) na ostatnich znaczących cyfrach. Teraz, w Pythonie 3, liczby dziesiętne są zaokrąglane do najbliższej liczby parzystej. Chociaż jest to niedogodność dla przenośności kodu, jest to podobno lepszy sposób zaokrąglania w porównaniu do zaokrąglania w górę, ponieważ unika stronniczości w kierunku dużych liczb. Aby uzyskać więcej informacji, zobacz doskonałe artykuły i akapity Wikipedii:
- https://en.wikipedia.org/wiki/Rounding#Round_half_to_even
- https://en.wikipedia.org/wiki/IEEE_floating_point#Roundings_to_nearest
Python 2
.
print 'Python', python_version()
Python 2.7.12
round(15.5)
16.0
round(16.5)
17.0
Python 3
print('Python', python_version())
Python 3.5.1
round(15.5)
16
round(16.5)
16
Więcej artykułów o Pythonie 2 i Pythonie 3
Oto lista kilku dobrych artykułów dotyczących Pythona 2 i 3, które poleciłbym jako kontynuację.up.
// Portowanie do Pythona 3
-
Czy powinienem używać Pythona 2 czy Pythona 3 do moich działań programistycznych?
-
Co nowego w Pythonie 3.0
-
Portowanie do Python 3
-
Portowanie kodu Python 2 do Python 3
-
Jak utrzymać Python 3 idzie do przodu
// Pro i anty Python 3
-
10 wspaniałych funkcji Pythona, których nie możesz używać ponieważ odmawiasz uaktualnienia do Pythona 3
-
Wszystko, czego nie chciałeś wiedzieć o Unicode w Pythonie 3
-
Python 3 zabija Pythona
-
Python 3 może ożywić Pythona
-
Python 3 jest w porządku
Wszystko, czego nie chciałeś wiedzieć o Unicode w Pythonie 3