《34》リファクタリング:重複するコードの断片 〈Python 2.x 版〉

実録:はじめてのプログラミング記事一覧
《34》リファクタリング:重複するコードの断片

《著》小粒ちゃん+α《監修》小泉ひよ子とタマゴ倶楽部
2009年3月2日(月)

今日の進捗

  • Language Reference: Numeric and Mathematical Modules; functools — Higher order functions and operations on callable objects
  • Python.use(better) -- セミナー研修テキスト
  • 連結リスト課題を「続・ひよ子のきもち」で公開
Comment
本人:野中 やっとリファクタリングメタプログラミングが一緒になった感じがします。
担当:伊藤/本間 。(^^)

何が問題か:重複するコードの断片

すでに紹介したメソッドを見ると、重複するコードの断片が少なくありません。たとえば、次に示す2つのメソッドでは、

    def __delitem__(self, key):
        prev,node = self.head,self.head.next
        n = 0
        while node:
            if n==key:
                prev.next = node.next
                del node
                break
            prev,node = node,node.next
            n += 1
        else:
            s = self.__class__.__name__
            raise IndexError,"%s assignment index out of range"%s
    def remove(self, value):
        prev,node = self.head,self.head.next
        while node:
            if node.item==value:
                prev.next = node.next
                del node
                break
            prev,node = node,node.next
        else:
            s = self.__class__.__name__
            raise ValueError,"%s.remove(x): x not in %s"%(s,s)

(強調した部分を除いて)その大半が同じなのが分かります。実際に、どちらのメソッドも要素を削除するのは共通なので、そのコードが重複するのも自然です。そこで、リファクタリングを実施して、これらの重複するコードの断片を抽出して、独立したメソッドを用意します。

リファクタリング:重複するコードの断片

リファクタリングの基本は「整理整頓」です。それには、因数分解〔factorization〕と同様に、共通項を括り出してそれらを削除することで、簡潔で見通しの良いコードになることを目指します。
まず、2つのメソッド __delitem__/remove に共通するメソッド removeNode を抽出することから始めます。そこで、if に続くブロックに着目すると、

class myList(object):
    def removeNode(self, value):
        prev, node = self.head, self.head.next
        n = 0
        while node:
            if ...:                  # (1)
                return self._removeNode_body(prev, node)
            prev, node = node, node.next
            n += 1
        else:
            s = self.__class__.__name__
            raise ...                # (2)

    def _removeNode_body(self, prev, node):
        prev.next = node.next
        del node
        return ...

2つの条件式に違いはあっても、ブロック本体は同じなのが分かります。そこで、共通するブロック本体を独立したメソッド _removeNode_body として抽出します。このとき、もとの局所変数 prev/node は、新たに引数として再定義されます。

Tips


Last updated♪09/03/03