Фічі Python 3, які ви не використовували — а варто було б

10 хв. читання

Внаслідок Python EOL більшість розробників переходять з Python 2 на Python 3. Проте здебільшого код на Python 3 все ще виглядає як код на Python 2, відрізняючи хіба що дужками. У статті оглянемо на прикладах, які фічі пропонує нам Python 3 і як вони полегшують розробку.

В наведених прикладах використовуватимемо Python 3.7, поруч з кожною фічею вказано мінімально допустиму версію Python.

f-strings (3.6+)

У жодній мові програмування не обійтися без роботи з рядками, тому важливо мати легкий та структурований спосіб для їх обробки. Більшість розробників Python віддають перевагу методу format для подібних завдань:

user = "Jane Doe"
action = "buy"
log_message = 'User {} has logged in and did an action {}.'.format(
  user,
  action
)
print(log_message)
# User Jane Doe has logged in and did an action buy.

Як альтернативу format Python 3 пропонує гнучкий спосіб інтерполяції рядків через f-strings. Приклад вище, але з використанням f-strings матиме такий вигляд:

user = "Jane Doe"
action = "buy"
log_message = f'User {user} has logged in and did an action {action}.'
print(log_message)
# User Jane Doe has logged in and did an action buy.

Pathlib (3.4+)

f-strings, звичайно, чудова фіча, але для рядків шляхів до файлів вже передбачені власні бібліотеки. Python 3 пропонує pathlib як зручну абстракцію для роботи зі шляхами.

Якщо ви не впевнені, чи варто вам використовувати pathlib, прочитайте цю статтю.

from pathlib import Path
root = Path('post_sub_folder')
print(root)
# post_sub_folder
path = root / 'happy_user'
# Робимо шлях абсолютним
print(path.resolve())
# /home/weenkus/Workspace/Projects/DataWhatNow-Codes/how_your_python3_should_look_like/post_sub_folder/happy_user

Анотація типів (3.5+)

Статична vs динамічна типізація — одвічна тема для суперечок у програмуванні. Вирішуйте самі, чому віддавати перевагу, проте зауважте, що Python 3 підтримує анотації типів.

def sentence_has_animal(sentence: str) -> bool:
  return "animal" in sentence
sentence_has_animal("Donald had a farm without animals")
# True

Переліки (3.4+)

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 (Last Recently Used) кеш (3.2+)

Кеш — невіддільна частина будь-якого програмного і апаратного забезпечення. Python 3 значно спрощує його використання, передбачаючи LRU (Least Recently Used) кеш як декоратор 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')
# Duration: 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')
# Duration: 6.866455078125e-05s

Розширене розпакування послідовностей (3.0+)

Нехай код скаже сам за себе (документація).

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

Класи даних (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)

Неявні пакети простору імен (3.3+)

Один зі способів структурувати код на Python — використовувати пакети (теки з файлом __init__.py).

Оглянемо приклад з офіційної документації Python:

sound/                          Пакети верхнього рівня 
      __init__.py               Ініціалізація пакету
      formats/                  Підпакет для перетворення форматів файлів
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Підпакет для effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Підпакет для filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

У Python 2 вам необхідно додати файл __init__.py для перетворення теки на пакет. У версії 3 з появою Неявних пакетів простору імен цей крок можна оминути:

sound/                          Пакети верхнього рівня
      __init__.py               Ініціалізація пакету
      formats/                  Підпакет для перетворення форматів файлів
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Підпакет для effects
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Підпакет для filters
              equalizer.py
              vocoder.py
              karaoke.py
              ...

Зауважте: як влучно помітили розробники, все не так просто, як описано вище. Офіційна специфікація PEP 420 наголошує, що файл __init__.py досі необхідний для створення пакетів. Якщо ви перенесете такий файл у теку, то створите нативний пакет простору імен, але з додатковими обмеженнями (офіційна документація щодо нативних пакетів простору імен описує всі обмеження більш детально).

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація