36

オプションの引数として (argparse を使用して) 辞書を設定しようとしています。次の行は私がこれまでに持っているものです:

parser.add_argument('-i','--image', type=dict, help='Generate an image map from the input file (syntax: {\'name\': <name>, \'voids\': \'#08080808\', \'0\': \'#00ff00ff\', \'100%%\': \'#ff00ff00\'}).')

しかし、スクリプトを実行すると:

 $ ./script.py -i {'name': 'img.png','voids': '#00ff00ff','0': '#ff00ff00','100%': '#f80654ff'}

script.py: error: argument -i/--image: invalid dict value: '{name:'

とはいえ、通訳の内部では、

>>> a={'name': 'img.png','voids': '#00ff00ff','0': '#ff00ff00','100%': '#f80654ff'}

うまく動作します。

では、代わりにどのように引数を渡す必要がありますか? 前もって感謝します。

4

13 に答える 13

62

Necroing this:json.loadsここでも機能します。あまり汚れていないようです。

import json
import argparse

test = '{"name": "img.png","voids": "#00ff00ff","0": "#ff00ff00","100%": "#f80654ff"}'

parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input', type=json.loads)

args = parser.parse_args(['-i', test])

print(args.input)

戻り値:

{u'0': u'#ff00ff00', u'100%': u'#f80654ff', u'voids': u'#00ff00ff', u'name': u'img.png'}

于 2013-08-01T20:29:54.967 に答える
15

完全を期すために、json.loads と同様に、yaml.load (PyPI の PyYAML から入手可能) を使用できます。これには、たとえば、整数を文字列に強制したり、yaml 変換セマンティクスを克服したりしない限り、コマンド ラインで個々のキーと値を引用する必要がないという点で、json よりも利点があります。ただし、スペースが含まれているため、明らかに文字列全体を引用符で囲む必要があります。

>>> import argparse
>>> import yaml
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-fna', '--filename-arguments', type=yaml.load)
>>> data = "{location: warehouse A, site: Gloucester Business Village}"
>>> ans = parser.parse_args(['-fna', data])
>>> print ans.filename_arguments['site']
Gloucester Business Village

確かに与えられた質問ではありますが、キーと値の多くは、yaml によるバーフィングを防ぐために引用または言い換える必要があります。文字列値ではなく数値が必要な場合、次のデータを使用すると非常にうまく機能するようです。

>>> parser.add_argument('-i', '--image', type=yaml.load)
>>> data = "{name: img.png, voids: 0x00ff00ff, '0%': 0xff00ff00, '100%': 0xf80654ff}"
>>> ans = parser.parse_args(['-i', data])
>>> print ans.image
{'100%': 4161164543L, 'voids': 16711935, 'name': 'img.png', '0%': 4278255360L}
于 2013-12-10T11:28:49.027 に答える
6

中括弧は多くのシェルで中括弧展開機能に使用される構文であるため、シェルが中括弧をいじっているに違いありません(こちらを参照)。

ユーザーが Python 構文を知っている必要がある、辞書などの複雑なコンテナーを渡すことは、コマンド ライン インターフェースでは不適切な設計のように思えます。代わりに、引数 group内の CLI でオプションを 1 つずつ渡し、解析されたグループからプログラムで dict を構築することをお勧めします。

于 2011-10-02T10:21:58.447 に答える
3

辞書リテラルのように見えるものを引数パーサーに確実に入れることができますが、それを引用する必要があるため、シェルがコマンドラインを解析すると、次のようになります。

  • 多くの代わりに単一の引数 (スペース文字は通常の引数区切り文字です)
  • 適切に引用されている (シェルは、引用符をグループ化に使用しているため、解析中に引用符を削除します)

したがって、次のようなもので、必要なテキストをプログラムに取得できます。

python MYSCRIPT.py -i "{\"name\": \"img.png\", \"voids\": \"#00ff00ff\",\"0\": \"#ff00ff00\",\"100%\": \"#f80654ff\"}"

ただし、この文字列は dict コンストラクターに対する有効な引数ではありません。代わりに、これは有効な python コード スニペットです。この引数の「タイプ」が であることを引数パーサーに伝えることができeval、それは機能します。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-i','--image', type=eval, help='Generate an image map...')
args = parser.parse_args()
print args

そしてそれを呼び出す:

% python MYSCRIPT.py -i "{\"name\": \"img.png\", \"voids\": \"#00ff00ff\",\"0\": \"#ff00ff00\",\"100%\": \"#f80654ff\"}"
Namespace(image={'0': '#ff00ff00', '100%': '#f80654ff', 'voids': '#00ff00ff', 'name': 'img.png'})

しかし、これは安全ではありません。入力は何でもかまいませんが、任意のコードを評価しています。これも同様に扱いにくいですが、次の方法の方がはるかに安全です。

import argparse
import ast

parser = argparse.ArgumentParser()
parser.add_argument('-i','--image', type=ast.literal_eval, help='Generate an image map...')
args = parser.parse_args()
print args

これも機能しますが、何を許可するかについてははるかに制限されていますeval

それでも、コマンド ラインで Python 辞書のように見える何かを、適切に引用符で囲んでユーザーに入力させるのは非常に扱いにくいものです。そして、事後にいくつかのチェックを行って、他の評価可能なものではなく辞書に渡され、正しいキーが含まれていることを確認する必要があります。次の場合は、はるかに使いやすくなります。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--image-name", required=True)
parser.add_argument("--void-color", required=True)
parser.add_argument("--zero-color", required=True)
parser.add_argument("--full-color", required=True)

args = parser.parse_args()

image = {
    "name": args.image_name,
    "voids": args.void_color,
    "0%": args.zero_color,
    "100%": args.full_color
    }
print image

為に:

% python MYSCRIPT.py --image-name img.png --void-color \#00ff00ff --zero-color \#ff00ff00 --full-color \#f80654ff
{'100%': '#f80654ff', 'voids': '#00ff00ff', 'name': 'img.png', '0%': '#ff00ff00'}
于 2011-10-02T15:28:15.917 に答える
2

私が見つけた最も簡単な方法の 1 つは、辞書をリストとして解析し、それを辞書に変換することです。たとえば、Python3 を使用する場合:

#!/usr/bin/env python3
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-i', '--image', type=str, nargs='+')
args = parser.parse_args()
if args.image is not None:
    i = iter(args.image)
    args.image = dict(zip(i, i))
print(args)

次に、コマンドラインで次のように入力できます。

./script.py -i name img.png voids '#00ff00ff' 0 '#ff00ff00' '100%' '#f80654ff'

目的の結果を得るには:

Namespace(image={'name': 'img.png', '0': '#ff00ff00', 'voids': '#00ff00ff', '100%': '#f80654ff'})
于 2013-12-05T13:53:55.197 に答える
1

一般的なアドバイス: eval は使用しないでください。

本当に必要な場合は... 「評価」は危険です。悪意のある入力を故意に入力する人がいないことが確実な場合に使用します。その場合でもデメリットが生じることがあります。悪い例を 1 つ取り上げました。

ただし、json.loads の代わりに eval を使用すると、いくつかの利点もあります。dict は、有効な json である必要はありません。したがって、 eval は「辞書」を受け入れるのにかなり寛容です。最終結果が確かに python 辞書であることを確認することで、「危険」な部分を処理できます。

import json
import argparse

tests = [
  '{"name": "img.png","voids": "#00ff00ff","0": "#ff00ff00","100%": "#f80654ff"}',
  '{"a": 1}',
  "{'b':1}",
  "{'$abc': '$123'}",
  '{"a": "a" "b"}' # Bad dictionary but still accepted by eval
]
def eval_json(x):
  dicti = eval(x)
  assert isinstance(dicti, dict)
  return dicti

parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input', type=eval_json)
for test in tests:
  args = parser.parse_args(['-i', test])
  print(args)

出力:

Namespace(input={'name': 'img.png', '0': '#ff00ff00', '100%': '#f80654ff', 'voids': '#00ff00ff'})
Namespace(input={'a': 1})
Namespace(input={'b': 1})
Namespace(input={'$abc': '$123'})
Namespace(input={'a': 'ab'})
于 2016-09-06T20:30:43.833 に答える
0

 あなたは試すことができます:

$ ./script.py -i "{'name': 'img.png','voids': '#00ff00ff','0': '#ff00ff00','100%': '#f80654ff'}"

私は今、私の電話でこれをテストしていません。

編集:ところで、私は@wimに同意します。引数として、dictの各kvを使用する方が、ユーザーにとってより良いと思います。

于 2011-10-02T10:54:17.177 に答える
0

以下は問題なく動作します。

parser = argparse.ArgumentParser()
parser.add_argument("-par", "--parameters",
                required=False,  default={"k1a":"v1a","k2a":"v2a"},
                type=json.loads)
args = parser.parse_args()
print(str(parameters))

result:
{'k1a': 'v1a', 'k2a': 'v2a'}

json.loads は文字列ではなくディクショナリを返すため、デフォルト値のタイプは dict である必要があります。デフォルト オブジェクトはディクショナリとして指定する必要があります。

import argparse,json,sys
sys.argv.extend(['-par','{"k1b":"v1b","k2b":"v2b"}'])
parser = argparse.ArgumentParser()
parser.add_argument("-par", "--parameters",
                required=False,  default={"k1":"v1","k2":"v2"},
                type=json.loads)
args = parser.parse_args()
print(str(args.parameters))

result: 
{'k1b': 'v1b', 'k2b': 'v2b'}
于 2021-08-07T01:12:59.087 に答える