Python(MyRangeクラス 関数オブジェクト活用編)

以前Python(MyRangeクラス 負数対応ver)で組み込み関数rangeを自作してみましたが、check関数や負数対応イテレータ作成が冗長だったので、__init__で内部関数を作成し、関数オブジェクトを渡すことで引数の変数を扱うことができるようにしたverプログラムです。

class MyRange():
    def __init__(self,*args):
        n_args = len(args)
        if n_args == 1:
            start,stop,step = 0,args[0],1
        elif n_args == 2:
            start,stop,step = args[0],args[1],1
        elif n_args == 3:
            [start,stop,step] = args
        else:
            raise Exception

        if not all([isinstance(x,int) for x in args]) or step == 0:
            raise ValueError

        if step > 0:
            in_range = lambda x: x < stop
        else:
            in_range = lambda x: x > stop

        cur = None

        def get_next():
            nonlocal cur
            if in_range(cur):
                result = cur
                cur += step
                return result
            else:
                raise StopIteration

        def initialize_iterator():
            nonlocal cur
            cur = start

        def get_value_by_index(i):
            result = start + step *i
            if not in_range(result):
                raise IndexError("MyRange: out of range")
            return result

        self.f = get_next
        self.i = initialize_iterator
        self.g = get_value_by_index

    def __iter__(self):
        self.i()
        return self

    def __next__(self):
        return self.f()

    def __getitem__(self,i):
        return self.g(i)
                
mr = MyRange(10,-2,-2)
for i in mr:
    print(i)
print([*MyRange(10,-2,-2)])
print("item:",mr[1])

すべてTrueかどうかのチェックを組み込み関数all()でチェックしたり、負数の場合の条件分岐をラムダ式で登録して用いることで、かなりすっきりしたプログラムになっています。
また、関数オブジェクトの受け渡しでイテレータや__getitem__を作成しているので、変数のカプセル化ができています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Python

次の記事

Python(Tableクラス設計)