21

少し問題があります。

私は自分の引数を解析するために使用argparseしますが、それは非常にうまく機能しています。

引数を持つために、私はします:

p_args = parser.parse_args(argv)
args = dict(p_args._get_kwargs())

しかし、問題p_argsは、これらの引数をコマンドラインでの位置順に並べる方法がわからないことです。これはdictだからです。

それで、コマンドラインでの順序によってタプル/リスト/順序付けされた辞書に引数を含める可能性はありますか?

4

6 に答える 6

19

引数の順序を維持するために、次のようなカスタムアクションを使用します。

import argparse
class CustomAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        if not 'ordered_args' in namespace:
            setattr(namespace, 'ordered_args', [])
        previous = namespace.ordered_args
        previous.append((self.dest, values))
        setattr(namespace, 'ordered_args', previous)
parser = argparse.ArgumentParser()
parser.add_argument('--test1', action=CustomAction)
parser.add_argument('--test2', action=CustomAction)

たとえば、次のように使用します。

>>> parser.parse_args(['--test2', '2', '--test1', '1'])
Namespace(ordered_args=[('test2', '2'), ('test1', '1')], test1=None, test2=None)
于 2012-01-27T01:50:01.400 に答える
6

引数がパーサーに表示される順序を知る必要がある場合は、次のようにパーサーを設定できます。

import argparse

parser = argparse.ArgumentParser(description = "A cool application.")
parser.add_argument('--optional1')
parser.add_argument('positionals', nargs='+')
parser.add_argument('--optional2')

args = parser.parse_args()
print args.positionals

このコードを実行する簡単な例を次に示します。

$ python s.py --optional1 X --optional2 Y 1 2 3 4 5
['1', '2', '3', '4', '5']

args.positionalsこれは、位置引数が順番に並んだリストであることに注意してください。詳細については、argparseのドキュメントを参照してください。

于 2012-01-26T23:41:08.443 に答える
5

の内部を理解することに依存しているため、これは少し壊れやすいですargparse.ArgumentParserが、書き直す代わりに、これがargparse.ArgumentParser.parse_known_args私が使用するものです:

class OrderedNamespace(argparse.Namespace):
    def __init__(self, **kwargs):
        self.__dict__["_arg_order"] = []
        self.__dict__["_arg_order_first_time_through"] = True
        argparse.Namespace.__init__(self, **kwargs)

    def __setattr__(self, name, value):
        #print("Setting %s -> %s" % (name, value))
        self.__dict__[name] = value
        if name in self._arg_order and hasattr(self, "_arg_order_first_time_through"):
            self.__dict__["_arg_order"] = []
            delattr(self, "_arg_order_first_time_through")
        self.__dict__["_arg_order"].append(name)

    def _finalize(self):
        if hasattr(self, "_arg_order_first_time_through"):
            self.__dict__["_arg_order"] = []
            delattr(self, "_arg_order_first_time_through")

    def _latest_of(self, k1, k2):
        try:
            print self._arg_order
            if self._arg_order.index(k1) > self._arg_order.index(k2):
                return k1
        except ValueError:
            if k1 in self._arg_order:
                return k1
        return k2

argparse.ArgumentParser.parse_known_argsこれは、各引数にデフォルト値を設定すると、オプションリスト全体を実行する知識を通じて機能します。ユーザー指定の引数が最初に開始されるということは、__setattr__前に見た引数にヒットすることを意味します。

使用法:

options, extra_args = parser.parse_known_args(sys.argv, namespace=OrderedNamespace())

options._arg_orderユーザーが指定したコマンドライン引数の順序を確認するか、コマンドラインで後で指定されたまたは指定されたoptions._latest_of("arg1", "arg2")ものを確認するために使用できます(私の目的では、2つのオプションのどちらがオーバーライドされるかを確認します)。--arg1--arg2

更新:リストに引数が含まれていないという_finalize病理学的ケースを処理するためのメソッドを追加する必要がありました)sys.argv()

于 2012-02-29T19:49:06.957 に答える
1

これを処理するために特別に作られたモジュールがあります:

https://github.com/claylabs/ordered-keyword-args

Orderedkwargsモジュールを使用せずに

def multiple_kwarguments(first , **lotsofothers):
    print first

    for i,other in lotsofothers:
         print other
    return True

multiple_kwarguments("first", second="second", third="third" ,fourth="fourth" ,fifth="fifth")

出力:

first
second
fifth
fourth
third

Orderedkwargsモジュールの使用について

from orderedkwargs import ordered kwargs  
@orderedkwargs  
def mutliple_kwarguments(first , *lotsofothers):
    print first

    for i, other in lotsofothers:
        print other
    return True


mutliple_kwarguments("first", second="second", third="third" ,fourth="fourth" ,fifth="fifth")

出力:

first
second
third
fourth
fifth

注:関数の上にデコレーターを付けてこのモジュールを使用する場合は、単一のアスタリスクが必要です。

于 2014-10-03T10:56:25.540 に答える
1

これが必要だったのは、ロギングの目的で、引数が解析された後に引数を出力するのが好きだったからです。問題は、引数が順番に出力されないことでした。これは本当に面倒でした。

カスタムアクションクラスは、私にはうまくいきませんでした。'store_true'コマンドラインで引数が指定されていない場合、カスタムアクションクラスが呼び出されないため、引数などの別のアクションを使用する他のdefault引数も機能しません。私にとってうまくいったのは、次のようなラッパークラスを作成することでした。

import collections

from argparse import ArgumentParser

class SortedArgumentParser():
    def __init__(self, *args, **kwargs):
        self.ap = ArgumentParser(*args, **kwargs)
        self.args_dict = collections.OrderedDict()      

    def add_argument(self, *args, **kwargs):
        self.ap.add_argument(*args, **kwargs)
        # Also store dest kwarg
        self.args_dict[kwargs['dest']] = None

    def parse_args(self):
        # Returns a sorted dictionary
        unsorted_dict = self.ap.parse_args().__dict__
        for unsorted_entry in unsorted_dict:
            self.args_dict[unsorted_entry] = unsorted_dict[unsorted_entry]

        return self.args_dict

長所は、add_argumentメソッドが元のメソッドとまったく同じ機能を持つ必要があることArgumentParserです。短所は、他のメソッドが必要な場合は、それらすべてをラップして作成する必要があるということです。幸いなことに、私が今まで使用したのはadd_argumentparse_argsだけだったので、これは私の目的をかなりうまく果たしました。親を使用したい場合は、さらに多くの作業を行う必要がありますArgumentParser

于 2016-07-18T00:05:06.323 に答える
0

これは、既存のソリューションに基づく私の単純なソリューションです。

class OrderedNamespace(argparse.Namespace):
    def __init__(self, **kwargs):
        self.__dict__["_order"] = [None]
        super().__init__(**kwargs)
    def __setattr__(self, attr, value):
        super().__setattr__(attr, value)
        if attr in self._order:
            self.__dict__["_order"].clear()
        self.__dict__["_order"].append(attr)
    def ordered(self):
        if self._order and self._order[0] is None:
            self._order.clear()
        return ((attr, getattr(self, attr)) for attr in self._order)

parser = argparse.ArgumentParser()
parser.add_argument('--test1', default=1)
parser.add_argument('--test2')
parser.add_argument('-s', '--slong', action='store_false')
parser.add_argument('--test3', default=3)

args = parser.parse_args(['--test2', '2', '--test1', '1', '-s'], namespace=OrderedNamespace())

print(args)
print(args.test1)
for a, v in args.ordered():
    print(a, v)

出力:

OrderedNamespace(_order=['test2', 'test1', 'slong'], slong=False, test1='1', test2='2', test3=3)
1
test2 2
test1 1
slong False

これにより、add_argument()でのアクションが可能になります。これは、カスタマイズされたアクションクラスソリューションでは困難です。

于 2019-11-21T22:23:24.773 に答える