Python でシングルトンを作る

Java だったら、private コンストラクタにした final クラスで synchronized の static メソッドでインスタンス取得する
お決まりの実装だけど、Python はいくつか方法がある。

getInstance() というメソッドでインスタンス取得させる方法

# -*- coding: utf-8 -*-
class MyClass:
    _instance = None
    @staticmethod
    def getInstance():
        if MyClass._instance == None:
            MyClass()
        return MyClass._instance
    def __init__(self):
        if MyClass._instance != None:
            raise Exception("This is not Singleton !!")
        else:
            MyClass._instance = self

    def setParam(self, p):
        self.p = p
        pass
    def getParam(self):
        return self.p

インスタンス取得、a も b も同じ

a = MyClass.getInstance()
b = MyClass.getInstance()

これなら、 MyClass() と実行しても、Exception("This is not Singleton !!") になる。

Python の通常のインスタンス生成でも、シングルトンにする方法
つまり、MyClass() で生成するインスタンスがシングルトンになり、
一見シングルトンなのかどうか判りづらい方法

class MyClass():
    p = None
    def __new__(self, *args, **kargs):
        if not hasattr(self, "_instance"):
            self._instance = super().__new__(self)
        return self._instance
    def setParam(self, p):
        self.p = p
        pass
    def getParam(self):
        return self.p
a = MyClass()
b = MyClass()

継承で書く!
singleton.py

class Singleton():
    _instance = None
    def __new__(self, *args, **kargs):
        if self._instance == None:
            self._instance = super(Singleton, self).__new__(self)
        return self._instance
from singleton import Singleton
class MyClass(Singleton):
    p = None
    def setParam(self, p):
        self.p = p
        pass
    def getParam(self):
        return self.p

デコレーターで書く!
utility.py

def singleton(cls):
    instances = {}
    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return getinstance

@singleton をクラス宣言に書く

from utility import singleton

@singleton
class MyClass():
    p = None
    def setParam(self, p):
        self.p = p
        pass
    def getParam(self):
        return self.p

Java に慣れしたんだ者にとって、専用インスタンスメソッド getInstance() が馴染むけど、
Pythonは、コンストラクタの引数を拡張できる方が良いのかな。