Если вы еще не начали переходить на Python3 то сейчас самое время!
Различий очень много. Как внутренние архитектурные решения, невидимые рядовому программисту, так и явные изменения, которые приходится использовать каждый день.
Для тех, кто только начинает знакомиться с 3й версией я собрал самые, на мой взгляд, заметные отличия 3й версии Python.
🔸Unicode по умолчанию
Для тех, кто пишет на Python2, всегда была актуальная проблема использования любых символов вне ASCII таблицы. Это относилось как к строкам в данных, так и просто комментариям по коду.
В Python3 по умолчанию строки это UNICODE, кодировка по умолчанию UTF-8. Теперь можно где угодно в строках использовать символы из кириллицы, таблицы Unicode, иероглифы, смайлы и эмодзи.
Конечно же это не относится к именам переменных и файлов! Только строки и коменты.
🔸Функция print()
Не смотря на то, что теперь приходится писать лишние скобочки, мы получили серьезный апгрейд такой простой, но полезной функции. Если вкратце, то print "объединился" с sys.stdout. Как это работает?
Как не переносить курсор на новую строку после печати?
PY2:
Логично предположить что вместо пустой строки можно подставить любые символы.
Форсировать вывод в stdout во время блокирующей операции в консольном приложении.
PY2:
Кроме того, с помощью аргумента file можно печатать в файл или другой подходящий интерфейс.
🔸Оператор деления
Теперь деление целых чисел не обязательно в результате будет иметь целое число. То есть, если числа int не делятся без остатка то результатом будет float
Как разделить два int и получить float?
PY2:
Между тем, чтобы работало как раньше, то есть деление без остатка, просто нужно использовать другой оператор:
В Python3 изменили принципы относительного импорта. Теперь стало проще и более предсказуемо. Но об этом лучше подробней и отдельно.
Все перечисленные выше фишки были доступны и в Python2 как бекпорт. То есть можно было активировать этот функционал через модуль __future__. Но когда оно по умолчанию, это сильно удобней)))
🔸 Асинхронное программирование
Теперь в Python3 удобно писать асинхронный код с помощью библиотеки asyncio и аналогичных.
🔸 F-String
Да, в Python добавился новый способ форматирования строки (если не ошибаюсь, уже 5й), но он офигенный!
PY2:
Нет, я не про OrderedDict, я про обычный dict. Теперь порядок ключей сохраняется! В каком порядке добавляли, в таком порядке они и итерируются. Мелочь, но приятно.
Это далеко не всё, но для начала достаточно 😉
#2to3
Различий очень много. Как внутренние архитектурные решения, невидимые рядовому программисту, так и явные изменения, которые приходится использовать каждый день.
Для тех, кто только начинает знакомиться с 3й версией я собрал самые, на мой взгляд, заметные отличия 3й версии Python.
🔸Unicode по умолчанию
Для тех, кто пишет на Python2, всегда была актуальная проблема использования любых символов вне ASCII таблицы. Это относилось как к строкам в данных, так и просто комментариям по коду.
В Python3 по умолчанию строки это UNICODE, кодировка по умолчанию UTF-8. Теперь можно где угодно в строках использовать символы из кириллицы, таблицы Unicode, иероглифы, смайлы и эмодзи.
Конечно же это не относится к именам переменных и файлов! Только строки и коменты.
🔸Функция print()
Не смотря на то, что теперь приходится писать лишние скобочки, мы получили серьезный апгрейд такой простой, но полезной функции. Если вкратце, то print "объединился" с sys.stdout. Как это работает?
Как не переносить курсор на новую строку после печати?
PY2:
print text,PY3:
print(text, end='')
Логично предположить что вместо пустой строки можно подставить любые символы.
Форсировать вывод в stdout во время блокирующей операции в консольном приложении.
PY2:
import sysPY3:
print text # или sys.stdout.write(text)
sys.stdout.flush()
print(text, flush=True)
Кроме того, с помощью аргумента file можно печатать в файл или другой подходящий интерфейс.
🔸Оператор деления
Теперь деление целых чисел не обязательно в результате будет иметь целое число. То есть, если числа int не делятся без остатка то результатом будет float
Как разделить два int и получить float?
PY2:
12/5PY3:
>>> 2 # ужасный результат!
12/float(5) # приходится делать так
>>> 2.4
12/5
>>> 2.4
Между тем, чтобы работало как раньше, то есть деление без остатка, просто нужно использовать другой оператор:
12//5🔸Относительный импорт
>>> 2
В Python3 изменили принципы относительного импорта. Теперь стало проще и более предсказуемо. Но об этом лучше подробней и отдельно.
Все перечисленные выше фишки были доступны и в Python2 как бекпорт. То есть можно было активировать этот функционал через модуль __future__. Но когда оно по умолчанию, это сильно удобней)))
🔸 Асинхронное программирование
Теперь в Python3 удобно писать асинхронный код с помощью библиотеки asyncio и аналогичных.
🔸 F-String
Да, в Python добавился новый способ форматирования строки (если не ошибаюсь, уже 5й), но он офигенный!
PY2:
value = 123PY3:
string = "Value = {}".format(value)
value = 123🔸Упорядоченный словарь
string = f"Value = {value}"
Нет, я не про OrderedDict, я про обычный dict. Теперь порядок ключей сохраняется! В каком порядке добавляли, в таком порядке они и итерируются. Мелочь, но приятно.
Это далеко не всё, но для начала достаточно 😉
#2to3
Поздно писать код, совместимый с Python2 и Python3 одновременно. Если вы матёрый программист, то, возможно, использовали библиотеку six для создания совместимого кода. Или использовали различные модули автоматизации для преобразования кода из Python2 в совместимый для Python2 и Python3. Например sixer или python-future.
Но это время прошло! Теперь пишем только на 3м Python. Совместимость с версией 2 скоро вовсе не потребуется (кроме отдельных тяжелых случаев поддержки legacy систем, но я надеюсь таких у вас нет или совсем мало)
Скорее всего, у многих появляется вопрос, а что делать с кодом который написан под Python2? Садиться и переписывать? Или хотя бы сделать совместимым с Python3?
Всё зависит от конкретной ситуации. Убедитесь что ваша инфраструктура готова под Python3 прежде чем начать.
Скорее всего пора переписывать и не оглядываться назад!
Но не всё так безнадёжно, в стандартной поставке Python уже давно есть готовый инструмент для автоматизации процесса. Это библиотека lib2to3 и прилагаемый скрипт 2to3.py
С чего начать?
1. Документация
Прежде всего почитайте документацию
https://docs.python.org/3.8/library/2to3.html
А также встроенная справка
для Windows
2. Тест
Прежде чем приступать к ожесточенным конвертациям, обязательно протестируйте весь процесс! Например, чтобы просто посмотреть какие будут изменения в скрипте, запустите команду с флагом --list-fixes
Нашел развёрнутую статью про тему 2to3, советую почитать.
http://python3porting.com/2to3.html
3. Конвертация
Не забываем что в качестве источника для конвертации можно указать директорию. И ВСЕГДА указывайте путь сохранения результата.
Пример конвертации пакета
#2to3
Но это время прошло! Теперь пишем только на 3м Python. Совместимость с версией 2 скоро вовсе не потребуется (кроме отдельных тяжелых случаев поддержки legacy систем, но я надеюсь таких у вас нет или совсем мало)
Скорее всего, у многих появляется вопрос, а что делать с кодом который написан под Python2? Садиться и переписывать? Или хотя бы сделать совместимым с Python3?
Всё зависит от конкретной ситуации. Убедитесь что ваша инфраструктура готова под Python3 прежде чем начать.
Скорее всего пора переписывать и не оглядываться назад!
Но не всё так безнадёжно, в стандартной поставке Python уже давно есть готовый инструмент для автоматизации процесса. Это библиотека lib2to3 и прилагаемый скрипт 2to3.py
С чего начать?
1. Документация
Прежде всего почитайте документацию
https://docs.python.org/3.8/library/2to3.html
А также встроенная справка
для Windows
python C:\python37\Tools\scripts\2to3.py --helpдля Linux
2to3-3.7 --help(имена зависят от установленных версий Python)
2to3-2.7 --help
2. Тест
Прежде чем приступать к ожесточенным конвертациям, обязательно протестируйте весь процесс! Например, чтобы просто посмотреть какие будут изменения в скрипте, запустите команду с флагом --list-fixes
2to3 --list-fixes my_script.py3. Полезные советы
Нашел развёрнутую статью про тему 2to3, советую почитать.
http://python3porting.com/2to3.html
3. Конвертация
Не забываем что в качестве источника для конвертации можно указать директорию. И ВСЕГДА указывайте путь сохранения результата.
Пример конвертации пакета
2to3 --output-dir=./py3/package_name -W -n ./package_name
#2to3
Одно из незаметных но приятных изменений в Python3, которое не часто упоминается, это проблема Leak of variables.
Относится она к конструкции List Comprehensions, он же генератор списков.
Лучше всего данный фикс показать на примере.
Python2
Но стоит помнить, что к обычным циклам это не относится.
Python3
#2to3
Относится она к конструкции List Comprehensions, он же генератор списков.
Лучше всего данный фикс показать на примере.
Python2
x = 'some_value'
my_list = [x for x in range(10)]
print x
>>> 9
Python3x = 'some_value'
my_list = [x for x in range(10)]
print(x)
>>> some_value
Переменная "х" в генераторе списка не затирает глобальную переменную с таким же именем. То есть внутри генератора действуют локальные переменные.Но стоит помнить, что к обычным циклам это не относится.
Python3
x = 'some_value'
for x in range(10):
pass
print(x)>>>9
#2to3
В Python2 был необычный способ записать текст в файл с помощью print
Хорошо, что в Python3 этот синтаксис более неактуален. Теперь запись в файл с помощью print выглядит куда более логично:
#2to3
>>> print >> open(path, 'w'), 'some text'
Те, кто часто пишет на Python, заметят как не "питонично" выглядит такая запись. Просто какой-то разрыв шаблонов.Хорошо, что в Python3 этот синтаксис более неактуален. Теперь запись в файл с помощью print выглядит куда более логично:
>>> print('some text', file=open(path, 'w'))
Хотя, я пока не встречал никого кто пишет что-то в файл с помощью print )))#2to3
Те кто работал с Python2 наверняка помнят, как приходилось поправлять расширение python-файла из переменной ˍˍfileˍˍ чтобы получить именно .py а не .pyc
Ну сразу бы так)
#2to3
source_path = os.path.splitext(__file__)[0] + '.py'В Python3 эта проблема ушла. Всегда возвращается путь именно к исходному файлу .py.
Ну сразу бы так)
#2to3
Всё начиналось с библиотеки six, что означает цифру 6 и является результатом умножения 2*3 (напомню что six это библиотека для написания кода одновременно совместимого для Python 2 и 3).
Но как обычно всегда найдется тот, кому не всё понравится и он напишет свой вариант) В итоге получаем небольшой ряд "числовых" библиотек примерно для одного и того же
https://pypi.org/project/six/
https://pypi.org/project/eight/
https://pypi.org/project/nine/
Выглядит забавно. Я решил проверить, есть ли другие библиотеки с числом в названии, хотя бы до 20. И вот что нашлось:
https://pypi.org/project/one/
https://pypi.org/project/two/
https://pypi.org/project/three/
four - свободно
https://pypi.org/project/five/
https://pypi.org/project/six/
https://pypi.org/project/seven/
https://pypi.org/project/eight/
https://pypi.org/project/nine/
ten - свободно
https://pypi.org/project/eleven/
https://pypi.org/project/twelve/
thirteen - свободно
fourteen - свободно
fifteen - свободно
https://pypi.org/project/sixteen/
seventeen - свободно
nineteen - свободно
twenty - свободно
Назначения у этих проектов, конечно, разные. Есть и заброшенные и популярные. Но места еще есть 😊 Занимаем пока свободно!
PS.
Всех уделал Em Fresh со своей линейкой Python-альбомов😁 (жмакнуть show more)
PPS. Всех читательниц моего канала поздравляю с праздником 🌼 🥳 💐
#offtop #libs #2to3
Но как обычно всегда найдется тот, кому не всё понравится и он напишет свой вариант) В итоге получаем небольшой ряд "числовых" библиотек примерно для одного и того же
https://pypi.org/project/six/
https://pypi.org/project/eight/
https://pypi.org/project/nine/
Выглядит забавно. Я решил проверить, есть ли другие библиотеки с числом в названии, хотя бы до 20. И вот что нашлось:
https://pypi.org/project/one/
https://pypi.org/project/two/
https://pypi.org/project/three/
four - свободно
https://pypi.org/project/five/
https://pypi.org/project/six/
https://pypi.org/project/seven/
https://pypi.org/project/eight/
https://pypi.org/project/nine/
ten - свободно
https://pypi.org/project/eleven/
https://pypi.org/project/twelve/
thirteen - свободно
fourteen - свободно
fifteen - свободно
https://pypi.org/project/sixteen/
seventeen - свободно
nineteen - свободно
twenty - свободно
Назначения у этих проектов, конечно, разные. Есть и заброшенные и популярные. Но места еще есть 😊 Занимаем пока свободно!
PS.
Всех уделал Em Fresh со своей линейкой Python-альбомов😁 (жмакнуть show more)
PPS. Всех читательниц моего канала поздравляю с праздником 🌼 🥳 💐
#offtop #libs #2to3
PyPI
six
Python 2 and 3 compatibility utilities
Что за магический модуль ˍˍfutureˍˍ?
Это имплементация поведения интерпретатора из будущих версий Python.
Разные версии в Python развиваются параллельно. Разработчики ядра Python внедрили модуль ˍˍfutureˍˍ чтобы помочь писать код на старых версиях, но совместимый с новыми версиями интерпретатора. Это помогает более мягко обновить Python, не переписывая всю кодовую базу. Можно сказать что это бекпорт фичей.
Модуль ˍˍfutureˍˍ позволяет "импортировать" функционал Python3 работая с Python2, или использовать фишки из Python3.9 имея в распоряжении только 3.6.
Но что именно делает этот модуль? Если вы откроете исходник, то ничего магического вы там не найдете. Простой класс, несколько флагов и набор инстансов этого класса. По идее, если его импортнуть, ничего поменяться не может, так как там нет никакого исполняемого кода! Только объявления объектов.
А ответ кроется в необходимости делать импорты из ˍˍfutureˍˍ самой первой строкой. Дело в том, что парсер специально заточен на поиск импорта этого модуля в первой строке. Он смотрит что вы там импортнули и специальным образом изменяет поведение интерпретатора, которое в него вшито с помощью бекпортов. Весь дальнейший синтаксический разбор будет с учётом изменений. Именно поэтому импорт ˍˍfutureˍˍ обязательно должен быть первым! Не можем же мы половину модуля исполнять по-старым правилам а вторую половину по-новым)))
#2to3
Это имплементация поведения интерпретатора из будущих версий Python.
Разные версии в Python развиваются параллельно. Разработчики ядра Python внедрили модуль ˍˍfutureˍˍ чтобы помочь писать код на старых версиях, но совместимый с новыми версиями интерпретатора. Это помогает более мягко обновить Python, не переписывая всю кодовую базу. Можно сказать что это бекпорт фичей.
Модуль ˍˍfutureˍˍ позволяет "импортировать" функционал Python3 работая с Python2, или использовать фишки из Python3.9 имея в распоряжении только 3.6.
Но что именно делает этот модуль? Если вы откроете исходник, то ничего магического вы там не найдете. Простой класс, несколько флагов и набор инстансов этого класса. По идее, если его импортнуть, ничего поменяться не может, так как там нет никакого исполняемого кода! Только объявления объектов.
А ответ кроется в необходимости делать импорты из ˍˍfutureˍˍ самой первой строкой. Дело в том, что парсер специально заточен на поиск импорта этого модуля в первой строке. Он смотрит что вы там импортнули и специальным образом изменяет поведение интерпретатора, которое в него вшито с помощью бекпортов. Весь дальнейший синтаксический разбор будет с учётом изменений. Именно поэтому импорт ˍˍfutureˍˍ обязательно должен быть первым! Не можем же мы половину модуля исполнять по-старым правилам а вторую половину по-новым)))
#2to3
GitHub
python/cpython
The Python programming language. Contribute to python/cpython development by creating an account on GitHub.
Что именно мы можем импортнуть из будущих версий? Явно не всё, иначе это была бы, собственно, новая версия. В ˍˍfutureˍˍ выносятся только ключевой функционал, от которого серьезно зависит синтаксис или использование возможностей языка. Самое очевидное это директива print, которая в Python3 стала функцией print().
🔸 Теперь это функция а не ключевое слово, её можно передать как аргумент или вернуть как результат
sep: разделитель для нескольких объектов
end: последний символ вместо перехода на новую строку
А вот так приходилось делать раньше:
Ну да, теперь приходится писать лишние скобочки и сложно переучиться на новый лад. Но плюсов, я думаю, больше.
#2to3 #tricks
from __future__ import print_function
Что стало удобней с этой функцией?🔸 Теперь это функция а не ключевое слово, её можно передать как аргумент или вернуть как результат
def get_logger():
if condition:
return some_handler.write
else:
return print
🔸 С помощью аргументов sep и end можем настроить минимальное форматирование вывода.sep: разделитель для нескольких объектов
end: последний символ вместо перехода на новую строку
>>> items1 = [1, 2, 3]
>>> items2 = [4, 5, 6]
>>> print(*items1, sep='-', end='-')
>>> print(*items2, sep='-')
1-2-3-4-5-6
🔸 Аргумент flush форсированно пробрасывает буфер аутпута в файл. Полезно для вывода из блокирующих операций. Например, когда вам нужно в stdout выводить прогресс операции, запущенной в subprocess. Если не сделать flush то весь аутпут прилетит только по завершению процесса.for i in range(100):
print(f'Progress: {i}%', flush=True)
time.sleep(1)
Этот прогресс мы можем отслеживать в реальном времени.А вот так приходилось делать раньше:
import sys
sys.stdout.write(text + '\n')
sys.stdout.flush()
🔸 Аргумент file позволяет перенаправить вывод в другой поток. Например в файл, сеть или что угодно, что имеет метод write.print(text, file=open('filename.txt', 'w'))
___________Ну да, теперь приходится писать лишние скобочки и сложно переучиться на новый лад. Но плюсов, я думаю, больше.
#2to3 #tricks
Вторая по частоте future-функция, которую я использовал, это абсолютный импорт
Изменения, которые вносит эта инъекция описаны в PEP328
Покажу простой пример.
Допустим, есть такой пакет:
1. модуль в моём пакете my_package.string
2. стандартный модуль string
И вот тут вступает в дело приоритет импортов. В Python2 порядок следующий: помимо иных источников, раньше ищется модуль внутри текущего пакета, а потом в стандартных библиотеках. Таким образом мы импортнём my_package.string.
Но в Python3 это поведение изменилось. Если мы указываем просто имя пакета, то ищется именно такой модуль, игнорируя имена в текущем пакете. Если мы хотим импортнуть именно подмодуль из нашего пакета то, мы должны теперь явно это указывать.
Подробней про импорты здесь:
https://docs.python.org/3/tutorial/modules.html
#2to3 #pep #basic
from __future__ import absolute_import
Что она делает? Изменения, которые вносит эта инъекция описаны в PEP328
Покажу простой пример.
Допустим, есть такой пакет:
/my_package
/__init__.py
/main.py
/string.py
Смотрим код в my_package/main.py# main.py
import string
Простой пример готов) Вопрос в том, какой модуль импортируется в данном случае? Есть два варианта:1. модуль в моём пакете my_package.string
2. стандартный модуль string
И вот тут вступает в дело приоритет импортов. В Python2 порядок следующий: помимо иных источников, раньше ищется модуль внутри текущего пакета, а потом в стандартных библиотеках. Таким образом мы импортнём my_package.string.
Но в Python3 это поведение изменилось. Если мы указываем просто имя пакета, то ищется именно такой модуль, игнорируя имена в текущем пакете. Если мы хотим импортнуть именно подмодуль из нашего пакета то, мы должны теперь явно это указывать.
from my_package import string
или относительный импорт, но с указанием пути относительно текущего модуля mainfrom . import string
Еще одной неоднозначностью меньше 😎Подробней про импорты здесь:
https://docs.python.org/3/tutorial/modules.html
#2to3 #pep #basic
Python Enhancement Proposals (PEPs)
PEP 328 – Imports: Multi-Line and Absolute/Relative | peps.python.org
The import statement has two problems:
Ранее я уже упоминал о другой фишке из ˍˍfutureˍˍ , это оператор деления.
Например:
Если нам требуется получить дробное значение при делении двух int то приходилось форсированно один из операндов конверировать в float.
То есть теперь деление int на int даёт float если результат не целое число.
В классах теперь доступны методы __floordiv__() и __truediv__() для определения поведения с этими операторами.
Данный переход описан в PEP238.
#pep #2to3 #basic
from __future__ import division
Суть проста. Раньше сложность типа данных результата поределялась типом самого сложного операнда.Например:
int/int => int
int/float => float
В первом случае оба операнда int, значит и результат будет int. Во втором float более сложный тип, поэтому результат будет float. Если нам требуется получить дробное значение при делении двух int то приходилось форсированно один из операндов конверировать в float.
12/float(5) => float
Но с новой "философией" это не требуется. В Python3 "floor division" заменили на "true division" а старый способ теперь работает через оператор "//". >>> 3/2
1.5
>>> 3//2
1То есть теперь деление int на int даёт float если результат не целое число.
В классах теперь доступны методы __floordiv__() и __truediv__() для определения поведения с этими операторами.
Данный переход описан в PEP238.
#pep #2to3 #basic
Telegram
Python Заметки
Если вы еще не начали переходить на Python3 то сейчас самое время!
Различий очень много. Как внутренние архитектурные решения, невидимые рядовому программисту, так и явные изменения, которые приходится использовать каждый день.
Для тех, кто только начинает…
Различий очень много. Как внутренние архитектурные решения, невидимые рядовому программисту, так и явные изменения, которые приходится использовать каждый день.
Для тех, кто только начинает…