ما هي أفضل طريقة تحليل سطر الأوامر الحجج ؟
-
09-06-2019 - |
سؤال
ما أسهل, tersest, و أكثر مرنة طريقة أو مكتبة تحليل بايثون سطر الأوامر الحجج ؟
المحلول
هذا الجواب يشير إلى optparse
والتي هي مناسبة لكبار السن من إصدارات بيثون.بايثون 2.7 وما فوق ، argparse
يستبدل optparse
.انظر هذا الجواب للحصول على مزيد من المعلومات.
و أشار كنت أفضل حالا الذهاب مع optparse على getopt.getopt حد كبير واحد-إلى-واحد الخرائط القياسية getopt(3) ج وظائف المكتبة ، وليس من السهل جدا للاستخدام.
optparse ، في حين يجري قليلا أكثر مطول, هو أفضل بكثير منظم و أبسط إلى تمديد في وقت لاحق.
وهنا نموذجية خط لإضافة خيار إلى محلل:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
فهذا يتحدث عن نفسه ؛ في وقت المعالجة ، فإنه لن يقبل -q أو الاستعلام الخيارات متجر حجة في سمة يسمى استعلام يحتوي على قيمة افتراضية إذا كنت لا تحديد في ذلك.بل هو أيضا توثيق عن النفس في ذلك تعلن مساعدة الحجة (التي سيتم استخدامها عند تشغيل مع -h/--help) هناك مع الخيار.
عادة لتحليل الحجج الخاصة بك مع:
options, args = parser.parse_args()
هذا بشكل افتراضي تحليل الحجج القياسية التي تم تمريرها إلى البرنامج النصي (sys.argv[1:])
خيارات.الاستعلام ثم سيتم تعيين إلى القيمة التي تم تمريرها إلى البرنامج النصي.
يمكنك إنشاء محلل ببساطة عن طريق القيام
parser = optparse.OptionParser()
هذه هي الأساسيات التي تحتاج إليها.هنا كامل بيثون السيناريو الذي يبين هذا:
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 خطوط من بيثون التي تظهر لك الأساسيات.
حفظه في sample.py تشغيل مرة واحدة مع
python sample.py
ومرة واحدة مع
python sample.py --query myquery
أبعد من ذلك, سوف تجد أن optparse من السهل جدا أن تمتد.في واحدة من بلدي المشاريع, أنا خلقت قيادة الطبقة التي تسمح لك عش subcommands في أمر الشجرة بسهولة.ويستخدم optparse بشكل كبير إلى سلسلة من الأوامر معا.إنه شيء لا يمكن أن تفسر بسهولة في بضعة أسطر, ولكن لا تتردد في تصفح في مستودع على الطبقة الرئيسية ، وكذلك فئة يستخدم هذا الخيار محلل
نصائح أخرى
إجابات أخرى لا أذكر أن argparse
هو الطريق للذهاب جديدة الثعبان, ولكن لا تعطي أمثلة الاستخدام.عن اكتمال هنا هو موجز قصير عن كيفية استخدام 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
باستخدام docopt
منذ عام 2012 الثعبان جدا سهلة وقوية حقا بارد وحدة حجة تحليل يسمى docopt.يعمل مع بيثون 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 الأسطر من التعليمات البرمجية بالإضافة إلى doc السلسلة التي هو أساسي على تحليل الحجج المتاحة في الحجج وجوه.قلت لك إنه رائع, أليس كذلك ;-)
باستخدام بيثون-النار
منذ عام 2017 بيثون-النار آخر بارد الوحدة التي يمكن أن تعطي 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
رائع أليس كذلك ؟
أنا أفضل انقر.فإنه ملخصات إدارة خيارات يسمح "(...) خلق جميلة سطر الأوامر واجهات في composable الطريقة مع القليل من قانون الضرورة".
هنا هو مثال على الاستخدام:
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.
تقريبا كل شخص يستخدم getopt
هنا هو مثال رمز الوثيقة :
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.في مثل 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()
المصدر: باستخدام بيثون لخلق UNIX أدوات سطر الأوامر
ومع ذلك اعتبارا من بايثون 2.7 optparse هو مستنكر ، انظر: لماذا استخدام argparse بدلا من optparse?
فقط في حال كنت قد تحتاج إلى أن هذا قد يساعد إذا كنت بحاجة إلى الاستيلاء على unicode الحجج على 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.انها جدا التعريفي:كنت أقول أسماء خيارات والآثار التي ينبغي أن يكون (على سبيل المثال ، وضع حقل منطقي) ، يد لك مرة أخرى القاموس بالسكان وفقا للمواصفات الخاصة بك.
consoleargs يستحق الذكر هنا.فمن السهل جدا للاستخدام.التحقق من ذلك:
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 رمز يمكن أن تكون أطول من التنفيذ الفعلي رمز!
هذه مشكلة أجد مع الأكثر شعبية حجة تحليل الخيارات هو أنه إذا كان لديك المعلمات متواضعة فقط ، رمز الوثيقة تصبح كبيرة بشكل غير متناسب إلى الفائدة التي يقدمونها.
قريب الوافد الجديد إلى حجة تحليل المشهد (على ما أظن) ، plac.
فإنه يجعل بعض اعترف المقايضات مع 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), يحذر مفقودة أو غير معروفة الحجج برشاقة, استخدام بسيط/مجموعة() حلقة ، ويعمل في بيثون 2.x و 3.x
يظهر نوعان من تبديل الأعلام (-د-ت) ، واثنين من القيم التي تسيطر عليها الحجج (أنا 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() هو العودة المقبل حجة في حين التحقق من البيانات المفقودة ، 'تخطي' يتخطى حلقة عندما NextArg() يستخدم, حفظ العلم تحليل واحد المتشددين.
مددت Erco نهج تسمح المطلوبة الموضعية الحجج و وسيطات اختيارية.هذه ينبغي أن يسبق -د-v etc.الحجج.
الموضعية و وسيطات اختيارية يمكن استرجاعها مع PosArg(أنا) و OptArg(أنا الافتراضي) على التوالي.عند اختياري حجة وجدت موضع بداية من البحث عن الخيارات (على سبيل المثال-ط) يتم نقل 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)