スポンサーリンク

Pythonの特殊メソッドまとめ|initやaddなど自作クラスを自由自在にカスタマイズ!

クラス設計・OOP入門
  1. はじめに
  2. 1. 特殊メソッドとは?|Pythonが裏で呼び出す“仕組み”
    1. 特徴1:Pythonの構文に“連動”する
    2. 特徴2:クラスに“人間らしい”振る舞いを与えられる
  3. 2. 算術演算子のカスタマイズ|__add__や__sub__
    1. __add__を使って「+」を使えるようにする
    2. 右側に対応する__radd__
    3. その他の算術演算子にも対応できる
    4. どんなときに使うの?
  4. 3. インスタンス生成の制御|__new__と__init__
    1. __new__と__init__の違いは?
    2. どんなときに使うの?
    3. __new__の基本構文と例
    4. __new__を使うときの注意点
  5. 4. 比較演算子の定義|__eq__や__lt__
    1. __eq__で「==」の挙動を定義する
    2. NotImplementedを返すとどうなる?
    3. <や>を使うには? __lt__, __gt__の出番
    4. functools.total_orderingでまとめて実装
  6. 5. []を使いたい!|__getitem__と__setitem__
    1. __getitem__|値の取得に対応する
    2. __setitem__|値の設定に対応する
    3. 応用例:インデックスでアクセスする
    4. よく使われる場面
  7. 6. 表示や変換をカスタマイズ|__str__や__int__
    1. __str__|printしたときの見た目を整える
    2. __repr__との違いは?
    3. __int__|int()で整数変換できるようにする
    4. __float__|float()での変換も可能
    5. 表示や変換のカスタマイズは「親しみやすさ」に直結
  8. まとめ|特殊メソッドを知ると、自作クラスがもっと楽しくなる!
    1. 👇 この記事で紹介した特殊メソッドの使いどころをおさらい!
    2. あわせて読みたい
  9. よくある質問(Q&A)
    1. 関連投稿:

はじめに

Pythonでクラスを使い始めると、最初は__init__selfといった基本的な仕組みだけで十分かもしれません。でも、使っていくうちに「オブジェクト同士を足せたらいいのに」とか、「printしたときに見やすく表示できたら便利だな」と思ったことはありませんか?

実は、Pythonにはそういったクラスの振る舞いを自由にカスタマイズできる“裏技”のような仕組みが用意されています。それが「特殊メソッド」です!

特殊メソッドは、名前が__xxx__のようにアンダースコアで挟まれた特別なメソッドで、Pythonの内部で特定のタイミングに自動で呼び出されます。たとえば、オブジェクトを生成したときに呼ばれる__init__や、+演算子の処理を担う__add__などがそれにあたります。

この仕組みを理解すれば、自作のクラスに「+」や「==」などの演算子を使えるようにしたり、print()でわかりやすく表示したり、辞書みたいにobj["key"]でアクセスしたりと、**まるで標準ライブラリのような“自然な使い心地”**を実現できます。

この記事では、そんな特殊メソッドの中から特に使いやすくて便利なものを厳選して紹介します。Pythonのクラス設計をさらにパワーアップさせたい方は、ぜひ参考にしてみてください!




1. 特殊メソッドとは?|Pythonが裏で呼び出す“仕組み”

Pythonには、__init____str__のように名前の前後にアンダースコア(_)が2つ付いたメソッドがあります。これらは「特殊メソッド(Special Method)」や「マジックメソッド(Magic Method)」と呼ばれ、Pythonの言語仕様によって自動的に呼び出される仕組みになっています。

たとえば次のような場面を思い出してください。

print("Hello")

このとき、実はPythonの中では次のような処理が行われています。

"Hello".__str__()

つまり、print()で文字列を表示するときは、文字列オブジェクトの__str__()という特殊メソッドが呼び出されているのです。


特徴1:Pythonの構文に“連動”する

特殊メソッドの最大の特徴は、Pythonの構文や演算子とセットで使われるという点です。

構文/演算子呼ばれる特殊メソッド
+__add__()
==__eq__()
print(obj)__str__()
obj[key]__getitem__()
obj[key] = x__setitem__()

これらは、自作クラスで定義しておくと、Pythonの標準的な操作に自然になじむような挙動を持たせることができます。


特徴2:クラスに“人間らしい”振る舞いを与えられる

普通にクラスを定義するだけでは、演算子や関数との連携ができません。でも、特殊メソッドを使えば:

  • + で自作のオブジェクト同士を合成
  • == で内容が一致するかを比較
  • print() で見やすく表示
  • [] で辞書のようにアクセス

など、人が直感的に使いやすい機能をクラスに持たせることが可能になります。

Pythonのクラスは、特殊メソッドがなくても普通に使えます。でも、これを知っておくと一気にクラス設計の幅が広がります。たとえば、データ分析用のオブジェクト、ゲームのキャラクタークラス、数式を扱うクラスなど、現実世界の動作をプログラムに“自然に”落とし込むことができます。




2. 算術演算子のカスタマイズ|__add__や__sub__

Pythonでは、数値に対して+-を使うのは当たり前ですよね。でも実は、自分で作ったクラスにも同じような演算子の使い方をさせることができるんです。

その秘密が、特殊メソッド __add____sub__ にあります。


__add__を使って「+」を使えるようにする

まずは例から見てみましょう。次のようなクラスがあるとします。

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

このままでは、p1 + p2のように2つのPointオブジェクトを足そうとすると、エラーになります。でも、__add__メソッドを追加すると……?

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)

こうすることで、次のように書けるようになります。

p1 = Point(3, 5)
p2 = Point(2, 4)
p3 = p1 + p2 # ← __add__が自動で呼ばれる!

print(p3.x, p3.y) # 結果:5 9

右側に対応する__radd__

通常、p1 + p2では左側(p1)の__add__()が使われます。でも、もし左側のオブジェクトがその演算に対応していなかったら、Pythonは**右側の__radd__()**を探してくれます。

def __radd__(self, other):
# 右側からの加算に対応
return self.__add__(other)

この仕組みは、異なる型のオブジェクト同士を足し算したいときにも便利です。


その他の算術演算子にも対応できる

Pythonには他にもいろんな演算子があり、それぞれに対応する特殊メソッドがあります。

演算子特殊メソッド
-__sub__()
*__mul__()
/__truediv__()
//__floordiv__()
%__mod__()
**__pow__()

これらを定義すれば、まるで数値と同じような自然な操作ができるクラスを作ることができます。


どんなときに使うの?

  • ベクトルや座標の計算を行うクラス
  • 金額や通貨を扱うクラス
  • データ集計用のオブジェクト

たとえば、NumPyの配列やPandasのデータフレームでもこのような特殊メソッドが活用されています。自分のクラスに“+”や“-”を使いたいと思ったら、ぜひ__add____sub__を試してみましょう!




3. インスタンス生成の制御|__new__と__init__

Pythonでクラスのインスタンスを作るとき、ふつうは__init__メソッドを使いますよね。たとえばこんな感じです:

class Person:
def __init__(self, name):
self.name = name

p = Person("Alice") # __init__が呼ばれる

この__init__は、「インスタンスが作られたあとに中身を初期化する」ためのメソッドです。でも実は、インスタンスを「作る」処理自体をカスタマイズできるもう一つの特殊メソッドがあるんです。それが、__new__です。


__new__と__init__の違いは?

メソッドタイミング主な役割
__new__インスタンスを作る前インスタンスを生成して返す
__init__インスタンスを作った後インスタンスを初期化する

__new__は、インスタンスそのものを作るタイミングで呼び出されるので、戻り値として作ったインスタンスを返す必要があります。この戻り値がないと、__init__も呼ばれません。


どんなときに使うの?

__new__を使うのは珍しいですが、次のようなケースで必要になります。

  • intstr などの イミュータブル(変更できない)な型を継承するとき
  • インスタンス生成の前に何か特殊な処理をしたいとき
  • シングルトンパターンなど、1つしかインスタンスを作らせたくない設計をしたいとき

__new__の基本構文と例

class CustomStr(str):
def __new__(cls, value):
print("CustomStr.__new__ called")
obj = super().__new__(cls, value.upper())
return obj

s = CustomStr("hello")
print(s) # 出力:HELLO

このコードでは、strを継承したカスタムクラスで、文字列を大文字に変換してからインスタンスを作っています。strはイミュータブルなので、__init__では値を変えられません。だからこそ、__new__で加工する必要があるんです。


__new__を使うときの注意点

  • __new__の**第1引数はselfではなくcls**になります(クラス自体を受け取る)。
  • super().__new__(cls, ...)のように、親クラスの__new__を呼び出してインスタンスを生成する必要があります。
  • インスタンスを返すのを忘れると、__init__が呼ばれずエラーになります。

ふだんは__init__だけで十分ですが、ちょっと高度なことをしたくなったら、__new__を思い出してみてください。インスタンス生成の流れを完全にコントロールできるようになりますよ!




4. 比較演算子の定義|__eq__や__lt__

Pythonでオブジェクト同士を==<で比較できたら便利ですよね。自作クラスでも、それを実現できるのが比較演算子に対応した特殊メソッドです。

このセクションでは、よく使われる以下のメソッドを紹介します:

  • __eq__(==)
  • __ne__(!=)
  • __lt__(<)
  • __le__(<=)
  • __gt__(>)
  • __ge__(>=)

__eq__で「==」の挙動を定義する

たとえば、2つのBookオブジェクトが「同じタイトルと著者を持っていたら等しい」としたい場合、こんなふうに書きます:

class Book:
def __init__(self, title, author):
self.title = title
self.author = author

def __eq__(self, other):
return (self.title == other.title) and (self.author == other.author)

このように定義すれば、次のような比較ができます:

book1 = Book("Python入門", "山田")
book2 = Book("Python入門", "山田")
book3 = Book("Python応用", "佐藤")

print(book1 == book2) # True
print(book1 == book3) # False

Pythonはbook1 == book2と書かれた時、自動でbook1.__eq__(book2)を呼び出してくれるんです。


NotImplementedを返すとどうなる?

比較対象の型が明らかに違う場合、比較できないことを示すためにNotImplementedを返すこともできます。

def __eq__(self, other):
if not isinstance(other, Book):
return NotImplemented
return self.title == other.title and self.author == other.author

このように書くと、Bookと無関係なオブジェクトと比較しても安全です。


<や>を使うには? __lt__, __gt__の出番

順位づけが必要なクラス(例:テストの点数、ランキング、価格など)では、大小比較もしたくなりますよね。

class Score:
def __init__(self, name, value):
self.name = name
self.value = value

def __lt__(self, other):
return self.value < other.value

これで次のように使えます:

s1 = Score("Aさん", 85)
s2 = Score("Bさん", 92)

print(s1 < s2) # True

さらに__gt__(大なり)、__le__(以下)、__ge__(以上)なども定義しておけば、ソート(並び替え)にも対応できます


functools.total_orderingでまとめて実装

すべての比較メソッドを書くのは面倒…というときは、@total_orderingデコレーターを使うと便利です!

from functools import total_ordering

@total_ordering
class Score:
def __init__(self, name, value):
self.name = name
self.value = value

def __eq__(self, other):
return self.value == other.value

def __lt__(self, other):
return self.value < other.value

このように**__eq____lt__だけ定義すれば、残りは自動で補完してくれます。**

自作クラスで比較ができるようになると、リストの中での検索や並び替え、重複チェックなどがグッと使いやすくなります。ぜひ活用してみてください!




5. []を使いたい!|__getitem__と__setitem__

Pythonでは、リストや辞書のように[](角括弧)を使ってデータにアクセスしたり、値を代入したりできますよね。

d = {"key": "value"}
print(d["key"]) # → "value"
d["key"] = "new value"

実はこの挙動、すべて特殊メソッド __getitem____setitem__ によって制御されているんです。そして、自作クラスでもこれらを定義すれば、まるで辞書や配列のように扱えるオブジェクトを作ることができます。


__getitem__|値の取得に対応する

まずは「値を取り出す」動作から見ていきましょう。

class MyBox:
def __init__(self):
self.data = {"a": 1, "b": 2}

def __getitem__(self, key):
return self.data[key]

使い方はとってもシンプル:

box = MyBox()
print(box["a"]) # 出力:1

このとき、box["a"]と書くと、自動的にbox.__getitem__("a")が呼ばれます。


__setitem__|値の設定に対応する

続いて、値を代入するには__setitem__を使います。

class MyBox:
def __init__(self):
self.data = {}

def __getitem__(self, key):
return self.data[key]

def __setitem__(self, key, value):
self.data[key] = value

これで次のように書けます:

box = MyBox()
box["x"] = 100
print(box["x"]) # 出力:100

Pythonの辞書と同じような操作が、自作クラスで再現できていますね!


応用例:インデックスでアクセスする

キーだけでなく、数値インデックスで配列のようにアクセスすることも可能です。

class NumberList:
def __init__(self, values):
self.values = values

def __getitem__(self, index):
return self.values[index]

def __setitem__(self, index, value):
self.values[index] = value

使い方はこんな感じ:

nums = NumberList([10, 20, 30])
print(nums[1]) # 出力:20
nums[1] = 99
print(nums[1]) # 出力:99

このように、[]による直感的なアクセスが自作クラスでも使えるようになると、コードがグッと読みやすく、扱いやすくなります。


よく使われる場面

  • データ構造(リスト、スタック、辞書など)を自作するとき
  • 行列や座標などの数値データ操作
  • クラスの内部状態に簡単にアクセスしたいとき

PandasのDataFrameやNumPyのndarrayでも、この仕組みが使われています。

角括弧でのアクセスは、ユーザーにとって非常に「自然な操作」です。それを自作クラスにも取り入れることで、より“Pythonらしい”オブジェクト設計ができるようになります!




6. 表示や変換をカスタマイズ|__str__や__int__

Pythonでは、オブジェクトをprint()したり、str()int()などの関数で変換したりすることがありますよね。自作クラスでも、これらの動作を自由にカスタマイズできるんです。

それを実現するのが、次のような特殊メソッドたちです:

  • __str__print()str()で表示するときの文字列)
  • __repr__(開発者向けの表示。省略可)
  • __int__int()で整数に変換するとき)
  • __float__float()で小数に変換するとき)

__str__|printしたときの見た目を整える

まずは基本中の基本、__str__です。

class User:
def __init__(self, name, age):
self.name = name
self.age = age

def __str__(self):
return f"{self.name}({self.age}歳)"

使ってみましょう:

user = User("たろう", 30)
print(user) # 出力:たろう(30歳)

このように、print()で表示される文字列を自由に決められます。デバッグやログ出力でも役立ちますね!


__repr__との違いは?

__repr__は、**開発者向けの“再現可能な文字列”**を返すことが推奨されています。

def __repr__(self):
return f"User('{self.name}', {self.age})"

これは、print()では使われませんが、インタラクティブシェルなどでオブジェクトをそのまま表示したときに使われます。


__int__|int()で整数変換できるようにする

数値っぽいクラスには、int()float()の挙動を持たせることもできます。

class Price:
def __init__(self, yen):
self.yen = yen

def __int__(self):
return self.yen

こうすると:

p = Price(980)
print(int(p)) # 出力:980

つまり、自作クラスを数値としても使えるようになるということです。


__float__|float()での変換も可能

上と同じように、__float__を使えば小数への変換にも対応できます。

def __float__(self):
return float(self.yen)

これを定義すれば、float(obj)と書いたときにも好きな値を返せます。


表示や変換のカスタマイズは「親しみやすさ」に直結

自作クラスがあまりに“無機質”な表示だと、使う側にとってわかりづらくなってしまいます。でも、__str____int__などをしっかり定義しておけば、

  • printで見やすい
  • ログに出しても意味が通じる
  • 変換も簡単

といった具合に、クラスがぐっと「人にやさしい」設計になります。

これで、特殊メソッドを活用した主要なクラスカスタマイズ方法はひと通りカバーできました。




まとめ|特殊メソッドを知ると、自作クラスがもっと楽しくなる!

この記事では、Pythonの**特殊メソッド(マジックメソッド)**について、初心者でもわかりやすく解説してきました。

特殊メソッドは、__init____str__をはじめとする「アンダースコア2つ」で囲まれた特別な名前を持つメソッドで、Pythonが裏側で自動的に呼び出してくれる便利な仕組みです。


👇 この記事で紹介した特殊メソッドの使いどころをおさらい!

メソッド主な役割
__add__, __sub__+-などの演算子をカスタマイズ
__new__, __init__インスタンスの生成と初期化
__eq__, __lt__などオブジェクトの比較(==、<など)
__getitem__, __setitem__[]でのアクセスや代入を実現
__str__, __int__, __float__表示や型変換の振る舞いを定義

これらを活用すれば、自作クラスに「人間らしい使い方」を与えることができ、コードがもっと直感的で読みやすくなります。

はじめのうちは__str____eq__あたりから、少しずつ試していくのがおすすめです。
慣れてきたら、演算や[]の操作もカスタマイズして、あなただけの便利なクラス設計にチャレンジしてみてください!


あわせて読みたい

特殊メソッドを理解したら、Pythonのクラス設計やオブジェクト指向の基礎もあわせてチェックしておきましょう!


よくある質問(Q&A)

Q
特殊メソッドって、自分で直接呼び出してもいいの?
A

可能ではありますが、基本的にはPythonの構文(+==[]print()など)によって自動的に呼び出されるものです。直接obj.__add__(other)のように書くこともできますが、コードの可読性が下がるため、通常は演算子や関数を使ったほうが自然です。

Q
すべての特殊メソッドを実装しないといけないの?
A

いいえ、必要なものだけを実装すれば大丈夫です。たとえば、数値同士の加算をしたいだけなら__add__だけで十分ですし、表示を整えたいなら__str__だけ書けばOKです。

Q
__repr____str__はどう違うの?
A

__str__は主にユーザー向けの見やすい表示__repr__は**開発者向けの「再現性ある表示」**が目的です。__repr__だけを定義しておくと、__str__が定義されていないときの代用として使われます。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク