在Python中创建单例

时间:2011-07-20 10:47:57

标签: python singleton decorator base-class metaclass

这个问题不是讨论singleton design pattern是否可取,是反模式还是任何宗教战争,而是讨论如何在Python中最好地实现这种模式这种方式最为pythonic。在这种情况下,我将“最pythonic”定义为表示它遵循“最小惊讶原则”

我有多个类可以成为单例(我的用例是记录器,但这并不重要)。

,当我可以简单地继承或装饰时,我不希望在添加了gumph的几个类中混乱。

最佳方法:


方法1:装饰者

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

赞成

  • 装饰器的添加方式通常比多重继承更直观。

缺点

  • 虽然使用MyClass()创建的对象将是真正的单例对象,但MyClass本身是一个函数,而不是类,因此您无法从中调用类方法。也适用于m = MyClass(); n = MyClass(); o = type(n)();,然后是m == n && m != o && n != o

方法2:基类

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

赞成

  • 这是一个真正的课程

缺点

  • 多重继承 - eugh!从第二个基类继承期间可能会覆盖__new__吗?人们必须考虑的不仅仅是必要的。

方法3:A metaclass

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__用于其正确目的(并让我知道它)

缺点

  • 有没有?

方法4:装饰器返回一个具有相同名称的类

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__的类子类化。

30 个答案:

答案 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 1part 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 2Python 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个参数并且仍然是单例,因此它略有不同有效。

enter image description here 这是您可以多次调用单例方法的证明,并显示该类的一个实例仍在使用并且没有创建新对象。

#/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%。) 这是更新的答案:

enter image description here

这是复制和粘贴代码的代码:)

#/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?)。这段代码实现了两个目标

  1. 使Foo的实例在任何地方(全局)均可访问。
  2. 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失败)
  • propertyclassmethodstaticmethod仍将按预期工作
  • __init__()构造函数仅执行一次
  • 您可以再次使用@singleton从修饰的类继承(没用吗?)

缺点:

  • 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)

  • 如果一个人想要拥有多个相同类的实例,但是只有当args或kwargs不同时,才可以使用this
  • 例如
    1. 如果您有一个处理serial通讯的类,并且要创建一个实例,想要将串行端口作为参数发送,那么采用传统方法将无法使用
    2. 使用上述装饰器,如果args不同,则可以创建该类的多个实例。
    3. 对于相同的参数,装饰器将返回已经创建的相同实例。
>>> 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.

我认为它有一些其他解决方案的好处:

  • 它清晰简洁(我的眼睛; D)。
  • 它的动作是完全封装的。您不需要对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()

注意事项:

  1. 如果你不是python2.x中的对象的子类,你将得到一个旧式的类,它不使用__new__
  2. 装饰__new__时必须使用@classmethod进行装饰,否则__new__将成为未绑定的实例方法
  3. 这可以通过使用元类来改进,因为这样可以使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)

说明:

  1. 创建新类,继承自给定cls
    (如果有人想要cls),则不会修改singleton(list)

  2. 创建实例。在覆盖__new__之前,这很容易。

  3. 现在,当我们轻松创建实例时,使用之前定义的方法覆盖__new__
  4. 该函数仅在调用者期望的情况下返回instance,否则会引发TypeError
    当有人试图从装饰类继承时,不符合条件。

  5.   

    如果__new__()返回cls的实例,则会调用新实例的__init__()方法,如__init__(self[, ...]),其中self是新实例和其余参数与传递给__new__()的参数相同。

    instance已初始化,因此函数会替换__init__,函数无效。

  6. See it working online

答案 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