Comments 25
Типы, как и читаемый код в целом, нужны не просто для других людей.
Через пару месяцев ты сам становишься "другим человеком"
Поражает, что питон, декларируя, что явное лучше неявного, полагается на неясность в выводе типов.
А Шаблоны или generic есть в пютоне? То-есть, в первой версии я вижу код, который складывает str значение двух любых типов.
Может и 1+2=12, может и [1,2] + [2,3]=[1,2][2,3], может и 1.2+2.3=1.22.3, а после добавление аннотации, код только с int начал работать, то-есть для float нужно писать второй раз такую функцию
~~~
А, дочитал, есть, ну ок
Ух ты, новости из 2015.
В свое время, до третьей версии питона, я отмечал ожидаемый тип переменной в имени переменной: temp__int, urls__list_str, updated_data__list_any, response__sparse_dict_int_str. Тип переменной именно суффиксом, а не префиксом, для удобства работы с автодополнением в редакторе. Также и для функций, тип возвратного значения заносится в имя.
Эти соглашения в readme потом пишутся одним абзацем. Вообще не о чем говорить, а польза большая. Хотя бы то, что ты явно задумываешься о типах переменных и можешь избежать оплошностей по неосторожности, которые всплыли бы потом, во время исполнения
а мы теперь вводим в него статическую типизацию
Аннотации типов это просто фича языка, которая позволяет вам более точно выразить ваши ожидания от типов.
def concat(a: int, b: int) -> str:
return a+b
Как придумать еще один вариант записи комментариев, который может не отражать содержимого.
Аннотации типов нужны по большей части для самого программиста и IDE.
Интерпретатор сейчас их не валидирует никак - к огромному сожалению.
Нужны анализаторы. За такое они по рукам надают
Так можно вообще на любой язык набросить. Отстрелить себе намеренно ногу и публично предать язык анафеме: вот, ногу мне повредил.
ну так на базу нужно натравить тайп чекер. просто текст кода понятно что можно что угодно написать.
Я стараюсь документировать код, а аннотиции типов это самая легкая форма документации.
Есть поддержка со стороны языка и инструментов.
Забыли сказать про главную проблему типизации.
Если объект на тип который вы ссылаетесь, еще не определён, можно его тип взять в кавычки.
class Foo:
def foo(self) -> "Foo":
return self
Иногда аннотации позволяют выразить то, что сложно сделать в коде.
Mapping это неизменяемый словарь. Родной реализации такого словаря в Питоне нет, писать самому или устанавливать зависимости не всегода хочется.
В данном случае я явно указываю свои ожидания, что возвращаемое значние менять не надо.
from typing import Mapping
def get_config() -> Mapping:
config = {}
...
return config
Забыли сказать про главную проблему типизации.
Если объект на тип который вы ссылаетесь, еще не определён, можно его тип взять в кавычки.
Теперь в 3.10 можно указывать в методе класса, сам класс.
class Foo:
def do_something() -> Foo:
return Foo()
А в 3.11 нам завезут тип Self, который решает проблему типизации при наследовании, когда метод возвращает именно self, и у наследника это по сути будет уже другой тип.
from typing import TypeVar, Type
T = TypeVar('T')
class A:
@classmethod
def a(cls: Type[T]) -> T:
return cls()
def b(self: T) -> T:
setattr(self, 'b_attr', True)
return self
class B(A):
def c(self) -> bool:
return getattr(self, 'b_attr', False) or False
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from some.other.module import SomeOtherType
def some_func(some_arg: 'SomeOtherType') -> bool: ...
В этом случае тайпхинт аргумента - строго ForwardReference (в кавычках, как строка).
Когда говорят о типах - примеры это всегда самое сложное.
Потому, что вы вводите типы, чтобы сделать код более хм... разумным.
Но когда вы приводите плохой пример - вы портите всё впечатление от разумных доводов.
Скажем вместо того, чтобы типизировать вот эту функцию - её просто (ровно в таком виде) не надо писать никогда:
def concat(a: int, b: int) -> str:
return str(a) + str(b)
Т.е. может существовать либо "библиотечная" ф-ия:
def concat(a: str, b: str) -> str:
return a + b
.....
x = concat(str(a), str(b))
Либо прикладная функция:
def getForm15Result(a: int, b: int) -> str:
return str(a) + str(b)
Там аннотации типов используются для прозрачного разбора и преобразования аргументов команды. Например:
@bot.command(pass_context=True)
def plus(context, x: int, y: int):
context.send(f'{x} + {y} = {x+y}')
При вводе команды "!plus 2 3", библиотека попытается разбить строку на правильное число параметров и конвертировать их в нужные типы. Если получится — то вызовет обработчик plus() с правильными аргументами.
Для пользователя библиотеки это дико удобно, по-моему.
Динамичный питон до сих пор статично выдаёт ошибку при print( int(x) ), понятное дело, что это неправильный параметр для данной функции, да и с подобным в основном сталкиваются новички.
По основной теме:
питон динамичен, многие стараются делать универсальные функции для разных типов данных, особенно, если функция будет что-то перебирать. Порой проще добавить образно .to_list() , чем делать отдельную функцию под серию и под список.
Но, если не подразумеваются разные входные данные, то конечно вместо несколько строк описания - лучше просто сделать аннотацию.
Почему я начал использовать аннотации типов в Python – и вам тоже советую