24

引数がある場合'-a', '-b', '-c', '-d'add_mutually_exclusive_group()関数を使用すると、プログラムはそのうちの1つだけを使用する必要があります。プログラムがまたはのいずれかのみを受け入れるように、それを組み合わせる方法はあります'-a 999 -b 999''-c 999 -d 999'

編集:より明確にするために簡単なプログラムを追加します:

>>> parser = argparse.ArgumentParser()
>>> group = parser.add_mutually_exclusive_group()
>>> group.add_argument('-a')
>>> group.add_argument('-b')
>>> group.add_argument('-c')
>>> group.add_argument('-d')

その後、のみ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d呼び出すことができます。argparseグループに除外グループを設定して、./app.py -a .. -b .. | ./app.py -c .. -d ..呼び出されるだけにすることはできますか?

4

4 に答える 4

7

編集:気にしないでください。argparseを呼び出すときにオプションを作成する必要があるという恐ろしい選択をするからですgroup.add_argument。それは私のデザインの選択ではありません。この機能が必要な場合は、ConflictsOptionParserを使用して試してみてください。

# exclusivegroups.py
import conflictsparse

parser = conflictsparse.ConflictsOptionParser()
a_opt = parser.add_option('-a')
b_opt = parser.add_option('-b')
c_opt = parser.add_option('-c')
d_opt = parser.add_option('-d')

import itertools
compatible_opts1 = (a_opt, b_opt)
compatible_opts2 = (c_opt, d_opt)
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
    parser.register_conflict(exclusive_grp)


opts, args = parser.parse_args()
print "opts: ", opts
print "args: ", args

したがって、それを呼び出すと、目的の効果が得られることがわかります。

$ python exclusivegroups.py -a 1 -b 2
opts:  {'a': '1', 'c': None, 'b': '2', 'd': None}
args:  []
$ python exclusivegroups.py -c 3 -d 2
opts:  {'a': None, 'c': '3', 'b': None, 'd': '2'}
args:  []
$ python exclusivegroups.py -a 1 -b 2 -c 3
Usage: exclusivegroups.py [options]

exclusivegroups.py: error: -b, -c are incompatible options.

警告メッセージは、との両方に互換性がないことを通知しません'-a''-b''-c'より適切なエラーメッセージを作成することができます。以下の古い、間違った答え。

古い編集: [この編集は間違っていますが、このように機能すれば完璧な世界ではないでしょうargparseか?]argparse以前の答えは実際には正しくありませんでしたが、相互に排他的なオプションごとに1つのグループを指定することでこれを行うことができます。プロセスを一般化するために使用itertoolsすることもできます。そして、すべての組み合わせを明示的に入力する必要がないようにします。

import itertools
compatible_opts1 = ('-a', '-b')
compatible_opts2 = ('-c', '-d')
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
    group = parser.add_mutually_exclusive_group()
    group.add_argument(exclusive_grp[0])
    group.add_argument(exclusive_grp[1])
于 2011-01-22T21:31:44.883 に答える
5

自分でこの問題に遭遇しただけです。argparseのドキュメントを読んだところ、argparse内でそれを実現する簡単な方法はないようです。parse_known_argsの使用を検討しましたが、すぐにargparseの特別な目的のバージョンを作成することになります;-)

おそらくバグレポートが必要です。それまでの間、ユーザーに少し余分な入力を行わせる場合は、サブグループ(gitやsvnの引数の動作など)を使用して偽造することができます。

    subparsers = parser.add_subparsers()
    p_ab = subparsers.add_parser('ab')
    p_ab.add_argument(...)

    p_cd = subparsers.add_parser('cd')
    p_cd.add_argument(...)

理想的ではありませんが、少なくともそれはあまり醜いハッカーなしでargparseからあなたに良いものを与えます。結局、スイッチを廃止し、必要なサブ引数でサブパーサー操作を使用することになりました。

于 2012-11-20T15:04:59.910 に答える
3

argparse@hpauljのコメントで参照されている拡張リクエストは、9年以上経ってもまだ開いているので、他の人が私が発見した回避策の恩恵を受ける可能性があると考えました。拡張リクエストのこのコメントに基づいて、次の構文を使用して、2つの異なる相互に排他的なグループにオプションを追加できることがわかりました。

#!/usr/bin/env python                                                                                                                                                                     
import argparse
import os
import sys

def parse_args():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )

    parser.add_argument("-d", "--device", help="Path to UART device", default="./ttyS0")

    mutex_group1 = parser.add_mutually_exclusive_group()
    mutex_group2 = parser.add_mutually_exclusive_group()

    mutex_group1.add_argument(
        "-o",
        "--output-file",
        help="Name of output CSV file",
        default="sensor_data_sent.csv",
    )

    input_file_action = mutex_group1.add_argument(
        "-i", "--input-file", type=argparse.FileType("r"), help="Name of input CSV file"
    )

    # See: https://bugs.python.org/issue10984#msg219660
    mutex_group2._group_actions.append(input_file_action)

    mutex_group2.add_argument(
        "-t",
        "--time",
        type=int,
        help="How long to run, in seconds (-1 = loop forever)",
        default=-1,
    )

    # Add missing ']' to usage message
    usage = parser.format_usage()
    usage = usage.replace('usage: ', '')
    usage = usage.replace(']\n', ']]\n')
    parser.usage = usage

    return parser.parse_args()


if __name__ == "__main__":
    args = parse_args()
    print("Args parsed successfully...")
    sys.exit(0)

これは私の目的には十分に機能します:

$ ./fake_sensor.py -i input.csv -o output.csv                                                                                                                                             
usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
fake_sensor.py: error: argument -o/--output-file: not allowed with argument -i/--input-file

$ ./fake_sensor.py -i input.csv -t 30         
usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
fake_sensor.py: error: argument -t/--time: not allowed with argument -i/--input-file

$ ./fake_sensor.py -i input.csv
Args parsed successfully...

$ ./fake_sensor.py -o output.csv
Args parsed successfully...

$ ./fake_sensor.py -o output.csv -t 30
Args parsed successfully...

もちろん、のプライベートメンバーへのアクセスargparseはかなり脆弱なので、本番コードではおそらくこのアプローチを使用しません。また、賢明な読者は、使用法のメッセージが誤解を招くことに気付くかもしれません。それは、使用できないときに一緒に使用できることを意味しているから-oです-i(!)ただし、このスクリプトはテストのみに使用しているので、あまり心配していません。(「実際の」使用法メッセージを修正すると、このタスクに費やすことができるよりもはるかに長い時間がかかると思いますが、これに対する巧妙なハックを知っている場合はコメントしてください。)

于 2020-03-31T19:08:57.817 に答える
0

サブパーサー?

unhammerの答えに似ていますが、より多くのユーザーコントロールがあります。注:私は実際にこのメソッドをテストしていませんが、理論的にはPythonの機能で動作するはずです。

2つのグループのそれぞれに1つずつ、合計2つのパーサーを作成し、条件を使用して相互に排他的な部分を実行できます。基本的に、引数の解析の一部にのみargparseを使用します。この方法を使用すると、ハンマーの答えの制限を超えることもできます。

# Python 3
import argparse

try:
    parser = argparse.ArgumentParser()
    parser.add_argument('-a')
    parser.add_argument('-b')
    args = parser.parse_args
except argparse.ArgumentError:
    parser = argparse.ArgumentParser()
    parser.add_argument('-c')
    parser.add_argument('-d')
    args = parser.parse_args
于 2018-07-20T02:30:00.227 に答える