Python(フィボナッチ数イテレータ&クラスのゲッター、セッター)
自作MyRangeクラスと同様に特殊メソッドを利用してフィボナッチ数を返すイテレータをプログラムしました。
また、これはmode引数を設定することで要素数を閾値とするか、最大値を閾値とするかを選べるようにしたいと思ってself.modeを定義していますが、このコードでは、まだ未実装になります。(現在は要素数が閾値)
また、modeがデフォルトで0の場合は要素数を閾値とし、modeを1にすると最大値を閾値とするようにしています。
クラス内変数は直接、値を書き換えてしまったらクラス内部で意図しない問題を引き起こしてしまう場合があります。
そこで、内部の値にアクセスする場合は「アクセサ」と呼ばれる内部の値を得るためのメソッドを用意しましょう。 @propertyというデコレータを使うと、メソッドに対して変数のようにアクセスすることができるようになります。(ゲッターの指定) @ゲッター名.setter というデコレータを使うと、 セッターを定義することができます。 上記のコードではprint("mode:",fib.mode,"threshold:",fib.threshold)がゲッターを利用している箇所で、fib.mode = 1、fib.threshold = 200がセッターを利用している箇所になります。 次回は素数イテレータについて投稿します。
class Fibonacci:
def __init__(self,x=10,*,mode=0):
self.x = x
self.mode = mode
@staticmethod
def fib(n):
if n == 0 or n == 1:
return 1
else:
return Fibonacci.fib(n-1)+Fibonacci.fib(n-2)
def __str__(self):
return "fibonacci numbers"
def __iter__(self):
self.count = 0
return self
def __next__(self):
if self.count >= self.x:
raise StopIteration
result = Fibonacci.fib(self.count)
self.count += 1
return result
fib = Fibonacci(20)
print("str:",str(fib))
for i in fib:
print(i,end=" ")
最初はPython(再帰recursion)の投稿で利用した関数をそのままクラスのメソッドとして追加し、イテレータで関数を呼んで計算結果を返すようにしましたが、これでは引数の数が大きくなると計算の負荷が毎回再帰処理で計算されてしまうため、スタックオーバーになってしまいます。また、これはmode引数を設定することで要素数を閾値とするか、最大値を閾値とするかを選べるようにしたいと思ってself.modeを定義していますが、このコードでは、まだ未実装になります。(現在は要素数が閾値)
class Fibonacci:
def __init__(self,x=10,*,mode=0):
"""@param x 閾値(default=10)
@param mode 0=個数 1=最大値(default=0)"""
if not Fibonacci.is_num(x) or not Fibonacci.is_num(mode)\
or (mode < 0 or mode > 1):
raise ValueError
self._x = x
self._mode = mode
@staticmethod
def is_num(x):
return isinstance(x,int)
@property
def mode(self):
return self._mode
@property
def threshold(self):
return self._x
@mode.setter
def mode(self,value):
if not Fibonacci.is_num(value) or (value < 0 or value > 1):
raise ValueError
self._mode = value
@threshold.setter
def threshold(self,value):
if not Fibonacci.is_num(value):
raise ValueError
self._x = value
def __str__(self):
return "fibonacci numbers"
def __iter__(self):
self._count = 0
self._preResult = 1
self._result = 1
return self
def __next__(self):
if self._mode == 0 and self._count >= self._x:
raise StopIteration
if self._count == 0 or self._count == 1:
self._count += 1
return self._result
else:
result = self._preResult + self._result
if self._mode == 1 and result >= self._x:
raise StopIteration
self._preResult = self._result
self._result = result
self._count += 1
return result
fib = Fibonacci()
print("str:",str(fib))
print("mode:",fib.mode,"threshold:",fib.threshold)
for i in fib:
print(i,end=" ")
fib.mode = 1
fib.threshold = 200
print("\nmode:",fib.mode,"threshold:",fib.threshold)
for i in fib:
print(i,end=" ")
改良verのコードではiterにself._preResultと_resultを保存できるようにし、nextでフィボナッチ数の計算を行うようにしました。また、modeがデフォルトで0の場合は要素数を閾値とし、modeを1にすると最大値を閾値とするようにしています。
raise StopIteration
でイテレータを止めることができるようになりますが、modeの値と比較条件を変化させることで挙動が変わるようにしています。
また、改良コードではゲッター・セッターという内部の値にアクセスするためのメソッドを用意しました。クラス内変数は直接、値を書き換えてしまったらクラス内部で意図しない問題を引き起こしてしまう場合があります。
そこで、内部の値にアクセスする場合は「アクセサ」と呼ばれる内部の値を得るためのメソッドを用意しましょう。 @propertyというデコレータを使うと、メソッドに対して変数のようにアクセスすることができるようになります。(ゲッターの指定) @ゲッター名.setter というデコレータを使うと、 セッターを定義することができます。 上記のコードではprint("mode:",fib.mode,"threshold:",fib.threshold)がゲッターを利用している箇所で、fib.mode = 1、fib.threshold = 200がセッターを利用している箇所になります。 次回は素数イテレータについて投稿します。