这个问题不是讨论singleton design pattern是否可取,是反模式还是任何宗教战争,而是讨论如何在Python中最好地实现这种模式这种方式最为pythonic。在这种情况下,我将“最pythonic”定义为表示它遵循“最小惊讶原则”。
我有多个类可以成为单例(我的用例是记录器,但这并不重要)。
,当我可以简单地继承或装饰时,我不希望在添加了gumph的几个类中混乱。最佳方法:
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__
吗?人们必须考虑的不仅仅是必要的。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.__name__ = class_.__name__
return class_w
@singleton
class MyClass(BaseClass):
pass
赞成
缺点
_sealed
属性super()
在基类上调用相同名称的方法,因为它们会递归。这意味着您无法自定义__new__
,也无法将需要您调用__init__
的类子类化。答案 0 :(得分:516)
答案 1 :(得分:76)
class Foo(object):
pass
some_global_variable = Foo()
模块只导入一次,其他一切都是过度思考。不要使用单例并尽量不使用全局变量。
答案 2 :(得分:58)
使用模块。它只导入一次。在其中定义一些全局变量 - 它们将是单例的'属性'。添加一些函数 - 单例的'方法'。
答案 3 :(得分:21)
你可能永远不需要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不会重新执行代码。
答案 4 :(得分:14)
这是你的单行:
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
您的对象急切地实例化。这可能是也可能不是你想要的。
答案 5 :(得分:7)
使用多种解决方案查看Stack Overflow问题 Is there a simple, elegant way to define singletons in Python? 。
我强烈建议观看Alex Martelli关于python设计模式的讨论:part 1和part 2。特别是,在第1部分中,他讨论了单身人士/共享状态对象。
答案 6 :(得分:3)
这是我自己实现的单身人士。你所要做的就是装饰课程;要获得单例,您必须使用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)
答案 7 :(得分:2)
方法3似乎非常简洁,但是如果您希望程序在Python 2和Python 3中运行,则它不起作用。即使使用Python版本的测试来保护单独的变体也会失败,因为Python 3版本在Python 2中提供了语法错误。
感谢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',但我没有尝试过(我已经尝试了代码)。
答案 8 :(得分:1)
嗯,除了同意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.__name__ = 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 __name__ is preserved
True # this is actually the same instance
答案 9 :(得分:1)
这个怎么样:
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)()
(也返回相同的实例)来阻止您创建其他实例。
答案 10 :(得分:1)
以前的答案是正确的,但我不同意方法1“问题所在的MyClass本身是一个函数,而不是一个类,因此您不能调用类方法”下作为问题一部分发布的声明。参见下面的示例,该方法在MyClass中多次调用,该方法用单例标记修饰。
另外,请注意,这与发布的某些答案非常相似,并且基于python document,但由于类和函数的设计方式是可以接收1或0个参数并且仍然是单例,因此它略有不同有效。
这是您可以多次调用单例方法的证明,并显示该类的一个实例仍在使用并且没有创建新对象。
#/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")
由于扫帚的负责人(发布问题的人)已经对他的原始问题提供了一些反馈,因此我根据他的反馈去了一个新的解决方案(我仍然保留以前的回答,因为我认为这可能对某些人有用即使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()
答案 11 :(得分:1)
使用函数属性也非常简单
def f():
if not hasattr(f, 'value'):
setattr(f, 'value', singletonvalue)
return f.value
答案 12 :(得分:0)
也许我误解了单例模式,但是我的解决方案是这个简单而实用的(pythonic?)。这段代码实现了两个目标
Foo
的实例在任何地方(全局)均可访问。Foo
只能存在一个实例。这是代码。
#!/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 __name__ == '__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!
答案 13 :(得分:0)
我只是偶然做了一个简单的,我想我会分享它...
class MySingleton(object):
def __init__(self, *, props={}):
self.__dict__ = props
mything = MySingleton()
mything.test = 1
mything2 = MySingleton()
print(mything2.test)
mything2.test = 5
print(mything.test)
答案 14 :(得分:0)
经过一段时间的努力,我最终想到了以下内容,以便从单独的模块调用配置对象时,它只会被加载一次。元类允许将全局类实例存储在内置指令中,这在当前看来是存储适当程序全局的最简洁的方法。
import builtins
# -----------------------------------------------------------------------------
# So..... you would expect that a class would be "global" in scope, however
# when different modules use this,
# EACH ONE effectively has its own class namespace.
# In order to get around this, we use a metaclass to intercept
# "new" and provide the "truly global metaclass instance" if it already exists
class MetaConfig(type):
def __new__(cls, name, bases, dct):
try:
class_inst = builtins.CONFIG_singleton
except AttributeError:
class_inst = super().__new__(cls, name, bases, dct)
builtins.CONFIG_singleton = class_inst
class_inst.do_load()
return class_inst
# -----------------------------------------------------------------------------
class Config(metaclass=MetaConfig):
config_attr = None
@classmethod
def do_load(cls):
...<load-cfg-from-file>...
答案 15 :(得分:0)
我将推荐一个使用元类的优雅解决方案
class Singleton(type):
# Inherit from "type" in order to gain access to method __call__
def __init__(self, *args, **kwargs):
self.__instance = None # Create a variable to store the object reference
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
# if the object has not already been created
self.__instance = super().__call__(*args, **kwargs) # Call the __init__ method of the subclass (Spam) and save the reference
return self.__instance
else:
# if object (Spam) reference already exists; return it
return self.__instance
class Spam(metaclass=Singleton):
def __init__(self, x):
print('Creating Spam')
self.x = x
if __name__ == '__main__':
spam = Spam(100)
spam2 = Spam(200)
输出:
Creating Spam
从输出中可以看到,仅实例化了一个对象
答案 16 :(得分:0)
我更喜欢这种解决方案,我发现它非常清楚直接。 例如,它正在使用仔细检查,是否已经有其他线程创建了它。 要考虑的另一件事是确保反序列化不会创建任何其他实例。 https://gist.github.com/werediver/4396488
import threading
# Based on tornado.ioloop.IOLoop.instance() approach.
# See https://github.com/facebook/tornado
class SingletonMixin(object):
__singleton_lock = threading.Lock()
__singleton_instance = None
@classmethod
def instance(cls):
if not cls.__singleton_instance:
with cls.__singleton_lock:
if not cls.__singleton_instance:
cls.__singleton_instance = cls()
return cls.__singleton_instance
if __name__ == '__main__':
class A(SingletonMixin):
pass
class B(SingletonMixin):
pass
a, a2 = A.instance(), A.instance()
b, b2 = B.instance(), B.instance()
assert a is a2
assert b is b2
assert a is not b
print('a: %s\na2: %s' % (a, a2))
print('b: %s\nb2: %s' % (b, b2))
答案 17 :(得分:0)
我也更喜欢装饰器语法而不是从元类派生。我的两分钱:
from typing import Callable, Dict, Set
def singleton(cls_: Callable) -> type:
""" Implements a simple singleton decorator
"""
class Singleton(cls_): # type: ignore
__instances: Dict[type, object] = {}
__initialized: Set[type] = set()
def __new__(cls, *args, **kwargs):
if Singleton.__instances.get(cls) is None:
Singleton.__instances[cls] = super().__new__(cls, *args, **kwargs)
return Singleton.__instances[cls]
def __init__(self, *args, **kwargs):
if self.__class__ not in Singleton.__initialized:
Singleton.__initialized.add(self.__class__)
super().__init__(*args, **kwargs)
return Singleton
@singleton
class MyClass(...):
...
与提供的其他装饰器相比,它有一些好处:
isinstance(MyClass(), MyClass)
仍然可以工作(从仓促返回函数而不是类将使isinstance失败)property
,classmethod
和staticmethod
仍将按预期工作__init__()
构造函数仅执行一次缺点:
print(MyClass().__class__.__name__)
将返回Singleton
而不是od MyClass
。如果您仍然需要此功能,我建议使用上面建议的元类。如果您需要基于构造函数参数的其他实例,则需要改进此解决方案(siddhesh-suhas-sathe提供的解决方案可以提供此解决方案。)
最后,根据其他建议,考虑在python中使用模块。模块是对象。您甚至可以将它们传递给变量,然后将其注入其他类。
答案 18 :(得分:0)
优点
这是一个真正的类自动神奇地覆盖继承使用元类 出于其正当目的(并让我意识到这一点) 缺点
有吗?
这将是序列化的问题。如果您尝试从文件 (pickle) 反序列化对象,它不会使用 __call__
,因此它会创建新文件,您可以使用带有 __new__
的基类继承来防止这种情况发生。
答案 19 :(得分:0)
如果您想使用 metaclass
作为属性,可以使用 instance
。例如;
class SingletonMeta(type):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
cls._instance = None
cls._locker = threading.Lock()
@property
def instance(self, *args, **kwargs):
if self._instance is None:
with self._locker:
if self._instance is None:
self._instance = self(*args, **kwargs)
return self._instance
class MyClass(metaclass=SingletonMeta):
def __init__(self):
# init here
pass
# get the instance
my_class_instance = MyClass.instance
答案 20 :(得分:0)
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
>>>
答案 21 :(得分:0)
如果您不需要懒惰地初始化Singleton实例,那么以下操作应该很容易且线程安全:
class A:
instance = None
# Methods and variables of the class/object A follow
A.instance = A()
这样A
是在模块导入时初始化的单例。
答案 22 :(得分:0)
一个班轮(我不自豪,但它能胜任):
class Myclass:
def __init__(self):
# do your stuff
globals()[type(self).__name__] = lambda: self # singletonify
答案 23 :(得分:0)
我将我扔进戒指。它是一个简单的装饰者。
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
的实施进行任何改变。这包括不需要为您的类使用元类(请注意,上面的元类是在工厂,而不是&#34;真正的&#34;类)。YourClass
,它看起来像一个类(因为它),并且他们正常使用它。无需使呼叫者适应工厂功能。YourClass()
实例化的内容仍然是您实施的YourClass
的真实实例,而不是任何类型的代理,因此不会产生副作用。isinstance(instance, YourClass)
并且类似的操作仍然按预期工作(尽管这个位确实需要abc,因此排除了Python&lt; 2.6)。我确实遇到了一个缺点:真实类的classmethods和staticmethods不能通过隐藏它的工厂类来透明地调用。我很少使用它,以至于我从来没有遇到过这种需求,但是通过在工厂上使用自定义元类来实现__getattr__()
来委托all-ish属性可以很容易地解决这个问题。访问真正的班级。
我发现实际上发现更有用的相关模式(并非我说这些事情经常需要这些事情)是一个&#34; Unique&#34;使用相同参数实例化类的模式导致返回相同的实例。即a&#34;每个参数单身&#34;。以上内容适应了这一点,变得更加简洁:
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
所有这一切,我确实同意一般的建议,如果你认为你需要其中一件事,你真的应该停下片刻并问自己是否真的这样做。 99%的时间,YAGNI。
答案 24 :(得分:0)
它与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
已。{/ p>
但鼓励用户普遍使用the
方法:
Elvis.the().leave(Building.the())
要完成此操作,您还可以覆盖__delattr__()
以在尝试删除instance
时引发异常,并覆盖__del__()
以便它引发异常(除非我们知道该计划即将结束......)
感谢那些帮助评论和编辑的人,其中更受欢迎。虽然我使用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
答案 25 :(得分:0)
代码基于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
(如果有人想要cls
),则不会修改singleton(list)
创建实例。在覆盖__new__
之前,这很容易。
__new__
。 该函数仅在调用者期望的情况下返回instance
,否则会引发TypeError
。
当有人试图从装饰类继承时,不符合条件。
如果
__new__()
返回cls
的实例,则会调用新实例的__init__()
方法,如__init__(self[, ...])
,其中self是新实例和其余参数与传递给__new__()
的参数相同。
instance
已初始化,因此函数会替换__init__
,函数无效。
答案 26 :(得分:-1)
我无法记住我找到这个解决方案的地方,但我发现它是最优雅的解决方案。从我的非Python专家的角度来看:
class SomeSingleton(dict):
__instance__ = None
def __new__(cls, *args,**kwargs):
if SomeSingleton.__instance__ is None:
SomeSingleton.__instance__ = dict.__new__(cls)
return SomeSingleton.__instance__
def __init__(self):
pass
def some_func(self,arg):
pass
为什么我喜欢这个?没有装饰器,没有元类,没有多重继承......如果你决定不再让它成为Singleton,只需删除__new__
方法。由于我是Python的新手(以及一般的OOP),我希望有人会直截了当地说明为什么这是一个糟糕的方法?
答案 27 :(得分:-2)
此解决方案在模块级别导致一些命名空间污染(三个定义而不仅仅是一个),但我发现很容易理解。
我希望能够编写类似这样的内容(延迟初始化),但不幸的是,类在自己定义的主体中不可用。
# wouldn't it be nice if we could do this?
class Foo(object):
instance = None
def __new__(cls):
if cls.instance is None:
cls.instance = object()
cls.instance.__class__ = Foo
return cls.instance
由于这是不可能的,我们可以在
中分解初始化和静态实例急切的初始化:
import random
class FooMaker(object):
def __init__(self, *args):
self._count = random.random()
self._args = args
class Foo(object):
def __new__(self):
return foo_instance
foo_instance = FooMaker()
foo_instance.__class__ = Foo
延迟初始化:
急切的初始化:
import random
class FooMaker(object):
def __init__(self, *args):
self._count = random.random()
self._args = args
class Foo(object):
def __new__(self):
global foo_instance
if foo_instance is None:
foo_instance = FooMaker()
return foo_instance
foo_instance = None
答案 28 :(得分:-2)
这个答案很可能不是你想要的。我想要一个单身,因为只有那个对象有它的身份,以便与之比较。就我而言,它被用作Sentinel Value。答案非常简单,使任何对象mything = object()
和python的性质,只有那个东西才会有它的身份。
#!python
MyNone = object() # The singleton
for item in my_list:
if item is MyNone: # An Example identity comparison
raise StopIteration
答案 29 :(得分:-2)
这是我实施单身人士的首选方式:
class Test(object):
obj = None
def __init__(self):
if Test.obj is not None:
raise Exception('A Test Singleton instance already exists')
# Initialization code here
@classmethod
def get_instance(cls):
if cls.obj is None:
cls.obj = Test()
return cls.obj
@classmethod
def custom_method(cls):
obj = cls.get_instance()
# Custom Code here