2016-03-06 32 views
9

Bazı komut satırı python programları yazıyor ve bunu yapmak için argparse kullanıyordum. Kodumu biraz aşağıdaki gibi yapıyorum.Bağımsız değişkenleri argolse'den açma

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) 

O arg1 ve arg2 3 kez aramak zorunda gerçekten süper sinir bozucu. İki kere yapmam gerektiğini anlıyorum.

parse_args İşlevinin döndürdüğü ad alanını bir tuple olarak işlemenin bir yolu var mı? Ya da daha iyisi isteğe bağlı silahlar için bir tuple ve bir dict olarak ve açmak?

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) 

cevap

3

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

Bu sınıf, okunabilir bir dize gösterimi ile sadece bir obje alt sınıf kasten basit. Eğer niteliklerin dict benzeri bir görünüm için tercih ederseniz, standart Python deyim kullanabilirsiniz) (vars:

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

Not o büyük ilerlemeler veya değişiklikleri en azından gelen biri optparse - argparse, sizinki gibi konumsal argümanların isteğe bağlı olarak aynı şekilde ele alınmasıdır. Her ikisi de argsNamespace nesnesinde görünür. optparse'da, konumlar, ayrıştırma tanımlanmış seçeneklerden yalnızca sol üstündür.

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

args artık Namespace ve extras bir listesi: Eğer argümanlar omiting ve parse_known_args kullanarak argparse aynı etkiyi alabilir. Örneğin

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

: Daha sonra olarak işlev diyebiliriz aynı argparse paragraf kendi Namespace sınıfını tanımlamak olabileceğini göstermektedir

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'} 

O.Bir sözlük gibi davranan birini (**args olarak kullanmak için) ve ad alanı olarak tanımlamak zor olmaz. Tüm argparse'un tümü, getattr ve setattr ile çalışmasıdır. https://stackoverflow.com/a/34932478/901925

Orada

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

ben nasıl fikir vermek: Geçen Ocak benzer yanıt için

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

:

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

başka standart Python özelliği bana bir tuplea olarak vars(args) geçmesine izin verir ayrıştırmadan sonra 'isteğe bağlı' dan 'pozisyonları' ayırmak.


İşte API, içeren özel bir ad sınıf var, bir sözlük olarak kendisini dönen bir araç: başka bir fikir

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'} 

- çoklu nargs (2 birini kullanın konumsal argüman için '*', '+'). Sonra, işlevinize iletirken yazacak tek bir adınız vardır.

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

bunu main() pozisyonel argümanları verme konusunda kafayı neden olduğu

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

yapıyor nesi var?

Dürüst olmak gerekirse, genellikle modülün başında a) [küçük komut dosyaları vb. Için] ayrıştırma argümanını yapıyorum, bu da bana tüm işlevlerin kapsamı olan bir değişken sağlar veya b) [genellikle]

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

Başka bir paketten içe/içe aktarırsam, ana işlevim için bir tuple args paketlemek zorunda kalmak istemiyorum. Parse_arguments' yöntem çağrısı seviyorum. Ben gerçekten bunu seviyorum. –

5

görebilirsiniz benzer bir soru here sorular: main() içeride senin deyim kullanmak faydalı olacaktır.

Düzenleme: Bir iç yöntemi kullanmak olmaz bir yol mu arıyorsunuz, ben vars() kullanarak önerdi this discussion bulundu. Bu oldukça iyi çalışıyor:

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

Bu BÜYÜK bir cevaptır .... Kütüphane tasarımı tarafından kamusal bir şeyin parçası olmayan bir şeye güvenmekten daha çok hoşlanacağım çünkü ben bir canım ve hayatım bitiyor. –

+0

Cheers @BenHoff :-) Sizin için çalışıyorsa [kabul ediyorum] (http://stackoverflow.com/help/someone-answers) cevabımı yapabilirsiniz. –

+0

Üzgünüm orada bir _but_ eksik. Bu harika bir cevap .... ** Ama ** Kütüphane tasarımıyla uğraşmayı tercih etmekteyim çünkü halkın bir parçası olmayan bir şeye güvenmekteyim çünkü ben bir canım ve hayatımda sonunu bitiriyorum. –

İlgili konular