さるへい備忘録

さるへいのやったことを綴っているブログです。基本的にテクノロジーの話題です。

Pythonで学ぶデザインパターン入門 Singletonパターン

結城先生の Java言語で学ぶデザインパターン入門 のコードを Python に書き直していくシリーズ第5段です。

Singletonパターンとは

定義した範囲内で、そのものが1つしか存在しないことを保証するパターンです。

よくある例でいうと、実行環境内でインスタンス1個以上作られないことを保証するといったことをよくやります。
具体的には、クラスAのインスタンスAを作った後に、もう一度クラスAからインスタンスを生成したらインスタンスAがそのまま返されるという形のものです。
普通なら、別のインスタンスが返りますが、シングルトンパターンの場合は絶対にそのインスタンスを1個以上存在させることはしません。

ソースコード

コードの概要

パターン説明の際に紹介した具体例を実装します。
常にインスタンスが1個しか作られないことを保証するといった動作のものです。

こういった仕組みは言語特有の機能を利用するものが多く、 Java言語で学ぶデザインパターン入門Java特有の機能を利用したものでした。
なので今回に関しては本のコードを写経するわけではなく、 Python 特有のシングルトンパターンの実装を紹介します。

ソースコード

Singleton クラス

# coding: utf-8
import threading


class Singleton(object):

    _instance = None
    _lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)

        return cls._instance

    def __init__(self):
        print('initメソッドは毎回呼ばれるので注意')

Pythonでいうコンストラクタは __init__ ですが、インスタンス生成時に __new__ というメソッドが呼び出されます。
今回はそれを上書きして、クラス変数を利用して必ず1個しかインスタンスを保持しないような形にしました。
cls._instance がない場合だけ、スーパークラスにもともと存在しているインスタンス生成メソッドを呼び出す形です。
しかし、もともとのコンストラクタの __init__ は毎回呼び出されてしまうことに注意してください。

_lock = threading.Lock() は、マルチスレッドを考慮した制限になります。

実行ファイル

# coding: utf-8
from Singleton.singleton import Singleton

if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()

    if s1 is s2:
        print('Singleton')
    else:
        print('Not Singleton')

Singleton と表示されたらOKですね。
シングルトンパターンじゃなかったら別のインスタンスになるので Not Singleton と表示されてしまいます。

実際どう便利か

このパターンはいろいろなところで利用することが想定されるパターンです。
たとえば、お金の計算処理などは同じデータに2回も処理が入ってはいけません。
そのようなケースは実際には多々に存在します。
むしろインスタンスを1個だけに限定するパターンは紹介には使われますが実際にはそこまで利用されることはないかもしれませんね。