Pythonの__add__メソッドを徹底解説! オブジェクト同士の「足し算」を自由に定義しよう
Pythonで数値や文字列を+
演算子で足し算するのは日常的ですよね。でも、自分で作ったクラスのオブジェクト同士を足し算したいと思いませんか? 例えば、2つのベクトルオブジェクトを足し合わせて新しいベクトルを作ったり、カスタムデータ構造を結合したりするような場合です。
そんな時にPythonでその「足し算」の挙動をカスタマイズできるのが、特殊メソッド(マジックメソッド)の1つである**__add__
メソッド**です。
この記事では、__add__
メソッドの基本的な使い方から、その役割、そしてカスタムオブジェクトに独自の足し算を実装する方法まで、初心者の方にも分かりやすく徹底的に解説します。__add__
をマスターすれば、あなたのPythonコードはもっと直感的で、オブジェクト指向プログラミングの幅が格段に広がるでしょう!
__add__
メソッドとは? なぜ使うのか?
__add__
は、Pythonの特殊メソッド(Special Method)、あるいは**マジックメソッド(Magic Method)**と呼ばれるメソッドの一つです。これらのメソッドは、__
(アンダースコア2つ)で始まり、__
で終わる名前を持ち、特定のPythonの構文や組み込み関数が呼び出されたときに自動的に実行されます。
__add__
メソッドは、オブジェクトに対して**+
演算子**が使用されたときに呼び出されるメソッドです。
なぜ__add__
を使うのでしょうか?
演算子のオーバーロード(Operator Overloading): 独自のクラスで
+
演算子が使われたときの動作を、自由に定義できるようになります。これにより、カスタムオブジェクトを数値や文字列のように自然に操作できます。コードの可読性向上: 複雑な処理を関数呼び出しではなく、直感的な
+
演算子で表現できるため、コードが読みやすくなります。ドメイン固有の操作: 扱うデータや概念に合わせて、意味のある「足し算」を実装できます。例えば、ベクトルの加算、複素数の加算、通貨の合計などです。
__add__
メソッドの基本的な使い方
__add__
メソッドは、クラスの内部で定義します。通常、2つの引数を受け取ります。
構文
class MyClass:
def __add__(self, other):
# self: +演算子の左側のオブジェクト (MyClassのインスタンス)
# other: +演算子の右側のオブジェクト (任意の型)
# ここで足し算のロジックを実装し、結果を返す
pass
戻り値
__add__
メソッドは、足し算の結果となる新しいオブジェクトを返す必要があります。元のオブジェクト(self
)を変更するべきではありません。これは、数値の足し算が元の数値を変更せず、新しい数値を返すのと同じ原則です。
具体例1:二次元ベクトルの加算
最も分かりやすい例として、二次元ベクトルを表現するクラスで__add__
を実装してみましょう。
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self): # オブジェクト表示用(開発者向け)
return f"Vector({self.x}, {self.y})"
def __add__(self, other):
# other が Vector型かチェック
if isinstance(other, Vector):
# 新しい Vector オブジェクトを返す
return Vector(self.x + other.x, self.y + other.y)
else:
# Vector型でない場合はエラーを返すか、適切な処理を行う
return NotImplemented # 他の型との足し算をサポートしないことを示す
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2 # __add__ メソッドが呼び出される
print(v3) # 出力: Vector(4, 6)
# 数値との加算はエラーになる (NotImplementedが返されるため)
# print(v1 + 5) # TypeError: unsupported operand type(s) for +: 'Vector' and 'int'
この例では、Vector
オブジェクト同士を+
で足し算すると、それぞれのx
とy
成分が加算された新しいVector
オブジェクトが生成されます。
__add__
の動作と注意点
1. 戻り値は新しいオブジェクト
先述の通り、__add__
は新しいオブジェクトを返すべきです。元のオブジェクトをインプレースで変更したい場合は、__iadd__
(+=
演算子用)を使用します。
# NG例(__add__でselfを変更すべきではない)
class BadVector:
def __init__(self, x, y): self.x, self.y = x, y
def __repr__(self): return f"BadVector({self.x}, {self.y})"
def __add__(self, other):
self.x += other.x # BAD! 元のオブジェクトを変更している
self.y += other.y # BAD!
return self
bv1 = BadVector(1, 2)
bv2 = BadVector(3, 4)
bv3 = bv1 + bv2
print(bv3) # BadVector(4, 6)
print(bv1) # BadVector(4, 6) # bv1も変更されてしまう!
このように、__add__
でself
を変更してしまうと、予期せぬ副作用(元のオブジェクトまで変わってしまう)が生じるため、必ず新しいオブジェクトを返してください。
2. other
引数の型チェック
__add__
メソッドは、other
として任意の型のオブジェクトを受け取る可能性があります。したがって、other
の型をチェックし、適切に処理を分岐させることが重要です。
isinstance(other, MyClass)
:other
が特定のクラスのインスタンスであるかを確認します。NotImplemented
を返す: もしother
がself
のクラスとの足し算をサポートしない型である場合、NotImplemented
を返すべきです。これにより、Pythonはother
側の__radd__
メソッド(後述)を試したり、最終的にTypeError
を発生させたりします。TypeError
を直接発生させるよりも推奨されます。
3. __radd__
との関係(Reverse Add)
+
演算子で左右のオブジェクトの型が異なる場合、Pythonは特殊なルールでどちらの__add__
メソッドを呼び出すかを決定します。
例えば obj1 + obj2
という式があったとき:
obj1.__add__(obj2)
が試されます。もし
obj1.__add__(obj2)
がNotImplemented
を返した場合、Pythonはobj2.__radd__(obj1)
(リバース加算)を試します。どちらも
NotImplemented
を返すか、対応するメソッドが存在しない場合、TypeError
が発生します。
これにより、例えばMyClass
のオブジェクトと組み込み型(例: int
)を足し合わせる場合でも、適切に処理を定義できます。
class MyNumber:
def __init__(self, value):
self.value = value
def __repr__(self): return f"MyNumber({self.value})"
def __add__(self, other):
if isinstance(other, MyNumber):
return MyNumber(self.value + other.value)
elif isinstance(other, int):
return MyNumber(self.value + other)
return NotImplemented # これが重要
def __radd__(self, other): # other + self が呼び出された時
if isinstance(other, int):
return MyNumber(other + self.value)
return NotImplemented
num = MyNumber(10)
print(num + MyNumber(5)) # MyNumber(15) (MyNumber.__add__ が呼び出される)
print(num + 3) # MyNumber(13) (MyNumber.__add__ が呼び出される)
print(5 + num) # MyNumber(15) (int.__add__ が NotImplemented を返し、MyNumber.__radd__ が呼び出される)
__radd__
は、左側のオブジェクトが右側のオブジェクトを処理できない場合に、右側のオブジェクトのメソッドが呼び出されるという「フォールバック」の役割を果たします。
まとめ
__add__
メソッドは、Pythonのオブジェクト指向プログラミングにおいて、カスタムクラスに直感的で自然な「足し算」の挙動を与えるための強力なツールです。
+
演算子の動作をカスタマイズするための特殊メソッド。常に新しいオブジェクトを返すべきで、元のオブジェクトを直接変更しない。
other
引数の型を適切にチェックし、サポートしない型の場合は**NotImplemented
を返す**。__radd__
メソッドと連携して、異なる型のオブジェクト間の加算も処理できる。
__add__
を使いこなすことで、あなたのカスタムクラスはよりPythonicで、まるで組み込み型のように自然に振る舞うようになります。ぜひ今日学んだことを、あなたのコーディングに活かしてみてくださいね!
■「らくらくPython塾」が切り開く「呪文コーディング」とは?
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座