SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

よろずプログラマーのためのPython導入ガイド

Java meets Python - 第5回 二分木と辞書

よろずプログラマーのためのPython導入ガイド (7)

値の獲得

 メソッドgetを利用すると、任意のキーに対応する値を参照できます。

>>> m
{'A': 65, 'C': 67, 'B': 66}
>>> m.get("A")
65
>>> m.get("@")
>>> print m.get("@")
None

 引数に指定したキーが辞書に含まれるなら、それに対応する値が得られます。指定したキーが辞書に含まれないなら、その値が存在しないことを表わすNoneが得られます。ここでは、キー"A"は辞書mに含まれるので、対応する値 65 が得られます。また、キー"@"は辞書mに含まれないので、Noneが得られます。

 ただし、対話モードでは、リターン値としてのNoneは出力されません。そこで、値を出力するために、ここではprint文を使っています。

class Tnode(BinTree):
    def get(self, key):
        value = None
        node = self._detect(key)
        if node: value = node.count
        return value

 メソッドgetでは、補助関数_detectを再利用しています。まず、リターン値を表わす変数valueには、初期値としてNoneを設定しておきます。次に、_detectを使って、指定した単語keyを含むノードnodeを獲得します。そして、ifに続く条件式nodeを満たすなら、該当するノードが存在するので、その単語の出現頻度node.countをリターン値valueとして設定します。

 では実際に、これらのメソッドの動作を確認してみましょう。

>>> p
good(1,as(2,,can(1,be(1,,),)),happy(2,,))
>>> p.get("happy")
2
>>> p.get("god")
None

 getの引数に指定した単語が、二分木に含まれるなら、それに対応する値が得られます。ここでは、単語"happy"は二分木pに含まれるので、その値 2 が得られます。また、単語"god"は二分木pに含まれないので、Noneが得られます。

値の参照(獲得)

 演算子 [] を利用すると、任意のキーに対応する値を参照できます。

>>> m
{'A': 65, 'C': 67, 'B': 66}
>>> m["A"]
65
>>> m["@"]
Traceback (most recent call last):
...
KeyError: '@'

 引数に指定したキーが辞書に含まれるなら、それに対応する値が得られます。指定したキーが辞書に含まれないなら、例外を生成します。ここでは、キー"A"は辞書mに含まれるので、対応する値 65 が得られます。また、キー"@"は辞書mに含まれないので、例外オブジェクトKeyErrorを生成すると共に、エラーメッセージとして、指定した単語'@'を出力します。

メソッド __getitem__ は何処に

 メソッド__getitem__は、演算子 [] の操作を規定します。

class Tnone(BinTree):
    def __getitem__(self, key): return None

class Tnode(BinTree):
    def __getitem__(self, key):
        node = self._detect(key)
        if node: return node.count
        raise KeyError, key

 ここでは、補助関数_detectを再利用しています。まず、変数nodeには、_detectを使って得られる、指定した単語keyを含むノードを設定します。次に、ifに続く条件式nodeを満たすなら、該当するノードが存在するので、その単語の出現頻度node.countをリターン値とします。そして、条件式を満たさないなら、該当するノードが存在しないので、例外KeyErrorを生成すると共に、エラーメッセージとして、指定した単語keyを出力します。

 では実際に、これらのメソッドの動作を確認してみましょう。

>>> p
good(1,as(2,,can(1,be(1,,),)),happy(2,,))
>>> p.tree()
            +--
      +-- 'as'(2)
                        +--
                  +-- 'be'(1)
                        +--
            +-- 'can'(1)
                  +--
+-- 'good'(1)
            +--
      +-- 'happy'(2)
            +--
>>> p["happy"]
2
>>> p["god"]
Traceback (innermost last):
...
KeyError: god

 演算子 [] の中に指定した単語が、二分木に含まれるかどうかを判定した結果True/Falseが得られます。ここでは、単語"happy"は二分木pに含まれるので、その出現頻度 2 が得られます。また、単語"god"は二分木pに含まれないので、例外KeyErrorを生成すると共に、エラーメッセージとして指定した単語godを出力します。

値の設定(更新/追加)

 演算子 [] を演算子 = と共に利用すると、キーに対応する値を設定できます。

>>> m
{'A': 65, 'C': 67, 'B': 66}
>>> m["C"] = hex(m["C"])
>>> m
{'A': 65, 'C': '0x43', 'B': 66}
>>> m["@"] = ord("@")
>>> m
{'A': 65, '@': 64, 'C': '0x43', 'B': 66}

 引数に指定したキーが辞書に含まれるなら、それに対応する値を設定(更新)します。指定したキーが辞書に含まれないなら、新たなキーと値を設定(追加)します。ここでは、キー"C"は辞書mに含まれるので、対応する値'0x43'を設定します。また、キー"@"は辞書mに含まれないので、新たなキー"@"と値64を設定します。

メソッド __setitem__ は何処に

 メソッド__setitem__は、演算子 [] の操作を規定します。

class Tnone(BinTree):
    def __setitem__(self, key): return None

class Tnode(BinTree):
    def __setitem__(self, key, value):
        node = addtree(self, key)
        node = node._detect(key)
        if node: node.count = value

 ここでは、補助関数_detectを再利用しています。まず、addtreeを使って、指定した単語keyを追加する対象となるノードを獲得して、そのノードを変数nodeに保持させます。次に、_detectを使って、指定した単語keyを含むノードnodeを獲得します。そして、ifに続く条件式nodeを満たすなら、該当するノードが存在するので、その単語の出現頻度node.countに値valueを設定します。

 では実際に、これらのメソッドの動作を確認してみましょう。

>>> p
good(1,as(2,,can(1,be(1,,),)),happy(2,,))
>>> p["happy"] = 3
>>> p
good(1,as(2,,can(1,be(1,,),)),happy(3,,))

 演算子 [] の中に指定した単語"happy"は、二分木pに含まれるので、その出現頻度を 3 に設定(更新)します。

>>> p["god"] = 4
>>> p
good(1,as(2,,can(1,be(1,,),god(4,,))),happy(3,,))
>>> p.tree()
            +--
      +-- 'as'(2)
                        +--
                  +-- 'be'(1)
                        +--
            +-- 'can'(1)
                        +--
                  +-- 'god'(4)
                        +--
+-- 'good'(1)
            +--
      +-- 'happy'(3)
            +--

 演算子 [] の中に指定した単語"god"は、二分木pに含まれないので、新たにノードを生成します。そのノードには、単語"god"とその出現頻度 4 を設定(追加)します。

例外:AttributeError は語る

 最後にもう一度、メソッド__getitem__/__setitem__を実現する前まで、話を戻します。

>>> p
good(1,as(2,,can(1,be(1,,),)),happy(2,,))
>>> p["happy"]
Traceback (innermost last):
...
AttributeError: __getitem__
>>> p["happy"] = 3
Traceback (innermost last):
...
AttributeError: __setitem__

 実行時に例外オブジェクトAttributeErrorを生成すると共に、エラーメッセージとして、未定義のメソッドの名前__getitem__/__setitem__が出力されます。これらが、演算子 [] の操作を規定することは、その実行結果からも明らかです。

誰がために辞書はある

 エラーメッセージが出力されると、初心者は、必要以上にプレッシャーを感じてしまいます。少しでも早く「その痕跡を消してしまいたい」という気持ちも理解できます。しかし、ときには「転んでもタダでは起きない」姿勢も必要です。

 エラーメッセージを遠ざけるのではなく、むしろお友達として付き合うなら、良好な関係を築けるかもしれません。というのも、エラーメッセージは、迷子になりがちな開発の途上では、親切な水先案内人となるからです。次の表を見てください。

 この対応表は、ある例外が発生したときに、その原因を探るための道標となります。左列には、クラスBinTreeの傘下で実現したメソッド群が並んでいます。中列には、各メソッドを実現するときに、その手本とした、組み込み型dictのプロトコルの一部を示しています。右列には、関連する例外オブジェクトの一覧があります。

 例えば、__getitem__を再定義しないまま、演算子 [] を適用しようとすると、例外AttributeErrorを生成します。また、__getitem__を再定義しても、適切でないキーを指定すると、例外KeyErrorを生成します。前者は、プログラミング過程における想定外の出来事で、適切なプロセスを経る(メソッドを再定義)ように提供者を導きます。後者は、実行過程における想定内の出来事(仕様の一部)で、適切な使用法(存在するキーを指定)へと利用者を導きます。プログラマーには、提供者/利用者の二面性があるので、例外オブジェクトが語りかける警告に耳を傾けるのは重要です。

 マトリックス型の組織では、裏マトリックスチームが、エラーメッセージを収集して、それを再利用可能なリソース(反面教師)として体系化します。裏という呼称は便宜的なもので、その活動はコインの裏表と似ています。ともすると「裏」という言葉に日陰者のイメージを連想しがちですが「影があるから輪郭が見えてくる」ものです。

 エラーメッセージをキーにして、適切な値(対処法)が得られる逆引き辞書づくりのプロジェクトX(バツ)を、アプリケーション開発と並行して行う余裕があれば、いつか、プロジェクトX(エックス)の番組で、皆さんのプロジェクトが取り上げられる日が訪れるかもしれませんね。

《余録》
 編集S「プロジェクトXは放送終了(2005年12月28日)しました」
 ひよ子「ぴっ…」

参考文献

  • 『鳩よ! 1991年3月号』 特集:谷川俊太郎 いるかいるか いないかいるか
  • 3ページ目の節見出しは、ここからの引用。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
よろずプログラマーのためのPython導入ガイド連載記事一覧

もっと読む

この記事の著者

小泉ひよ子とタマゴ倶楽部(コイズミヒヨコトタマゴクラブ)

http://tamago-club.cocolog-nifty.com/「楽しくなければ仕事じゃない」が私たちのモットー。99%の苦悩の連続も、1%の成功に報われます。だからこそ、この仕事が楽しくて仕方がないのです。楽をするための努力なら惜しみません。何もせず楽をしているのと、努力をしたから楽ができるのと...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

本間 こりす(ホンマ コリス)

新人です。他のみなさんに支えられながら、マイペースで頑張ります。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1803 2008/04/04 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー