Поскольку поддержка Python 2.0 прекратилась в 2020 году, многие люди начинают переходить на третью версию этого языка программирования. Сегодня рассмотрим некоторые функции, которые доступны лишь в Python 3, но которые будут очень полезными для решения тех или иных задач.
Все примеры, которые приводятся здесь, написаны на Python 3.7, и каждая функция содержит минимальную версию Python для этой же функции.
F-строки (Python 3.6+)
F-строки – важная составляющая языка программирования. Без них тяжело сделать хоть что-то и при этом сохранить читабельность кода. Следовательно, необходимо иметь структурированный метод, позволяющий работать со строками. Подавляющее количество людей, которые работают с Python, предпочитают format python.
user = "Андрей" action = "покупка" log_message = 'Пользователь {} зашел на сайт и выполнил действие: {}'.format( user, action ) print(log_message) # Пользователь Андрей зашел на сайт и выполнил действие: покупка
Вместе с format, Python 3 предоставляет продвинутый способ выполнения интерполяции строк через f-строки. Давайте конвертируем код выше в f-string.
user = "Юрий" action = "продажа" log_message = f'Пользователь {user} зашел на сайт и выполнил действие: {action}' print(log_message) # Пользователь Юрий зашел на сайт и выполнил действие: продажа
Pathlib (Python 3.4+)
F-строки – это превосходное решение, но ряд строк, таких как пути файлов имеют собственные библиотеки, которые делают работу существенно проще. Python 3 предоставляет pathlib в качестве хорошей абстракции для того, чтобы работать с путями файлов.
from pathlib import Path root = Path('post_sub_folder') print(root) # post_sub_folder path = root / 'happy_user' # Делаем путь абсолютным print(path.resolve()) # /home/weenkus/post_sub_folder/happy_user
Подсказки типов | Ожидание типа
Споры о том, какие типизирование более предпочтительное, – статическое или динамическое, продолжаются и до сих пор. Каждый человек имеет собственное мнение по этому поводу. Вообще, это сам разработчик должен решать, когда ему необходимо вписывать типы.
В любом случае, надо знать о том, что Python 3 поддерживает подсказки типов.
def sentence_has_animal(sentence: str) -> bool: return "animal" in sentence print(sentence_has_animal("У Ивана есть своя собственная Bitcoin ферма")) # True
Перечисления enum
Python 3 предусматривает возможность писать перечисления, используя класс Enum. Его можно назвать интересным вариантом, как можно с удобством инкапсулировать перечень констант, чтобы они не были разбросаны по всему коду абсолютно без структуры.
from enum import Enum, auto class Monster(Enum): ZOMBIE = auto() WARRIOR = auto() BEAR = auto() print(Monster.ZOMBIE) # Monster.ZOMBIE
Перечисление – это набор символических имен (членов), которые связаны между собой постоянным и уникальным значением. С перечислением, члены можно сравнить по идентичности. При этом непосредственно возможны повторы непосредственно перечисления.
for monster in Monster: print(monster) # Monster.ZOMBIE # Monster.WARRIOR # Monster.BEAR
Встроенный LRU кэш
Кэш можно найти фактически в каком-угодно горизонтальном отрезке программного обеспечения, который мы сейчас пользуемся. Python 3 делает их использование очень простым, используя кэш LRU в качестве декоратора, который называется lru_cache.
Внизу вы можете увидеть простую функцию Фибоначчи. Насколько мы знаем, она от кэширования только выиграет. Ведь она использует рекурсию для того, чтобы работать, многократно повторяя аналогичные действия.
import time def fib(number: int) -> int: if number == 0: return 0 if number == 1: return 1 return fib(number-1) + fib(number-2) start = time.time() fib(40) print(f'Duration: {time.time() - start}s') # Длительность: 30.684099674224854s
Теперь нами может использоваться lru_cache для оптимизации (эта техника называется меморизацией). Время выполнения отличается. Оно может быть как несколькими наносекундами, так и несколькими секундами.
from functools import lru_cache @lru_cache(maxsize=512) def fib_memoization(number: int) -> int: if number == 0: return 0 if number == 1: return 1 return fib_memoization(number-1) + fib_memoization(number-2) start = time.time() fib_memoization(40) print(f'Duration: {time.time() - start}s') # Длительность: 6.866455078125e-05s
Повторяемая расширенная распаковка
Здесь все понятно исходя из кода.
head, *body, tail = range(5) print(head, body, tail) # 0 [1, 2, 3] 4 py, filename, *cmds = "python3.7 script.py -n 5 -l 15".split() print(py) print(filename) print(cmds) # python3.7 # script.py # ['-n', '5', '-l', '15'] first, _, third, *_ = range(10) print(first, third) # 0 2
Классы данных (Python 3.7 и новее)
Python 3 также представляет классы данных, которые не обладают множеством ограничений. Поэтому они могут использоваться для того, чтобы сокращать стандартный код, поскольку декоратором автоматически генерируются специальные методы, такие как __init__() и __repr()__. Из официального заявления, они описываются как “изменяемые названные кортежи со значениями по умолчанию”.
class Armor: def __init__(self, armor: float, description: str, level: int = 1): self.armor = armor self.level = level self.description = description def power(self) -> float: return self.armor * self.level armor = Armor(5.2, "Common armor.", 2) armor.power() # 10.4 print(armor) # <__main__.Armor object at 0x7fc4800e2cf8>
Если же использовать классы данных, то получаем такую реализацию класса Armor.
from dataclasses import dataclass @dataclass class Armor: armor: float description: str level: int = 1 def power(self) -> float: return self.armor * self.level armor = Armor(5.2, "Common armor.", 2) armor.power() # 10.4 print(armor) # Armor(armor=5.2, description='Common armor.', level=2)
Пространство имен
Один из методов структуризации кода Python заключается в пакетах (папки с файлом __init__.py). Приведем пример из официальной документации Python.
sound/ Пакет верхнего уровня __init__.py Инициализировать звукового пакета formats/ Подпакет для преобразования формата файла __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ Подпакет для звуковых эффектов __init__.py echo.py surround.py reverse.py ... filters/ Подпакет для фильтров __init__.py equalizer.py vocoder.py karaoke.py ...
В Python 2, каждая папка, которая приведена выше, должна иметь файл __init__.py, который делает папку пакетом Python. В Python 3, с появлением неявных пакетов пространств имен, в этих файлах больше нет необходимости.
sound/ Пакет верхнего уровня __init__.py Инициализировать звукового пакета formats/ Подпакет для преобразования формата файла wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ Подпакет для звуковых эффектов echo.py surround.py reverse.py ... filters/ Подпакет для фильтров equalizer.py vocoder.py karaoke.py ...
Впрочем, как многие читатели заметили, это может оказаться не так уж и легко, как указано в этом разделе. Если анализировать спецификацию 420 в PEP, то файл __init__.py все равно еще может использоваться для обычных пакетов. Если удалить его из структуры папки, это превратит его в пакет пространства имен, включающий в себя дополнительные ограничения.
Официальная документация нативных пакетов пространств имен содержит неплохие примеры этого. Помимо этого, там можно найти названия всех ограничений.