Как лучше всего анализировать аргументы командной строки?
-
09-06-2019 - |
Вопрос
Что такое самый простой, краткий, и большинство гибкий метод или библиотека для анализа аргументов командной строки Python?
Решение
Этот ответ предполагает optparse
что подходит для старых версий Python.Для Python 2.7 и выше: argparse
заменяет optparse
.Видеть этот ответ Чтобы получить больше информации.
Как отмечали другие люди, вам лучше использовать optparse, а не getopt.getopt — это по сути однозначное отображение стандартных функций библиотеки C getopt(3), и его не очень легко использовать.
optparse, хотя и немного более многословен, гораздо лучше структурирован и его проще расширять в дальнейшем.
Вот типичная строка для добавления опции в ваш парсер:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
Это в значительной степени говорит само за себя;во время обработки он принимает -q или --query в качестве параметров, сохраняет аргумент в атрибуте с именем query и имеет значение по умолчанию, если вы его не укажете.Это также самодокументируется, поскольку вы объявляете аргумент справки (который будет использоваться при запуске с -h/--help) прямо там же, вместе с опцией.
Обычно вы анализируете свои аргументы с помощью:
options, args = parser.parse_args()
По умолчанию будут анализироваться стандартные аргументы, передаваемые в скрипт (sys.argv[1:]).
В options.query будет установлено значение, которое вы передали в скрипт.
Вы создаете парсер, просто выполняя
parser = optparse.OptionParser()
Это все основы, которые вам нужны.Вот полный скрипт Python, который показывает это:
import optparse
parser = optparse.OptionParser()
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
options, args = parser.parse_args()
print 'Query string:', options.query
5 строк Python, которые покажут вам основы.
Сохраните его в sample.py и запустите один раз с помощью
python sample.py
и однажды с
python sample.py --query myquery
Кроме того, вы обнаружите, что optparse очень легко расширить.В одном из моих проектов я создал класс Command, который позволяет легко вкладывать подкоманды в дерево команд.Он активно использует optparse для объединения команд в цепочку.Это не то, что я могу легко объяснить в нескольких строках, но не стесняйтесь покопайтесь в моем репозитории для основного класса, а также класс, который его использует, и анализатор опций
Другие советы
В других ответах упоминается об этом argparse
это подходящее решение для нового Python, но не приводите примеров использования.Для полноты приведем краткое описание того, как использовать argparse:
1) Инициализировать
import argparse
# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')
2) Добавить аргументы
# Required positional argument
parser.add_argument('pos_arg', type=int,
help='A required integer positional argument')
# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
help='An optional integer positional argument')
# Optional argument
parser.add_argument('--opt_arg', type=int,
help='An optional integer argument')
# Switch
parser.add_argument('--switch', action='store_true',
help='A boolean switch')
3) Разбор
args = parser.parse_args()
4) Доступ
print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)
5) Проверьте значения
if args.pos_arg > 10:
parser.error("pos_arg cannot be larger than 10")
Применение
Правильное использование:
$ ./app 1 2 --opt_arg 3 --switch
Argument values:
1
2
3
True
Неверные аргументы:
$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'
$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10
Полная помощь:
$ ./app -h
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
Optional app description
positional arguments:
pos_arg A required integer positional argument
opt_pos_arg An optional integer positional argument
optional arguments:
-h, --help show this help message and exit
--opt_arg OPT_ARG An optional integer argument
--switch A boolean switch
Использование докопта
С 2012 года Python имеет очень простой, мощный и действительно прохладный модуль для разбора аргументов называется документация.Он работает с Python 2.6–3.5 и не требует установки (просто скопируйте его).Вот пример, взятый из документации:
"""Naval Fate.
Usage:
naval_fate.py ship new <name>...
naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
naval_fate.py ship shoot <x> <y>
naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
naval_fate.py (-h | --help)
naval_fate.py --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__, version='Naval Fate 2.0')
print(arguments)
Итак, вот оно:2 строки кода плюс строка документа, которая является Essential, и вы получите ваши аргументы, проанализированные и доступные в вашем объекте аргументов.Я же говорил тебе, что это круто, не так ли ;-)
Использование Python-огонь
С 2017 года Python-огонь есть еще один классный модуль, который может предоставить интерфейс CLI для вашего кода, при этом вы делаете нуль разбор аргументов.Вот простой пример из документации (эта небольшая программа предоставляет функцию double
в командную строку):
import fire
class Calculator(object):
def double(self, number):
return 2 * number
if __name__ == '__main__':
fire.Fire(Calculator)
Из командной строки вы можете запустить:
> calculator.py double 10
20
> calculator.py double --number=15
30
Круто, не так ли?
я предпочитаю Нажмите.Он абстрагирует параметры управления и позволяет «(...) создавать красивые интерфейсы командной строки компонуемым способом с минимальным количеством кода».
Вот пример использования:
import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for x in range(count):
click.echo('Hello %s!' % name)
if __name__ == '__main__':
hello()
Он также автоматически генерирует красиво отформатированные страницы справки:
$ python hello.py --help
Usage: hello.py [OPTIONS]
Simple program that greets NAME for a total of COUNT times.
Options:
--count INTEGER Number of greetings.
--name TEXT The person to greet.
--help Show this message and exit.
Практически все используют получить выбор
Вот пример кода документа:
import getopt, sys
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
output = None
verbose = False
for o, a in opts:
if o == "-v":
verbose = True
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-o", "--output"):
output = a
Короче говоря, вот как это работает.
У вас есть два типа вариантов.Те, кто получает аргументы, и те, кто похож на переключателей.
sys.argv
в значительной степени твой char** argv
в С.Как и в C, вы пропускаете первый элемент, который является именем вашей программы, и анализируете только аргументы: sys.argv[1:]
Getopt.getopt
будет анализировать его в соответствии с правилом, которое вы указываете в аргументе.
"ho:v"
здесь описаны короткие аргументы: -ONELETTER
.А :
Значит это -o
принимает один аргумент.
Окончательно ["help", "output="]
описывает длинные аргументы ( --MORETHANONELETTER
).А =
после вывода еще раз означает, что вывод принимает один аргумент.
Результатом является список пар (опция, аргумент).
Если опция не принимает никаких аргументов (например, --help
здесь) arg
часть представляет собой пустую строку.Затем вы обычно хотите просмотреть этот список и проверить имя параметра, как в примере.
Надеюсь, это помогло вам.
Использовать optparse
который поставляется со стандартной библиотекой.Например:
#!/usr/bin/env python
import optparse
def main():
p = optparse.OptionParser()
p.add_option('--person', '-p', default="world")
options, arguments = p.parse_args()
print 'Hello %s' % options.person
if __name__ == '__main__':
main()
Источник: Использование Python для создания инструментов командной строки UNIX
Однако начиная с Python 2.7 optparse устарел, см.: Зачем использовать argparse, а не optparse?
На всякий случай, это может помочь, если вам нужно схватить Аргументы Юникода в Win32 (2K, XP и т. д.):
from ctypes import *
def wmain(argc, argv):
print argc
for i in argv:
print i
return 0
def startup():
size = c_int()
ptr = windll.shell32.CommandLineToArgvW(windll.kernel32.GetCommandLineW(), byref(size))
ref = c_wchar_p * size.value
raw = ref.from_address(ptr)
args = [arg for arg in raw]
windll.kernel32.LocalFree(ptr)
exit(wmain(len(args), args))
startup()
Облегченные аргументы командной строки по умолчанию
Хотя argparse
отлично подходит и является правильным ответом для полностью документированных переключателей командной строки и расширенных функций. Вы можете использовать значения аргументов функции по умолчанию для очень простой обработки простых позиционных аргументов.
import sys
def get_args(name='default', first='a', second=2):
return first, int(second)
first, second = get_args(*sys.argv)
print first, second
Аргумент «имя» фиксирует имя сценария и не используется.Вывод теста выглядит следующим образом:
> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20
Для простых сценариев, где мне просто нужны значения по умолчанию, я считаю этого вполне достаточным.Вы также можете включить некоторое приведение типов в возвращаемые значения, или все значения командной строки будут строками.
Я думаю, что лучший способ для более крупных проектов — это optparse, но если вы ищете простой способ, возможно, http://werkzeug.pocoo.org/documentation/script это что-то для тебя.
from werkzeug import script
# actions go here
def action_foo(name=""):
"""action foo does foo"""
pass
def action_bar(id=0, title="default title"):
"""action bar does bar"""
pass
if __name__ == '__main__':
script.run()
Таким образом, в основном каждая функция Action_* подвергается воздействию командной строки, и хорошее сообщение справочного сообщения генерируется бесплатно.
python foo.py
usage: foo.py <action> [<options>]
foo.py --help
actions:
bar:
action bar does bar
--id integer 0
--title string default title
foo:
action foo does foo
--name string
Я предпочитаю optparse getopt.Это очень декларативно:вы сообщаете ему названия параметров и эффекты, которые они должны иметь (например, установку логического поля), и он возвращает вам словарь, заполненный в соответствии с вашими спецификациями.
консольаргс заслуживает упоминания здесь.Он очень прост в использовании.Проверьте это:
from consoleargs import command
@command
def main(url, name=None):
"""
:param url: Remote URL
:param name: File name
"""
print """Downloading url '%r' into file '%r'""" % (url, name)
if __name__ == '__main__':
main()
Теперь в консоли:
% python demo.py --help
Usage: demo.py URL [OPTIONS]
URL: Remote URL
Options:
--name -n File name
% python demo.py http://www.google.com/
Downloading url ''http://www.google.com/'' into file 'None'
% python demo.py http://www.google.com/ --name=index.html
Downloading url ''http://www.google.com/'' into file ''index.html''
Код Argparse может быть длиннее фактического кода реализации!
Проблема с большинством популярных вариантов анализа аргументов заключается в том, что если ваши параметры скромны, код для их документирования становится непропорционально большим по сравнению с той пользой, которую они приносят.
Относительным новичком в сцене анализа аргументов (я думаю) является место.
Он делает некоторые общепризнанные компромиссы с argparse, но использует встроенную документацию и просто оборачивает main()
тип функция функция:
def main(excel_file_path: "Path to input training file.",
excel_sheet_name:"Name of the excel sheet containing training data including columns 'Label' and 'Description'.",
existing_model_path: "Path to an existing model to refine."=None,
batch_size_start: "The smallest size of any minibatch."=10.,
batch_size_stop: "The largest size of any minibatch."=250.,
batch_size_step: "The step for increase in minibatch size."=1.002,
batch_test_steps: "Flag. If True, show minibatch steps."=False):
"Train a Spacy (http://spacy.io/) text classification model with gold document and label data until the model nears convergence (LOSS < 0.5)."
pass # Implementation code goes here!
if __name__ == '__main__':
import plac; plac.call(main)
Вот метод, а не библиотека, которая, похоже, у меня работает.
Цель здесь - быть кратким, каждый аргумент анализируется одной строкой, аргументы выстраиваются в ряд для удобства чтения, код прост и не зависит от каких-либо специальных модулей (только os + sys), изящно предупреждает об отсутствующих или неизвестных аргументах. , используйте простой цикл for/range() и работает в Python 2.x и 3.x.
Показаны два переключаемых флага (-d, -v) и два значения, управляемые аргументами (-i xxx и -o xxx).
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
# Parse command line
skip = 0
for i in range(1, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("%d,%d,%s,%s" % (debug,verbose,infile,outfile))
Цель NextArg() — вернуть следующий аргумент при проверке недостающих данных, а команда «skip» пропускает цикл при использовании NextArg(), сводя анализ флага к одной строке.
Я расширил подход Erco, включив в него необходимые позиционные аргументы и необязательные аргументы.Они должны предшествовать -d, -v и т. д.аргументы.
Позиционные и необязательные аргументы можно получить с помощью PosArg(i) и OptArg(i, по умолчанию) соответственно.Если найден необязательный аргумент, начинается поиск параметров (например.-i) перемещается на 1 вперед, чтобы избежать «неожиданного» фатального исхода.
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
def PosArg(i):
'''Return positional argument'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
return sys.argv[i]
def OptArg(i, default):
'''Return optional argument (if there is one)'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
if sys.argv[i][:1] != '-':
return True, sys.argv[i]
else:
return False, default
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
options_start = 3
# --- Parse two positional parameters ---
n1 = int(PosArg(1))
n2 = int(PosArg(2))
# --- Parse an optional parameters ---
present, a3 = OptArg(3,50)
n3 = int(a3)
options_start += int(present)
# --- Parse rest of command line ---
skip = 0
for i in range(options_start, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("Number 1 = %d" % n1)
print("Number 2 = %d" % n2)
print("Number 3 = %d" % n3)
print("Debug = %d" % debug)
print("verbose = %d" % verbose)
print("infile = %s" % infile)
print("outfile = %s" % outfile)