pythonでシングルトンを__new__使わず、かつ__init__呼び出しを防いで実現する方法

# シングルトンとは
複数のインスタンスを作ることを禁止したクラスのこと。
例えば「スケジュール帳」が2個も3個もあると、スケジュールを管理するのは返って大変になる。
このような場合に「スケジュール帳のクラスをシングルトンにする」ことで、「スケジュール帳は1個しかない！シンプル！」を実現できる。

# javaなどの言語で実現するシングルトン
1. コンストラクタを`private`化し、外から勝手に呼べなくする。
2. `static`な(つまりクラスの)`private`変数`myinstance`を`NULL`としておく
3. `get_instance`メソッドなどを作る。
 - 最初に呼ばれた場合、そのまま`private`なコンストラクタに引数を送りつけ、インスタンスを作って、これを`myinstance`に代入の上、`myinstance`を返却する
 - 2回目以降に呼ばれた場合、単に`myinstance`を返却する
 - 最初に呼ばれたのか、それとも2回目以降に呼ばれたのかは、`myinstance`が`NULL`かどうかにより判断できる

要は、コンストラクタを隠蔽することによって、初期化に関する主導権を外部から奪い、外部には「唯一のインスタンス」だけを渡す。

# pythonでのシングルトンは何故難しいか
しかし、pythonにおけるオブジェクト指向では、アクセス制御ができない。
`疑似private`なプロパティを作る方法は存在するが、コンストラクタ`__init__`では`疑似private`にすることは不可能。
故に、`__init__`より前に動く`__new__`をいじるなどするか、
あるいは「コンストラクタ、**呼べるけど呼んじゃダメ**だからね！」と、外部に大人の都合を押し付けることになる。
この場合、「子供」(大人の都合を押し付けるべきでない相手)に対してシングルトンを提供できない。
(オブジェクト指向のメリットの重要な一つは、「外部の利用者が内部仕様を知らなくてよい」ことであり、つまり「子供」でも利用出来ることだ。)

# `__new__`を使わずに頑張る方法
`__new__`を使えるプログラマは別に困らないかもしれないが、`__new__`を使えないプログラマにとって、シングルトンを作る方法が今のところない。`__new__`を使わずに、「`private`な`__init__`」を実現できればうれしい。

`private`な`__init__`が実現できてほしい理由は、「外部から呼ばれないような`__init__`が作りたい」からである。
であれば別に「外部の利用者が知らないような引数を受け取った時だけ動作する`__init__`」を作れば、それでいいじゃないか。

つまり

```python
class シングルトン:
    def __init__(self, *args, **kwargs):
        if "秘密のキーワード" in kwargs and kwargs["秘密のキーワード"] == "秘密の値":
            print("おぉ！秘密のキーワードと秘密の値を知っているってことは、"+
                  "今俺はシングルトンクラス内部から呼ばれたということだね！")
            print("だったら、外部に見られたくない処理を行えるね！")
        else:
            raise TypeError("ごめんね！シングルトンだから外部からの初期化はできないことになってるのよー")
```
とすれば、「`秘密のキーワード`と`秘密の値`を知らない外部にとっては`__init__`は無効になっていて、
かつ内部からは`__init__`が問題なく利用可能」という状況が実現する。
これはもう、「`private`な`__init__`」と同様な能力を持っているといってよさそうだ。

# 例

```python
モード = 0
# 0: もっとも新しいインスタンスを生かす場合
# 1: もっとも古いインスタンスを生かす場合
# それ以外のintオブジェクト: 別のインスタンスが作られそうな時TypeError

class Singleton:
    _instance = None

    @classmethod
    def get_instance(cls, *args, **kwargs):
        kwargs.update({"__singleton":"__singleton"})
        mode = モード
        # 0: もっとも新しいインスタンスを生かす場合
        # 1: もっとも古いインスタンスを生かす場合
        # それ以外のintオブジェクト: 別のインスタンスが作られそうな時TypeError

        if mode:
            if mode != 1 and cls._instance is not None: 
                raise TypeError("singleton継承型のオブジェクトを複数生成することはできません")
            cls._instance = cls._instance or cls(*args, **kwargs)
        else:
            cls._instance = ("dummy" if cls._instance.__init__(*args, **kwargs) else cls._instance) or cls(*args, **kwargs)
        
        return cls._instance

    @classmethod
    def assert_initialize(cls, *args, **kwargs):
        if "__singleton" in kwargs.keys() and kwargs["__singleton"] == "__singleton":
            del kwargs["__singleton"]
            return (args, kwargs)
        else:
            raise type("AccessException", (Exception,), {})("private化されたコンストラクタにアクセスしないでください")      

class MySingleton(Singleton):
    def __init__(self, *args, **kwargs):
        (args, kwargs) = type(self).assert_initialize(*args, **kwargs)
        self.args = args
        self.kwargs = kwargs

try:
    MySingleton()
except Exception as e:
    print("エラーメッセージ", e) # private化されたコンストラクタにアクセスしないでください

mysingleton1 = MySingleton.get_instance(1,2,3,abc="A")
mysingleton2 = MySingleton.get_instance(4,5,6,abc="B")

print("mysingleton1 == mysingleton2", mysingleton1 == mysingleton2)
print("mysingleton1", mysingleton1.args, mysingleton1.kwargs)
print("mysingleton2", mysingleton2.args, mysingleton2.kwargs)

```

`モード = 0`とした場合、
次の結果を得る

```
エラーメッセージ private化されたコンストラクタにアクセスしないでください
mysingleton1 == mysingleton2 True
mysingleton1 (4, 5, 6) {'abc': 'B'}
mysingleton2 (4, 5, 6) {'abc': 'B'}
```

`モード = 1`とした場合、
次の結果を得る

```
エラーメッセージ private化されたコンストラクタにアクセスしないでください
mysingleton1 == mysingleton2 True
mysingleton1 (1, 2, 3) {'abc': 'A'}
mysingleton2 (1, 2, 3) {'abc': 'A'}
```

`モード = 2`とした場合、
次の結果を得る

```
エラーメッセージ private化されたコンストラクタにアクセスしないでください
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-50-02ff95b76478> in <module>()
     44 
     45 mysingleton1 = MySingleton.get_instance(1,2,3,abc="A")
---> 46 mysingleton2 = MySingleton.get_instance(4,5,6,abc="B")
     47 
     48 print("mysingleton1 == mysingleton2", mysingleton1 == mysingleton2)

<ipython-input-50-02ff95b76478> in get_instance(cls, *args, **kwargs)
     17         if mode:
     18             if mode != 1 and cls._instance is not None:
---> 19                 raise TypeError("singleton継承型のオブジェクトを複数生成することはできません")
     20             cls._instance = cls._instance or cls(*args, **kwargs)
     21         else:

TypeError: singleton継承型のオブジェクトを複数生成することはできません
```

# 参考
https://www.techscore.com/tech/DesignPattern/Singleton.html/