Комментарии 15
Как придумать самим себе проблему, типизировав формальный параметр, и затем её героически решать.
>>> sin(True)
0.8414709848078965
>>> sin(Decimal(1))
0.8414709848078965
>>> sin(Fraction(1, 1))
0.8414709848078965
и не типизирована docs.python.org/3/library/math.html#math.sin
Параметр только позиционный
>>> sin(x=True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: math.sin() takes no keyword arguments
Наверно, не стоило использовать название реальной ф-ции, но думал, кавычек в тексте хватит.
def sin(x: Number):
Вопрос в том, зачем так было писать. Неважно, как эта функция называется.
Так-то уж, если по существу разбираться, элементарные типы вроде int по своей реализации не являются наследниками абстрактных классов.
Я не понимаю, что такое “число”. Это вредная генерализация понятия.
Со времён после Фортрана II договорились иногда разрешать использовать целые константы в качестве вещественных, но нельзя же этот весьма дурно пахнущий трюк эксплуатировать, расширяя до бесконечности.
def f(x: Union[int, float, Decimal, Fraction, Complex])
?Я бы предпочёл видеть f(x). А если уж хочется расписать типы, то тогда надо для начала разбираться, int там должно быть по существу задачи или float.
Бессмысленно специфицировать тип просто исходя из того, что технически в состоянии принять синус в конечном итоге. Это то же самое, что отсутствие спецификации, только запутаннее.
А решение-то — единственный кусок кода (псевдокод, ибо питонам не обучен):def sin(int x)
sin(float::x)
end
Раз требуется, чтобы параметр был определённого типа — пишете обёртку, которая берёт "любой" тип, и приводит его к "определённому".
В общем случае это не работает — представьте, что «определённым» типом является int, а «любым» — float или complex. Уверены, что есть разумные правила приведения?
Кстати, что насчёт ситуации, когда приведение типа завершилось неудачно?
В python приведение типа работает только для анализатора docs.python.org/3/library/typing.html#typing.cast
Кроме того, оно приводит любой тип к любому
from typing import cast
def s(x: str):
pass
s(cast(str, 1))
# Success: no issues found in 1 source file
Что равнозначно отсутствию проверки типов совсем.
Но как таковой проблемы нет, случаев, когда в одну ф-цию захочется передавать все эти типы очень немного, ничто не мешает в таких общих случаях тип не декларировать или перечислять все базовые типы:
def f(x: Union[float, Decimal])?
Или объявить протокол:
from decimal import Decimal
from typing import cast, Protocol
class MyNumber(Protocol):
def __add__(self, other):
pass
def __mul__(self, other):
pass
def __pow__(self, power, modulo=None):
pass
def s(x: MyNumber):
pass
s(cast(str, 1))
s(Decimal(1))
Строка не пройдёт:
ws.py:21: error: Argument 1 to "s" has incompatible type "str"; expected "MyNumber"
ws.py:21: note: 'str' is missing following 'MyNumber' protocol member:
ws.py:21: note: __pow__
Found 1 error in 1 file (checked 1 source file)
Правда, не пройдёт только из-за того, что у неё не определёна операция возведения в степень.
Если бы вы сначала разобрались, а не побежали бы поскорее писать статью на Хабр, вы бы написали статью совсем о другом, другой длины и с нормальным разбором конкретной темы. В текущем варианте вы прыгаете с одного вопроса на другой и смешиваете две разных системы.
Для начала стоило бы в статье оставить ссылку на само обсуждение.
Так называемый number (или numeric) tower изначально определён как модуль numbers в PEP 3141 от далёкого 2007 года. То есть за год до релиза Python 3 и за семь лет до появления тайпхинтов в 2014. Тот же самый PEP 484, прямо в том же абзаце, который вы привели в пример, предлагает использовать реальные классы для реализации numeric tower, а вы это предложение игнорируете и продолжаете использовать старые абстрактные классы.
Более того, давайте посмотрим в тот самый PEP 3141 и узнаем, как должен быть определён Number:
class Number(metaclass=ABCMeta): pass
То есть, в общем-то, никаких методов нам этот класс не даёт (потому что это протокол для абстрактного числа, а число может иметь совершенно разные свойства и разные операции — к примеру, если вы принимаете два числа, вы не можете их сравнивать, потому что сравнение не определено для комплексных чисел). Что вы имеете в виду, когда пишете x: Number
?
Давайте и дальше читать половину документации и бежать оформлять текст на Хабр из-за этого.
Статья написана в пятницу и представляет собой обычную не очень серьёзную пятничную хабра статью. Не стоит относиться к ней как к статье по теории типов в Oxford University Press или IEEE.
P.S. Ссылку забыл добавить, сейчас пофикшу, спасибо.
Да я не говорю, что статья должна тянуть на серьёзное исследование, просто она какая-то пустая, что ли. Я за 5 минут пролистал обсуждение и пробежался по PEP 484/3141 достаточно, чтобы расписать суть лучше.
Хотелось бы, чтобы авторы статей на Хабре тоже разбирались в предмете статьи, хотя бы в виде 10-минутного прочтения литературы об этом.
В питоне реально приятно работать. Не смотря на некоторые проблемы, привлекает своей универсальностью и не особо сложный. Но Ява всё же поинтереснее будет
Приключения чисел в python и mypy или the numeric tower