python解析命令行

getopt:和C中的getopt()等價。
optparse:2.7后已不推薦使用。
argparse:基于optparse的新庫。
docopt:根據文檔描述,自動生成。另一份參考文檔:docopt

更詳細的內容可參考上述文檔。

getopt


若對C的getopt()函數不熟悉,或者傾向于使用較少的代碼,或者需要對幫助信息和錯誤信息有更高要求,以上情況優先使用argparse
該模塊主要提供兩個函數,以及一個異常判斷。

getopt.getopt(args, options[, long_options])
args是需要解析的列表,通常情況下,是sys.argv[1:]
options是解析列表時使用的范式,如果某一項(單個字母)后面需要參數,則在此項后添加':'
long_options必須是字符串列表,字符串開頭的'--'不能包括,若某一項后面需要參數,則在此項后添加'='。可選型的參數是不支持long_options的。是根據輸入是否是字符串列表中唯一一項的前綴來匹配的。
返回值分為兩個部分。第一部分是(option, value)格式的列表,第二部分是解析完后剩余部分。

getopt.gnu_getopt(args, options[, long_options])
作用同上。
區別在于getopt()一旦遇到未配置的選項,就會停止解析。而此函數使用GNU規則,即已配置的選項和未配置的選項是可以混雜的。

exception getopt.GetoptError**
當一個無法識別的選項,或者一個必須要有參數傳入的選項未傳入參數時,拋出此異常。
exception getopt.error**
GetoptError的舊名,為了向后兼容而保留。

具體實例可參考文檔,不推薦使用。

argparse


一個簡單例子:

import argparse

parser = argparse.ArgumentParser(description='Example with long option names')

parser.add_argument('--noarg', action="store_true", default=False)
parser.add_argument('--witharg', action="store", dest="witharg")
parser.add_argument('--witharg2', action="store", dest="witharg2", type=int)

print parser.parse_args(['--noarg', '--witharg', 'val', '--witharg2=3'])

argparse中,最常用的就是上述三部分了:創建一個ArgumentParser對象;使用add_argument()方法來為創建的ArgumentParser對象添加argument的解析規則;最后調用parse_args()來解析傳入的內容,依據的是第二步制定的規則,生成的是一個Namespace對象,若未傳參數給parse_args(),那么默認從sys.argv來獲取命令行入參。

class argparse.ArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[],formatter_class=argparse.HelpFormatter, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None,conflict_handler='error', add_help=True)
prog:程序的名字,默認是argv[0]。若設置,則在幫助信息中,可以使用%(prog)s來作為格式化的引用(修改一處全局受用)。
usage:幫助信息的usage字段,描述程序的各種用法,默認情況下會依據add_argument()來自動生成。
description:一個簡單描述程序主要干啥以及怎么用的字符段。位于usage字符段和optional arguments字符段之間。
epilogoptional arguments字符段之后的字符段。
parents:繼承的父parser,為了避免一些公共的內容重復定義,父parser在初始化時會設置add_help=False,這是為了防止出現父與子parser的-h沖突而拋出異常。
formatter_class:對于help輸出進行格式化,除了輸出的樣式外,如果設置為ArgumentDefaultsHelpFormatter,則會自動在help輸出中添加已定義的default值。
prefix_chars:options前的字符,默認為'-',可以添加其他字符,如'-+',但是如果沒有包括'-',那么對應的option如'-h'就無法解析。
fromfile_prefix_chars:有時會使用文件給parse_args()傳入參數,為了能夠識別文件字符串,如"demo.txt",需要設置此值,如"@",那么所有以此字符為開頭的字符串都被當作是文件,所以傳給parse_args()的參數應該是@demo.txt。在該文件中,一行只能有一個參數。如文件中的'-f\nbar'會被解析成['-f','bar']
argument_default:一般情況下,默認值使用add_argument()來添加,或者使用set_defaults()設置一些鍵值對來添加。剩下一種情況就是設置此項(此處沒看明白是咋回事)。
conflict_handler:解決在add_argument()階段有沖突的option的依據策略,默認為error即拋出異常。一般情況下遇到沖突是拋出異常即可,但是如果設置了parents,那么需要重寫父parser中的規則的時候,就需要將此項設置為resolve,但是重寫是精確匹配的,如老規則定義了-h/--help,重寫了-h,那么--help還是老規則。
add_help:是否添加-h/--helpoption,默認為True。為False時,是要做parent(其實可以設置子Parser重寫)。默認是-h/--help,若prefix_chars中沒有包含'-',那么就以其中第一個字符作為代替。

ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][,metavar][, dest])
name or flags:是位置參數,則需要傳入名字;要是可選參數,則需要進行定義,如'-f','--foo'。
action:定義傳入的參數如何處理。

  • action='store',默認取值,保存傳入參數。
  • action='store_const',需要添加const,意味著該argument的值不從命令行輸入,而是取const的值。
  • action='store_true' or action='store_false''store_const'的特殊情形,意味著const的值為TrueFalse
  • action='append',表示傳入的值會作為一個列表的一項,意味著option可以在命令行中多次出現。
  • action='append_const',傳入列表的項由const定義,通常用在需要多個argument將值傳入一個列表中的場景。
  • action='count',輸出argument出現的次數。
  • action='help',已默認添加。
  • action='version',需要定義version,使用時輸出版本信息并退出。
  • 自定義,通過定義一個argparse.Action子類來實現。實際上,上面的這些可選項都是通過這種形式定義的。

nargs:通常一個選項后跟一個參數,通過設置此項可以實現不同情況。

  • nargs=N,一個選項后可以跟多個參數(action='append'時,依然是一個選項后跟一個參數,只不過選項可以多次出現),參數的個數必須為N的值,這些參數會生成一個列表,當nargs=1時,會生成一個長度為1的列表。
  • nargs=?,如果沒有在命令行中出現對應的項,則給對應的項賦值為default。特殊的是,對于可選項,如果命令行中出現了此可選項,但是之后沒有跟隨賦值參數,則此時給此可選項并不是賦值default的值,而是賦值const的值。
  • nargs=*,和N類似,但是沒有規定列表長度。
  • nargs=+,和*類似,但是給對應的項當沒有傳入參數時,會報錯error: too few arguments
  • nargs=argparse.REMAINDER,所有剩余的參數,均轉化為一個列表賦值給此項,通常用此方法來將剩余的參數傳入另一個parser進行解析。

如果nargs沒有定義,則可傳入參數的數量由action決定,通常情況下為一個,并且不會生成長度為一的列表。
const,一種是定義action='store_const'action='append_const'時使用。一種是定義nargs='?'時,可選項出現在命令行中,但之后并沒有跟隨賦值的參數,作為默認值傳給此可選項。
default:默認值。
如果是一個字符串,那么Parser解析的時候會將它作為命令行傳入值,使用type的值來進行轉換類型,但是如果不是的話,就會使用定義的值而不進行類型轉換。
如果設置了nargs='?'nargs='*',那么當沒有參數賦值給該項時,會使用default定義的值。
default=argparse.SUPPRESS時,則表示命令行中未出現某一項時,不會對它進行默認賦值。
type:用于類型檢查和類型轉換。
使用FileType可簡化對文件的操作。
還可以自定義函數,輸入是一個字符串,輸出是轉換后的字符串。
當設置choices的時,類型檢查會變得容易,因為只需要在一個范圍內比較即可。
choices:給定了取值范圍,超出會報錯。
type也有定義時,會先使用type進行類型檢查,所以choices中的取值必須符合type的定義,否則在parse_args()時會報錯。
任何支持in操作符的均可作為choices的賦值,所以字典,列表,集合,等等其他容器均都支持。
required:默認情況下,可選項(前面有'-')被認為并不一定需要出現在命令行參數中,但是如果設置了required=True的話,則必須出現。此類設置違背人的常識,應避免使用。
help:幫助信息。
之前提到的%(prog)s可用于此處程序名的格式化,此外,還有%(default)s格式化default的值,%(type)s格式化type的值。
設置為argparse.SUPPRESS可不顯示幫助信息。
metavar:在Parser生成幫助信息時,需要有字符代表需要傳入的值。(這一段和dest相同,使用的就是dest的值)如果是位置參數,則用它本身代替;如果是可選參數,則使用它的大寫來代替。使用metavar可替換默認的字符。
dest:大部分的選項都需要通過命令行來給其賦值,這些值的名字通過dest來定義,默認的規則如同metavar中所述。

ArgumentParser.parse_args(args=None, namespace=None)
args轉換為namespace對象的一個值。默認情況下,sys.argv賦值給args,一個空的Namespace對象會被創建。
解析時,會對傳入的參數進行檢查,若不符合要求就會報錯。
一般情況下,會自動判斷傳入的值到底是一個可選參數,還是一個負數(都用'-'開頭)。但有時位置參數的值必須是一個'-'開頭的值,如'-f',那么使用parser.parse_args(['--', '-f'])'--'代表后續的所有傳入值都需要看做是位置參數。
parse_args()會返回填充好的Namespace對象,若要將它變為字典,可使用Python自帶的vars()

vars(...)
    vars([object]) -> dictionary   
    Without arguments, equivalent to locals().
    With an argument, equivalent to object.__dict__.

也可不使用Namespace,而是傳入一個提前生成的對象。

其他
ArgumentParser.add_subparsers([title][, description][, prog][, parser_class][, action][, option_string][, dest][, help][, metavar])用來定義子Parser。
class argparse.FileType(mode='r', bufsize=None)用來給add_argument()中的type參數賦值。
ArgumentParser.add_argument_group(title=None, description=None)定義一個組。
ArgumentParser.add_mutually_exclusive_group(required=False)定義組中只能有一個選項出現。
ArgumentParser.set_defaults(kwargs)設置默認值。
ArgumentParser.get_default(dest)獲取默認值。
ArgumentParser.print_usage(file=None)
ArgumentParser.print_help(file=None)
ArgumentParser.format_usage()
ArgumentParser.format_help()以上四種都是幫助信息相關的。
ArgumentParser.parse_known_args(args=None, namespace=None)只解析知道的部分。
ArgumentParser.convert_arg_line_to_args(arg_line)
ArgumentParser.exit(status=0, message=None)
ArgumentParser.error(message)

docopt


理念是好的幫助信息應該正好包含生成命令行解析器所需要的全部信息。

docopt.docopt(doc, argv=None, help=True, version=None, options_first=False)
doc參數可以是一個模塊的docstring(__doc__),或者是其他符合格式的幫助信息。
argv默認情況下使用sys.argv[1:],或者可以使用一個字符串。
help默認為True,當輸入-h--help后(需提前設置好),解析器能夠自動生成對應的幫助文本。需要手動管理的可設置為False。
version版本信息,是可選參數。
options_first默認為False。當設置為True時,不允許可選參數和位置參數進行混合,即在出現的第一個位置參數之后的所有參數,均被當作是位置參數,這是為了和POSIX保持兼容。
返回值是一個字典,key是option,value就是對應輸入的參數。

幫助信息格式分為兩部分,Usage patternOption descriptions。只有符合格式的字符串才會被識別并解析,其余字符串會被忽略。
Usage pattern
舉例:

Usage: my_program.py [-hso FILE] [--quiet | --verbose] [INPUT ...]

Usage pattern是doc的子字符串。開始于usage:(大小寫不敏感),結束于一行空行。
位于usage:之后的第一個單詞是程序的名字,可以重復多次進行不同pattern的定義。

"""
Usage: my_program.py FILE 
       my_program.py COUNT FILE
"""

每個pattern都由以下部分組成。
一個是<arguments>, ARGUMENTS格式的定義,要么是用尖括號包括,要么是大寫。
還有一個是-options,必須要以“-”開頭,可以堆棧好幾個option,如-oiv等價于-o -i -v。option是可以有參數的,如-f FILE-f=FILE-fFILE,都是等價的。其他一些選擇在下方的option descriptions中進行具體定義。
最后一個是commands,除了以上提及的兩種情況,剩下的格式,再加上兩個特殊的命令:單個的“-”和雙個的“-”,這些都歸屬于此。

commands中,[ ]表示可選。( )表示必須存在,所有沒有用[ ]包裹的字符串都默認被( )包裹。
|是管道符,若某一個選項必須存在,則將他們用( )包裹,如my_program.py(--clockwise | --counter-clockwise) TIME,若都是可選項,則用[ ]包裹,如my_program.py[--left | --right]
...表示有一個或多個元素,如my_program.py FILE ...表示一個或多個FILE可接受,而my_program.py [FILE ...]表示0個或多個FILE可接受。
[options](大小寫敏感)是任意options的縮寫。可以使用它來定義該pattern可以使用任何在下方Option descriptions中定義的option。
[--]是為了分隔可選參數和位置參數,如Usage: my_program [options] [--] <file>...,其中中括號可去除,變為必填項。
[-]若出現,則表示程序需要使用stdin,禁止使用file。而單個的-則是一個普通字符。

如果在usage pattern中重復出現同名位置參數多次,或者同名有參數的可選參數多次,那么傳入的值會被解析成一個列表。如Usage: my_program.py <file> <file> --path=<path>...的結果會是args['<file>'] == ['file1', 'file2']以及args['--path'] == ['./here', './there']

Option descriptions
舉例:

-h --help    show this
-s --sorted  sorted output
-o FILE      specify output file [default: ./test.txt]
--quiet      print less text
--verbose    print more text

此部分位于usage pattern下方,它可以有三方面作用:定義同義的短option和長option;某個option是否需要傳入參數;某個option是否有默認參數。
規則如下:
每行定義一個option,必須以一個或兩個“-”開頭。
為定義需要傳入的參數,可以在對應的option后方加上一個字符串,兩者以空格或“=”相隔,兩者都是可行的,但推薦只使用一種風格。

-o FILE --output=FILE       # without comma, with "=" sign
-i <file>, --input <file>   # with comma, wihtout "=" sign

使用兩個空格來將option本身與它的描述想分隔(按照示例應該是至少兩個空格)。

--verbose More text.   # BAD, will be treated as if verbose option had
                       # an argument "More", so use 2 spaces instead
-q        Quit.        # GOOD
-o FILE   Output file. # GOOD
--stdout  Use stdout.  # GOOD, 2 spaces

在option對應的描述后方進行默認參數的設置,格式是[default:<my-default-value>]

--coefficient=K  The K coefficient [default: 2.95]
--output=FILE    Output file [default: test.txt]
--directory=DIR  Some directory [default: ./]

若某option是可重復的,則默認參數會以空格作為分割符進行分割,生成一個字符串列表。否則,作為一個字符串整體。

docopt不適用于大型多層次的命令行參數解析(例如git,但是官方給出了一個example)。同時它沒有對數據的校驗功能,無法向用戶報錯。
使用try docopt可進行docopt在線命令行參數解析。

舉例


例題是:知道創宇面試題
使用argparse

import argparse
from argparse import ArgumentDefaultsHelpFormatter

parser = argparse.ArgumentParser(prog="Spider", description='Knownsec Interview Spider By Docopt.', formatter_class=ArgumentDefaultsHelpFormatter)

parser.add_argument('-u', dest='url', action='store', required=True, help='the url the spider begins with')
parser.add_argument('-d', dest='deep', action='store', required=True, type=int, help='the depth of spider')
parser.add_argument('-f', dest='logfile', action='store', default='spider.log', help='the name of logfile')
parser.add_argument('-l', dest='loglevel(1-5)', action='store', type=int, choices=range(1,6), default=1, help='the details level of the log, range 1 to 5')
parser.add_argument('--testself', dest='testself', action='store_true', help='the self test by this program')
parser.add_argument('--thread', dest='thread_number', action='store', type=int, default=10, help="the thread pool's capacity")
parser.add_argument('--dbfile', dest='dbfile_filepath', action='store', required=True, help='the sqlite3 file path')
parser.add_argument('--key', dest='keyword', action='store', help='the keyword to search in webpage')


print parser.parse_args()

輸出:

python argparse_demo.py -u 123.com -d 1 --dbfile 123.txt -f logfile -l 1 --testself --thread 2 
Namespace(dbfile_filepath='123.txt', deep=1, keyword=None, logfile='logfile', loglevel(1-5)=1, testself=True, thread_number=2, url='123.com')

體會就是功能很強大,實現很方便。所以我傾向于使用它。

使用docopt

"""
Knownsec Interview Spider By Docopt.

Usage:
  docopt_demo.py -u <url> -d <deep> [-f <logfile>] [-l <loglevel>] [--testself] [--thread <number>] --dbfile <filepath>  [--key=<keyword>]
  docopt_demo.py -h | --help
  docopt_demo.py --version

Options:
  -h --help               Show this screen.
  --version               Show version.
  -u <url>                the url the spider begins with
  -d <deep>               the depth of spider
  -f <logfile>            the name of logfile [default: spider.log]
  -l <loglevel>           the details level of the log, range 1 to 5 [default: 1]
  --testself              the self test by this program
  --thread <number>       the thread pool's capacity [default: 10]
  --dbfile <filepath>     the sqlite3 file path
  --key=<keyword>         the keyword to search in webpage

"""
from docopt import docopt

if __name__ == '__main__':
    arguments = docopt(__doc__, version='Spider 1.0')
    print arguments

輸出:

python docopt_demo.py  -u 123.com -d 1 --dbfile 123.txt -f logfile -l 1 --testself --thread 2 

{'--dbfile': '123.txt',
 '--help': False,
 '--key': None,
 '--testself': True,
 '--thread': '2',
 '--version': False,
 '-d': '1',
 '-f': 'logfile',
 '-l': '1',
 '-u': '123.com'}

可見,如果選項不需要參數,則-h和--version這種沒有設置的會賦值為False,而--testself會賦值為True;對于需要參數的選項,如果沒有設置,如--key,會被賦值為None,而有設置并且給出參數的,會賦值對應的參數,如--dbfile。
那么,對于有設置但是沒有給出參數的呢,并不會拋出異常報錯,而是把Usage部分(有時加上Options部分)輸出,真是太不友好了,debug的時候真是坑爹啊。

另外,使用docopt時候需要注意__doc__的用法,如果是寫函數的__doc__,則在函數名之下開始寫,而一個模塊的則必須在開頭寫,也就是在import之前寫,否則__doc__ == None


20161226
今天了解了一個很方便的庫:click,作為補充。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容