この質問は、 シングルトンデザインパターン が望ましいかどうか、反パターンか、あるいはあらゆる宗教戦争のための議論ではなく、このパターンがどのようにしてPythonに実装されるのかを議論するためのものですそれが最もPythonicな方法です。この場合、私は「ほとんどのピートニック」を「最小の驚きの原則」 に従うことを意味すると定義します。
シングルトンになるクラスが複数あります(私のユースケースはロガーのためのものですが、これは重要ではありません)。私が単純に継承または装飾することができるときに私は追加されたガムフでいくつかのクラスを雑然とさせたくありません。
最良の方法
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
長所
短所
m = MyClass(); n = MyClass(); o = type(n)();
そしてm == n && m != o && n != o
についてもclass Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, BaseClass):
pass
長所
短所
__new__
は、2番目の基本クラスからの継承中に上書きされる可能性がありますか?必要以上のことを考えなければなりません。class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
#Python2
class MyClass(BaseClass):
__metaclass__ = Singleton
#Python3
class MyClass(BaseClass, metaclass=Singleton):
pass
長所
__metaclass__
をその適切な目的のために使用します(そしてそれを私に知らせました)短所
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class_, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w,
class_).__new__(class_,
*args,
**kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__= class_.__name__
return class_w
@singleton
class MyClass(BaseClass):
pass
長所
短所
_sealed
属性のポイントは何ですかsuper()
を使用して基本クラスで同じ名前のメソッドを呼び出すことはできません。つまり、__new__
をカスタマイズできず、__init__
を呼び出す必要があるクラスをサブクラス化することはできません。class Foo(object):
pass
some_global_variable = Foo()
モジュールは一度だけインポートされ、他のものはすべてひっくり返ります。シングルトンを使用せず、グローバルを使用しないようにしてください。
モジュールを使用してください。一度だけインポートされます。その中にいくつかのグローバル変数を定義します - それらはシングルトンの '属性'になります。いくつかの機能を追加します - シングルトンの「メソッド」です。
あなたはおそらくPythonのシングルトンを必要としないでしょう。すべてのデータと関数をモジュールに定義するだけで、事実上のシングルトンができます。
あなたが本当に絶対にシングルトンクラスを持っている必要があるならば、私は一緒に行きます:
class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
使用するには:
from mysingleton import my_singleton
my_singleton.foo()
mysingleton.pyはMy_Singletonが定義されているファイル名です。これは、ファイルが初めてインポートされた後、Pythonがコードを再実行しないために機能します。
これがあなたのためのワンライナーです:
singleton = lambda c: c()
使い方は次のとおりです。
@singleton
class wat(object):
def __init__(self): self.x = 1
def get_x(self): return self.x
assert wat.get_x() == 1
あなたのオブジェクトは熱心にインスタンス化されます。これはあなたが望むものかもしれません。
Stack Overflowに関する質問をチェックしてください。Pythonでシングルトンを定義するための簡単で洗練された方法はありますか。いくつかの解決策があります。
私は、Alex Martelliによるpythonのデザインパターンに関する講演を見ることを強くお勧めします: part 1 および part 2 。特に、第1回で、彼はシングルトン/共有状態オブジェクトについて話しました。
これが私自身のシングルトンの実装です。あなたがしなければならないのはクラスを飾ることだけです。シングルトンを取得するには、Instance
メソッドを使用する必要があります。これが例です:
@Singleton
class Foo:
def __init__(self):
print 'Foo created'
f = Foo() # Error, this isn't how you get the instance of a singleton
f = Foo.Instance() # Good. Being explicit is in line with the Python Zen
g = Foo.Instance() # Returns already created instance
print f is g # True
そしてこれがそのコードです。
class Singleton:
"""
A non-thread-safe helper class to ease implementing singletons.
This should be used as a decorator -- not a metaclass -- to the
class that should be a singleton.
The decorated class can define one `__init__` function that
takes only the `self` argument. Other than that, there are
no restrictions that apply to the decorated class.
To get the singleton instance, use the `Instance` method. Trying
to use `__call__` will result in a `TypeError` being raised.
Limitations: The decorated class cannot be inherited from.
"""
def __init__(self, decorated):
self._decorated = decorated
def Instance(self):
"""
Returns the singleton instance. Upon its first call, it creates a
new instance of the decorated class and calls its `__init__` method.
On all subsequent calls, the already created instance is returned.
"""
try:
return self._instance
except AttributeError:
self._instance = self._decorated()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through `Instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
方法3はとてもすっきりしているように見えますが、あなたのプログラムを Python 2 と Python 3 の両方で実行したいのであれば、うまくいきません。 Python 3バージョンではPython 2の構文エラーが発生するため、Pythonバージョンのテストで個別のバリアントを保護することもできません。
Mike Watkinsに感謝: http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ 。プログラムをPython 2とPython 3の両方で動作させたい場合は、次のようにする必要があります。
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
MC = Singleton('MC', (object), {})
class MyClass(MC):
pass # Code for the class implementation
代入の 'object'は 'BaseClass'に置き換える必要があると思いますが、試したことはありません(図のようにコードを試しました)。
これはどう:
def singleton(cls):
instance=cls()
cls.__new__ = cls.__call__= lambda cls: instance
cls.__init__ = lambda self: None
return instance
シングルトンであるべきクラスのデコレータとしてそれを使用してください。このような:
@singleton
class MySingleton:
#....
これは別の答えではsingleton = lambda c: c()
デコレータに似ています。他の解決策と同様に、唯一のインスタンスはクラスの名前(MySingleton
)を持ちます。ただし、この解決策では、MySingleton()
を実行することで、クラスからインスタンスを「作成」(実際には唯一のインスタンスを取得)できます。また、type(MySingleton)()
(同じインスタンスを返す)を実行して追加のインスタンスを作成することもできません。
前の答えは正しいですが、私は方法1の質問の一部として投稿された「MyClass自体はクラスではなく関数であるため、クラスメソッドを呼び出すことはできません」というステートメントに同意しません。下記の私の例を見てください。そのメソッドは、singletonタグで装飾されたMyClassで複数回呼び出されています。
また、これは投稿されたいくつかの回答と非常によく似ており、 python document に基づいていますが、クラスと関数は1または0の引数を受け取り、シングルトンでも動作するように設計されているため、少し異なります。
これは、シングルトンのメソッドを複数回呼び出すことができ、クラスの1つのインスタンスがまだ使用されており、新しいオブジェクトが作成されていないことを示しています。
#/usr/bin/env python
def singleton(cls):
instances = {}
def getinstance(anyArgs=None):
if cls not in instances:
instances[cls] = cls(anyArgs)
return instances[cls]
return getinstance
@singleton
class MyClass:
def __init__(self,count=None):
print("print argument if any exists",count)
def test(self, counter):
# time.sleep(1000)
print("-->",counter)
return counter
### create two objects to see if we get a singleton behavior !
a = MyClass(10000)
a.test(1)
b = MyClass()
b.test(2)
if a != b:
print("this is not a singleton")
#lets makesure it's still is the same object
if a!=b:
print("error")
Theheadofabroom(質問を投稿した人)が彼の最初の質問についていくつかのフィードバックを与えてから、私は彼のフィードバックに基づいて新しい解決策に取り組みました(私は以前の答えを続けました。 heheadofabroomが求めているのは100%正確ではありません。これが更新された答えです。
コピーして貼り付けるためのコードは次のとおりです。
#/usr/bin/env python
from functools import wraps
def singleton(cls):
instances = {}
def getinstance(anyArgs=None):
if cls not in instances:
instances[cls] = cls(anyArgs)
return instances[cls]
return getinstance
def add_function(cls):
def outer_decorate_it(somefunction):
@wraps(somefunction)
def wrapper( *args, **kwargs):
return somefunction(*args, **kwargs)
setattr(cls, somefunction.__name__, wrapper)
return somefunction
return outer_decorate_it
@singleton
class MyClass():
def __init__(self,count=None):
print("print argument if any exists",count)
@add_function(MyClass)
def testit():
print("It's me the function from the class")
MyClass.testit()
さて、モジュールレベルのグローバルを持つことについての一般的なPythonicの提案に同意する以外に、これはどうですか?
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class2, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w, class2).__new__(class2, *args, **kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__= class_.__name__
return class_w
@singleton
class MyClass(object):
def __init__(self, text):
print text
@classmethod
def name(class_):
print class_.__name__
x = MyClass(111)
x.name()
y = MyClass(222)
print id(x) == id(y)
出力は以下のとおりです。
111 # the __init__ is called only on the 1st time
MyClass # the __is preserved
True # this is actually the same instance
Tolli's answer に基づくコード。
#decorator, modyfies new_cls
def _singleton(new_cls):
instance = new_cls() #2
def new(cls):
if isinstance(instance, cls): #4
return instance
else:
raise TypeError("I can only return instance of {}, caller wanted {}".format(new_cls, cls))
new_cls.__new__ = new #3
new_cls.__init__ = lambda self: None #5
return new_cls
#decorator, creates new class
def singleton(cls):
new_cls = type('singleton({})'.format(cls.__name__), (cls,), {} ) #1
return _singleton(new_cls)
#metaclass
def meta_singleton(name, bases, attrs):
new_cls = type(name, bases, attrs) #1
return _singleton(new_cls)
説明:
与えられたcls
から継承して、新しいクラスを作成します
(誰かがsingleton(list)
などを望んでいる場合には、cls
は変更されません)
インスタンスを作成します。 __new__
をオーバーライドする前は、とても簡単です。
__new__
をオーバーライドします。この関数は、呼び出し元が期待しているものだけがinstance
を返し、そうでなければTypeError
を送出します。
誰かが装飾されたクラスから継承しようとしたときに条件が満たされません。
__new__()
がcls
のインスタンスを返す場合、新しいインスタンスの__init__()
メソッドが呼び出されます _は、__init__(self[, ...])
のように、selfは新しいインスタンスで、残りの引数は__new__()
に渡されたものと同じです。
instance
はすでに初期化されているので、functionは__init__
を何もしないfunctionに置き換えます。
それはfabによる答えに少し似ていますが、まったく同じではありません。
シングルトン規約 は、コンストラクタを複数回呼び出すことができることを要求しません。シングルトンは一度だけ作成されるべきなので、それは一度だけ作成されるように見られるべきではありませんか?コンストラクタを「なりすまし」すると、読みやすさが損なわれることは間違いありません。
だから私の提案はちょうどこれです:
class Elvis():
def __init__(self):
if hasattr(self.__class__, 'instance'):
raise Exception()
self.__class__.instance = self
# initialisation code...
@staticmethod
def the():
if hasattr(Elvis, 'instance'):
return Elvis.instance
return Elvis()
これは、ユーザーコードによるコンストラクターやフィールドinstance
の使用を除外するものではありません。
if Elvis() is King.instance:
... Elvis
がまだ作成されていないこと、そしてKing
が作成されていることを確実に知っていれば。
しかし は usersがthe
メソッドを普遍的に使うことを推奨します。
Elvis.the().leave(Building.the())
これを完全にするために、instance
を削除しようとした場合は__delattr__()
をオーバーライドしてExceptionを発生させ、__del__()
をオーバーライドしてExceptionを発生させることもできます(プログラムが終了していることがわからない限り)。
コメントや編集を手伝ってくれた方々、どうもありがとうございました。私はJythonを使用していますが、これはより一般的に機能し、スレッドセーフであるはずです。
try:
# This is jython-specific
from synchronize import make_synchronized
except ImportError:
# This should work across different python implementations
def make_synchronized(func):
import threading
func.__lock__ = threading.Lock()
def synced_func(*args, **kws):
with func.__lock__:
return func(*args, **kws)
return synced_func
class Elvis(object): # NB must be subclass of object to use __new__
instance = None
@classmethod
@make_synchronized
def __new__(cls, *args, **kwargs):
if cls.instance is not None:
raise Exception()
cls.instance = object.__new__(cls, *args, **kwargs)
return cls.instance
def __init__(self):
pass
# initialisation code...
@classmethod
@make_synchronized
def the(cls):
if cls.instance is not None:
return cls.instance
return cls()
注意点:
__new__
を使わない古いスタイルのクラスを得るでしょう__new__
を装飾するときは@classmethodで装飾する必要があります。そうしないと__new__
がアンバインドされたインスタンスメソッドになります。the
をクラスレベルのプロパティにすることを可能にし、おそらくそれをinstance
にリネームすることを可能にするので、これはおそらくメタクラスの使用によって改善することができます。一つのライナー(私は誇りに思っていませんが、それは仕事をします):
class Myclass:
def __init__(self):
# do your stuff
globals()[type(self).__name__] = lambda: self # singletonify
Singletonのインスタンスを遅延初期化する必要がない場合は、次の手順が簡単でスレッドセーフです。
class A:
instance = None
# Methods and variables of the class/object A follow
A.instance = A()
このようにA
はモジュールのインポート時に初期化されるシングルトンです。
私は私のリングに投げます。シンプルなデコレーターです。
from abc import ABC
def singleton(real_cls):
class SingletonFactory(ABC):
instance = None
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = real_cls(*args, **kwargs)
return cls.instance
SingletonFactory.register(real_cls)
return SingletonFactory
# Usage
@singleton
class YourClass:
... # Your normal implementation, no special requirements.
利点私はそれが他の解決策のいくつかに対して持っていると思います:
YourClass
の実装について一つだけ変更する必要はありません。これには、あなたのクラスにメタクラスを使用する必要がないことも含まれます(上記のメタクラスはファクトリ上にあり、「実際の」クラスにはありません)。YourClass
を単純にインポートします。それはクラスのように見え(それがそうであるため)、そして彼らは通常それを使います。発信者をファクトリ機能に適応させる必要はありません。YourClass()
がインスタンス化するものは、まだあなたが実装したYourClass
の本当のインスタンスであり、いかなる種類のプロキシでもないので、その結果生じる副作用の可能性はありません。isinstance(instance, YourClass)
と同様の操作はまだ期待通りに動作します(ただしこのビットにはabcが必要なのでPython <2.6は使えません)。1つ欠点があります。実際のクラスのクラスメソッドと静的メソッドは、それを隠しているファクトリクラスを介して透過的に呼び出すことはできません。このようなニーズに遭遇することは決してないので、これを使用することはめったにありませんでしたが、__getattr__()
を実装するファクトリ上のカスタムメタクラスを使用して本当のクラスにall-ish属性アクセスを委任することで簡単に修正できます。
私が実際にもっと便利だと思った(この種のことがとても頻繁に必要とされているわけではない)関連パターンは、 同じ引数でクラスをインスタンス化する という結果になる "Unique"パターンです。同じインスタンスを取り戻します。すなわち「引数ごとのシングルトン」上記はこれによく適応し、さらに簡潔になります。
def unique(real_cls):
class UniqueFactory(ABC):
@functools.lru_cache(None) # Handy for 3.2+, but use any memoization decorator you like
def __new__(cls, *args, **kwargs):
return real_cls(*args, **kwargs)
UniqueFactory.register(real_cls)
return UniqueFactory
とは言っても、私はあなたがこれらのことのうちの1つが必要であると思うなら、あなたは本当にしばらくの間停止して、あなたが本当にそうであるかどうかあなた自身に尋ねるべきだという一般的なアドバイスに同意します。 99%の時間、YAGNI。
たぶん私はシングルトンパターンを理解し損ねるかもしれませんが、私の解決策はこのシンプルで実用的です(pythonic?)。このコードは2つの目標を満たします
Foo
のインスタンスをどこからでもアクセス可能にします(グローバル)。Foo
のインスタンスは1つだけ存在できます。これがコードです。
#!/usr/bin/env python3
class Foo:
me = None
def __init__(self):
if Foo.me != None:
raise Exception('Instance of Foo still exists!')
Foo.me = self
if __== '__main__':
Foo()
Foo()
出力
Traceback (most recent call last):
File "./x.py", line 15, in <module>
Foo()
File "./x.py", line 8, in __init__
raise Exception('Instance of Foo still exists!')
Exception: Instance of Foo still exists!
serial
通信を処理するクラスがあり、引数としてシリアルポートを送信するインスタンスを作成する場合、従来のアプローチでは機能しません>>> from decorators import singleton
>>>
>>> @singleton
... class A:
... def __init__(self, *args, **kwargs):
... pass
...
>>>
>>> a = A(name='Siddhesh')
>>> b = A(name='Siddhesh', lname='Sathe')
>>> c = A(name='Siddhesh', lname='Sathe')
>>> a is b # has to be different
False
>>> b is c # has to be same
True
>>>