可能重复:
Is there a simple, elegant way to define Singletons in Python?
我有以下示例代码,其中我从Singleton派生一个类(希望它是一个):
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
class Tracer(Singleton):
def __init__(self):
print "Init"
a = Tracer()
b = Tracer()
尝试时,您会看到再次调用__init__
Tracer
方法。是不是有单身人士让另一个实例引用原始实例?我不想再次运行__init__
方法,因为它可能会覆盖以前的信息。也许单身人士是错的还是有用?
答案 0 :(得分:6)
我之前的回答没有用,我已将其删除。但是我发现了一个高评价的SO answer。主要区别在于它使用Singleton
元类而不是基类,并重载其实例类的__call__()
方法而不是其__new__()
方法。这为其单例类实例的实例的创建过程提供了所需的控制。可以定义一个额外的方法来删除其中的一个或多个 - 比如用于测试目的。
另一个值得注意的实现细节是,元类维护了_instances
的字典,而不是只能保存单个值的字典。这允许它跟踪无限数量的单例实例(因为它可能是多个元类,因为它可以重用)。
将它应用于您的示例代码将完成以下任务:
class Singleton(type):
"""Metaclass."""
_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]
class Tracer(object):
__metaclass__ = Singleton
def __init__(self):
print("Init")
a = Tracer()
b = Tracer()
print('a is b: {}'.format(a is b)) # same object? -> True
输出:
Init
a is b: True
<强>更新强>
指定元类的语法在Python 2和3之间有所不同。对于后者,您需要将Tracer
类定义更改为:
#!/usr/bin/env python3
class Tracer(object, metaclass=Singleton):
def __init__(self):
print("Init")
编写可以在两者版本2和3的Python中工作的东西是可能的,但是因为你 不能 只是有条件地定义它:
## Won't work ##
if sys.version_info[0] < 3: # Python 2?
class Tracer(object):
__metaclass__ = Singleton
def __init__(self):
print("Init")
else: # Python 3
class Tracer(object, metaclass=Singleton): # causes SyntaxError in Python 2
def __init__(self):
print("Init")
因为else
子句中的定义在Python 2中导致SyntaxError
(即使块中的代码永远不会被执行)。类似于Benjamin Peterson的six模块的with_metaclass()
函数所做的解决方法,看起来像这样:
class Tracer(Singleton("SingletonBaseClass", (object,), {})):
def __init__(self):
print("Init")
这会动态创建一个继承所需元类的基类,从而避免由于两个Python版本之间的元类语法差异而导致的任何错误。 (它通过显式使用定义的元类来创建临时基类来实现。)
答案 1 :(得分:2)
您的__init__
被调用两次,但是在同一个对象上。你已经创建了一个单例,但Python不知道它是什么,所以它初始化了每个创建的对象。
如果您想要追求单身模式,则必须将初始化代码移至__new__
,或转移到__new__
调用的其他方法。
请记住:
单身人士是Java的常态,但在Python中却不受欢迎。
单身人士使您的代码更难以测试,因为它们是从一个测试到下一个测试的全局状态。