Оглавление

Описание

typing (тайпинг)

Шаблоны или generic

mypy

Статический анализ

Тайпинги

Синтаксис

Как указать тип переменных?

Как указать тип аргументов и возвращаемого значения в функции?

Как указать типы при написании классов?

Стандартные типы-классы

Generic

Примеры generics в Python:

Mypy

Частые ошибки

Ожидать, что функции всегда возвращают значение и не могут вернуть None

Указывать значения по умолчанию для изменяемых типов

Забывать указывать тип внутри generics (List, Dict, Set, Tuple)

Описание

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

typing (тайпинг)

int, str, float и так далее. Любые системные и пользовательские типы в Python.

Шаблоны или generic

специальные типы, в которых можно указывать внутренние типы. Мы с вами познакомились с шаблонами на примере List, Tuple, Dict, Set. Такие типы можно создаваться самостоятельно, об этом подробнее написано в официальной https://docs.python.org/3/library/typing.html#building-generic-types

mypy

это статический анализатор (утилита, которая выполняет статический анализ кода) для Python 3. Если вы используете типизацию в Python, то mypy сможет проверить код и найти распространенные ошибки. Важно помнить, что типизация является лишь подсказками для mypy, даже если mypy завершается с ошибка, программа на Python всё равно запустится.

Статический анализ

процесс, при котором программа проверяет код другой программы без ее запуска. Этот процесс похож на код-ревью. Программа, как будто другой человек, проводит проверку кода и дает рекомендации, что нужно исправить. Подробнее прочитать можно в wiki.

Тайпинги

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

Синтаксис

Для обозначения базовых типов переменных используются сами типы:


                    
🎯 str
🎯 int
🎯 float
🎯 bool
🎯 и так далее
                

Как указать тип переменных?

В функции hello объявили 3 переменных: var1 типа int, var2 типа str, var3 типа dict.


                    
def hello():
    var1: int = 0
    var2: str = ''
    var3: dict = {}
                

Как указать тип аргументов и возвращаемого значения в функции?

Функция greeting принимает переменную name типа str и возвращает строку.


                    
def greeting(name: str) -> str:
   return 'Hello ' + name
                

Как указать типы при написании классов?

Конструктор класса Person (def __init__) принимает переменную name типа str и ничего не возвращает, в Python это означает, что функция возвращает None.


                    
class Person:
   def __init__(self, name: str) -> None:
       self.name = name
      
   def get_greeting(self) -> str:
       buf: str = 'Hello ' + self.name
       return buf
                

Стандартные типы-классы

Стандартные типы-классы, которые необходимы для написания кода: 🎯 Any — любой тип. Любой системный (int, float, ...) и пользовательский тип (class User: ...) соответствует типу Any. Этот тип стоит использовать только в крайних случаях, когда вы уверены, что не можете однозначно определить тип возвращаемых данных. 🎯 Optional[<type>] — type или None. Используется для пометки, что в переменной может быть значение None. Например:


                    
res = {}
var: Optional[str] = res.get("key")
                

🎯 Union[<type1>, <type2>, ...] — type1 или type2 или ... Используется, если код умеет работать с несколькими типами данных. Распространенный пример — функция умеет работать с целыми и дробными числами:


                    
def sum_int(a: Union[int, float], b: Union[int, float]) -> Union[int, float]:
    return a + b
                

Generic

Для описания списков, множеств, словарей подойдут шаблоны или generic. Такие типы могут принимать параметры, которые указывают, какой тип содержится внутри generic. Так, например, List[int] указывает на то, что список состоит только из целочисленных значений.


                                                   
from typing import List

def func(n: int) -> List[int]:
    return list(range(n))

Функция вернет список чисел от 0, ... , n–1
                

Примеры generics в Python:


                    
🎯 Set[int] — множество (set) из чисел.

🎯 Tupe[str, str] — кортеж ("hi", "hello") из двух строковых переменных.

🎯 Dict[int, str] — словарь, где ключи будут иметь тип int, а значения — тип str.

🎯 Iterable[str] — объекты, которые реализуют метод __iter__, элементами этого итератора являются числа. Таким типом нужно помечать переменные, созданные генераторами или итераторами.
                

Mypy

Типизация в Python носит необязательный характер. Код может не соблюдать типы, при этом запускаться и работать. Но возникает вероятность появления неожиданных ошибок. Поэтому лучше соблюдать типы и использовать утилиту mypy для проверки корректности использования типов.


                    
Для установки необходимо вызвать:

`python3 -m pip install mypy`
                

Команда mypy запускает проверку ваших файлов и распечатывать все найденные ошибки. Mypy проверят ваш код статически: это означает, что он будет проверять наличие ошибок, даже не запуская ваш код, анализируя ваш код, словно человек.


                    
Для запуска проверки файла или папки нужно вызвать:

`mypy program.py`

или 

`mypy my_directory/`
                

Команда mypy запускает проверку ваших файлов и распечатывать все найденные ошибки. Mypy проверят ваш код статически: это означает, что он будет проверять наличие ошибок, даже не запуская ваш код, анализируя ваш код, словно человек.


                    
[mypy]
disallow_untyped_defs = True
                

Этот параметр запрещает объявлять функции без указания типов принимаемых и возвращаемых значений. Подробнее об этом можно прочитать в официальной документации mypy.


                                                   
Если никак не получается решить ошибку mypy и вы знаете, что делаете, то можно ее проигнорировать: 

err_var: int = ""  # type: ignore
                

Частые ошибки

Забыть установить mypy


                    
python3 -m pip install mypy
                

Ожидать, что функции всегда возвращают значение и не могут вернуть None

Например, получать из словаря с помощью метода get ключи и ожидать, что он не может быть None.


                                                   
Плохо

from typing import Dict

d: Dict[str, int] = {}
var1: int = d.get("key")
                

                                                   
Хорошо

from typing import Dict, Optional

d: Dict[str, int] = {}
var1: Optional[int] = d.get("key")
                

Указывать значения по умолчанию для изменяемых типов


                                                   
Плохо

@dataclass
class Person:
    first_name: str
    last_name: str
    children: list = []
                

                                                   
В случае запуска такого кода будет вызвано исключение:

ValueError: mutable default <class 'list'> for field children is not allowed: use default_factory
                

                                                   
Хорошо

@dataclass
class Person:
    first_name: str
    last_name: str
    children: list = field(default_factory=list)
                

Забывать указывать тип внутри generics (List, Dict, Set, Tuple)

При создании схемы на основе датакласса выше будет выведена абсолютно неочевидная ошибка:


                                                   
Плохо

@dataclass
class Person:
    first_name: str
    last_name: str
    children: List

PersonSchema = marshmallow_dataclass.class_schema(Person)
                

                    
File ".../python3.9/site-packages/marshmallow_dataclass/__init__.py", line 447, in _field_for_generic_type
    child_type = field_for_schema(arguments[0], base_schema=base_schema)
IndexError: tuple index out of range
                

                                                   
Хорошо

@dataclass
class Person:
    first_name: str
    last_name: str
    children: List[int]
                
© 2023 Все права защищены