Python(MyRangeクラス)
組み込みモジュールのrangeの劣化verになりますが自作で同様の機能を持ったクラスを特殊メソッドのオーバーライドで実装してみました。
class MyRange:
def __init__(self,*xs):
first,end,step = MyRange.check(xs)
self.first = first
self.end = end
self.step = step
@staticmethod
def err(message=""):
raise SyntaxError(message)
@staticmethod
def check(xs):
first,step = 0,1
n = len(xs)
if n == 0 or n > 3:
MyRange.err()
elif n == 1:
if xs[0] <= 0 or not isinstance(xs[0],int):
MyRange.err()
else:
end = xs[0]
elif n == 2:
if not isinstance(xs[0],int) or not isinstance(xs[1],int):
MyRange.err()
elif xs[0] >= xs[1]:
MyRange.err()
else:
first = xs[0]
end = xs[1]
elif n == 3:
if not isinstance(xs[0],int) or not isinstance(xs[1],int)\
or not isinstance(xs[2],int):
MyRange.err()
if xs[0] >= xs[1] or xs[2] <= 0:
MyRange.err()
else:
first = xs[0]
end = xs[1]
step = xs[2]
return first,end,step
def __contains__(self,x):
num = self.first
while num < self.end:
if x == num:
return True
num += self.step
return False
def __str__(self):
return "class MyRange"
def __iter__(self):
self.num = self.first
return self
def __next__(self):
if self.num < self.end:
result = self.num
self.num += self.step
return result
else:
raise StopIteration
def __getitem__(self,i):
if i >= self.__len__():
raise IndexError
count = 0
num = self.first
while count <= i:
result = num
num += self.step
count += 1
return result
def __len__(self):
tmp_end = self.end // self.step
tmp_first = self.first // self.step
return tmp_end-tmp_first
mr = MyRange(2,10,3)
print("str:",str(mr))
print(4 in mr)
for i in mr:
print(i)
print([*MyRange(2,10,3)])
print("len:",len(mr))
print("item:",mr[1])
本家rangeでは第三引数に負の数を設定した場合、最大最小を逆転したリストを生成できるようにしたり、第一と第二引数を評価して値が超えていたら空のリストを返したりする機能があるのですが、それらは未実装でエラーを出すようにしています。
def __init__(self,*xs):に可変引数を扱うことができるようにし、check(xs):のような検査関数を作成して初期値の設定ができるようにしています。
def __iter__(self):にself.num = self.firstを設定することで、イテレータとして呼び出された場合、毎回同じ挙動で初期値が設定されるようにしています。
def __contains __ (self,x):やdef __ getitem __ (self,i):では最大値や要素数の数になるまで繰り返し処理を行い、値があるかどうかをチェックして返すように定義しました。本家rangeを使わずに実装しているのでwhileループで実装しています。
(forループでrangeが使える有難さを再実感しました)
def __len__(self):では最初の要素と最後の要素をstepの数でいくつ含まれるかを計算し、要素数を求めるようにしています。
def __contains __ (self,x):やdef __ getitem __ (self,i): 、 def __len__(self): でstepを正の数と決めて実装しているので、負の数への対応を考える場合、冗長にならないように高階関数やクロージャを利用して負も扱うことができるように対応していきたいと思います。