###
6.20.4.4 例

以下に引数をとらず、単に見つかったオプションを記録するだけの コールバックオプションの例を示します:

    def record_foo_seen (option, opt, value, parser):
        parser.saw_foo = 1

    parser.add_option("--foo", action="callback", callback=record_foo_seen)

もちろん、``store_true'' アクションを使っても同じことができます。 もう少し興味深い例もあります: -a がコマンドライン上に 見つかった事実を記録するが、-b が見つかると -a を消し去るというものです。

    def check_order (option, opt, value, parser):
        if parser.values.b:
            raise OptionValueError("can't use -a after -b")
        parser.values.a = 1
    ...
    parser.add_option("-a", action="callback", callback=check_order)
    parser.add_option("-b", action="store_true", dest="b")

このコールバックを同様のオプションに対して複数回使いたい (オプションが見つかるとフラグが設定されるが、-b が見つかると常に消し去られる) 場合、少しだけ作業する必要が あります: すなわち、エラーメッセージと設定されるフラグを 一般化しておかなければなりません。

    def check_order (option, opt, value, parser):
        if parser.values.b:
            raise OptionValueError("can't use %s after -b" % opt)
        setattr(parser.values, option.dest, 1)
    ...
    parser.add_option("-a", action="callback", callback=check_order, dest='a')
    parser.add_option("-b", action="store_true", dest="b")
    parser.add_option("-c", action="callback", callback=check_order, dest='c')

もちろん、ここでは任意の条件を入れることができます -- できることは、 すでに定義されたオプションの値に対するチェックにとどまりません。 例えば、満月 (full moon) にならないと呼び出してはならないオプション があったとすると、やらなければならない作業は以下のようになります:

    def check_moon (option, opt, value, parser):
        if is_full_moon():
            raise OptionValueError("%s option invalid when moon full" % opt)
        setattr(parser.values, option.dest, 1)
    ...
    parser.add_option("--foo",
                      action="callback", callback=check_moon, dest="foo")

(is_full_moon() の定義は読者の練習用に残しておきます。)

固定個の引数

決まった数の引数をとるような callback オプションを定義する際には、 状況は少し興味深いものとなります。callback オプションが引数を とるよう定義する操作は ``store'' や ``append'' オプションと同様です: type を定義すると、オプションは単一の引数をとり、この値は 指定された型に変換可能でなくてはなりません; 加えて nargs を定義すると、オプションは指定数の引数をとるようになります。

標準的な ``store'' アクションをエミュレートするだけの例を以下に 示します:

    def store_value (option, opt, value, parser):
        setattr(parser.values, option.dest, value)
    ...
    parser.add_option("--foo",
                      action="callback", callback=store_value,
                      type="int", nargs=3, dest="foo")

`optparse` は 3 つの引数を取り出し、整数に変換しようと配慮 することに気をつけてください; これらの値を保存する必要があります (あるいは、何らかの処理を行う必要があります: 明らかに、この例 ではコールバックを使う必要はありません。想像力を働かせてください！)

可変個の引数

オプションが可変個の引数をとるようにしたいのなら、状況はやや 困難になります。この場合、コールバックを書かなければなりません; `optparse` では可変個の引数に対する組み込みの機能は まったく提供していません。このため、慣習的な Unix コマンドライン 解析のための本格的な書法を扱わなくてはなりません。 (以前は、`optparse` はこの問題に対する配慮を行っていましたが、 これは不具合がありました。この不具合は、この種のコールバックを より複雑にすることで修正されました。) とりわけ、コールバックでは、裸の -- や - 引数のことを考えなければなりません; やりかたは以下のようになります:

- 裸の -- が存在し、何らかのオプションの引数で ない場合、コマンドライン処理を停止させ、-- 自体は消失します。

- 裸の - も同様にコマンドライン処理を停止させますが、 - 自体は残されます。

- -- か - のいずれかがオプションに 対する引数となり得ます。

オプションが可変個の引数をとるようにさせたいなら、いくつかの 巧妙で厄介な問題に配慮しなければなりません。どういう実装を とるかは、アプリケーションでどのようなトレードオフを考慮するか によります (このため、`optparse` では可変個の引数に 関する問題を直接的に取り扱わないのです)。

とはいえ、可変個の引数をもつオプションに対するスタブ (stub、仲介 インタフェース) を以下に示しておきます:

    def varargs (option, opt, value, parser):
        assert value is None
        done = 0
        value = []
        rargs = parser.rargs
        while rargs:
            arg = rargs[0]

            # Stop if we hit an arg like "--foo", "-a", "-fx", "--file=f",
            # etc.  Note that this also stops on "-3" or "-3.0", so if
            # your option takes numeric values, you will need to handle
            # this.
            if ((arg[:2] == "--" and len(arg) > 2) or
                (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
                break
            else:
                value.append(arg)
                del rargs[0]

         setattr(parser.values, option.dest, value)

    ...
    parser.add_option("-c", "--callback",
                      action="callback", callback=varargs)

この実装固有の弱点は、-c 以後に続いて負の数を表す 引数があった場合、-c の引数ではなく次のオプションとして 解釈されるということです。この問題の修正は読者の練習課題として おきます。