読者です 読者をやめる 読者になる 読者になる

何かを書き留める何か

数学や読んだ本について書く何かです。最近は社会人として生き残りの術を学ぶ日々です。

Pythonで頑張る『Java言語で学ぶデザインパターン入門』【Iteratorパターン】

Python Design Pattern

電気通信大学で情報系(通信系?)らしきことを学んだが、不幸な事にオブジェクト指向プログラミングに触れる機会が無かった。プログラムと言えば講義の課題と数学の研究の実験のみでオブジェクト指向プログラミングを知らなくても生きていける環境にあった。そして現在、仕事でプログラミングを行っている。OJT(お前が 自分で トレーニング)な会社であるためこのままでは常識を知らぬまま時が過ぎし恥を晒すことになる。恥をかくならば今しかない。会社でちょっとJavaを扱ったのをいい機会に今更ながらデザインパターンを学ぼうかと思い立った。デザインパターンの原典といてば言わずもがなGoFである。

オブジェクト指向における再利用のためのデザインパターン

オブジェクト指向における再利用のためのデザインパターン

しかし、読もうとしても頭に入らない。そこでそれなりに評判がある『Java言語で学ぶデザインパターン入門』をまず読んで慣れることにした。
増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門

ただ読んでいたら面白くないのでこれをPythonで書き換えたらどうだろうかと思い立った。『Java言語で学ぶデザインパターン入門』ではIteratorパターンから始まっているのでそれから始める。

GoFによると、「リストのような集約オブジェクトは、その内部構造を明らかにすることなく、要素にアクセスする方法をユーザに対して提供するべきである」(P275)とある。集約オブジェクトからアクセスや走査のための役割を取り出して扱うとよいとのことである…うーん、本当にわかっているのだろうか。
以下はPythonで書き直したIteratorパターンの例である。問題は、Pythonのリスト、タプル、集合には既にイテレータが定義してあるので以下のように行う必要があるのかいう疑問が湧いてくるのである…。なお、PythonにはJavaのようなインターフェースは存在しないが、抽象基底クラスを用いれば一応実現できる。

import collections.abc

class Book(object):
    def __init__(self, name):
        self.name = name
    def getname(self):
        return self.name

class BookShelf(collections.abc.Iterable):
    def __init__(self):
        self.__books = []
    def getbookat(self, index):
        return self.__books[index]
    def appendbook(self, book):
        self.__books.append(book)
    def __len__(self):
        return len(self.__books)
    def __iter__(self):
        return BookShelfIterator(self)

class BookShelfIterator(collections.abc.Iterator):
    __index = 0
    def __init__(self, bookshelf):
        self.__bookshelf = bookshelf
    def __next__(self):
        try:
            ret = self.__bookshelf.getbookat(self.__index)
            self.__index += 1
            return ret
        except IndexError:
            raise StopIteration
        
if __name__ == '__main__':
    bookshelf = BookShelf()
    bookshelf.appendbook(Book("ドラえもん"))
    bookshelf.appendbook(Book("パーマン"))
    bookshelf.appendbook(Book("キテレツ大百科"))
    bookshelf.appendbook(Book("オバケのQ太郎"))

    for book in bookshelf:
        print(book.getname())
    for book in bookshelf:
        print(book.getname())

なんだか、もやもやする。
collections.abc.Iterableをが__iter__()を提供している、というのが「アクセスや走査のための役割を取り出して扱う」を意味するのだろうか。ユーザにcollections.abc.Iteratorを継承したイテレータを書かせることがIteratorパターンの旨み、なのか?