Реализуете интерфейсы командной строки в стиле «[команда] [действие] [параметр]»?

Каков самый «чистый» способ реализовать пользовательский интерфейс командной строки, похожий на git, например:

git push origin/master
git remote add origin git://example.com master

В идеале также позволяет более гибкий синтаксический анализ, например,

jump_to_folder app theappname v2
jump_to_folder app theappname source
jump_to_folder app theappname source v2
jump_to_folder app theappname build v1
jump_to_folder app theappname build 1
jump_to_folder app theappname v2 build

jump_to_folder - это имя сценария, app - это команда, theappname - это параметр «фиксированного местоположения», «сборка» и «v2» и т. д. - аргументы (например, возможными аргументами могут быть любое число / любое число с префиксом av или сборка / источник / tmp / config)

Я мог бы просто вручную проанализировать аргументы с помощью серии if / else / elifs, но должен быть более элегантный способ сделать это?

В качестве чисто теоретического примера я мог бы описать схему пользовательского интерфейса.

app:
    fixed: application_name

    optional params:
        arg subsection:
            "build"
            "source"
            "tmp"
            "config"

        arg version:
            integer
            "v" + integer

Затем проанализируйте предоставленные аргументы, используя приведенную выше схему, и получите словарь:

>>> print schema.parse(["app", "theappname", "v1", "source"])
{
    "application_name": "theappname",
    "params":{
        "subsection": "source",
        "version":"v1"
    }
}

Такая система существует? Если нет, как мне реализовать что-то в этом роде?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
15
0
6 105
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Прямо из одного из моих скриптов:

import sys

def prog1_func1_act1(): print "pfa1"
def prog2_func2_act2(): print "pfa2"

commands = {
    "prog1 func1 act1": prog1_func1_act1,
    "prog2 func2 act2": prog2_func2_act2
}

try:
    commands[" ".join(sys.argv[1:])]()
except KeyError:
    print "Usage: ", commands.keys()

Это довольно быстрое и грязное решение, но оно отлично подходит для моего использования. Если бы мне пришлось немного его очистить, я бы, вероятно, добавил бы argparse в смесь для анализа позиционных аргументов и аргументов ключевого слова.

Проблема в том, что аргументы исправлены. Например, вы не могли легко иметь параметр "v001" .. "v102", если бы не создавали ключ для каждой комбинации ..

dbr 12.12.2008 14:34

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

kmelvn 12.12.2008 14:40

Кроме того, вы можете добавить метакоманду help, которая распечатывает содержимое команд и показывает их строки .__ doc__

pjz 12.12.2008 17:52

кроме того, аргументы на самом деле не фиксированы, потому что команды в списке команд принимают все аргументы, поэтому их можно анализировать в каждой команде (а общие синтаксические выражения могут быть исключены). Или, если вы имеете в виду, что список команд ограничен, рассмотрите возможность переопределения Getkey в объекте команд.

pjz 12.12.2008 17:54

В Python есть модуль для анализа параметров командной строки, optparse.

К сожалению, он анализирует командную строку параметры, а не аргументы, как запрашивает dbr

Piotr Lesnicki 12.12.2008 14:10

Точно. Насколько я могу судить, он лучше всего подходит для аргументов типа "-f 2 -v -z 55", если я чего-то не упускаю?

dbr 12.12.2008 14:32

Модуль cmd, вероятно, подойдет для этого.

Пример:

import cmd

class Calc(cmd.Cmd):
    def do_add(self, arg):
        print sum(map(int, arg.split()))

if __name__ == '__main__':
    Calc().cmdloop()

Запустить его:

$python calc.py
(Cmd) add 4 5
9
(Cmd) help

Undocumented commands:
======================
add  help

(Cmd)

См. Документы Python или Сайт PyMOTW для получения дополнительной информации.

Вот мое предложение.

  1. Немного измените грамматику.

  2. Используйте optparse.

В идеале также позволяет более гибкий синтаксический анализ, например,

jump_to_folder -n theappname -v2 cmd 
jump_to_folder -n theappname cmd source 
jump_to_folder -n theappname -v2 cmd source 
jump_to_folder -n theappname -v1 cmd build 
jump_to_folder -n theappname -1 cmd build 
jump_to_folder -n theappname -v2 cmd build

Тогда у вас есть 1 или 2 аргумента: команда всегда является первым аргументом. Это необязательный аргумент - всегда второй аргумент.

Все остальное - варианты, в произвольном порядке.

Ответ принят как подходящий

argparse идеально подходит для этого, особенно "подкоманды" и позиционные аргументы

import argparse


def main():
    arger = argparse.ArgumentParser()

    # Arguments for top-level, e.g "subcmds.py -v"
    arger.add_argument("-v", "--verbose", action = "count", default=0)

    subparsers = arger.add_subparsers(dest = "command")

    # Make parser for "subcmds.py info ..."
    info_parser = subparsers.add_parser("info")
    info_parser.add_argument("-m", "--moo", dest = "moo")

    # Make parser for "subcmds.py create ..."
    create_parser = subparsers.add_parser("create")
    create_parser.add_argument("name")
    create_parser.add_argument("additional", nargs = "*")

    # Parse
    opts = arger.parse_args()

    # Print option object for debug
    print opts

    if opts.command == "info":
        print "Info command"
        print "--moo was %s" % opts.moo

    elif opts.command == "create":
        print "Creating %s" % opts.name
        print "Additional: %s" % opts.additional

    else:
        # argparse will error on unexpected commands, but
        # in case we mistype one of the elif statements...
        raise ValueError("Unhandled command %s" % opts.command)


if __name__ == '__main__':
    main()

Это можно использовать так:

$ python subcmds.py create myapp v1 blah
Namespace(additional=['v1', 'blah'], command='create', name='myapp', verbose=0)
Creating myapp
Additional: ['v1', 'blah']
$ python subcmds.py info --moo
usage: subcmds.py info [-h] [-m MOO]
subcmds.py info: error: argument -m/--moo: expected one argument
$ python subcmds.py info --moo 1
Namespace(command='info', moo='1', verbose=0)
Info command
--moo was 1

Хороший! Именно это и прописал врач! Спасибо!

Eugene Sajine 12.07.2012 00:47

Другие вопросы по теме