Python 演算子のオーバーロード
Python 演算子のオーバーロード
使用するオペランドに応じて、Python の演算子の意味を変更できます。このチュートリアルでは、Python オブジェクト指向プログラミングで演算子のオーバーロードを使用する方法を学習します。
Python 演算子のオーバーロード
Python 演算子は組み込みクラスで機能します。ただし、同じ演算子でも型が異なれば動作も異なります。たとえば、+
演算子は、2 つの数値の算術加算、2 つのリストのマージ、または 2 つの文字列の連結を実行します。
同じ演算子がコンテキストに応じて異なる意味を持つことを可能にする Python のこの機能は、演算子のオーバーロードと呼ばれます。
では、ユーザー定義クラスのオブジェクトでそれらを使用するとどうなるでしょうか? 2-D 座標系でポイントをシミュレートしようとする次のクラスを考えてみましょう。
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p1 = Point(1, 2)
p2 = Point(2, 3)
print(p1+p2)
出力
Traceback (most recent call last): File "<string>", line 9, in <module> print(p1+p2) TypeError: unsupported operand type(s) for +: 'Point' and 'Point'
ここで、 TypeError
が Python は 2 つの Point
を追加する方法を知らなかったため、発生しました
ただし、演算子のオーバーロードを使用して Python でこのタスクを達成できます。しかし、最初に、特殊関数について理解しましょう。
Python 特殊関数
二重下線 __
で始まるクラス関数 Python では特殊関数と呼ばれます。
これらの関数は、クラスに対して定義する典型的な関数ではありません。 __init__()
上記で定義した関数はその 1 つです。そのクラスの新しいオブジェクトを作成するたびに呼び出されます。
Python には他にも多くの特殊関数があります。それらの詳細については、Python Special Functions をご覧ください。
特別な関数を使用して、組み込み関数と互換性のあるクラスを作成できます。
>>> p1 = Point(2,3)
>>> print(p1)
<__main__.Point object at 0x00000000031F8CC0>
print()
が必要だとします。 Point
の座標を出力する関数 私たちが得たものの代わりにオブジェクト。 __str__()
を定義できます オブジェクトの印刷方法を制御するクラスのメソッド。これを達成する方法を見てみましょう:
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x,self.y)
print()
を試してみましょう
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return "({0}, {1})".format(self.x, self.y)
p1 = Point(2, 3)
print(p1)
出力
(2, 3)
その方がいいです。組み込み関数 str()
を使用すると、これと同じメソッドが呼び出されることがわかります。 または format()
.
>>> str(p1)
'(2,3)'
>>> format(p1)
'(2,3)'
したがって、 str(p1)
を使用すると または format(p1)
、Python は内部的に p1.__str__()
を呼び出します 方法。したがって、その名前、特別な機能です。
それでは、演算子のオーバーロードに戻りましょう。
+ 演算子のオーバーロード
+
をオーバーロードするには 演算子、__add__()
を実装する必要があります クラスで機能します。大きな力には大きな責任が伴います。この関数内で、好きなことを行うことができます。しかし、Point
を返す方が賢明です 座標和のオブジェクト。
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x, self.y)
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y)
それでは、加算操作をもう一度試してみましょう:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x, self.y)
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y)
p1 = Point(1, 2)
p2 = Point(2, 3)
print(p1+p2)
出力
(3,5)
実際に起こることは、 p1 + p2
を使用すると 、Python は p1.__add__(p2)
を呼び出します これは Point.__add__(p1,p2)
です .この後、指定した方法で追加操作が実行されます。
同様に、他の演算子もオーバーロードできます。実装する必要がある特別な機能を以下に示します。
演算子 | 式 | 社内 |
---|---|---|
追加 | p1 + p2 | p1.__add__(p2) |
引き算 | p1 - p2 | p1.__sub__(p2) |
掛け算 | p1 * p2 | p1.__mul__(p2) |
パワー | p1 ** p2 | p1.__pow__(p2) |
部門 | p1 / p2 | p1.__truediv__(p2) |
フロア区分 | p1 // p2 | p1.__floordiv__(p2) |
余り (剰余) | p1 % p2 | p1.__mod__(p2) |
ビット単位の左シフト | p1 << p2 | p1.__lshift__(p2) |
ビットごとの右シフト | p1 >> p2 | p1.__rshift__(p2) |
ビットごとの AND | p1 & p2 | p1.__and__(p2) |
ビットごとの OR | p1 | p2 | p1.__or__(p2) |
ビット単位の XOR | p1 ^ p2 | p1.__xor__(p2) |
ビットごとの NOT | ~p1 | p1.__invert__() |
比較演算子のオーバーロード
Python は、演算子のオーバーロードを算術演算子のみに制限していません。比較演算子もオーバーロードできます。
小なり記号 <
を実装したいとします。 Point
の記号 クラス。
原点からのこれらの点の大きさを比較し、この目的のために結果を返しましょう。次のように実装できます。
# overloading the less than operator
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return "({0},{1})".format(self.x, self.y)
def __lt__(self, other):
self_mag = (self.x ** 2) + (self.y ** 2)
other_mag = (other.x ** 2) + (other.y ** 2)
return self_mag < other_mag
p1 = Point(1,1)
p2 = Point(-2,-3)
p3 = Point(1,-1)
# use less than
print(p1<p2)
print(p2<p3)
print(p1<p3)
出力
True False False
同様に、他の比較演算子をオーバーロードするために実装する必要がある特別な関数を以下に示します。
演算子 | 式 | 社内 |
---|---|---|
未満 | p1 < p2 | p1.__lt__(p2) |
以下 | p1 <= p2 | p1.__le__(p2) |
等しい | p1 == p2 | p1.__eq__(p2) |
等しくない | p1 != p2 | p1.__ne__(p2) |
より大きい | p1 > p2 | p1.__gt__(p2) |
以上 | p1 >= p2 | p1.__ge__(p2) |
Python