LoginSignup
5
7

More than 3 years have passed since last update.

Pythonのargparseでbool型のオプション引数を与えたらハマった話

Last updated at Posted at 2019-10-02

やりたいこと

実行時のオプション引数で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

:rolling_eyes::question:

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)' で設定する!

5
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7