私はPythonで次のようにシングルトンを定義することを提案されました:
class Controller:
pass
# ...
controller = Controller()
ただし、この方法では、controller
を派生クラスで置き換えることはできません。
Python Djangoでシングルトンを定義する他の賢明な方法は何ですか?
多分、再利用可能なアプリを定義するとき、シングルトンインスタンスをアプリで定義するのではなく、それを使用するプログラムで定義する必要がありますか?これを行う利点と欠点は何ですか?
Pythonでのシングルトンの使用
シングルトンは、意味的にメモリに1つだけ存在するオブジェクトです。
None
は、頻繁に使用されるシングルトンです。 NotImplemented
はもう1つ、使用頻度は非常に低いです。シングルトンIDをテストできます。
>>> maybe_None = None
その後
maybe_None is None
True
を返します。
オブジェクトインスタンスを使用して、モジュールのグローバル名前空間に機能を必要としないインスタンスを作成できます(グローバル定数なのですべて大文字)。
SINGLETON = object()
グローバル名前空間のオブジェクトを上書きしないように注意してください。良い名前を付けると、誰かが何か悪いことをしているときにそれが明白になります。
これは、あなたが与えた例に似ています。ただし、オブジェクトの作成に負荷がかかる場合は、私がやっていることはしません。オブジェクトを使用したくない場合でも、モジュールのインポートに負荷がかかるようになります。
インポート時にシングルトンを作成したくない場合は、いつでもモジュールを安価にインポートする必要があります。
たとえば、ドキュメントを動的に生成するときに、モジュールを安価にインポートしたいとします。
安価なインポートを好むもう1つのケースは、単体テストの実行です。
また、使用するメソッドは継承をサポートしていません。
これを回避する方法をいくつか紹介します。
クラスのインスタンスを1つだけ持つ場合は、さまざまな方法でこれを行うことができます。
__new__
をカスタマイズし、クラス属性instance
を使用しますclass Controller(object):
instance = None
def __new__(cls):
if cls.instance is not None:
return cls.instance
else:
inst = cls.instance = super(Controller, cls).__new__()
return inst
また、これは継承をサポートすることに注意してください。
関数をメモする関数属性を作成できます
def get_controller():
if hasattr(get_controller, 'instance'):
return get_controller.instance
else:
inst = get_controller.instance = Controller()
return inst
モジュールまたはクラスの名前空間を使用してインスタンスを保持することもできます。これは、関数とモジュールの両方がシングルトンである必要があるためです。
または、lru_cacheを使用して(get_controllerは引数を取らないため)、それをメモします。
from functools import lru_cache
@lru_cache
def get_controller():
return Controller()
get_controller
に引数を追加した場合、 lru_cache は、引数の一意の組み合わせごとにシングルトンを返します(キャッシュサイズまで(理論的には))。その後、インスタンスは無視されるため、注意してください。引数を追加する場合はこれで-関数属性の例で行ったように、おそらく独自の動作を実装する方が良いでしょう。
これは、たとえば、継承をサポートできます。
@lru_cache
def get_controller(controller_type):
if issubclass(controller_type, Controller):
return controller_type()
else:
raise TypeError('must supply a Controller type')