新しいアクションの追加はもう少しトリッキーです。というのも optparse が使っている二つのアクションの分類を理解する必要があるからです。
この分類には重複する部分があります。デフォルトの ``store'' アクションには
store、store_const、append、count などがありますが、
デフォルトの ``typed'' オプションは store、append、callback
の三つです。
アクションを追加する際に、以下の Option のクラス属性(全て文字列のリストです) の中の少なくとも一つに付け加えることでそのアクションを分類する必要があります。
ALWAYS_TYPED_ACTIONSALWAYS_TYPED_ACTIONS のリストにあるオプションに、
デフォルト型 string を割り当てるということだけです。
実際に新しいアクションを実装するには、Option の take_action() メソッドをオーバライドしてそのアクションを認識する場合分けを追加しなければなりません。
例えば、extend アクションというのを追加してみましょう。このアクションは
標準的な append アクションと似ていますが、コマンドラインから一つだけ値を
読み取って既存のリストに追加するのではなく、複数の値をコンマ区切りの文字列として
読み取ってそれらで既存のリストを拡張します。すなわち、もし "-names" が
string 型の extend オプションだとすると、次のコマンドライン
--names=foo,bar --names blah --names ding,dong
の結果は次のリストになります。
["foo", "bar", "blah", "ding", "dong"]
再び Option のサブクラスを定義します。
class MyOption (Option):
ACTIONS = Option.ACTIONS + ("extend",)
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
def take_action(self, action, dest, opt, value, values, parser):
if action == "extend":
lvalue = value.split(",")
values.ensure_value(dest, []).extend(lvalue)
else:
Option.take_action(
self, action, dest, opt, value, values, parser)
注意すべきは次のようなところです。
extend はコマンドラインの値を予期していると同時にその値をどこかに格納します
ので、STORE_ACTIONS と TYPED_ACTIONS の両方に入ります。
extend アクションに string 型を割り当てるように
extend アクションは ALWAYS_TYPED_ACTIONS にも入れてあります。
values は optparse_parser.Values クラスのインスタンスであり、
非常に有用な ensure_value() メソッドを提供しています。
ensure_value() は本質的に安全弁付きの getattr() です。
次のように呼び出します。
values.ensure_value(attr, value)
values に attr 属性が無いか None だった場合に、
ensure_value() は最初に value をセットし、
それから value を返します。
この振る舞いは extend、append、count のように、データを変数に
集積し、またその変数がある型 (最初の二つはリスト、最後のは整数) であると期待されるアクション
を作るのにとても使い易いものです。ensure_value() を使えば、
作ったアクションを使うスクリプトはオプションに保存先にデフォルト値をセットすることに
煩わされずに済みます。デフォルトを None にしておけば ensure_value() が
それが必要になったときに適当な値を返してくれます。