クラスとメソッド
クラスの基礎の例で示した簡単なクラスArtist をもう一度見てみましょう。 code: sample_class_hieral.py
class Artist:
pass
queen = Artist()
print(dir(queen))
code:bash
$ python sample_class_hieral1.py
'__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__' そうです、何も定義していないはずなのに、複数のアトリビュートが存在しています。
特殊メソッド
コンストラクタとして実行される __init__() などは特殊メソッド(Magic Method) と言われます。
例えば次の特殊メソッドはインスタンスオブジェクトの比較演算(2項演算)で呼び出されるものです。
__lt__() : 未満 (Less Than)、x<y は x.__lt__(y)を呼び出す
__le__(): 以下(Less Than or Equal)、x<=yはx.__le__(y)を呼び出す
__eq__(): 同じ(Equal)、x==yはx.__eq__(y)を呼び出す
__ne__(): 違う(Not Equal)、x!=yはx.__ne__(y)を呼び出す
__gt__(): より大きい(Greater Than)、x>yはx.__gt__(y)を呼び出す
__ge__(): 以上(Greater Than or Equal)、x>=yはx.__ge__(y)を呼び出す
code: 0712_class_magic_method.py
class Price:
def __init__(self, price=0):
self.price = price
p1 = Price(10)
p2 = Price(20)
print(dir(p1))
print(p1 == p2)
print(p1 != p2)
これを実行してみましょう。
code: bash
$ python 0712_class_magic_method.py
'__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'price' False
True
特殊メソッドの__eq__と__ne__が呼びされてうまくいっているようにみえます。
ただしここでの比較は price の値ではなく単にインスタンスが等しいか等しくないかの比較になっています。そこで設定した price の値で比較をできるようにこの特殊メソッドを自分で定義してみましょう。
code: 0713_class_redefine_magic_methods.py
class Price:
def __init__(self, price=0):
self.price = price
def __eq__(self, other):
if other is None or not isinstance(other, Price):
return NotImplemented
return self.price == other.price
def __ne__(self, other):
return not self.__eq__(other)
p1 = Price(10)
p2 = Price(20)
print(p1 == p1)
print(p1 != p2)
print(p1.__eq__(1))
print(p1 == 1)
ここで使用しているNotImplementedは組み込み定数で、実装されていないときに返すものです。
これ実行すると次のようになります。
code: bash
$ python 0713_class_redefine_magic_methods.py
True
True
NotImplemented
False
あれ、p1 == 1 を実行したときにはp1.__eq__(1) が呼び出されるはずなのに、 NotImplementedになっていないですね。
1. x.__eq__(y) を実行する
NotImplemented が返された場合 2 へ、そうでなければ実行した結果を返す
2. y.__eq__(x) を実行する
NotImplemented が返された場合 3 へ、そうでなければ実行した結果を返す
3. x と y の同一性を比較し、その結果を返す
これらは、y が x の サブクラスである場合、 2 と 1 の順序が逆転します。
サブクラスについては、後で説明しています。
ここでは単純にそういうものと理解しましょう
つまり、この例でNotImplementedにならなかったのは、Priceクラスだけの評価ではなく、int型オブジェクトでの__eq__()が評価されるためです。
code: 0714_class_redefine_magic_methods.py
class Price:
def __init__(self, price=0):
self.price = price
def __eq__(self, other):
if other is None or not isinstance(other, Price):
return NotImplemented
return self.price == other.price
def __ne__(self, other):
return not self.__eq__(other)
def __lt__(self, other):
if other is not None or not isinstance(other, Price):
return NotImplemented
return self.price < other.price
def __le__(self, other):
return self.__lt__(other) or self.__eq__(other)
def __gt__(self, other):
return not self.__le__(other)
def __ge__(self, object):
return not self.__lt__(object)
p1 = Price(10)
p2 = Price(20)
print(p1 == p2)
print(p1 != p2)
print(p1 < p2)
print(p1 <= p2)
print(p1 > p2)
print(p1 >= p2)
こうした既にあるメソッドを再定義することをメソッドオーバーライド(Method Override) といいます。とくに、演算子に結びついた特殊メソッドの再定義のことを、
オペレータオーバライド(Operator Override) と呼びます。