【Python入門】特殊メソッドをマスターする12のステップ

Pythonの特殊メソッドを解説する記事のサムネイルPython
この記事は約17分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

この記事を読めばPythonの特殊メソッドを使いこなせるようになります。

特殊メソッドはPythonの中核をなすもので、この記事を通してそれを理解し、より効率的で強力なコードを書くためのスキルを身につけましょう。

12のステップで一緒に学びましょう。

●特殊メソッドとは

特殊メソッドはPythonのクラス内で定義されるメソッドの一つで、その名の通り特殊な動作をします。

これらのメソッドは通常、ダブルアンダースコアで囲まれた名前(__name__)を持ち、特定のPython構文や操作に対応する振る舞いを定義します。

●特殊メソッドの種類

Pythonには多くの特殊メソッドが存在しますが、その中でも特によく使用されるいくつかをピックアップし、その役割と使い方を説明します。

○__init__メソッド

__init__メソッドはクラスのインスタンス化時に自動的に呼び出される特殊メソッドです。

このメソッドは主にインスタンスの初期設定を行うために使用され、インスタンス変数の初期化などを行います。

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

sample = SampleClass(10)
print(sample.value)  # 10

このコードではSampleClassというクラスを定義し、その__init__メソッドを使ってインスタンス変数valueを初期化しています。

この例では、SampleClassのインスタンスを作成する際に渡される引数が、インスタンス変数valueの初期値となります。

○__str__メソッド

__str__メソッドは、クラスのインスタンスをprint関数で出力する際やstr関数で文字列に変換する際に自動的に呼び出されます。

このメソッドを使うことで、クラスのインスタンスがどのように文字列として表現されるかを自分で定義することができます。

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

    def __str__(self):
        return f'SampleClass({self.value})'

sample = SampleClass(10)
print(sample)  # SampleClass(10)

このコードでは、__str__メソッドを使ってSampleClassのインスタンスを文字列化する方法を定義しています。

この例では、SampleClassのインスタンスがprint関数で出力されると、”SampleClass(value)”という形式の文字列が出力されます。

○__len__メソッド

__len__メソッドは、組み込みのlen関数がクラスのインスタンスに対して呼び出されたときに自動的に呼び出されます。

このメソッドを使うことで、クラスのインスタンスが「長さ」を持つかのように振る舞うことができます。

class SampleClass:
    def __init__(self, elements):
        self.elements = elements

    def __len__(self):
        return len(self.elements)

sample = SampleClass([1, 2, 3, 4, 5])
print(len(sample))  # 5

このコードでは、SampleClassというクラスを定義し、その__len__メソッドを使ってインスタンスが持つ”長さ”を定義しています。

この例では、SampleClassのインスタンスが持つelementsリストの長さが、そのインスタンスの”長さ”として認識されます。

○__del__メソッド

__del__メソッドは、Pythonのガベージコレクタ(メモリ上の不要なオブジェクトを自動的に削除するシステム)によってインスタンスが削除されるときに呼び出されます。

このメソッドは主に、インスタンスが不要になったときに必要なクリーンアップを行うために使用されます。

class SampleClass:
    def __del__(self):
        print("SampleClass instance has been deleted.")

sample = SampleClass()
del sample  # SampleClass instance has been deleted.

このコードではSampleClassというクラスを定義し、その__del__メソッドを使ってインスタンスが削除されたときの振る舞いを定義しています。

この例では、SampleClassのインスタンスが削除されると、”SampleClass instance has been deleted.”と表示されます。

○__getitem__メソッド

__getitem__メソッドは、クラスのインスタンスにブラケット記法(インスタンス[key])でアクセスされたときに自動的に呼び出されます。

このメソッドを使うことで、クラスのインスタンスがリストや辞書のように振る舞うことができます。

class SampleClass:
    def __init__(self, elements):
        self.elements = elements

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

sample = SampleClass([1, 2, 3, 4, 5])
print(sample[2])  # 3

このコードではSampleClassというクラスを定義し、その__getitem__メソッドを使ってインスタンスに対するブラケット記法のアクセスを定義しています。

この例では、SampleClassのインスタンスが持つelementsリストから特定の要素を取得することができます。

○__setitem__メソッド

__setitem__メソッドは、クラスのインスタンスにブラケット記法(インスタンス[key] = value)を使って値を設定したときに自動的に呼び出されます。

このメソッドを使うことで、クラスのインスタンスがリストや辞書のように振る舞うことができます。

class SampleClass:
    def __init__(self, elements):
        self.elements = elements

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

sample = SampleClass([1, 2, 3, 4, 5])
sample[2] = 10
print(sample.elements)  # [1, 2, 10, 4, 5]

このコードではSampleClassというクラスを定義し、その__setitem__メソッドを使ってインスタンスに対するブラケット記法による値の設定を定義しています。

この例では、SampleClassのインスタンスが持つelementsリストの特定の位置に値を設定することができます。

○__iter__メソッド

__iter__メソッドは、クラスのインスタンスに対してイテレーション(繰り返し処理)を開始するときに自動的に呼び出されます。

このメソッドを使うことで、クラスのインスタンスがイテレータとして振る舞うことができます。

class SampleClass:
    def __init__(self, elements):
        self.elements = elements
        self.index = 0

    def __iter__(self):
        return self

sample = SampleClass([1, 2, 3, 4, 5])
for element in sample:
    print(element)

このコードではSampleClassというクラスを定義し、その__iter__メソッドを使ってインスタンスに対するイテレーションを定義しています。

この例では、SampleClassのインスタンスが持つelementsリストの要素に対して繰り返し処理を行うことができます。

○__next__メソッド

__next__メソッドは、クラスのインスタンスがイテレータとして動作するときに、次の値を取得するために呼び出されます。

class SampleClass:
    def __init__(self, elements):
        self.elements = elements
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < len(self.elements):
            result = self.elements[self.index]
            self.index += 1
            return result
        else:
            raise StopIteration

sample = SampleClass([1, 2, 3, 4, 5])
for element in sample:
    print(element)  # 1 2 3 4 5

このコードではSampleClassというクラスを定義し、その__next__メソッドを使ってインスタンスに対するイテレーション中の次の値の取得を定義しています。

この例では、SampleClassのインスタンスが持つelementsリストの要素を一つずつ順番に取得しています。

○__eq__メソッド

__eq__メソッドは、クラスのインスタンスが等しさを比較するために’==’演算子を使うときに自動的に呼び出されます。

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

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

sample1 = SampleClass(5)
sample2 = SampleClass(5)
print(sample1 == sample2)  # True

このコードではSampleClassというクラスを定義し、その__eq__メソッドを使ってインスタンス間の等価性比較を定義しています。

この例では、SampleClassのインスタンス同士が等しいかどうかは、それぞれが保持するvalueの値が等しいかどうかで判断されます。

○__ne__メソッド

__ne__メソッドは、クラスのインスタンスが等しさを比較するために’!=’演算子を使うときに自動的に呼び出されます。

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

    def __ne__(self, other):
        if isinstance(other, SampleClass):
            return self.value != other.value
        return NotImplemented

sample1 = SampleClass(5)
sample2 = SampleClass(10)
print(sample1 != sample2)  # True

このコードではSampleClassというクラスを定義し、その__ne__メソッドを使ってインスタンス間の不等価性比較を定義しています。

この例では、SampleClassのインスタンス同士が等しくないかどうかは、それぞれが保持するvalueの値が等しくないかどうかで判断されます。

●特殊メソッドの応用例

これまでに紹介した特殊メソッドを使用することで、Pythonのクラスはリストや辞書のような組み込み型と同様の振る舞いをすることができます。

○サンプルコード1:カスタムリストクラスの作成

Pythonの特殊メソッドを利用すると、カスタムリストクラスを作成することができます。

下記のコードは、リストに新しい要素が追加されるたびに、その要素が整数かどうかをチェックするカスタムリストクラスを紹介しています。

class CustomList:
    def __init__(self):
        self.inner_list = []

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

    def __setitem__(self, index, value):
        if not isinstance(value, int):
            raise ValueError("このリストは整数値のみを受け入れます")
        self.inner_list[index] = value

    def append(self, value):
        self.__setitem__(len(self.inner_list), value)

このコードではCustomListというクラスを定義しており、内部に通常のリストを保持します。特殊メソッド__getitem__と__setitem__を定義することで、このカスタムリストは通常のリストと同じように、インデックスを使ってアクセスすることが可能です。さらに、__setitem__メソッド内で値が整数であることを確認しており、もし整数でない値が追加されようとするとエラーを出すようにしています。

下記のコードは、このカスタムリストの利用例を表しています。

my_list = CustomList()
my_list.append(1)  # 追加できる
print(my_list[0])  # 1が出力される
try:
    my_list.append('a')  # 追加できない(エラーが出る)
except ValueError as e:
    print(e)  # "このリストは整数値のみを受け入れます"と出力される

このコードでは、新しいCustomListを作成し、そのリストに整数値を追加しています。

そして、整数値を追加しようとしたときには、カスタムリストがエラーを返すことで、そのリストが整数値のみを受け入れることを保証しています。

○サンプルコード2:カスタム辞書クラスの作成

特殊メソッドを使って、Pythonで独自の辞書クラスを作成することも可能です。

下記のコードでは、カスタム辞書クラスを作成し、そのクラスが特定のキーを持つことを保証しています。

class CustomDict:
    def __init__(self):
        self.inner_dict = {}

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

    def __setitem__(self, key, value):
        if not isinstance(key, str):
            raise ValueError("この辞書は文字列キーのみを受け入れます")
        self.inner_dict[key] = value

このコードでは、CustomDictという新しいクラスを定義し、内部に通常の辞書を保持しています。特殊メソッド__getitem__と__setitem__を定義することで、このカスタム辞書は通常の辞書と同様にキーを使ってアクセスできます。

さらに、__setitem__メソッドでキーが文字列であることを確認しており、文字列でないキーが追加されようとするとエラーを出すようにしています。

下記のコードは、このカスタム辞書の使用例を表しています。

my_dict = CustomDict()
my_dict['key'] = 'value'  # 追加できる
print(my_dict['key'])  # 'value'が出力される
try:
    my_dict[1] = 'value'  # 追加できない(エラーが出る)
except ValueError as e:
    print(e)  # "この辞書は文字列キーのみを受け入れます"と出力される

このコードを実行すると、新しいCustomDictが作成され、その辞書に文字列キーと値を追加します。

その後、整数キーを追加しようとしたときには、カスタム辞書がエラーを返すことで、その辞書が文字列キーのみを受け入れることを保証します。

Pythonの特殊メソッドを活用すれば、このように自分だけのカスタムクラスを作ることができ、その振る舞いを自在にコントロールできます。

しかし、特殊メソッドを使うときには注意が必要な点がいくつかあります。次に、それらの注意点とその対処法について説明します。

●特殊メソッドの注意点と対処法

Pythonの特殊メソッドは強力で便利なツールですが、その使用には注意が必要です。

ここでは、その主な注意点と対処法について詳しく説明します。

①特殊メソッドの名称

Pythonの特殊メソッドはアンダースコア2つで始まり、アンダースコア2つで終わる名称が必要です。

このルールを破ると、メソッドが特殊メソッドとして機能しない可能性があります。

したがって、この命名規則を厳守することが重要です。

class Example:
    def not_a_special_method(self):
        pass

上記のコードは、特殊メソッドの命名規則を破っています。

このメソッドは特殊メソッドとしては機能せず、普通のメソッドとして扱われます。

②継承と特殊メソッド

特殊メソッドは通常、クラス階層の最上位で定義されます。

サブクラスでは、親クラスの特殊メソッドを上書きすることができます。

しかし、親クラスの特殊メソッドを直接呼び出す場合には注意が必要です。

class Parent:
    def __init__(self):
        print("Parent __init__")

class Child(Parent):
    def __init__(self):
        super().__init__()  # 親クラスの__init__を呼び出す
        print("Child __init__")

このコードでは、子クラスの__init__メソッドでsuper()関数を使って親クラスのinitメソッドを呼び出しています。

このように、特殊メソッドを上書きする際には、必要に応じて親クラスのメソッドを呼び出すことが重要です。

③特殊メソッドとオペレータオーバーロード

Pythonの特殊メソッドはオペレータオーバーロードにも使用されます。

この特性を利用すれば、クラスに独自の算術演算子や比較演算子の挙動を定義できます。

しかし、予想外の挙動を避けるためには、オペレータの本来の意味を尊重することが重要です。

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)

上記のコードは、Pointクラスに__add__メソッドを追加しています。

これにより、2つのPointオブジェクトを加算することが可能になります。

しかし、これは”+”演算子が普通に意味する”追加”と一致するため、予想外の挙動を引き起こさないでしょう。

まとめ

この記事では、Pythonの特殊メソッドについて詳細に探求しました。

特殊メソッドはPythonの中心的な部分であり、その理解はPythonプログラミングスキルを向上させるのに不可欠です。

まず、特殊メソッドの名前はアンダースコア2つで始まり、アンダースコア2つで終わる必要があることを確認しました。

これにより、特殊メソッドがPythonの内部機能として適切に動作することが保証されます。

次に、継承と特殊メソッドについて学びました。

子クラスでは親クラスの特殊メソッドを上書きできますが、親クラスの特殊メソッドを直接呼び出す際には注意が必要であることを覚えておいてください。

また、特殊メソッドとオペレータオーバーロードの間にある密接な関係を見てきました。Pythonでは、特殊メソッドを使用して独自の演算子の挙動を定義することが可能です。

しかし、これを行う際には、オペレータの本来の意味を尊重することが重要であることを忘れないでください。

以上が特殊メソッドの主要な注意点と対処法の概要です。

これらを心に留めて、特殊メソッドを活用すれば、Pythonプログラミングの経験がさらに豊かになるでしょう。

この知識を活用し、次回のプログラミングプロジェクトであなたのコードが新たな高みに達することを祈っています。