สิ่งที่ง่ายที่สุด , tersestและส่วนใหญ่มีความยืดหยุ่นวิธีการหรือห้องสมุดสำหรับการแยกหลามอาร์กิวเมนต์บรรทัดคำสั่ง?
สิ่งที่ง่ายที่สุด , tersestและส่วนใหญ่มีความยืดหยุ่นวิธีการหรือห้องสมุดสำหรับการแยกหลามอาร์กิวเมนต์บรรทัดคำสั่ง?
คำตอบ:
คำตอบนี้แสดงให้เห็นoptparse
ว่าแบบไหนเหมาะกับงูหลามรุ่นเก่า สำหรับงูหลาม 2.7 และสูงกว่าแทนที่argparse
optparse
ดูคำตอบนี้สำหรับข้อมูลเพิ่มเติม
ในฐานะที่เป็นคนอื่นชี้ให้เห็นว่าคุณจะดีกว่าไปกับ optparse มากกว่า getopt getopt เป็นการทำแผนที่แบบหนึ่งต่อหนึ่งของฟังก์ชั่นไลบรารีมาตรฐาน getopt (3) C และไม่ได้ใช้งานง่ายนัก
optparse ในขณะที่ verbose มากขึ้นเล็กน้อยมีโครงสร้างที่ดีขึ้นและง่ายต่อการขยายในภายหลัง
นี่คือบรรทัดทั่วไปในการเพิ่มตัวเลือกใน parser ของคุณ:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
มันค่อนข้างพูดสำหรับตัวเอง; เวลาประมวลผลจะยอมรับ -q หรือ - แบบสอบถามเป็นตัวเลือกเก็บอาร์กิวเมนต์ในแอตทริบิวต์ที่เรียกว่าแบบสอบถามและมีค่าเริ่มต้นหากคุณไม่ได้ระบุไว้ นอกจากนี้ยังเป็นการจัดทำเอกสารด้วยตนเองเมื่อคุณประกาศอาร์กิวเมนต์วิธีใช้ (ซึ่งจะใช้เมื่อเรียกใช้ด้วย -h / - วิธีใช้) ตรงนั้นพร้อมตัวเลือก
คุณมักจะแยกวิเคราะห์ข้อโต้แย้งของคุณด้วย:
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 บรรทัดที่แสดงพื้นฐาน
บันทึกใน sample.py และเรียกใช้ครั้งเดียวด้วย
python sample.py
และอีกครั้งด้วย
python sample.py --query myquery
นอกเหนือจากนั้นคุณจะพบว่า optparse นั้นง่ายต่อการขยาย ในหนึ่งในโปรเจคของฉันฉันสร้างคลาสคำสั่งที่ให้คุณซ้อนคำสั่งย่อยในทรีคำสั่งได้อย่างง่ายดาย มันใช้ optparse อย่างหนักเพื่อเชื่อมโยงคำสั่งเข้าด้วยกัน มันไม่ใช่สิ่งที่ฉันสามารถอธิบายได้อย่างง่ายดายในไม่กี่บรรทัด แต่รู้สึกอิสระที่จะเรียกดูในพื้นที่เก็บข้อมูลของฉันสำหรับชั้นเรียนหลักเช่นเดียวกับชั้นเรียนที่ใช้มันและตัวแยกวิเคราะห์ตัวเลือก
-mcProfile -o program.prof
แต่ agrparcer กำลังดักจับ args เหล่านี้ฉันจะส่ง args เหล่านี้ไปยัง python exe ได้อย่างไร?
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 เป็นเรื่องง่ายมากที่มีประสิทธิภาพและจริงๆเย็นโมดูลสำหรับอาร์กิวเมนต์แยกเรียกว่าdocopt นี่คือตัวอย่างที่นำมาจากเอกสาร:
"""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
วิธีใหม่สะโพกคือargparse
สำหรับเหล่านี้ด้วยเหตุผล argparse> optparse> getopt
update:ณ py2.7 argparseเป็นส่วนหนึ่งของไลบรารี่มาตรฐานและoptparseเลิกใช้แล้ว
ฉันชอบคลิกคลิกมันเป็นนามธรรมจัดการตัวเลือกและช่วยให้ "(... ) การสร้างอินเตอร์เฟซบรรทัดคำสั่งที่สวยงามในวิธีการแต่งที่มีรหัสน้อยเท่าที่จำเป็น"
นี่คือตัวอย่างการใช้งาน:
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
ส่วนนั้นเป็นสตริงว่าง จากนั้นคุณมักจะต้องการวนซ้ำในรายการนี้และทดสอบชื่อตัวเลือกดังตัวอย่าง
ฉันหวังว่านี่จะช่วยคุณได้
getopt
ของ Python เวอร์ชั่นใหม่กว่าคำตอบนี้ล้าสมัยแล้ว
getopt
ยังไม่เลิกใช้ ... แต่เอกสารระบุว่าส่วนใหญ่มีไว้สำหรับผู้ใช้ที่คุ้นเคยกับgetopt()
ฟังก์ชั่นC และยอมรับว่าสำหรับผู้ใช้รายอื่นargparse
อาจเป็นทางออกที่ดีกว่าช่วยให้ "เขียนรหัสน้อยลงและรับ ความช่วยเหลือและข้อความแสดงข้อผิดพลาดที่ดีขึ้น ".
ใช้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
ในกรณีที่คุณอาจจำเป็นต้องใช้สิ่งนี้อาจช่วยถ้าคุณต้องการคว้าอาร์กิวเมนต์ 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
อาร์กิวเมนต์ 'name' รวบรวมชื่อสคริปต์และไม่ได้ใช้ ผลการทดสอบมีลักษณะดังนี้:
> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20
สำหรับสคริปต์ง่ายๆที่ฉันต้องการค่าเริ่มต้นบางอย่างฉันพบว่ามันค่อนข้างเพียงพอ คุณอาจต้องการรวมการบีบบังคับบางประเภทในค่าส่งคืนหรือค่าบรรทัดคำสั่งทั้งหมดจะเป็นสตริง
ฉันชอบ optparse เพื่อ getopt มันเป็นการประกาศที่ดีมาก: คุณบอกชื่อของตัวเลือกและเอฟเฟกต์ที่ควรมี (เช่นการตั้งค่าฟิลด์บูลีน) และมันจะช่วยให้คุณคืนค่าพจนานุกรมตามข้อมูลจำเพาะของคุณ
ฉันคิดว่าวิธีที่ดีที่สุดสำหรับโครงการขนาดใหญ่คือ 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
declarative_parser
ผมได้พัฒนาแพคเกจขนาดเล็กใช้สร้างข้อโต้แย้งอัตโนมัติ: แน่นอนว่าหากมีการทำงานร่วมกับ Werkzeug werkzung.script
มันอาจจะดีกว่าที่จะให้ อย่างไรก็ตามฉันเป็นแฟนตัวยงของวิธีการดังกล่าว
รหัส 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)
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''
นี่คือวิธีการไม่ใช่ห้องสมุดที่ดูเหมือนจะใช้ได้สำหรับฉัน
เป้าหมายที่นี่จะสั้นกระชับแต่ละอาร์กิวเมนต์แยกวิเคราะห์โดยบรรทัดเดียว args line up สำหรับการอ่านรหัสง่ายและไม่ขึ้นอยู่กับโมดูลพิเศษใด ๆ (เฉพาะ OS + sys) เตือนเกี่ยวกับข้อโต้แย้งที่ขาดหายไปหรือไม่รู้จักอย่างสง่างาม ใช้การวนลูปแบบง่ายๆสำหรับ / 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 () คือการส่งคืนอาร์กิวเมนต์ถัดไปขณะตรวจสอบข้อมูลที่หายไปและ 'ข้าม' ข้ามลูปเมื่อใช้ NextArg () เพื่อรักษาสถานะการแยกวิเคราะห์ลงในหนึ่ง liners
ฉันขยายวิธีการของ Erco เพื่ออนุญาตให้มีการขัดแย้งกับตำแหน่งที่ต้องการและสำหรับข้อโต้แย้งเพิ่มเติม สิ่งเหล่านี้ควรอยู่หน้าอาร์กิวเมนต์ -d, -v ฯลฯ
อาร์กิวเมนต์ตำแหน่งและตัวเลือกสามารถเรียกคืนได้ด้วย PosArg (i) และ OptArg (i, default) ตามลำดับ เมื่อพบอาร์กิวเมนต์ที่เป็นทางเลือกตำแหน่งเริ่มต้นของการค้นหาตัวเลือก (เช่น -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)