この記事では、Pythonの特殊メソッド(マジックメソッド、ダンダーメソッドとも呼ばれる)について解説します。特殊メソッドは、クラスの挙動をカスタマイズするための強力な機能であり、適切に活用することでコードの可読性や表現力を向上させることができます。
特殊メソッドとは
特殊メソッドは、メソッド名の前後に2つのアンダースコア (__
) が付いたメソッドです。これらのメソッドは、特定の演算子や組み込み関数がオブジェクトに対して適用された際に、暗黙的に呼び出されます。例えば、+
演算子は __add__
メソッドを、len()
関数は __len__
メソッドを呼び出します。また、特殊メソッドをオーバーライド(再定義)することで、クラスのインスタンスに対する演算や操作をカスタマイズできます。
主要な特殊メソッド
以下に、主要な特殊メソッドとその役割、使用例を示します。
1. オブジェクトの生成と初期化 (__new__
, __init__
)
__new__(cls, *args, **kwargs)
: オブジェクトの生成を担当します。通常はobject.__new__(cls)
を呼び出してオブジェクトを生成し、そのオブジェクトを返します。__init__(self, *args, **kwargs)
: オブジェクトの初期化を担当します。__new__
で生成されたオブジェクトを受け取り、属性の初期化などを行います。
class Person: def __new__(cls, name, age): print("__new__が呼ばれました") instance = super().__new__(cls) # object.__new__(cls) と同じ return instance def __init__(self, name, age): print("__init__が呼ばれました") self.name = name self.age = age person = Person("太郎", 20) print(person.name) # 出力: 太郎 print(person.age) # 出力: 20
2. 文字列表現 (__str__
, __repr__
)
__str__(self)
:str()
関数やprint()
関数で呼び出され、オブジェクトの人間にとって読みやすい文字列表現を返します。__repr__(self)
:repr()
関数で呼び出され、オブジェクトの公式な文字列表現を返します。デバッグ時などに有用です。__str__
が定義されていない場合は、__repr__
が代わりに使われます。
class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return f"({self.x}, {self.y})" def __repr__(self): return f"Point({self.x}, {self.y})" point = Point(1, 2) print(str(point)) # 出力: (1, 2) print(repr(point)) # 出力: Point(1, 2)
3. 算術演算 (__add__
, __sub__
, __mul__
, __truediv__
など)
これらのメソッドをオーバーライドすることで、オブジェクト間の算術演算を定義できます。
class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) else: raise TypeError("Vector同士の足し算のみ可能です。") def __str__(self): return f"({self.x}, {self.y})" v1 = Vector(1, 2) v2 = Vector(3, 4) v3 = v1 + v2 print(v3) # 出力: (4, 6)
4. 比較演算 (__eq__
, __ne__
, __lt__
, __gt__
など)
オブジェクト間の比較を定義します。
class Fraction: # 分数クラス def __init__(self, numerator, denominator): self.numerator = numerator self.denominator = denominator def __eq__(self, other): if isinstance(other, Fraction): return self.numerator * other.denominator == self.denominator * other.numerator return False f1 = Fraction(1, 2) f2 = Fraction(2, 4) print(f1 == f2) # 出力: True
5. コンテナ型のエミュレート (__len__
, __getitem__
, __setitem__
, __delitem__
など)
これらのメソッドを実装することで、クラスのインスタンスをリストや辞書のように扱うことができます。
class MyList: def __init__(self, data): self.data = data def __len__(self): return len(self.data) def __getitem__(self, index): return self.data[index] my_list = MyList([1, 2, 3]) print(len(my_list)) # 出力: 3 print(my_list[1]) # 出力: 2
6. callableオブジェクト (__call__
)
このメソッドを実装することで、オブジェクトを関数のように呼び出すことができます。
class Greeter: def __init__(self, greeting): self.greeting = greeting def __call__(self, name): return f"{self.greeting}, {name}!" greet = Greeter("Hello") print(greet("World")) # 出力: Hello, World!
特殊メソッドのオーバライド
Pythonの特殊メソッドをオーバーライドすることで、クラスの振る舞いをカスタマイズできます。ここでは、具体的なユースケースをコード例とともに紹介します。
1. オブジェクトの初期化 (init)
オブジェクトの生成時に自動的に呼び出される__init__
メソッドをオーバーライドすることで、インスタンス変数の初期化などをカスタマイズできます。
class Dog: def __init__(self, name, breed): self.name = name self.breed = breed self.tricks = [] def add_trick(self, trick): self.tricks.append(trick) my_dog = Dog("ポチ", "柴犬") print(my_dog.name) # 出力: ポチ print(my_dog.breed) # 出力: 柴犬 my_dog.add_trick("お手") print(my_dog.tricks) # 出力: ['お手']
2. 文字列表現 (str, repr)
__str__
はstr()
関数やprint()
関数でオブジェクトを文字列に変換する際に、__repr__
はrepr()
関数でオブジェクトの「公式の」文字列表現を取得する際に呼び出されます。
class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return f"({self.x}, {self.y})" def __repr__(self): return f"Point({self.x}, {self.y})" p = Point(3, 4) print(str(p)) # 出力: (3, 4) print(repr(p)) # 出力: Point(3, 4)
3. 比較演算子 (eq, ne, lt, gt, le, ge)
これらの特殊メソッドをオーバーライドすることで、オブジェクト同士の比較方法を定義できます。
class Fraction: def __init__(self, numerator, denominator): self.numerator = numerator self.denominator = denominator def __eq__(self, other): if isinstance(other, Fraction): return self.numerator * other.denominator == self.denominator * other.numerator return False f1 = Fraction(1, 2) f2 = Fraction(2, 4) print(f1 == f2) # 出力: True
4. 数値演算子 (add, sub, mul, truediv など)
これらの特殊メソッドをオーバーライドすることで、オブジェクトに対する算術演算を定義できます。
class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) raise TypeError("Vector同士の加算のみ可能です。") v1 = Vector(1, 2) v2 = Vector(3, 4) v3 = v1 + v2 print(v3.x, v3.y) # 出力: 4 6
5. コンテナ型としての振る舞い (len, getitem, setitem, delitem, iter)
これらの特殊メソッドをオーバーライドすることで、オブジェクトをリストや辞書のように扱うことができます。
class WordList: def __init__(self, words): self.words = words def __getitem__(self, index): return self.words[index] def __len__(self): return len(self.words) def __iter__(self): return iter(self.words) word_list = WordList(["apple", "banana", "cherry"]) print(word_list[0]) # 出力: apple print(len(word_list)) # 出力: 3 for word in word_list: print(word) # 出力: # apple # banana # cherry
6. 関数呼び出し (call)
__call__
をオーバーライドすることで、オブジェクトを関数のように呼び出すことができます。
class Greeter: def __init__(self, greeting): self.greeting = greeting def __call__(self, name): return f"{self.greeting}, {name}!" greet = Greeter("Hello") print(greet("World")) # 出力: Hello, World!
まとめ
この記事で紹介した特殊メソッドは一部であり、他にも様々な特殊メソッドが存在します。これらを適切にオーバーライドすることで、Pythonのオブジェクト指向プログラミングをより柔軟に、そして表現力豊かに記述することができます。重要なのは、これらの特殊メソッドはPythonによって暗黙的に呼び出されるという点です。そのため、これらのメソッドを適切に実装することで、自然な構文でオブジェクトを操作できるようになります。