Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonの演算子バインディングとは?仕組みをわかりやすく解説

Pythonの演算子バインディングとは

Pythonでは、==< などの比較演算子を使った式は、そのまま計算されるのではなく、オブジェクトが持つ特殊メソッド(ダンダーメソッド)に処理が「バインド」されて実行されます。この仕組みを演算子バインディング(operator binding)と呼びます。演算子の実際の動作は、左右のオブジェクトがどのメソッドを実装しているかによって決まります。

a == b はどのように評価されるのか

例えば、次のような式を考えてみましょう。

a == b

この式が評価されるとき、Pythonインタープリタは以下の手順で処理を進めます。

  1. まず、左辺のオブジェクト a に対して __eq__() メソッドが定義されているかを探します。
  2. 見つかった場合は、右辺の b を引数として a.__eq__(b) を実行します。
  3. このメソッドが NotImplemented を返した場合、今度は逆方向の呼び出し、つまり次の式を試みます。
b.__eq__(a)

両方の試みが NotImplemented だった場合は、最終的にオブジェクトの同一性(is 相当)による比較が行われ、結果が決まります。

なぜ逆方向の呼び出しが必要なのか

このフォールバック機構があることで、異なる型同士の比較でも柔軟に対応できます。例えば、自作クラスと組み込み型を比較するケースを見てみましょう。

class Num:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        if isinstance(other, Num):
            return self.value == other.value
        if isinstance(other, int):
            return self.value == other
        return NotImplemented

print(Num(5) == 5)   # True:Num.__eq__(5) が処理を担当
print(5 == Num(5))   # True:int 側が NotImplemented を返すため
                     #       Num(5).__eq__(5) が呼ばれる

int 型は Num オブジェクトとの比較方法を知らないため NotImplemented を返しますが、Pythonが自動的に逆方向の呼び出しを試みることで、正しく True という結果が得られます。

他の演算子でも同じ仕組みが使われている

演算子バインディングは等価比較だけのものではありません。

  • a < b → まず a.__lt__(b)、失敗すれば b.__gt__(a)
  • a + b → まず a.__add__(b)、失敗すれば b.__radd__(a)

このように、Pythonの演算子は「左オペランド優先・右オペランドへの委譲」という一貫したルールで動作しています。独自クラスで演算子をサポートしたい場合は、対応する特殊メソッドを実装し、扱えない型には必ず NotImplemented を返すようにすると、Pythonの標準的な挙動と自然に整合します。

  1. Pythonの「not in」演算子とは?使い方と動作をわかりやすく解説

    Pythonには、要素があるシーケンス(リスト・タプル・文字列など)に含まれていないことを判定するための「not in」というメンバーシップ演算子が用意されています。 not in 演算子は、指定したシーケンスの中に変数が見つからない場合に True を返し、見つかった場合は False を返します。以下に具体的な例を示します。 >>> a = 10 >>> b = 4 >>> l1 = [1,2,3,4,5] >>> a not in l1 True >>> b not in l1 False この例で

  2. Pythonのドット(.)とは?属性やメソッドへのアクセス方法をわかりやすく解説

    Pythonにおける「ドット(.)」の基本 Pythonでは、ほぼすべての要素がオブジェクトとして扱われます。そして、すべてのオブジェクトには、それぞれ固有の属性(アトリビュート)とメソッドが備わっています。オブジェクトと、それらの属性やメソッドとをつなぐ役割を果たすのが、「ドット(.)」という記号です。 具体例:Dogクラスを使って理解しよう 例えば、「Dog(犬)」というクラスがあるとします。このとき、Fidoという名前の犬は、Dogクラスのインスタンス(オブジェクト)に相当します。 class Dog: pass Fido = Dog() このクラスに eats()(食べ