След като разгледах SQL бази данни с Python и Flask, „тук“ и „тук“, днес исках да представя концепцията за типови подсказки в Python, техните случаи на използване, както и техните плюсове и минуси. Подсказките за тип могат да бъдат страхотни инструменти за подобряване на четливостта на вашия код, но те не винаги са най-доброто решение.

Тази публикация е предназначена като въведение за начинаещи в тази тема и може да напиша повече, ако има повече интерес. В резултат на това очаквам това да бъде лесно и бързо четене. Ако имате някакви коментари или предложения, уведомете ме в раздела за коментари по-долу.

Какво представляват Python Type-Hints?

Подсказките за тип Python бяха въведени за първи път в PEP 484 и излязоха с Python 3.5. Както подсказва името, типовите подсказки са „подсказки“ за типа на променливите или обектите във вашия код.

Те ви позволяват да декларирате типа на променливите и връщаните типове на вашите функции. Това обаче не означава, че подсказките за тип правят Python статично въведен. Те са просто „намеци“, което означава, че не влияят върху работата на вашата програма.

Ако те нямат ефект върху кода, защо трябва да използваме подсказки за тип? Краткият отговор е, че те могат да бъдат полезни за самодокументиране на код. Освен това линтери и IDE могат да ги използват, за да подобрят познанията си за вашия код.

Въпреки че подсказките за тип са налични от известно време, всяка нова версия на Python добавя нови функции. Следващите примери са написани с мисъл за Python 3.9.4. Ако получите грешки при изпълнение на кода, може би първо проверете дали използвате съвместима версия.

Анотиране на прости променливи

Първият пример ще бъде за анотиране на основни типове python в променливи:

x:int = 10 
f: float = 0.4 
name:str = "hello"

Както можете да видите, ние казваме на IDE, че x е int променлива, f е float и name е str. Основният синтаксис за намек за тип е да въведете името на вашата променлива, последвано от двоеточие и след това основен тип на Python.

Не забравяйте обаче, че подсказките за тип са просто предложение и не се прилагат, когато кодът се изпълнява (въпреки че определени среди за изпълнение може да са в състояние да ги наложат, мисля). Бих могъл лесно да променя стойностите в променливите по следния начин:

x: int = 100 
# I can assign any value to x 
x = "Janice"

Мога също да задам неправилна стойност от самото начало:

x:int = "this is a string"

Както можете да видите по-горе, нищо не ми пречи да игнорирам подсказките за тип. Идеята обаче е, че ако ги използвате, това ще ви принуди да сте по-внимателни относно типовете на вашите променливи.

И накрая, можете дори да анотирате променливи, преди да им присвоите стойност:

a:int #a has no value yet 
# ... do something here 
my_str = "this is a string" 
a = len(my_str) #we only now assign a value to a

Анотиране на контейнерни обекти (Dicts, списъци, кортежи и т.н.)

По мое мнение анотирането на контейнерни обекти е мястото, където съветите за тип могат да станат объркани и понякога дори да намалят четливостта. Нека започнем с прост пример, променлива от списък:

# here I'm stating that my_list will 
#  only contain str and int values 
from typing import Union
my_list: list[Union[str, int]]

В горния пример можете да видите, че ние декларираме, че списъкът може да съдържа низове, както и цели числа.

Следващият пример е за анотиране на речници на Python. В случай на dicts има два елемента, които трябва да бъдат анотирани: ключове и стойности. Ето примера за синтаксис:

# simple annotation where keys and values are strings 
simple_dict: dict[str, str] = {
 'city' : 'London', 
 'Country' : 'UK', 
 'name' : 'James' 
}

В този пример ключовете на нашия dict ще бъдат низове, както и техните стойности. Често обаче съхраняваме много видове стойности в речник. Ето как да коментирате тези случаи:

#use "typing" module 
from typing import Union, Any 
my_dict: dict[str, Union[str,int,float,None,Any]] = { 
    'name' : 'James', 
    'age' : 20, 
    'height' : 1.8, 
}

В примера ние заявяваме, че стойностите на речника могат да бъдат: str, int, float, None или Any. Използваме импортирането, за да посочим, че стойността може да бъде всяка от посочените опции. Типът е всеобхватен израз, който е съвместим с всички други типове. Основно показва, че всеки тип е приемлив.

Трябва също да спомена, че на Python 3.10, следвайки PEP 604, можете директно да анотирате няколко типа, без да импортирате . Вместо това можете да използвате прекия път на Union „|“, както в следния пример:

# annotation for Python 3.10 
my_dict: dict[str, str|int|float|None|Any] = { 
    'name' : 'James', 
    'age' : 20, 
    'height' : 1.8, 
}

Функционална анотация

Подсказките за тип могат също да се използват за анотиране на функции и техните връщани типове. Ето един пример:

#add ints or floats 
def add_numbers(a:Union[int,float], b:Union[int,float]) -> Union[int,float]: 
    return a + b 
#function that does not return anything 
def good_morning(name:str) -> NoReturn: 
    print(f"Good morning {name}!")

В първия случай отново използвам модула typing за импортиране на Union. Вторият пример използва, за да покаже, че функцията прави не връща стойност.

Тези примери обхващат анотации на основните функции. Освен това можете да използвате следния синтаксис, за да посочите незадължителни параметри във функция:

from typing import Optional 
#function with optional parameters 
def some_function(a:int, b:str, c:Optional[Union[int,float]]) -> int: 
    pass

В този случай използваме, за да посочим, че стойността може да бъде всяка от споменатите или . По същество е еквивалентно на правенето на: Union[int, float, None].

Персонализирани класове и типове

Освен използването на вградени типове на Python за анотации, би било чудесно, ако можем да използваме наши собствени персонализирани класове като съвети за тип. За щастие можем да направим точно това. Да приемем, че имаме клас SimpleClassи искаме да декларираме променлива към екземпляр на класа. Можем да го направим по следния начин:

class SimpleClass(object): 
    number = 10 
    text = "SimpleClass" 
a: type[SimpleClass] = SimpleClass()

И така, като използваме ключовата дума type, можем да посочим персонализиран клас тип. Ще работи и за функции, когато трябва да върнем този клас или да го приемем като параметър:

def alter_class(my_class: type[SimpleClass]) -> type[SimpleClass]:
    my_class.name = 20 
    return my_class

В този пример функцията alter_class взема обект от тип SimpleClass и връща същия тип обект.

Предимства и недостатъци

Сега, след като разгледах някои от наличните основни съвети за тип, исках да спомена техните плюсове и минуси.

Професионалисти за подсказване на типа

  • Накарайте ви да мислите по-внимателно за вашия код и вашите променливи
  • IDE и линтерите ще разберат по-добре вашия код и дори биха могли да ви предупредят, ако сте направили грешка.
  • Подсказките за тип са бърз начин да имате самодокументиращ се код

Ако трябва да бъда честен, според мен основният недостатък на подсказките за тип е, че когато се използват прекомерно, те могат да претрупат кода и да го направят труден за четене. Не съм показвал примери за това. Независимо от това, можете да си представите колко досадно би било да има тези подсказки навсякъде в кода.

Моето лично мнение

Не съм използвал подсказки за тип много често, но малко по малко се ориентирам към тях. От една страна, когато се използват правилно, те могат да добавят много яснота при препрочитане на написаното от мен. От друга страна, не ми харесва, че са просто предложения. Ще ми е много по-удобно да отделя време да ги използвам, ако знаех, че ще бъдат уважавани. Мисля, че човек лесно може да забрави, че тези анотирани променливи все още могат да приемат всякаква стойност във всяка точка. Надяваме се, че IDE могат да помогнат за това.

В моя код съм склонен да имам доста дълги и описателни имена. Чувствам, че обикновено предават намерението ми доста добре. Разбирам обаче също така, че подсказките за тип предоставят по-стандартизиран начин за документиране на нашия код.

И със сигурност виждам ползата от използването на съвети за тип в големи кодови проекти. Особено такива, които се поддържат от много различни хора, по различно време. За скриптове за бързо изхвърляне вероятно не си струва твърде много.

Последни мисли

Днес предоставих основно въведение в съветите за тип на Python. Те съществуват от известно време, но все още не ги виждам да се използват много, затова исках да ги обясня тук.

Оставете коментар по-долу с всякакви предложения или мнения за тази публикация. Аз наистина го оценявам. Освен това не забравяйте да се абонирате за бюлетина, ако искате да поддържате връзка.

Можете също да се абонирате за моя канал в YouTube за видеоклипове относно Python проекти, автоматизация и крипто:

И накрая, ако искате да останете свързани и в крак с това, което публикувам, можете да се присъедините към моя бюлетин тук. Искам този бюлетин да бъде полезен източник на съвети и трикове, които научавам, както и място за разговори за нови проекти, върху които може да работя в бъдеще.

Първоначално публикувано в https://andresberejnoi.com на 28 март 2022 г.