argparseを便利に使う
自作モジュールが増えてくると、コマンドライン引数の受け方が複雑になってきて、解決できないことがあるかもしれません。
この記事は、そんなときに役に立つかもしれない方法です。
まずは、コードです。
test.py から my_module.py を使うというものです。
test.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--mode', default='test', type=str)
args = parser.parse_args()
print(args)
if args.mode == 'test':
import my_module
my_module.show_param()
else:
raise NotImplementedError
my_module.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--param', default='aaa', type=str)
args = parser.parse_args()
print(args)
def show_param():
print(args.param)
これを、コマンドライン引数を使わずに、実行すると、こうなります。
$ python test.py
Namespace(mode='test')
Namespace(param='aaa')
aaa
Namespace(mode='test')
Namespace(param='aaa')
aaa
まずは、test.py にコマンドライン引数を渡してみます。
この例では、else 側に落ちて、NotImplementedError になります。
実装通りに動作しています。
$ python test.py --mode test2
Namespace(mode='test2')
NotImplementedError
Namespace(mode='test2')
NotImplementedError
次に、my_module.py にコマンドライン引数を渡してみます。
$ python3 test.py --param bbb
usage: test.py [-h] [--mode MODE] test.py: error: unrecognized arguments: --param bbb
usage: test.py [-h] [--mode MODE] test.py: error: unrecognized arguments: --param bbb
test.py が --param を受けられないので、エラーになってしまいます。
これ、argparse を使っている人が、まれに出くわす問題だと思います。
これの回避方法を考えてみたいと思います。
ある階層ではコマンドライン引数をスルーさせる
上記の問題は、特定のコマンドライン引数しか受け取らない仕組みがあればいいはずです。
その実装方法です。
test2.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--mode', default='test', type=str)
args, unknown = parser.parse_known_args()
print('args:', args)
print('unknown:', unknown)
if args.mode == 'test':
import my_module
my_module.show_param()
else:
raise NotImplementedError
my_module.py はそのままです。
test2.py が受け取れないコマンドライン引数である --param を渡してみます。
$ python test2.py --param bbb
args: Namespace(mode='test')
unknown: ['--param', 'bbb'] Namespace(param='bbb')
bbb
args: Namespace(mode='test')
unknown: ['--param', 'bbb'] Namespace(param='bbb')
bbb
ということで、回避方法は、parse_known_args() を使う、でした。
これによって、test2.py は --param 引数があってもスルーできるので、エラーになりません。