How to initialize Singleton-derived object once
Possible Duplicate:
Is there a simple, elegant way to define Singletons in Python?
我有以下示例代码,其中我从一个单例派生一个类(希望它是一个):
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |
当您尝试时,您将看到再次调用
我以前的回答不起作用,我已将其删除。不过,我找到了一个评价很高的答案。主要区别在于,它使用
另一个值得注意的实现细节是,元类维护一个
将它应用到示例代码中可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
输出:
1 2 | Init a is b: True |
更新
指定元类的语法在python 2和3之间有所不同。对于后者,您需要将
1 2 3 4 5 | #!/usr/bin/env python3 class Tracer(object, metaclass=Singleton): def __init__(self): print("Init") |
编写一个既适用于Python版本2又适用于Python版本3的代码是可能的,但是要复杂一点,因为您不能简单地有条件地这样定义它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ## 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") |
因为
1 2 3 | class Tracer(Singleton("SingletonBaseClass", (object,), {})): def __init__(self): print("Init") |
这将动态创建一个继承所需元类的基类,从而避免由于两个Python版本之间的元类语法差异而导致的任何错误。(它通过显式使用定义的元类来创建临时的基类来实现。)
您的
如果您想采用单例模式,则必须将初始化代码移到
记住:
单元格是Java中的规范,但在Python中是不赞成的。
单例使代码更难测试,因为它们是从一个测试到下一个测试的全局状态。