Python: частные типы в подсказках типа?

#python #types #argparse #python-typing

#python #типы #argparse #python-типизация

Вопрос:

Мне нравятся подсказки типа, особенно для параметров моего метода. В моем текущем скрипте одна функция должна извлекать параметр типа argparse._SubParsersAction . Как видно из подчеркивания, это частный тип по соглашению. Я думаю, именно поэтому PyCharm выдает сообщение об ошибке Cannot find reference '_SubParsersAction' in 'argparse.pyi' при попытке его импорта (хотя оно есть).

Скрипт запускается, но кажется неправильным. Сообщение об ошибке кажется мне разумным, поскольку подразумеваются частные типы… ну, частные. Поэтому мой первый вопрос заключается в том, почему общедоступный метод ArgumentParser.add_subparsers() в первую очередь возвращает объект частного типа.

Я искал общедоступный суперкласс или интерфейс и _SubParsersAction действительно расширяется argparse.Action , но это мне не помогает, поскольку Action не определяет _SubParsersAction add_parser() метод (который мне нужен).

Итак, мои следующие вопросы: могу ли я использовать подсказки типа с argparse API? Или это возможно только частично, потому что API был разработан задолго до появления подсказок типа? Или моя идея ввода не соответствует системе типов Python?

Вот мой затронутый фрагмент кода. Он создает анализатор аргументов с вспомогательными аргументами, как описано в документации (https://docs.python.org/dev/library/argparse.html#sub-commands ).

main.py

 from argparse import ArgumentParser

import sub_command_foo
import sub_command_bar
import sub_command_baz


def main():
    parser = ArgumentParser()
    sub_parsers = parser.add_subparsers()

    sub_command_foo.add_sub_parser(sub_parsers)
    sub_command_bar.add_sub_parser(sub_parsers)
    sub_command_baz.add_sub_parser(sub_parsers)

    args = parser.parse_args()
    args.func(args)


if __name__ == '__main__':
    main()
  

sub_command_foo.py

 from argparse import _SubParsersAction, Namespace


def add_sub_parser(sub_parsers: _SubParsersAction):
    arg_parser = sub_parsers.add_parser('foo')
    
    # Add arguments...

    arg_parser.set_defaults(func=run)


def run(args: Namespace):
    print('foo...')
  

Проблема заключается в sub_command_foo.py . PyCharm показывает сообщение об ошибке Cannot find reference '_SubParsersAction' in 'argparse.pyi' в первой строке from argparse import _SubParsersAction, Namespace .

Ответ №1:

Я не использую pycharm и мало что делал с подсказками типа, поэтому не могу вам помочь. Но я argparse хорошо знаю. Основная часть этого модуля была написана до 2010 года, и с тех пор он был изменен черепашьими темпами. Он хорошо организован в смысле ООП, но документация — это скорее прославленный учебник, чем формальная ссылка. То есть он фокусируется на функциях и методах, которые понадобятся пользователям, и не пытается формально документировать все классы и методы.

Я провожу большую часть своего тестирования в интерактивном ipython сеансе, где я могу просматривать объекты, возвращаемые командами.

В Python различие между общедоступными и частными классами и методами не такое формальное, как в других языках. Префикс ‘_’ действительно обозначает «частные» вещи. Обычно они не документируются, но они все еще доступны. Иногда импорт ‘*’ импортирует все объекты, которые не начинаются с него, но argparse имеют более явный __all__ список.

argparser.ArgumentParser создает экземпляр объекта. Но этот класс наследуется от 2 «частных» классов. add_argument Метод создает Action объект и помещает его в parser._actions список. Он также возвращает его пользователю (хотя обычно эта ссылка игнорируется). Действие на самом деле является подклассом (все из которых являются «частными»). add_subparsers это просто специализированная версия этого add_argument .

add_parser Метод создает ArgumentParser объект

Мне кажется, что подсказка типа, требующая отдельного импорта «частных» классов, контрпродуктивна. Вы не должны явно ссылаться на эти классы, даже если ваш код их создает. Некоторые люди (компании) опасаются, что их можно изменить без уведомления и, таким образом, нарушить их код. Зная, как медленно argparse меняется, я бы не стал слишком много об этом.