"--foo True"または "--foo False"として書かれたブール値のコマンドライン引数を解析するためにargparseを使いたいと思います。例えば:
my_program --my_boolean_flag False
しかし、次のテストコードは私が望むことをしません。
import argparse
parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", type=bool)
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse(cmd_line)
残念ながら、parsed_args.my_bool
はTrue
に評価されます。 cmd_line
を["--my_bool", ""]
に変更してもbool("")
はFalse
に評価されるので、これは驚くべきことです。
Argparseで"False"
、"F"
、およびそれらの小文字をFalse
に解析する方法を教えてください。
以前の提案を使用した、argparse
からの「正しい」解析エラーを使用したさらに別の解決策:
def str2bool(v):
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
Elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
これはデフォルト値でスイッチを作るのにとても便利です。例えば
parser.add_argument("--Nice", type=str2bool, nargs='?',
const=True, default=Nice,
help="Activate Nice mode.")
私は使用することができます:
script --Nice
script --Nice <bool>
それでもデフォルト値を使用します(ユーザー設定に固有)。そのアプローチの(間接的に関連した)欠点は、 'nargs'が位置的な引数をとらえるかもしれないということです この関連する質問 そして このargparseバグレポート を見てください。
これを行うためのもっと規範的な方法は、次のとおりです。
command --feature
そして
command --no-feature
argparse
はこのバージョンをうまくサポートしています:
parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
もちろん、もしあなたが本当に--arg <True|False>
バージョンが欲しいのなら、ast.literal_eval
を "type"として、あるいはユーザ定義関数として渡すことができます。
def t_or_f(arg):
ua = str(arg).upper()
if 'TRUE'.startswith(ua):
return True
Elif 'FALSE'.startswith(ua):
return False
else:
pass #error condition maybe?
Mgilsonの回答をお勧めしますが、相互に排他的なグループと一緒に--feature
と--no-feature
を同時に使用することはできません。
command --feature
そして
command --no-feature
だがしかし
command --feature --no-feature
スクリプト:
feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument('--feature', dest='feature', action='store_true')
feature_parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
あなたがそれらの多くを設定しようとしているなら、あなたはこのヘルパーを使うことができます:
def add_bool_arg(parser, name, default=False):
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument('--' + name, dest=name, action='store_true')
group.add_argument('--no-' + name, dest=name, action='store_false')
parser.set_defaults(**{name:default})
add_bool_arg(parser, 'useful-feature')
add_bool_arg(parser, 'even-more-useful-feature')
type=bool
とtype='bool'
が何を意味するのかについては、いくらか混乱があるようです。一方(または両方)が 'bool()
関数を実行するか、'ブール値を返す 'ことを意味するのでしょうか。現状ではtype='bool'
は意味がありません。 add_argument
または'bool' is not callable
を使用した場合と同じように、type='foobar'
はtype='int'
エラーを返します。
しかしargparse
には、このようにキーワードを定義できるレジストリがあります。これは主にaction
に使われます。 `action = 'store_true'あなたは登録されたキーワードを見ることができます:
parser._registries
辞書を表示する
{'action': {None: argparse._StoreAction,
'append': argparse._AppendAction,
'append_const': argparse._AppendConstAction,
...
'type': {None: <function argparse.identity>}}
たくさんのアクションが定義されていますが、デフォルトタイプのargparse.identity
だけがあります。
このコードは 'bool'キーワードを定義します。
def str2bool(v):
#susendberg's function
return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # add type keyword to registries
p.add_argument('-b',type='bool') # do not use 'type=bool'
# p.add_argument('-b',type=str2bool) # works just as well
p.parse_args('-b false'.split())
Namespace(b=False)
parser.register()
は文書化されていませんが隠されてもいません。 type
とaction
は関数とクラスの値を取るので、ほとんどの場合、プログラマはそれについて知る必要はありません。両方のカスタム値を定義するスタックオーバーフローの例はたくさんあります。
前の説明から明らかでない場合、bool()
は「文字列を解析する」という意味ではありません。 Pythonのドキュメントから:
bool(x):標準の真理値検定手順を使って値をブール値に変換します。
これとは対照的
int(x):数値または文字列xを整数に変換します。
1ライナー:
parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
これは、デフォルト値を設定するための追加の行がない別のバリエーションです。ブール値には常に値が割り当てられているため、事前チェックなしで論理ステートメントで使用できます。
import argparse
parser = argparse.ArgumentParser(description="Parse bool")
parser.add_argument("--do-something", default=False, action="store_true" , help="Flag to do something")
args = parser.parse_args()
if args.do_something == True:
print("Do something")
else:
print("Don't do something")
print("Check that args.do_something=" + str(args.do_something) + " is always a bool")
私は同じ問題を探していました、そしてimhoは素晴らしい解決策です:
def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
そしてそれを使って文字列を真偽値にパースします。
@mgilsonが言ったことに加えて、--flag
と--no-flag
が同時に使用されないことを強制するのを簡単にする ArgumentParser.add_mutually_exclusive_group(required=False)
メソッドもあることに注意すべきです。
これは私が期待していることすべてに有効です。
add_boolean_argument(parser, 'foo', default=True)
parser.parse_args([]) # Whatever the default was
parser.parse_args(['--foo']) # True
parser.parse_args(['--nofoo']) # False
parser.parse_args(['--foo=true']) # True
parser.parse_args(['--foo=false']) # False
parser.parse_args(['--foo', '--nofoo']) # Error
コード:
def _str_to_bool(s):
"""Convert string to bool (in argparse context)."""
if s.lower() not in ['true', 'false']:
raise ValueError('Need bool; got %r' % s)
return {'true': True, 'false': False}[s.lower()]
def add_boolean_argument(parser, name, default=False):
"""Add a boolean argument to an ArgumentParser instance."""
group = parser.add_mutually_exclusive_group()
group.add_argument(
'--' + name, nargs='?', default=default, const=True, type=_str_to_bool)
group.add_argument('--no' + name, dest=name, action='store_false')
非常によく似た方法は、使用することです。
feature.add_argument('--feature',action='store_true')
また、引数に--featureを設定した場合
command --feature
type --featureを設定しない場合、引数はTrueになります。引数のデフォルトは常にFalseです。
もっと簡単な方法は以下のように使うことです。
parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])
class FlagAction(argparse.Action):
# From http://bugs.python.org/issue8538
def __init__(self, option_strings, dest, default=None,
required=False, help=None, metavar=None,
positive_prefixes=['--'], negative_prefixes=['--no-']):
self.positive_strings = set()
self.negative_strings = set()
for string in option_strings:
assert re.match(r'--[A-z]+', string)
suffix = string[2:]
for positive_prefix in positive_prefixes:
self.positive_strings.add(positive_prefix + suffix)
for negative_prefix in negative_prefixes:
self.negative_strings.add(negative_prefix + suffix)
strings = list(self.positive_strings | self.negative_strings)
super(FlagAction, self).__init__(option_strings=strings, dest=dest,
nargs=0, const=None, default=default, type=bool, choices=None,
required=required, help=help, metavar=metavar)
def __call__(self, parser, namespace, values, option_string=None):
if option_string in self.positive_strings:
setattr(namespace, self.dest, True)
else:
setattr(namespace, self.dest, False)
最も簡単な方法はchoicesを使用することです。
parser = argparse.ArgumentParser()
parser.add_argument('--my-flag',choices=('True','False'))
args = parser.parse_args()
flag = args.my_flag == 'True'
print(flag)
--my-flagを渡さないとFalseに評価されます。ユーザーに選択肢を明示的に指定させたい場合は、required = Trueオプションを追加できます。
最も規範的な方法は次のようになると思います。
parser.add_argument('--ensure', nargs='*', default=None)
ENSURE = config.ensure is None