web-dev-qa-db-ja.com

リストをPythonコマンドラインから渡す

pythonスクリプトをいくつかの引数を指定してコマンドラインから実行したいのですが、引数の1つはスクリプトの1つのセグメントに固有のオプションのリストである必要があります。 「コマンドラインリスト」文字列がコンマから分割された後に実際にリストを作成することによって、これを行う唯一の方法は解析ですか?その場合、どのように対処しますか?

例:-details = ['name'、 'title'、 'address']

26
Sam

プログラム:

import sys, ast, getopt, types

def main(argv):            
    arg_dict={}
    switches={'li':list,'di':dict,'tu':Tuple}
    singles=''.join([x[0]+':' for x in switches])
    long_form=[x+'=' for x in switches]
    d={x[0]+':':'--'+x for x in switches}
    try:            
        opts, args = getopt.getopt(argv, singles, long_form)
    except getopt.GetoptError:          
        print "bad arg"                       
        sys.exit(2)       

    for opt, arg in opts:        
        if opt[1]+':' in d: o=d[opt[1]+':'][2:]
        Elif opt in d.values(): o=opt[2:]
        else: o =''
        print opt, arg,o
        if o and arg:
            arg_dict[o]=ast.literal_eval(arg)

        if not o or not isinstance(arg_dict[o], switches[o]):    
            print opt, arg, " Error: bad arg"
            sys.exit(2)                 

    for e in arg_dict:
        print e, arg_dict[e], type(arg_dict[e])        

if __name__ == '__main__':
    main(sys.argv[1:])        

コマンドライン:

python py.py --l='[1,2,3,[1,2,3]]' -d "{1:'one',2:'two',3:'three'}" --tu='(1,2,3)'

出力:

args:  ['--l=[1,2,3,[1,2,3]]', '-d', "{1:'one',2:'two',3:'three'}", '--tu=(1,2,3)']
tu (1, 2, 3) <type 'Tuple'>
di {1: 'one', 2: 'two', 3: 'three'} <type 'dict'>
li [1, 2, 3, [1, 2, 3]] <type 'list'>

このコードスニペットは、-l--li=などの短いまたは長いコマンドスイッチを使用し、スイッチ後のテキストをPythonリスト、タプル、またはdict。解析されたデータ構造は、長い形式のスイッチキーを持つ辞書になります。

ast.literal_eval を使用することは比較的安全です。 pythonデータ定義のみを解析できます。

28
the wolf

argparse はこれに適しています。2.7および3.2の時点では標準ライブラリにありますが、それ以外の場合はpip install離れています。

可変長リストの指定に関する主な懸念は、引用符を使用してリストをシェル内の単一の引数として解釈することで対処できます(シェルに依存する可能性があります)。

% python prog.py 'name title address' spam

prog.pyには

import sys
my_list = sys.argv[1].split() 
# my_list is ['name', 'title', 'address']
if 'name' in my_list:
   do_something()

または類似。リストを区切るには、splitとともに引数を使用します。

% python prog.py "you're a foo, lift the bar"

my_list = [x.strip() for x in  sys.argv[1].split(',')]
# my_list is ["you're a foo", "lift the bar"]

ただし、代わりにargparseを使用してください。特に、-cスタイルのフラグを使用する場合。

質問を解釈する1つの方法は次のとおりです。

「私はすでにargparseを使用しています。これはPythonでコマンドライン引数を解釈する賢明な方法だからです。特定のカテゴリ内にあるオプションを指定するにはどうすればよいですか?」

あなたの質問では、私が使用しているシェルが詰まるものの例を示しました。

% python prog.py -v -details=['name', 'title', 'address'] --quickly -t 4

pythonに解析されません。引数を区切るためにスペースを使用し、シェル構文として[および]を使用する可能性があるためです。

代わりに以下をお勧めします

% python prog.py -v --details name title address --quickly -t 4

どこのprog.pyファイル

import argparse

parser = argparse.ArgumentParser() 
parser.add_argument('-v', action='store_true')
parser.add_argument('--details', nargs='*')
parser.add_argument('--quickly', action='store_true')
parser.add_argument('-t')

args = parser.parse_args()
#args is Namespace(details=['asdf', 'a', 'a'], quickly=False, t='4', v=True)
details = args.details
#details is ['asdf', 'a', 'a']

さて、あなたの質問によると、あなた自身で文字列を解析する必要はありませんでした。

26
Thomas

はい、 argparse が最善の策であり、名前付き引数の1つに値のリストを提供したい場合は、次のようになります(nargsパラメーターがこのキーです) ):

>>> import argparse
>>> arg_parser = argparse.ArgumentParser()
>>> arg_parser.add_argument('--details',
                            nargs='*',
                            type=str,
                            default=[],
                            help='a list of the details')

# your args on the command line like this example
>>> the_args = arg_parser.parse_args("--details 'name' 'title' 'address'".split())
>>> print the_args.details
["'name'", "'title'", "'address'"])
4
Mark Gemmill

the-wolf の可変長コレクションを明示的な文字列引数として使用するアプローチが本当に好きです。

私の考えでは、 nargs='*'には注目すべき欠点があります。文字列を位置引数として収集しようとすると(少なくとも1つの文字列が存在する必要があります)、またはサブパーサーを使用しようとすると、nargs='*'およびnargs='+'貪欲な補完を使用しますが、正当な理由で消費を停止することはないようです。オプションの引数または数値の構文が出現した場合でも、string()タイプは消費し続けます。 (これはサブパーサーでは予測が難しくなります)。

最良の場合、(位置とオプション)の後に配置された引数は無視され、さらに悪いことに、corruptデータ型をargparse配列に渡す可能性があります。

引用符付き文字列を検索するカスタムActionTypeを定義できるはずです。見つかった場合は、 the-wolf の例を適用します(ほぼ逐語的なようです)。

これにより、argparseで物事がきれいに保たれ、変数コレクションの一般的な使用がはるかに少なくなります。

0
user2097818