2016-03-06 70 views
9

我一直在編寫一些命令行python程序,並使用​​來做到這一點。我一直在構建我的代碼如下。從argparse解包參數

def main(arg1, arg2): 
    # magic 
    pass 

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 

    args = parser.parse_args() 

    main(args.arg1, args.arg2) 

這真是超級刺激得叫出來arg1arg2 3倍。我明白必須做兩次。

有沒有辦法將parse_args函數返回的命名空間當作元組來處理?或者更好的是作爲一個元組和一個可選參數的字典,並進行拆包?

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 
    parser.add_argument('--opt-arg', default='default_value') 

    args, kwargs = parser.magic_method_call_that_would_make_my_life_amazing() 

    # I get goosebumps just thinking about this 
    main(*args, **kwargs) 

回答

3

https://docs.python.org/3/library/argparse.html#the-namespace-object

這個類是刻意簡單,只是一個子類對象具有可讀的字符串表示。如果您希望擁有的屬性類似字典的視圖,您可以使用標準Python成語,瓦爾()

>>> 
>>> parser = argparse.ArgumentParser() 
>>> parser.add_argument('--foo') 
>>> args = parser.parse_args(['--foo', 'BAR']) 
>>> vars(args) 
{'foo': 'BAR'} 

注意,大進步,至少,從變化的一個optparse到​​是位置參數,比如你的,被視爲與可選項相同。它們都出現在argsNamespace對象中。在optparse中,定位符只是解析已定義選項的左邊界。您可以通過omiting你的論點,並使用parse_known_args獲得​​同樣的效果:

parser = argparse.ArgumentParser() 
args, extras = parser.parse_known_args() 

args現在是一個命名空間,並extras列表。然後,你可以調用你的函數爲:

myfoo(*extras, **vars(args)) 

例如:

In [994]: import argparse 
In [995]: def foo(*args, **kwargs): 
    .....:  print(args) 
    .....:  print(kwargs) 
    .....:  
In [996]: parser=argparse.ArgumentParser() 
In [997]: parser.add_argument('-f','--foo') 
Out[997]: _StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None) 
In [998]: args,extras = parser.parse_known_args(['-f','foobar','arg1','arg2']) 
In [999]: args 
Out[999]: Namespace(foo='foobar') 
In [1000]: extras 
Out[1000]: ['arg1', 'arg2'] 
In [1001]: foo(*extras, **vars(args)) 
('arg1', 'arg2') 
{'foo': 'foobar'} 

就在同​​款表明,你可以定義自己的Namespace類。定義一個行爲像字典(用作**args)和命名空間並不難。所有​​要求是它與getattrsetattr一起使用。

In [1002]: getattr(args,'foo') 
Out[1002]: 'foobar' 
In [1004]: setattr(args,'bar','ugg') 
In [1005]: args 
Out[1005]: Namespace(bar='ugg', foo='foobar') 

另一個標準Python功能讓我過去vars(args)作爲一個元組:

In [1013]: foo(*vars(args).items()) 
(('foo', 'foobar'), ('bar', 'ugg')) 
{} 

對於從去年1月份開始類似的答案:https://stackoverflow.com/a/34932478/901925

Neatly pass positional arguments as args and optional arguments as kwargs from argpase to a function

在那裏,我給出出主意如何解析後將'positionals'與'optionals'分開。


這裏有一個自定義命名空間類,包括它的API中,返回自己作爲一個字典的手段:

In [1014]: class MyNameSpace(argparse.Namespace): 
    ......:  def asdict(self): 
    ......:   return vars(self) 
    ......:  
In [1015]: args = parser.parse_args(['-f','foobar'], namespace=MyNameSpace()) 
In [1016]: args 
Out[1016]: MyNameSpace(foo='foobar') 
In [1017]: foo(**args.asdict()) 
() 
{'foo': 'foobar'} 

另一個想法 - 使用多nargs(2之一, '*','+')作爲位置參數。然後,只有一個名稱可以在將它傳遞給函數時使用。

parser.add_argument('pos',nargs='+') 
args = ... 
args.pos # a list, possibly empty 
foo(*args.pos, **vars(args)) 
4

什麼是錯的做

if __name__ == '__main__': 
    # do argparse stuff as above 
    main(args) 

也就是說,你爲什麼這麼掛了關於給main()位置參數?老實說,我通常會在模塊開頭解析a)[用於小腳本等],這爲我提供了一個在所有函數範圍內的變量,或者b)[通常]裏面main()我用你的成語:

def parse_arguments(): 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 
    args = parser.parse_args() 
    return args 

def main(): 
    args = parse_arguments() 
    # do stuff with args.arg1 and args.arg2 
+1

如果我從另一個包中導入/調用它,我不想將args包裝到主函數的元組中。我很喜歡'parse_arguments'方法調用。我真的很喜歡這個。 –

5

你可以看到一個類似的問題問here

編輯:尋找一種不使用內部方法的方式,我發現this discussion其中建議使用vars()。這工作得很好:

import argparse 

def main(arg1, arg2): 
    print arg1, arg2 

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('arg1') 
    parser.add_argument('arg2') 

    args = parser.parse_args() 
    main(**vars(args)) 
+0

這是一個偉大的答案....我寧願爲圖書館設計感到困惑,也不願意依靠某些不屬於公共API的內容,因爲我是一個偉大人物,而且我完成了人生的最後一刻。 –

+0

Cheers @BenHoff :-)如果它適合你,你可以[接受](http://stackoverflow.com/help/someone-answers)我的答案。 –

+0

對不起,我錯過了一個_but_在那裏。這是一個很好的答案...... **但是**我寧願爲圖書館設計感到困惑,而不願意依賴一些不屬於公共API的東西,因爲我是一個偉大人物,而且我完成了人生的最後一刻。 –