1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        如何優(yōu)雅地解析命令行選項(xiàng)

        共 5467字,需瀏覽 11分鐘

         ·

        2020-08-25 21:55

        文 |?軒轅御龍

        來(lái)源:Python 技術(shù)「ID: pythonall」

        如何優(yōu)雅地解析命令行選項(xiàng)

        隨著我們編程經(jīng)驗(yàn)的增長(zhǎng),對(duì)命令行的熟悉程度日漸加深,想來(lái)很多人會(huì)漸漸地體會(huì)到使用命令行帶來(lái)的高效率。

        自然而然地,我們自己寫(xiě)的很多程序(或者干脆就是腳本),也希望能夠像原生命令和其他程序一樣,通過(guò)運(yùn)行時(shí)輸入的參數(shù)就可以設(shè)定、改變程序的行為;而不必一層層找到相應(yīng)的配置文件,然后還要定位到相應(yīng)內(nèi)容、修改、保存、退出……

        想想就很麻煩好嗎

        01

        1. 手動(dòng)解析

        所以讓我們開(kāi)始解析命令行參數(shù)吧~

        在以前關(guān)于模塊的文章中我們提到過(guò)sys.args這個(gè)變量,其中保存的就是調(diào)用當(dāng)前腳本時(shí)傳入的命令行參數(shù)。

        我們先觀察一下這個(gè)變量:

        # test_sys.pyimport sys
        print(sys.argv)

        通過(guò)命令行調(diào)用:

        $ python test_sys.py -d today -t now --author justdopython --country China --auto

        得到如下輸出結(jié)果:

        ['test_sys.py', '-d', 'today', '-t', 'now', '--author', 'justdopython', '--country', 'China', '--auto']

        可見(jiàn),sys.argv其實(shí)就是將命令行參數(shù)按空格切分,得到的一個(gè)字符串列表。此外,命令行參數(shù)的第一個(gè)就是當(dāng)前運(yùn)行的腳本名稱(chēng)。

        我們?nèi)绻胍崛〕龈鱾€(gè)參數(shù)及其對(duì)應(yīng)的值,首先得區(qū)分出命令行的長(zhǎng)參數(shù)和短參數(shù),它們分別由“--”和“-”開(kāi)頭作為標(biāo)識(shí)。所以我們也以此作為判斷長(zhǎng)短參數(shù)的條件:

        import sys

        for command_arg in sys.argv[1:]: if command_arg.startswith('--'): print("%s 為長(zhǎng)參數(shù)" % command_arg) elif command_arg.startswith('-'): print("%s 為短參數(shù)" % command_arg)

        測(cè)試結(jié)果:

        $ python manually_parse_argv.py -d today -t now --author justdopython --country China --auto

        -d 為短參數(shù)-t 為短參數(shù)--author 為長(zhǎng)參數(shù)--country 為長(zhǎng)參數(shù)--auto 為長(zhǎng)參數(shù)

        緊接著,我們需要在解析出長(zhǎng)短參數(shù)這一步的基礎(chǔ)上,再解析出對(duì)應(yīng)的參數(shù)值:

        # manually_parse_argv.pyimport sys

        # 由于sys.argv的第一個(gè)變量是當(dāng)前腳本名稱(chēng),因此略過(guò)for index, command_arg in enumerate(sys.argv[1:]): if command_arg.startswith('--'): try: value = sys.argv[1:][index+1] if not value.startswith('-'): print("%s 為長(zhǎng)參數(shù),參數(shù)值為 %s" % (command_arg, value)) continue except IndexError: pass print("%s 為長(zhǎng)參數(shù),無(wú)參數(shù)值" % command_arg)
        elif command_arg.startswith('-'): try: value = sys.argv[1:][index+1] if not value.startswith('-'): print("%s 為短參數(shù),參數(shù)值為 %s" % (command_arg, value)) continue except IndexError: pass print("%s 為短參數(shù),無(wú)參數(shù)值" % command_arg)

        再測(cè)試一下:

        $ python manually_parse_argv.py -d today -t now --author justdopython --country China --auto
        -d 為短參數(shù),參數(shù)值為 today-t 為短參數(shù),參數(shù)值為 now--author 為長(zhǎng)參數(shù),參數(shù)值為 justdopython--country 為長(zhǎng)參數(shù),參數(shù)值為 China--auto 為長(zhǎng)參數(shù),無(wú)參數(shù)值

        看起來(lái)還不錯(cuò)。

        但是再看看我們的代碼……真正的邏輯還沒(méi)開(kāi)始,反倒是為了解析命令行參數(shù)已經(jīng)寫(xiě)了幾十行代碼。這一點(diǎn)都不pythonic——這還不包括一些其他關(guān)于異常情況的處理。

        更何況是要在每個(gè)類(lèi)似的程序中加入這么一段程序了。

        2. getopt模塊幫您忙

        Python的好處就在于,生態(tài)過(guò)于豐富,幾乎你要用到的每個(gè)功能,都已經(jīng)有人為你寫(xiě)好了現(xiàn)成的模塊以供調(diào)用。

        衣來(lái)伸手飯來(lái)張口的日子除了能在夢(mèng)中想想,在用Python寫(xiě)程序的時(shí)候也不是不可以奢望。

        比如命令行參數(shù)解析,就有一個(gè)名為getopt的模塊,既能夠準(zhǔn)確區(qū)分長(zhǎng)短命令行參數(shù),也能夠恰當(dāng)?shù)靥崛∶钚袇?shù)的值。

        咱們先來(lái)看看:

        # test_getopt.pyimport sysimport getopt

        opts, args = getopt.getopt(sys.argv[1:], 'd:t:', ["author=", "country=", "auto"])
        print(opts)print(args)

        打印結(jié)果:

        $ python test_getopt.py -d today -t now --author justdopython --country China --auto[('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')][]

        下面我們來(lái)分別解釋一下相關(guān)參數(shù)的含義。

        getopt模塊中的getopt函數(shù)用于解析命令行參數(shù)。

        該函數(shù)接受三個(gè)參數(shù):args,shortopts和longopts,分別代表“命令行參數(shù)”,“要接收的短選項(xiàng)”和“要接收的長(zhǎng)選項(xiàng)”。

        其中args和longopts均為字符串組成的列表,而shortopts則為一個(gè)字符串。

        同樣地,由于sys.argv的第一個(gè)值為當(dāng)前腳本名稱(chēng),所以多數(shù)情況下我們會(huì)選擇向args參數(shù)傳入sys.argv[1:]的值。

        而shortopts這個(gè)參數(shù)接受的字符串則表示需要解析哪些短選項(xiàng),字符串中每個(gè)字母均表示一個(gè)短選項(xiàng):

        import sysimport getopt

        opts, args = getopt.getopt(sys.argv[1:], 'dt')
        print(opts)print(args)

        輸出結(jié)果:

        $ python test_getopt.py -d  -t[('-d', ''), ('-t', '')][]

        當(dāng)然,如果輸入的參數(shù)少于預(yù)期,也不會(huì)導(dǎo)致解析失?。?/p>

        $ python test_getopt.py  -t[('-t', '')][]

        但要是給出了預(yù)期之外的參數(shù),就會(huì)導(dǎo)致模塊拋錯(cuò):

        $ python test_getopt.py -d  -t -kTraceback (most recent call last):  File "test_getopt.py", line 11, in     opts, args = getopt.getopt(sys.argv[1:], 'dt')  	...    raise GetoptError(_('option -%s not recognized') % opt, opt)getopt.GetoptError: option -k not recognized

        這樣的處理邏輯也符合我們使用命令的體驗(yàn),可以簡(jiǎn)單地理解為“寧缺毋濫”。

        如果短參數(shù)相應(yīng)的字母后帶了一個(gè)冒號(hào):,則意味著這個(gè)參數(shù)需要指定一個(gè)參數(shù)值。getopt會(huì)將該參數(shù)對(duì)應(yīng)的下一個(gè)命令行參數(shù)作為參數(shù)值(而不論下一個(gè)參數(shù)是什么形式):

        import sysimport getopt

        opts, args = getopt.getopt(sys.argv[1:], 'd:t')
        print(opts)print(args)
        # $ python test_getopt.py -d -t# [('-d', '-t')]# []

        此外,一旦getopt在預(yù)期接收到長(zhǎng)短選項(xiàng)的位置沒(méi)有找到以“--”或“-”開(kāi)頭的字符串,就會(huì)終止解析過(guò)程,剩下的未解析字符串均放在返回元組的第二項(xiàng)中返回。

        $ python test_getopt.py -d d_value o --pattern -t[('-d', 'd_value')]['o', '--pattern', '-t']

        類(lèi)似地,longopts參數(shù)表示需要解析的長(zhǎng)參數(shù)。

        列表中的每一個(gè)字符串代表一個(gè)長(zhǎng)參數(shù):

        import sysimport getopt

        opts, args = getopt.getopt(sys.argv[1:], '', ["author", "country"])
        print(opts)print(args)
        # $ python test_getopt.py --author --country# [('--author', ''), ('--country', '')]# []

        要解析帶有參數(shù)值的長(zhǎng)參數(shù),還應(yīng)在每個(gè)長(zhǎng)參數(shù)后附帶一個(gè)等于號(hào)(=),以標(biāo)識(shí)該參數(shù)需要帶值:

        import sysimport getopt

        opts, args = getopt.getopt(sys.argv[1:], '', ["author=", "country"])
        print(opts)print(args)
        # $ python test_getopt.py --author justdopython --country# [('--author', 'justdopython'), ('--country', '')]# []

        所以最終就得到了我們一開(kāi)始的解析結(jié)果:

        import sysimport getopt

        opts, args = getopt.getopt(sys.argv[1:], 'd:t:', ["author=", "country=", "auto"])
        print(opts)print(args)
        # $ python test_getopt.py -d today -t now --author justdopython --country China --auto# [('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')]# []

        解析完成后,我們?cè)購(gòu)膐pts中提取相應(yīng)的值即可。

        懶人福音

        getopt除了替我們節(jié)省了編寫(xiě)命令行參數(shù)解析代碼的時(shí)間和精力,另一方面還可以讓你在輸入命令行參數(shù)時(shí)少打幾個(gè)字母——當(dāng)然,嚴(yán)謹(jǐn)來(lái)講,我們并不建議此類(lèi)行為。慎用,慎用!

        getopt對(duì)長(zhǎng)參數(shù)的解析支持前綴匹配,只要輸入的參數(shù)能夠與某個(gè)指定參數(shù)唯一匹配,同樣能夠完成預(yù)期解析。

        $ python test_getopt.py -d today -t now --auth justdopython --coun China --auto[('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')][]

        可以看到,authorcountry兩個(gè)參數(shù)我們都只輸入了一部分,但是getopt依然進(jìn)行了正確的解析。

        總結(jié)

        本文講解了使用Python解析命令行參數(shù)的兩種方式,一種是略顯笨重的手動(dòng)解析,即自己編寫(xiě)程序自定義解析;另一種則是調(diào)用現(xiàn)成、且更加健壯的getopt模塊來(lái)完成解析。

        從此以后,我們終于可以擺脫繁瑣的配置文件,用一種優(yōu)雅簡(jiǎn)潔的方式來(lái)修改程序的行為了。

        參考

        getopt --- C 風(fēng)格的命令行選項(xiàng)解析器


        PS公號(hào)內(nèi)回復(fù)「Python」即可進(jìn)入Python 新手學(xué)習(xí)交流群,一起 100 天計(jì)劃!


        老規(guī)矩,兄弟們還記得么,右下角的 “在看” 點(diǎn)一下,如果感覺(jué)文章內(nèi)容不錯(cuò)的話,記得分享朋友圈讓更多的人知道!

        代碼獲取方式

        識(shí)別文末二維碼,回復(fù):200825

        瀏覽 41
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            一级毛片女女女女女女 | 大黄片国产做受 | 骚婷婷| 国产黄一级 | 93色色 | 一级特黄6O分钟免费 | 91免费版黄色 | 黄色免费观看网站 | 免费看靠逼视频 | 国产又粗又大的视频 |