やりたいこと
実行時のオプション引数でTrue/Falseを設定したい。
$ py test.py --hogeFlag False
False
みたいな感じでオプション引数からbool値を取って内部で処理を分けたいと思ってました。
コード
最初はこんな感じのコードでオプション引数を取得していました。
bool以外のオプション引数を使ったスクリプトを組んだことがあったのでその応用でいけるやろと思ってました。
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("--hogeFlag", type=bool, default=True)
return parser.parse_args()
結果
py test.py --hogeFlag False
True
Falseを指定したつもりがTrueになってますね・・・
原因
bool()
でbool値に変換されているのが原因だった。
type=bool
と指定しているとPythonは、設定された引数を bool()
に入れてbool型にしてくれるようです。
type=int
とかにすると int()
を通してint型にしてくれていたおかげで文字列が入るとエラーが起こっていたんですね。
確かにどの言語でも、コマンドライン引数も最初はstring型として取得されてましたね。
今回のケースでは下記のコマンドで動かしていました。
$ py test.py --hogeFlag False
type=bool
なので、この場合は bool('False')
という処理を動かしてbool値に変換しようとします。
この bool('False')
はどういう結果になるのか。サクッとPythonWinで動かしてみます
>>> print(bool('False'))
True
Trueになってるやん・・・
理由
pythonの真偽値でFalseと判定されるのは次のものらしいです(公式ドキュメントより抜粋)
偽であると定義されている定数: None と False
数値型におけるゼロ: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
空のシーケンスまたはコレクション: '', (), [], {}, set(), range(0)
コマンドライン引数やオプション引数は、取得時にはstr型として扱われます。
なので3つ目の空のシーケンスまたはコレクションの部分に判定されます。
''
のような空文字だけがFalseと判定され、それ以外はTrueと判定されるようです。
bool('False')
がTrueと判定される理由がわかりました。
対応
add_argument関数の引数には type
の他に action
というのもありました。
今回のケースではこちらを使用します。 参考
コード
parser.add_argument("--hogeFlag", action='store_true')
action='store_true'
というのが新しいところですね。
動きとしてはこうなります
$ py test.py --hogeFlag
True
$ py test.py
False
--hogeFlag
を指定した時だけ True
で、指定しない時は False
になりました!
余談ですが真逆の store_false
というのも設定することができます。動きは store_true
と反対なだけなのでここでは省きます。
まとめ
オプション引数でbool値を与えたいときは type=bool
ではなく action='store_true(またはfalse)'
で設定する!