pythonでコマンドラインツール書く時ほぼ必須レベルの、
clickっていうコマンドラインの引数とかいい感じにしてくれるイケてるpackageがあるけど、

http://click.pocoo.org/6/
http://blog.amedama.jp/entry/2015/10/14/232045

デコレータに指定したオプション名と引数名を対応させないとならないので、
オプションが多いと冗長になってしまうのがちょっと残念で、なんとかしたい。

before

a.py
# coding: utf-8
import click

@click.command()
@click.argument('arg_a')
@click.argument('arg_b')
@click.option('--opt-c')
@click.option('--opt-d')
def cmd(arg_a, arg_b, opt_c, opt_d):
    print(locals())

if __name__ == '__main__':
    cmd()

bash
$ python a.py  a b --opt-c c --opt-d d
{'opt_d': 'd', 'opt_c': 'c', 'arg_b': 'b', 'arg_a': 'a'}

そこで

とりあえず **kwargs で受けるようにしてみれば、まとめて受け取れるけど、
dictだとtypoが検知しづらいつらみがあるので、もうひと工夫。

ビルトインの type には2種類の使い方があって、
http://jfine-python-classes.readthedocs.io/en/latest/type-name-bases-dict.html
type(name, bases, dict) で新しい型のインスタンスを作って、dict の内容で初期化できる。

after

無名structみたいな感じで使える。
元が **kwargs なので、普通に引数で受け取った残りをdictでまとめるのもできる。

b.py
# coding: utf-8
import click

@click.command()
@click.argument('arg_a')
@click.argument('arg_b')
@click.option('--opt-c')
@click.option('--opt-d')
def cmd(**kwargs):
    opts = type('hoge', (object,), kwargs)

    print(dir(opts))
    print(type(opts))
    print(opts.__name__)
    print(opts.arg_a)
    print(opts.arg_b)
    print(opts.opt_c)
    print(opts.opt_d)

if __name__ == '__main__':
    cmd()
bash
$ python b.py  a b --opt-c c --opt-d d
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'arg_a', 'arg_b', 'opt_c', 'opt_d']
<class 'type'>
hoge
a
b
c
d

っていう話。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.