У січні 2020 року офіційно завершилась підтримка старої мажорної версії Python 2.
Будь який ваш новий проект варто починати уже на новій версії мови Python, а саме на версії 3.
Якщо ж ви займаєтесь довготривалим Python 2 проектом із великою кількістю коду, тоді рекомендую розробити стратегію повільної адаптації проекту під нову версію. Перехід не повинен бути важким і ризиковим. Можна доволі просто підтюнити ваш код так, щоб він одночасно працював і для Python 2 і Python 3.
В даній статті я наведу перелік основних відмінностей даних версій мови.
Мова піде більше про синтаксичні відмінності і базові концептуальні речі і менше про зовнішні бібліотеки, які перестали працювати на новому Python 3.
То ж, що нам приготував Python 3?
Це перша стаття у серії “Тримайте Ваш Python / Django Проект в Тонусі”.
Ми розпочали дану серії статтей у межах роботи над оновленням нашого бестселлера “Веб-розробка з Python та Django для Початківців” від версій Python 2 / Django 1.7 до Python 3 / Django 2.
В даній серії статтей ми покажемо як мігрувати не лише на нові Python та Django, але й оновлену роботу із фреймворками типу Twitter Bootstrap, деплойментом на найновіші Python/Django хостинги і тд. В майбутньому в дану серію статтей ми постійно додаватимемо інструкції по міграції на нові версії. Так що додавайте собі у закладки.
Якщо хочете першими отримувати новини про чергову статтю у серії “Тримайте ваш Python/Django Проект UP TO DATE”, підписуйтесь у формі внизу.
Отже, які основні відмінності між Python 2 та Python 3. Давайте розберемо по черзі:
1. Оператор Ділення
Ось який результат ви отримаєте в результаті операції ділення у різних версіях Python:
1 2 3 4 5 |
$ print 7 / 5 # Результат в Python 2: 1 # Результат в Python 3: 1.4 |
Інтерпретатор не видасть вам помилок. Тому, якщо ви хочете уникнути прихованих проблем, використовуйте змінні типу флоат із операцією ділення:
1 2 3 |
$ print 7.0 / 5.0 або $ print float(7) / float(5) |
2. Unicode
В Python 2 тип стрічки (str) є по замовчуванню закодованим у ASCII кодування.
В Python 3 тип стрічки є юнікодом (unicode).
Тобто тепер не потрібно конвертувати в стрічку в юнікод, робити операції і з нею і перед тим, як зберігати дані (в базу даних чи у файлову систему), знову повертати її у стрічку.
Натомість, ви отримуєте одразу юнікод, працюєте з ним, і далі віддаєте юнікод. Python 3 зробить всю важку роботу за вас.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Python 2 $ print type('my string') <type 'str'> $ print type('my string') <type 'unicode'> # Python 3 $ print(type('my string')) <type 'str'> $ print(type(u'my string')) <type 'str'> |
3. xrange
xrange із Python 2 більше не існує в Python 3.
В Python 3 ми маємо лише range. Ця функція робить те, що xrange робила в Python 3.
1 2 3 4 5 6 7 8 9 10 11 12 |
for x in xrange(1, 5): print(x), for x in range(1, 5): print(x), # Python 2 результат: 1 2 3 4 1 2 3 4 # Python 3 результат: NameError: name 'xrange' is not defined |
4. Робота з Помилками
Також в Python 3 трохи змінилась робота з помилками. Тепер ми повинні використовувати ключове слово “as” у гілці except:
1 2 3 4 5 6 7 8 9 10 11 |
# Python 2 try: not_defined_variable except NameError, err: print err, 'Variable is not defined' # Python 3 try: not_defined_variable except NameError as err: print(err, 'Variable is not defined') |
5. __future__ модуль
В Python 3 були введені не сумісні з Python 2 ключові слова та функції, котрі можна імпортнути за допомогою вбудованого модуля __future__ у Python 2.
Рекомендується використовувати __future__ модуль, якщо ви плануєте підтримку Python 3 у своєму коді.
Наприклад, якщо ми хочемо Python 3 цілочисельне ділення використати у Python 2, тоді потрібно виконати відповідний імпорт:
1 |
from __future__ import division |
А якщо нам потрібно зробити print як функцію, то ми можемо зробити наступний імпорт:
1 |
from __future__ import print_function |
Додаткові функції, які можна імпортнути із модуля __future__, перечислені у таблиці нижче:
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 |
6. next() функція
В Python 2 у нас була можливість викликати next() як функцію, а також як метод .next().
Тепер в Python 3 у нас залишилася лише функція.
Для того, щоб отримати значення в ітераторах для Python 3 нам треба використовувати next() метод.
Наприклад, наступний код на Python 2:
1 2 3 4 |
iterator = iter([1, 2, 3]) one = iterator.next() two = iterator.next() three = iterator.next() |
потрібно переписати в Python 3 на:
1 2 3 4 |
iterator = iter([1, 2, 3]) one = next(iterator) two = next(iterator) three = next(iterator) |
7. Витік ітераційної змінної в глобальний простір імен
В Python 2, ітераційна змінна у генераторах списка потрапляла до глобального простору імен.
Тепер у Python 3 цього немає.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Python 2: $ i = 1 $ print 'Before: i =', i Before: i = 1 $ print 'List comprehension: ', [i for i in range(5)] List comprehension: [0, 1, 2, 3, 4] $ print 'After: i =', i After: i = 4 # Python 3: $ i = 1 $ print('Before: i =', i) Before: i = 1 $ print('List comprehension: ', [i for i in range(5)]) List comprehension: [0, 1, 2, 3, 4] $ print('After: i =', i) After: i = 1 |
8. Порівняння різних типів даних
Тепер в Python 3 неможливо порівняти різні типи даних.
Якщо ми спробуємо порівняти їх, то отримаємо TypeError.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Python 2: $ print "[1, 2] > 'foo' = ", [1, 2] > 'foo' [1, 2] > 'foo' = False $ print "(1, 2) > 'foo' = ", (1, 2) > 'foo' (1, 2) > 'foo' = True $ print "[1, 2] > (1, 2) = ", [1, 2] > (1, 2) [1, 2] > (1, 2) = False # Python 3: $ print("[1, 2] > 'foo' = ", [1, 2] > 'foo') Traceback (most recent call last): File "comparing.py", line 1, in <module> print("[1, 2] > 'foo' = ", [1, 2] > 'foo') TypeError: '>' not supported between instances of 'list' and 'str' |
9. input
В Python 3 функція input() завжди повертає об’єкт str.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Python 2 >>> my_input = input('Введіть число: ') Введіть число: 123 >>> type(my_input) <type 'int'> >>> my_input = raw_input('Введіть число: ') Введіть число: 123 >>> type(my_input) <type 'str'> # Python 3 >>> my_input = input('Введіть число: ') Введіть число: 123 >>> type(my_input) <class 'str'> |
10. Ітаративні об’єкти замість списків
Деякі функції та методи тепер повертають так звані ітеративні об’єкти (ренджі) в Python 3, а не списки як це було у Python 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Python 2: $ print range(3) [0, 1, 2] $ print type(range(3)) <type 'list'> # Python 3: $ print(range(3)) range(0, 3) $ print(type(range(3))) <class 'range'> $ print(list(range(3))) [0, 1, 2] |
Ось список більш часто використовуваних методів та функцій, які більше не повертають списки в Python 3:
zip()
map()
filter()
- метод словника .keys()
- метод словника
.values()
- метод словника
.items()
11. Округлення десяткових дробів до найближчого парного числа
В Python 3 прийнятий новий стандарт округлення десоткових дробів.
Тепер десяткові округлюються до найближчого парного числа.
1 2 3 4 5 6 7 8 9 10 11 |
# Python 2: $ round(15.5) 16.0 $ round(16.5) 17.0 # Python 3: $ round(15.5) 16 $ round(16.5) 16 |
12. Функція print
Оператор print у Python 2 був замінений на функцію print()
Це означає, що нам потрібно огорнути об’єкт, який ми хочемо надрукувати, у дужки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Python 2: $ print 'Hello, World!' Hello, World! $ print('Hello, World!') Hello, World! $ print "text", ; print 'print more text on the same line' text print more text on the same line # Python 3: $ print('Hello, World!') print 'Hello, World!' $ print("some text,", end="") Hello, World! some text, print more text on the same line $ print(' print more text on the same line') File "<stdin>", line 1 print 'Hello, World!' ^ SyntaxError: Missing parentheses in call to 'print'. Did you mean print('Hello, World!')? |
Як швидко конвертувати Python 2 до 3?
І на завершення, лайфхак!
Не потрібно всю роботу із міграції вашого коду на Python 3 робити вручну.
Існує кілька інструментів для автоматизації портування кода.
Пам’ятайте, що вони лише допоможуть автоматизувати деякі частини вашого кода, а не весь проект. І тут ви, як программіст, повинні перевірити чи правильно воно промігрувало відповідно до логіки, яку ви очікуєте від вашого коду.
Ось список інструментів, які можуть вам допомогти перевести проект на Python 3:
- six – бібліотека для підтримки сумістності Python 2 та Python 3;
- python-modernize – інструмент базований на 2to3 бібліотеці, яка є вбудованою в Python;
- caniusepython3 – щоб дізнатися, які з ваших залежностей блокують використання Python 3.
***
Якщо ви вже промігрували не один проект на новий Python 3 – залиште ваш коментар і поділіться досвідом!
В наступних статтях перейдемо ближче до Django веб фреймворку і як він змінився у версії 2.
Якщо хочете отримувати сповіщення про наступні статті у даній серії – підписуйтесь у формі нижче:
Як людина, яка дуже вдячна за першу книгу(вже майже 3 роки працюю на позиції python dev), хочу залишити, швидше, стилістичний коментар.
1. todo link contents – в статті.
2. Посилання на початку статті на форму внизу не працює(принаймі в мене)
3. “Python 2” як підзаголовок під кожним пунктом виглядає дуже дивно – десь він є, десь немає. При тому, що позначення версії пітону також зустрічається в коментарях самої консолі.
4. Пункт №5. Модуль не “встроєний”, а “вбудований”(не знаю, мені, чомусь, ріже слух)
На додачу, до досвіду мігрування на 3 версію, мав досвід робити наступним чином: змінили в налаштуваннях віртуального оточення або докера версію на 3, і вже при старті проекту будуть видні перші помилки. Спочатку виправити їх. Якщо на проекті є тести(що було б дуже добре), то прогнати і їх, там теж буде трохи помилок. А після цього вже проходив би якоюсь бібліотекою, щоб прибрати сміття чи внести неочевидні фікси(як наприклад, з діленням)
Дякую за нотатки! Усе поправили.
Так, ми на проектах подібним чином працюємо при міграції.