Когда Гвидо ван Россум впервые написал, что он подумывает о том, чтобы попробовать включить в Питон опциональное описание типов аргументов и значений функций, а потом долго гасил флейм, я сразу эмоционально принял сторону ярых противников этой штуки. В конце концов, у нас же есть duck typing! И всякая идея декларировать тип объекта отдельно от того, что он и так сам собой представляет, ведет ко всем неудобствам сидения на двух стульях и выполнению двойной работы. И вообще — ересь какая-то :-)

Однако в сегодняшнем его посте о подготовке Питона 3000, я узнал, что решение о включении этой опциональной типизации (которая называется "function annotations") таки принято.

Тем не менее, вместо того, чтобы идти в угол плакать, я решил все же прочитать, что же оно на самом деле собой представляет: PEP 3107, Function Annotations. Все, оказывается, гораздо веселей, чем можно было думать! Для тех, кто не пойдет читать (знаю, сам такой :-) ), перескажу вкратце, что мне больше всего понравилось.

"Аннотации" — это выражения, которые как-то описывают параметры и возвращаемое значение функции, типа такого:

def func(a: Integer, b: String) -> Sequence:
  # ...

Но это не типы!

Во-первых, они не просто опциональны, а совсем опциональны. То есть, их не только не обязательно указывать, как таковые, но и даже если они указаны, в функцию все равно можно передавать все что угодно, как и раньше. Их роль — исключительно добавочная, для того, чтобы всякие сторонние тулзы могли делать больше предположений о коде и предоставлять лучший сервис. Речь идет о дополнении кода и подсказках в редакторе IDE, внешних проверяльщиках корректности кода и т.д. Цитируя PEP, аннотации "не имеют никакого собственного смысла; смысл определяется только сторонней библиотекой".

Во-вторых (после чего я теперь считаю, что аннотации — вещь!), они не обязаны быть похожими на типы. Это может быть любое выражение: число, строка, вычисление, ну и тип тоже, конечно. Можно например написать:

def  show(f: 'Filename or a file-like object'):
  # ...

И аннотацией к параметру "f" будет просто поясняющий текст. Также, насколько я понимаю, можно сказать "возвращаемое значение функции "process" предполагается таким же, как у функции "prepare":

def process() -> prepare.func_annotations['return']:
  # ...

Короче говоря, это не какая-то страшная "типизация", это просто такая структурированная документация, дающая полезные подсказки сторонним тулзам.

Кстати, первая альфа Питона 3000 обещается в этом августе. А релиз — в следующем августе. Пора начинать привыкать :-).

Комментарии: 38

  1. Michael Ilyin

    Это правильно. Я, например, начав разбираться с Django и Питоном, был неприятно удивлен тем, что не могу понять, что делает метод, что от него ожидать и чего в него можно передать, просто глянув на заголовок. Все таки строгая типизация и variant там, где нужно - это самый правильный подход IMHO.

  2. dacuan

    В мире С, C++ Java, PHP и т.п. для этих целей используется формат Doxygen (http://www.stack.nl/~dimitri/doxygen/)). Кстати, на их сайте заявлена поддержка и питона ;).

    Что заставляет придумывать новый подход и отказываться от проверенного решения?

  3. Иван Сагалаев

    Основная мотивация "почему не docstring'и", насколько я понял, в том, что docstring'и тогда получатся слишком сложными и слишком для многих вещей. С аннотациями проще работать — их не надо парсить отдельно. А сейчас да, именно в докстрингах все такое и принято хранить.

  4. dacuan

    С аннотациями проще работать — их не надо парсить отдельно.

    ЧТо значит "не надо парсить отдельно"? Как я понял этим занимаются редакторы и IDE, а Pyton'овский парсер их будет просто игнорировать. А для IDE особой разницы нет что аналицировать аннотации или Doxygen. Кроме того, формат Doxygen позволяет позволяет описать работу метода, в большинстве случаев простого указания типов и кратиких описаний параметров и возвращаемого результата будет не достаточно.

  5. Максим Деркачев

    2dacuan.
    Питоновский парсер их не будет игнорировать, он их будет засовывать в метаданные объекта. Примерно так же как сейчас он хранит докстринги в __doc__. То есть сам Python не будет делать никаких выводов из аннотаций, но будет их хранить структурированно. И дополнительно парсить докстринги, чтобы выдернуть из них информацию о параметре, не потребуется.

  6. Alex Lebedev

    Когда прочитал PEP, сама идея мне очень понравилась. С другой стороны, это лишь отличная потенциальная возможноть. Реальная польза будет целиком и полностью зависеть от тех самых третьесторонних библиотек, которые эти аннотации должны использовать. В Python 3.0, и вероятно, в несколько следующих версий тоже, ни одна из таких библиотек не войдет.

  7. bialix

    doxygen может и неплох для си, но для питона лучче epydoc

  8. mike

    @Максим

    т.е., доводя до конечной точки можно сказать, что аннотации == докстринги для параметров функций. Что правильно. Отдельное спасибо Ивану за разъяснение.

  9. koder

    Alex Lebedev:

    В Python 3.0, и вероятно, в несколько следующих > версий тоже, ни одна из таких библиотек не войдет.

    Если доделают то войдет библиотека для перегрузки
    ф-ций, так-же есть вполне устоявшаяся typechecker,
    ее то-же скорее всего перепишут. Кроме этого можно
    ожидать существенного улучшения автодополнения в IDE. И упрощений/улучшений в PyREX,shedskin,etc.

  10. Давид Мзареулян

    Мне кажется, это ужасная тенденция. В php эту недотипизацию вставили, в js собираются, теперь вот до питона дошли. И везде никакого практического смысла в ней нет, только раздувание кода и введение в язык новых сущностей. Нафига type hinting и комментарии к параметрам, если все IDE давно понимают докстринги?

  11. koder

    Для Давида Мзареуляня:
    помоему Вы не дочитали или неправильно поняли что
    это такое. Это не типизация - типизация не вписывается в duck typing, это не "док стринги" -
    их не надо парсить, это готовые данные. Питону катастрофически нужна опциональная типизация - это
    путь к решению многих проблем ( от оптимизации до упрощения написания инструментов типа pychecker ). Единственна IMHO проблема (точнее палка о двух
    концах) это отсутствие хоть каких-нибудь
    стандартов на аннотации - может привести к
    маленькому хаосу.

  12. Давид Мзареулян

    Да всё я дочитал. Почему Вы думаете, что "Питону катастрофически нужна опциональная типизация"? Что такого "катастрофического" без неё происходит, что потребовалось менять синтаксис языка?

  13. Давид Мзареулян

    Я уж не говорю о том, что Питон, вообще-то, и так строго типизированный язык. Так, на минуточку. Если кто забыл.

  14. koder

    Да всё я дочитал.

    Тогда предлагаю прочитать еще обсуждение с
    pydev рассылки и PEP соответствующий
    http://www.python.org/dev/peps/pep-3107/
    , что-бы подобные вопросы не возникали, там все расписано.

    и так строго типизированный язык

    Это динамическая типизация. Я уже описывал раньше утилиты/библиотеки которые сильно
    выиграют от статической типизации. Вот расширенное описание возможностей по оптимизации - будет возможна прозрачная статическая компиляция части кода инструментами типа pyrex. Очеь большая часть кода, который я пишу - статически типизированная.
    И иногда после профилирования приходится его переписывать на C и Pyrex'ом связывать с питоном.
    После введения аннотирования достаточно будет указать типы в такой ф-ции + добавить к ней декоратор - все остальное можно будет автоматизировать. То-же относится и к psyco - его работа существенно упростится, т.к. все что ему не хватает - это типов. Аналогично shedskin.
    И еще вагончик либ типа scipy.weave.

  15. Deepwalker

    То есть теперь получается, что если я захочу скорости на родном языке, мне надо будет всего лишь указать у критичных участков кода аннотации, декоратор и скорость взлетит? О счастье, холиварщики повоюют и сами станут пользоваться : )

  16. koder

    to Deepwalker.
    Я поправлюсь, на всякий случай. Это только
    потенциальная возможность, т.е. ничего
    подобного по-умолчанию встроено в питон не будет.
    Хотя ее реализация весьма простая, и я вполне
    представляю себе как это можно сделать, т.е. если
    это не сделают за меня, то я сделаю это сам )).

  17. Deepwalker

    Интересно, а что прикрутят к этому джанговцы? Они же достаточно активно используют возможности python в части интроспекции.

  18. koder

    Нашел еще одно интересное(IMO) применение комбинации декораторов для классов и аннотаций.
    Автоматическая перегрузка + сопоставление с образцом (то чем так гордятся любители Haskell и остальной функциональщины). Т.е. можно будет сделать так:

    class My(metaclass = Overloaded):
        def fact(x : int):
            return fact(x - 1) * x
        def fact(x : 0):
            return 1
        def fact(x):
            raise ValueError("'x' must be integer")</p>
    
  19. Максим Деркачев

    2 koder
    Такая штука будет и без аннотаций и декораторов, называется generic functions

  20. koder

    Максим Деркачев:

    Такая штука будет и без аннотаций и декораторов,
    называется generic functions

    Generic functions это то что будет
    сидеть "under the hood"(ключевое слово
    моего поста было "Автоматическая").
    Для generic functions нужно явно
    декораторами(overload или when) отмечать
    перегрузку для каждой перегружаемой
    ф-ции(http://www.python.org/dev/peps/pep-3124/),
    а за счет новых метаклассов это станет не
    нужно. when же будет основой для сопоставление с
    образцом. А аннотации нужны в любом случае -
    именно из них generic и вынимают данные о
    перегрузке и специализации.

    P.S. Спасибо Ивану за правку кода в моем посте.

  21. Max Ischenko

    отсутствие хоть каких-нибудь
    стандартов на аннотации - может привести к
    маленькому хаосу

    Возможно это by design. Свобода маневра чтобы дать best practices сформироваться.

  22. Артём Скорецкий

    Документации никогда не бывает много. Особенно если она является дополнительной и более структурированной, чем предыдущая.

    Описание параметров будет очень полезным для работы сторонних (уже существующих) утилит - скажем, для статической типизации (опциональной, между прочим).

    Кстати - если та же статическая типизация через аннотации будет востребована и станет популярной, то она рано или поздно появится в Python. Может, не в Python 3.5, а в Python 4000 ;)

  23. Давид Мзареулян

    Описание параметров будет очень полезным для работы сторонних (уже существующих) утилит - скажем, для статической типизации (опциональной, между прочим).

    Что автоматически а) поставит крест на свободе комментирования (утилитам-то конкретный формат подавай) и б) расплодит зоопарк этих самых форматов. И будем потом в затылке чесать, почему код, написанный в одном IDE не подхватывается в другом.

    Вот честно пытаюсь хоть один плюс в этом найти — не могу.

  24. Василий

    Лучше бы они вместо строчек, lambda добавили. Например вот так:

    def divide(a, b: b != 0):
    return a / b

  25. koder

    Давид Мзареулян написал:

    Что автоматически ...

    Вы повторяете то, что я уже написал выше.

    Вот честно пытаюсь хоть один плюс в этом найти
    - не могу.

    PEP мы так и не прочитали 8(. Не используйте
    аннотацию - никто не заставляет.

    Василий написал:

    Лучше бы они вместо строчек, lambda добавили.
    Например вот так:

    def divide(a, b : 'b != 0'):
        return a / b
    

    Так сойдет? Выражение компилируется при первом
    обращении к функции.

  26. Deepwalker

    Он хотел, чтобы проверялось b : ))
    Напишите себе декоратор - пусть проверяет.
    В том то и суть, что использование не ограничено.

  27. pythonwin

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

  28. Murkt

    Могу посоветовать посмотреть на PyPy и его Restricted Python. В принципе, действительно несколько похоже на статическую типизацию, и если я не ошибаюсь, RPython транслируется в низкоуровневые языки, и тогда всё красиво и быстро. А ограничений там кот наплакал.

  29. Murkt
  30. koder

    to Deepwalker

    Он хотел, чтобы проверялось b:))

    Это подразумевалось ;) -
    "Выражение компилируется при первом обращении к
    функции.". Скорее удобнее будет сделать это на
    классовых декораторах или сразу для всего модуля - что-бы не декорировать каждую ф-цию в отдельности.

    Напишите себе декоратор - пусть проверяет.

    Кстати то что подобное не используется сейчас
    сразу показывает насколько оно нужно. Это скорее
    ближе получается к "design by contract".

  31. koder

    Murkt:

    Могу посоветовать посмотреть на PyPy и его
    Restricted Python .....
    А ограничений там кот наплакал

    Из ограничений вся динамическая часть и интроспекция и стандартная библиотека и декораторы и .... ;). Ну да ладно, при компиляции это в любом случае не выживет. Основная проблема это невозможность "миксовать"(AFAIK) Python и RPython код, т.е. невозможно написать часть программы на RPython, а часть на Python и прозрачно вызывать ф-ции. IMHO удобнее PyReX + классы, выдранные из shedskin кода (хотя тоже так се).

  32. cleric

    Было бы отлично еслиб это введение помогло написать статический компилятор с поддержкой вывода типов. Иначе язык станет еще медленее, ибо все радости жизни вроде перегрузки функций/методов, сопоставления с образцом и тд, будут жрать ресурсы в ран-тайме.

  33. Oleg Andreev

    Фигня это. Нет мануала лучше, чем несколько примеров вызова функции (посмотрите api.rubyonrails.com). А тут язык загромаждают мусором.

  34. Murkt

    Фигня это. Нет мануала лучше, чем несколько примеров вызова функции

    К сожалению, JIT-компиляторам, анализаторам, IDE недоступен высший дзен.

    Их роль — исключительно добавочная, для того, чтобы всякие сторонние тулзы могли делать больше предположений о коде и предоставлять лучший сервис. Речь идет о дополнении кода и подсказках в редакторе IDE, внешних проверяльщиках корректности кода и т.д.

  35. Oleg Andreev

    Murkt: мне один умный товарищ говорил, что код пишут для того, чтобы его читал человек и лишь иногда — машина.

  36. Murkt

    Oleg Andreev: аннотации мешают восприятию кода?

  37. Макс Лапшин

    Забавная идея, ничего не скажешь. Главное, конечно, не вздумать отойти от duck-typing, впрочем это поставит крест на всём написанном объёме кода =)

  38. [...] Добавлены аннотации функций. [...]

Добавить комментарий