LoginSignup
21
18

More than 5 years have passed since last update.

Pythonのdocopt使い方メモ

Last updated at Posted at 2016-05-03

はじめに

Pythonのdocopt(引数の定義と解釈を行うライブラリ)の使い方・注意点メモです。
docoptは超便利ですが、docoptが超便利!っていう話は特に書きません。

使い方

__doc__にUsageとOptionsを定義しておき、docopt(__doc__)として参照します。
args = docopt(__doc__)とすればargsは代替引数やオプションをキーとした辞書になります。

argsのkeyとvalueを全て表示するテストスクリプトで試してみます。

"""Overview:
  サブコマンド・オプション・引数をdocoptで受け、keyとvalueを全表示する

Usage:
  docopt_test xx1 <yy1>
  docopt_test [-a] [-b|--bbb] [-c...]
              [-d|--ddd <D>] [-e <E>] [<z>...]
  docopt_test xx2 <yy2>  # サブコマンドをこの位置に書くのはダメな例。後述。

Options:
  xx1          : サブコマンド    → 有無を示すTrue/False
  <yy1>        : 必須引数        → 引数文字列のリスト
  xx2          : サブコマンド    → 有無を示すTrue/False
  <yy2>        : 必須引数        → 引数文字列のリスト
  -a           : 任意オプション(引数なし)  → 有無を示すTrue/False
  -b --bbb     : 任意オプション(引数なし)  → 有無を示すTrue/False
  -c...        : 任意オプション(引数なし)  → 指定回数を示す数値
  -d --ddd <D> : 任意オプション(引数あり)  → 引数文字列のリスト
  -e <E>       : 任意オプション(引数あり)  → 引数文字列のリスト
  <z>          : 任意引数                  → 引数文字列のリスト
"""

from docopt import docopt

if __name__ == '__main__':
    args = docopt(__doc__)
    print("  {0:<20}{1:<20}{2:<20}".format("kye", "value", "type"))
    print("  {0:-<60}".format(""))
    for k,v in args.items():
        print("  {0:<20}{1:<20}{2:<20}".format(str(k), str(v), str(type(v))))

実行結果は以下のようになりました。
リスト型なので順番は保証されません(=実行するたびに変わります)。
今回は見やすいように順序を定義順に揃えています。

$ python docopt_test.py
  kye                 value               type
  ------------------------------------------------------------
  xx1                 False               <class 'bool'>
  <yy1>               None                <class 'NoneType'>
  -a                  False               <class 'bool'>
  --bbb               False               <class 'bool'>
  -c                  0                   <class 'int'>
  --ddd               []                  <class 'list'>
  -e                  None                <class 'NoneType'>
  <z>                 []                  <class 'list'>
  xx2                 False               <class 'bool'>
  <yy2>               None                <class 'NoneType'>

引数を何も指定していないので値が全て None[]False になっています。

では次に-cc -d DDD GGG -aを指定してみます。
わかりやすいよう、変化した部分に★マークをつけています。

$ python docopt_test.py -cc -d DDD GGG -a HHH
  kye                 value               type
  ------------------------------------------------------------
  xx1                 False               <class 'bool'>
  <yy1>               None                <class 'NoneType'>
  -a               ★ True                <class 'bool'>
  --bbb               False               <class 'bool'>
  -c               ★ 2                   <class 'int'>
  --ddd            ★ ['DDD']             <class 'list'>
  -e                  None                <class 'NoneType'>
  <z>              ★ ['GGG', 'HHH']      <class 'list'>
  <yy2>               None                <class 'NoneType'>
  xx2                 False               <class 'bool'>

-cの指定回数2-d|--dddの引数DDD、位置引数GGGHHH-a指定が入ってきたのがわかると思います。

また定義外のオプションを指定するなど、解釈できない場合はUsageが表示されます。

$ python docopt_test.py -A
Usage:
  docopt_test xx1 <yy1>
  docopt_test [-a] [-b|--bbb] [-c...]
              [-d|--ddd <D>] [-e <E>] [<z>...]
  docopt_test xx2 <yy2>

注意点:Usageは定義順にチェックされ、最初に一致したもので解釈される

端的に表現するのが難しくてこんな章タイトルにしてしまいました。
実例を見ていただきましょう。サブコマンドxx1を指定します。
これは本当は必須引数が必要なので、サブコマンドだけを指定した場合エラーになりそうです。

と思いましたがエラーになりませんでした。
任意引数<z>としてxx1という文字列が渡されたことになっています。
そう解釈すれば一致する(解釈できる)からでしょう。

$ python docopt_test.py xx1
  kye                 value               type
  ------------------------------------------------------------
  xx1              ☆ False               <class 'bool'>
  <yy1>            ☆ None                <class 'NoneType'>
  -a                  False               <class 'bool'>
  --bbb               False               <class 'bool'>
  -c                  0                   <class 'int'>
  --ddd               []                  <class 'list'>
  -e                  None                <class 'NoneType'>
  <z>              ★ ['xx1']             <class 'list'>
  xx2                 False               <class 'bool'>
  <yy2>               None                <class 'NoneType'>

xx1 fooを与えてみると、xx1True<yy1>fooになります。

$ python docopt_test.py xx1 foo
  kye                 value               type
  ------------------------------------------------------------
  xx1              ★ True                <class 'bool'>
  <yy1>            ★ foo                 <class 'str'>
  -a                  False               <class 'bool'>
  --bbb               False               <class 'bool'>
  -c                  0                   <class 'int'>
  --ddd               []                  <class 'list'>
  -e                  None                <class 'NoneType'>
  <z>                 []                  <class 'list'>
  xx2                 False               <class 'bool'>
  <yy2>               None                <class 'NoneType'>

この調子でxx2 fooを与えてみると、全て<z>と解釈されてしまいます。
docopt_test xx2 <yy2>よりも先にdocopt_test [<z>...]が定義されているためでしょう。

$ python docopt_test.py xx2 foo
  kye                 value               type
  ------------------------------------------------------------
  xx1                 False               <class 'bool'>
  <yy1>               None                <class 'NoneType'>
  -a                  False               <class 'bool'>
  --bbb               False               <class 'bool'>
  -c                  0                   <class 'int'>
  --ddd               []                  <class 'list'>
  -e                  None                <class 'NoneType'>
  <z>              ★ ['xx2', 'foo']      <class 'list'>
  xx2              ☆ False               <class 'bool'>
  <yy2>            ☆ None                <class 'NoneType'>

そういった機会があるかどうかわかりませんが、
もしも、全てのパターンが一致してしまうようなUsageを定義するなら、後ろにもっていくようにしましょう
上記の例ではサブコマンドxx2を指定することができません。

21
18
0

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
21
18