Python PR

【Python】演算子をオーバーロードする特殊メソッドの使い方

記事内に商品プロモーションを含む場合があります

この記事では、Pythonで演算子をオーバーロードする方法を解説します。

intなどの組み込み型では、+-などの演算子を使って演算できたり、==などの比較演算子を使って比較を行うことができます。演算子のオーバーロードを行うことでユーザー定義型でも組み込み型と同じような振る舞いを持たせることができます。

つまり、演算子のオーバーロードとは、「ユーザー定義型で演算や比較を行えるようにするための機能」ということです。

Pythonで演算子をオーバーロードするには、クラスに、使用したい演算子に対応した特殊メソッドを定義するだけで簡単に実装することができます。

また、普通の関数をオーバーロードすることもできます。

引数が異なる関数を定義する方法

それでは、特殊メソッドの使い方を見ていきましょう!

比較演算子の特殊メソッド

比較演算子用の特殊メソッドをクラスに定義することで、そのクラスで比較を行えるようにできます。特殊メソッドのother引数には、比較対象のオブジェクトが渡されます。

演算子 機能 特殊メソッド
< 小なり __lt__(self, other)
<= 小なりイコール __le__(self, other)
> 大なり __gt__(self, other)
>= 大なりイコール __ge__(self, other)
== 等しい __eq__(self, other)
!= 等しくない __ne__(self, other)

例として、==演算子で等しいか判定できるクラスを定義してみます :

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __eq__(self, other):
        # 同じクラスかどうかの判定
        if type(other) == Num: 
            return self.num == other.num
        raise TypeError()

# インスタンス化
zero1 = Num(0)
one = Num(1)
zero2 = Num(0)

print(f'zero1 == one: {zero1 == one}')
print(f'zero1 == zero2: {zero1 == zero2}')

実行結果

zero1 == one: False
zero1 == zero2: True

他の特殊メソッドも同じ要領で実装できます。

算術演算子(左辺)の特殊メソッド

算術演算子(左辺)の特殊メソッドを見ていきます。ここで紹介する特殊メソッドは、計算時に自身が左辺の場合に呼び出されます。 A + Bの時は、Aが左辺でBが右辺となります。

演算子 機能 特殊メソッド
+ 足し算 __add__(self, other)
- 引き算 __sub__(self, other)
* 掛け算 __mul__(self, other)
/ 割り算 __truediv__(self, other)
// 切り捨て割り算 __floordiv__(self, other)
% 剰余(余り) __mod__(self, other)
** べき乗 __pow__(self, other)

例として、+演算子で足し算ができるクラスを定義してみます :

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __add__(self, other):
        # 同じクラスかどうかの判定
        if type(other) == Num: 
            return self.num + other.num
        raise TypeError()

# インスタンス化
one = Num(1)
two = Num(2)

print(f'one + two = {one + two}')

実行結果

one + two = 3

算術演算子(右辺)の特殊メソッド

計算時に自身が右辺の場合に呼び出される特殊メソッドです。特殊メソッドが左辺と右辺のどちらも定義されている場合は、左辺の特殊メソッドが優先されます。

演算子 機能 特殊メソッド
+ 足し算 __radd__(self, other)
- 引き算 __rsub__(self, other)
* 掛け算 __rmul__(self, other)
/ 割り算 __rtruediv__(self, other)
// 切り捨て割り算 __rfloordiv__(self, other)
% 剰余(余り) __rmod__(self, other)
** べき乗 __rpow__(self, other)

例として、+演算子で足し算ができるクラスを定義します。先ほどの特殊メソッドと異なり左辺に置くことはできないので注意してください :

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __radd__(self, other):
        if type(other) == int:
            return self.num + other

# インスタンス化
one = Num(1)

print(f'2 + one = {2 + one}')

# 以下のように左辺に置くとエラー
one + 2

実行結果

2 + one = 3

算術代入演算子の特殊メソッド

代入演算子を実装するための特殊メソッドも用意されています。

機能 特殊メソッド
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

例として、+=演算子で代入演算できるクラスを定義します :

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __iadd__(self, other):
        if type(other) == Num:
            self.num +=  other.num
            return self

# インスタンス化
one = Num(1)
two = Num(2)

# 計算
one += two

print(f'one += two = {one.num}')

実行結果

one += two = 3

単項演算子の特殊メソッド

単項演算子も特殊メソッドで実装することができます。

機能 特殊メソッド
+instance __pos__(self)
-instance __neg__(self)
~instance __invert__(self)

例として、+instanceでインクリメントできるクラスを定義します :

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __pos__(self):
        self.num += 1
        return self.num

# インスタンス化
zero = Num(0)

# 単項演算
+zero

print(f'zero.num = {zero.num}')
print(f'zero.num = {+zero}')

実行結果

zero.num = 1
zero.num = 2

まとめ

この記事では、Pythonで演算子のオーバーロードをする方法を解説しました。

演算子のオーバーロードを実装することで組み込み型に似たユーザー定義型を作成することができます。比較や演算をよく行うクラスでは、あらかじめオーバーロードしておくと便利です。

ただし、全く使わないような特殊メソッドは定義しても邪魔にしかならないので必要なメソッドのみを定義しましょう!

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ