#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
меняется, я бы не стал слишком много об этом.