Singletonパターンの罠


Singletonでハマりました。


Singletonを書いたモジュールを、メインスクリプトとして実行したことが問題です。

#encoding:shift-jis
"""
singleton.py

Singltonを定義したモジュール
> python singleton.py
とすると、ハマる
"""
from __future__ import division, with_statement, print_function
__metaclass__ = type #全てのclassを新スタイルにする

class Singleton:
    #型どおりのSingleton
    _instance = None
    def __new__(cls):
        if cls._instance is None:
            cls._instance = object.__new__(cls)
        return cls._instance
    
    def __init__(self):
        self._value = None
    
    def set_value(self, v):
        self._value = v
    
    def print_value(self):
        print(self._value)
    
def main():
    import singleton
    import sub
    sub.set_value_egg() #value を "egg"に設定
    
    Singleton().print_value()
    # => None
    # 設定した値と違う!?
    
    print(Singleton())      # => <__main__.Singleton object at 0xXXXXXXXX>
    print(singleton.Singleton())  # => <singleton.Singleton object at 0xXXXXXXXX>
    print(sub.Singleton())  # => <singleton.Singleton object at 0xXXXXXXXX>
    
if __name__ == "__main__":
    main()
#encoding:shift-jis
"""
sub.py

Singletonを呼び出して何かするモジュール
"""
from __future__ import division, with_statement, print_function

from singleton import Singleton
def set_value_egg():
    Singleton().set_value("egg")

> python singleton.py

または

> python -m singleton

で、コメントにあるように、set_value_eggで値をセットしたのに、print_valueではもとの値のままです。


これは、メインスクリプト用の__main__という独立したモジュールが生成される事が原因です。


singleton.pyにあるように、メインスクリプトとモジュールとで、変数Singletonの値が違っています。


これを回避するには、

def main():
    from singleton import Singleton
    import sub
    sub.set_value_egg() #value を "egg"に設定
    
    Singleton().print_value()
    # => egg
if __name__ == "__main__":
    main()

と、メインスクリプトに定義されているクラスでも、importするようにします。