Как всем известно, Python3.8 был выпущен 14 октября этого года. Я бы показал вам, как установить Python 3.8 в RHEl/CentOS.

Процесс установки

cd /opt
wget https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz

Теперь распакуйте загруженный tar-пакет

Скомпилируйте исходный код Python

cd Python-3.8.0
sudo ./configure --enable-optimizations
sudo make altinstall

Проверить версию Python

python3.8 -V

Что нового в Python3.8?

  1. Оператор Walrus: выражение присваивания

Существует новый синтаксис ‘:=’, который присваивает значения переменным как часть более крупного выражения. Его ласково называют «моржовым оператором» из-за его сходства с глазами и бивнями моржа.

В Python3.8 выражения присваивания позволяют присваивать и возвращать значение в одном и том же выражении.

>>> print(x:=True)
True

Оператор walrus не делает ничего, что было бы невозможно без него. Это только делает определенные конструкции более удобными и иногда может более четко передать цель вашего кода.

Одной из сильных сторон оператора walrus являются циклы while, в которых вам необходимо инициализировать и обновить переменную.

Код Python3:

a = list()
b = input("Enter text")
while b != "exit":
    inputs.append(b)
    current = input("enter text")

Код Python3.8 с использованием Walrus:

a = list()
while (b := input("enter text: ")) != "quit":
    inputs.append(b)

2. Только позиционные аргументы

Специальный маркер / теперь можно использовать при определении аргументов метода, чтобы указать, что функционал принимает только позиционные аргументы слева от маркера. Аргументы, содержащие только ключевое слово, были доступны в Python с маркером * в функциях, а добавление маркера / для аргументов, основанных только на позиционировании, повышает согласованность языка и обеспечивает надежную структуру API. До Python 3.8 такие только позиционные были возможны только для встроенных функций.

В питоне3:

>>> def inc(x):
         return x+1
>>> inc(2)
3
>>> x=2
>>> inc(x)
3
>>> inc(x=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: incr() got some positional-only arguments passed as
           keyword arguments: 'x'

В питоне 3.8:

>>> def inc(x):
         return x+1
>>> inc(x=2)
3

3.f-строки теперь поддерживают «=»

Программисты Python часто используют отладку в стиле printf. В старые времена это было довольно многословно:

print "foo=", foo, "bar=", bar

f-строки делают это немного лучше:

print(f"foo={foo} bar={bar}")

Но вам все равно придется повторяться: вы должны написать строку «foo», а затем выражение «foo».

Спецификатор =, используемый как f'{expr=}', расширяется до текста выражения, знака равенства, а затем повторения оцениваемого выражения. Итак, теперь вы можете просто написать:

print(f"{foo=} {bar=}")

4. Reversed() теперь работает с dict

Начиная с python3.7 словари сохраняют порядок вставки ключей. В pyhton3.8 встроенная функция reversed()built-in используется для доступа к словарю в порядке, обратном вставке.

>>> my_dict = dict(a=1, b=2)
>>> list(reversed(my_dict))
['b', 'a']
>>> list(reversed(my_dict.items()))
[('b', 2), ('a', 1)]

5. Упрощенная итерируемая распаковка для return и yield

Это непреднамеренное поведение существовало с Python 3.2, который запрещал распаковку итерируемых объектов без круглых скобок в операторах return и yield.

Так, было разрешено:

def foo():
    rest = (4, 5, 6)
    t = 1, 2, 3, *rest
    return t

Но это привело к тому, что SyntaxError.Последняя версия исправляет это поведение, поэтому теперь разрешены следующие два подхода.

def baz():
    rest = (4, 5, 6)
    return 1, 2, 3, *rest
def baz():
    rest = (4, 5, 6)
    yield 1, 2, 3, *rest

6. Предупреждения о новом синтаксисе

Интерпретатор Python теперь выдает SyntaxWarning в некоторых случаях, когда запятая пропущена перед кортежем или списком. Итак, когда вы случайно делаете это:

data = [
    (1, 2, 3)  # oops, missing comma!
    (4, 5, 6)
]

Вместо показа TypeError: 'tuple' object is not callable, который на самом деле не говорит вам, что не так, будет показано полезное предупреждение о том, что вы, вероятно, пропустили запятую. Довольно полезно при отладке!

Компилятор теперь также выдает SyntaxWarning, когда проверки подлинности (is и is not) используются с определенными типами литералов (например, строками, целыми числами и т. д.). Вы редко хотите сравнивать идентификаторы с литералами, отличными от None, и предупреждение компилятора может помочь избежать ряда неуловимых ошибок.

7. Улучшение производительности

В этом выпуске интерпретатору добавлено несколько ускорений производительности, как и в предыдущем выпуске 3.7.

  • operator.itemgetter() теперь на 33% быстрее. Это стало возможным благодаря оптимизации обработки аргументов и добавлению быстрого пути для общего случая одиночного неотрицательного целочисленного индекса в кортеж (что является типичным вариантом использования в стандартной библиотеке).
  • Поиск полей в collections.namedtuple() теперь более чем в два раза быстрее, что делает их самой быстрой формой поиска переменных экземпляра в Python.
  • Конструктор list не перераспределяет внутренний буфер элементов, если итерация ввода имеет известную длину (вход реализует len). Это делает созданный список в среднем на 12% меньше.
  • Запись переменных класса теперь выполняется в два раза быстрее: при обновлении атрибута, отличного от Dunder, возникал ненужный вызов для обновления слотов, что оптимизировано.
  • Вызов некоторых простых встроенных функций и методов теперь выполняется на 20–50 % быстрее. Накладные расходы на преобразование аргументов в эти методы уменьшены.
  • uuid.UUID теперь использует слоты, чтобы уменьшить объем памяти.

8. Улучшения в модулях ввода

Python имеет динамическую типизацию, но поддерживает использование подсказок типа через модуль typing, что позволяет сторонним инструментам проверять программы Python. Python 3.8 добавляет новые элементы в typing, чтобы сделать возможными более надежные проверки:

  • Декоратор final и аннотация типа Final указывают, что декорированные/аннотированные объекты не должны переопределяться, подклассифицироваться или переназначаться в какой-либо момент.
  • Тип Literal ограничивает выражения определенным значением или списком значений, не обязательно одного и того же типа.
  • Тип TypedDict позволяет создавать словари, в которых значения, связанные с определенными ключами, ограничены одним или несколькими конкретными типами. Обратите внимание, что эти ограничения ограничены тем, что может быть определено во время компиляции, а не во время выполнения.

9. Многопроцессорная общая память

В Python 3.8 модуль multiprocessing теперь предлагает класс SharedMemory, который позволяет создавать области памяти и совместно использовать их между различными процессами Python.

В предыдущих версиях Python обмен данными между процессами мог осуществляться только путем записи их в файл, отправки через сетевой сокет или сериализации с использованием модуля Python pickle. Общая память обеспечивает гораздо более быстрый путь для передачи данных между процессами, позволяя Python более эффективно использовать несколько процессоров и процессорных ядер.

Сегменты общей памяти могут быть выделены как необработанные области байтов или они могут использовать неизменяемые спископодобные объекты, в которых хранится небольшое подмножество объектов Python — числовые типы, строки, байтовые объекты и объект None.

10. Новая версия протокола pickle

Модуль Python pickle предоставляет способ сериализации и десериализации структур данных Python — например, позволяет сохранить словарь как есть в файл и перезагрузить его позже. Различные версии Python поддерживают разные уровни протокола pickle, а более поздние версии поддерживают более широкий спектр возможностей и более эффективную сериализацию.

Версия 5 pickle, представленная в Python 3.8, предоставляет новый способ обработки объектов, реализующих буферный протокол Python, таких как байты, представления памяти или массивы NumPy. Новый pickle сокращает количество копий памяти, которые необходимо сделать для таких объектов.

Внешние библиотеки, такие как NumPy и Apache Arrow, поддерживают новый протокол pickleprotocol в своих привязках к Python. Новый pickle также доступен в качестве надстройки для Python 3.6 и Python 3.7 от PyPI.

11. Другие интересные функции

importlib.metadata

В стандартной библиотеке Python 3.8 доступен один новый модуль: importlib.metadata. С помощью этого модуля вы можете получить доступ к информации об установленных пакетах в вашей установке Python. Вместе со своим сопутствующим модулем importlib.resources importlib.metadata улучшает функциональность более старого pkg_resources.

>>> from importlib import metadata
>>> metadata.version("pip")
'19.2.3'

>>> pip_metadata = metadata.metadata("pip")
>>> list(pip_metadata)
['Metadata-Version', 'Name', 'Version', 'Summary', 'Home-page', 'Author',
 'Author-email', 'License', 'Keywords', 'Platform', 'Classifier',
  'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier',
  'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier',
  'Classifier', 'Classifier', 'Requires-Python']

>>> pip_metadata["Home-page"]
'https://pip.pypa.io/'

>>> pip_metadata["Requires-Python"]
'>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*'

>>> len(metadata.files("pip"))
668

Вы также можете получить доступ к зависимостям пакета:

>>> metadata.requires("realpython-reader")
['feedparser', 'html2text', 'importlib-resources', 'typing']

requires() перечисляет зависимости пакета. Вы можете видеть, что realpython-reader, например, использует feedparser в фоновом режиме для чтения и анализа ленты статей.

Новые и улучшенные функции math и statistics

Python 3.8 вносит множество улучшений в существующие пакеты и модули стандартных библиотек. math в стандартной библиотеке есть несколько новых функций. math.prod() работает аналогично встроенному sum(), но для мультипликативных произведений:

>>> import math
>>> math.prod((2, 8, 7, 7))
784
>>> 2 * 8 * 7 * 7
784

Эти два утверждения эквивалентны. prod() будет проще использовать, когда у вас уже есть факторы, сохраненные в итерируемом объекте.

Еще одна новая функция — math.isqrt(). Вы можете использовать isqrt(), чтобы найти целую часть квадратичных корней:

>>> import math
>>> math.isqrt(9)
3
>>> math.sqrt(9)
3.0
>>> math.isqrt(15)
3
>>> math.sqrt(15)
3.872983346207417

Вы можете видеть, что isqrt() возвращает целочисленный результат, а math.sqrt() всегда возвращает float.

Теперь вам проще работать с n-мерными точками и векторами в стандартной библиотеке. Вы можете найти расстояние между двумя точками с помощью math.dist() и длину вектора с помощью math.hypot():

>>> import math
>>> point_1 = (16, 25, 20)
>>> point_2 = (8, 15, 14)
>>> math.dist(point_1, point_2)
14.142135623730951
>>> math.hypot(*point_1)
35.79106033634656
>>> math.hypot(*point_2)
22.02271554554524

Это упрощает работу с точками и векторами с помощью стандартной библиотеки.

Модуль statistics также имеет несколько новых функций:

  • statistics.fmean() вычисляет среднее значение float чисел.
  • statistics.geometric_mean() вычисляет среднее геометрическое float чисел.
  • statistics.multimode() находит наиболее часто встречающиеся значения в последовательности.
  • statistics.quantiles() вычисляет точки отсечения для разделения данных на n непрерывных интервалов с равной вероятностью.

В следующем примере показаны используемые функции:

>>> import statistics
>>> data = [9, 3, 2, 1, 1, 2, 7, 9]
>>> statistics.fmean(data)
4.25
>>> statistics.geometric_mean(data)
3.013668912157617
>>> statistics.multimode(data)
[9, 2, 1]
>>> statistics.quantiles(data, n=4)
[1.25, 2.5, 8.5]

В Python 3.8 появился новый класс statistics.NormalDist, упрощающий работу с нормальным распределением Гаусса.

Оптимизация

Для Python 3.8 сделано несколько оптимизаций. Некоторые из них ускоряют выполнение кода. Другие уменьшают объем памяти. Например, поиск полей в namedtuple выполняется значительно быстрее в Python 3.8 по сравнению с Python 3.7:

>>> import collections
>>> from timeit import timeit
>>> Person = collections.namedtuple("Person", "name twitter")
>>> raymond = Person("Raymond", "@raymondh")
>>> # Python 3.7
>>> timeit("raymond.twitter", globals=globals())
0.05876131607996285
>>> # Python 3.8
>>> timeit("raymond.twitter", globals=globals())
0.0377705999400132

Вы можете видеть, что поиск .twitter в namedtuple на 30-40% быстрее в Python 3.8. Списки экономят место, когда они инициализируются из итерируемых объектов с известной длиной. Это может сэкономить память:

>>> import sys
>>> # Python 3.7
>>> sys.getsizeof(list(range(20191014)))
181719232
>>> # Python 3.8
>>> sys.getsizeof(list(range(20191014)))
161528168

В этом случае список использует примерно на 11% меньше памяти в Python 3.8 по сравнению с Python 3.7.

Другие оптимизации включают повышение производительности в subprocess, более быстрое копирование файлов с помощью shutil, улучшенную производительность по умолчанию в pickle и более быстрые операции operator.itemgetter.

РЕЗЮМЕ

В Python3.8 добавлен ряд новых функций. Теперь Python стал лучше и быстрее. Для получения более подробной информации об изменениях и функциях в python3.8 посетите https://docs.python.org/3/whatsnew/3.8.html.