《こちらに移動中です》

Previous|10/10|Next

Python.use(better, follow=”K&R”) # for novice 記事一覧

改訂♪2008/10/05

メソッド keys/values/items

組み込み型 dict には、次の3つのメソッドを適用できます。クラス eXdict の傘下でも、これに準拠します。

  • メソッド keys を利用すると「キー」を列挙したリストが得られます。
  • メソッド values を利用すると「値」を列挙したリストが得られます。
  • メソッド items を利用すると、要素対(キー/値)からなる「タプル」を列挙したリストが得られます。

何が問題か?


# cz_08.py -------------------------------------------- before ---
class Tnode(BinTree):
def keys(self):
node = [self.word]
left = self.left .keys()
right = self.right.keys()
return left + node + right
def values(self):
node = [self.count]
left = self.left .values()
right = self.right.values()
return left + node + right
def items(self):
node = [(self.word, self.count)]
left = self.left .items()
right = self.right.items()
return left + node + right

3つのメソッド keys/values/items の本体を見ると、その違いは変数 node に保持する情報と、再帰的なメソッド呼び出しだけだと分かります。そこで、これらの異なるコードの断片から共通する構造を抽出して、それを再利用可能にするために、リファクタリングを履行します。

ある解決法


class Tnode(BinTree):
def _do(self, func):
node = [eval("self._%s()"%func)]
left = eval("self.left .%s()"%func)
right = eval("self.right.%s()"%func)
return left + node + right

まず、引数 func が参照する関数オブジェクトごとに、異なる情報 node を得ます。次に、左右の部分木 left/right に対しては、引数 func が参照する関数オブジェクトに、その後処理を委ねます。そして、これらを連結したリスト left+node+right をリターン値とします。


def _keys (self): return self.word

メソッド keys に固有の処理を記述します。ここでは、単語 self.word をリターン値とします。


def _values(self): return self.count

メソッド values に固有の処理を記述します。ここでは、出現頻度 self.count をリターン値とします。


def _items (self): return self.word, self.count

メソッド items に固有の処理を記述します。ここでは、単語/出現頻度を要素対とするタプル self.word,self.count をリターン値とします。


共通する処理(テンプレート)_do と、メソッドごとに固有の処理 _keys/_values/_items とを分割統治したので、コードの見通しが良くなり、その保守も容易になります。


# cz_08.py -------------------------------------------- after ---
class eXdict:
def keys (self): return self._do("keys")
def values(self): return self._do("values")
def items (self): return self._do("items")

def _do(self, func): raise NotImplementedError

リファクタリング後のメソッド keys/values/items では、前述した補助関数 _do の引数に、各処理を識別する "keys"/"values"/"items" を指定するだけです。
抽象クラス eXdict では、メソッド _do が、例外 NotImplementedError を生成します。これは、子孫クラスで、このメソッドを再定義しないときに、プログラマーの注意を喚起します。


Previous|10/10|Next