Python 状态下的单例设计模式
singleton design pattern in Python with state
我正在尝试在 Python 中实现一个单例,在阅读 this post 之后,我发现自己比以前更加困惑。答案太多了,其中许多都获得了相当多的选票。现在的问题可能不是我有一个单例,而是状态只需要初始化一次。我尝试了几个实现 SingletonA
和 SingletonB
但我无法让它工作。对于我的实际问题,__init__
函数非常繁重,所以我只需要执行一次。这是我目前所拥有的:
class ClassA:
def __init__(self):
# some state
print("Creating state in A")
self.X = 1.
self.Y = 2.
class SingletonA(ClassA):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(SingletonA, cls).__new__(
cls, *args, **kwargs)
return cls._instance
class ClassB:
__shared_state = {}
def __init__(self):
if not bool(ClassB.__shared_state):
# some state
print("Creating state in B")
self.X = 1.
self.Y = 2.
self.__dict__ = self.__shared_state
def singleton(cls):
obj = cls()
# Always return the same object
cls.__new__ = staticmethod(lambda cls: obj)
# Disable __init__
try:
del cls.__init__
except AttributeError:
pass
return cls
@singleton
class SingletonB(ClassB):
pass
if __name__ == "__main__":
a1 = SingletonA()
a2 = SingletonA()
if (id(a1) == id(a2)):
print("Same",a1.X, a1.Y)
else:
print("Different",a1.X, a1.Y)
b1 = SingletonB()
b2 = SingletonB()
if (id(b1) == id(b2)):
print("Same",b1.X, b1.Y)
else:
print("Different",b1.X, b1.Y)
正在打印:
$ python singleton.py
Creating state in B
Creating state in B
Same 1.0 2.0
Creating state in A
Creating state in A
Same 1.0 2.0
指出我确实有一个单身人士class,但我想避免创建状态。
如果我没理解错的话,这就是你所需要的:
# edited according to discussion in comments
class C:
_shared_dict = None
def __init__(self):
if self._shared_dict is None:
print("initializing")
self.x = 1
self.y = 2
self.__class__._shared_dict = self.__dict__
else:
self.__dict__ = self._shared_dict
a=C()
b=C()
print(id(a), a.x, a.y)
print(id(b), b.x, b.y)
所有实例将共享相同的数据,并且该数据将只计算一次。
请注意,您可以在读取时将共享数据引用为self._shared_dict
,但在写入时必须使用class属性self.__class__._shared_dict
的全名。
这行不通,因为 __init__
方法是在对象创建后通过 __new__
调用的。摘自 Python Language Reference
If __new__()
returns an instance of cls, then the new instance’s __init__()
method will be invoked like __init__(self[, ...])
, where self
is the new instance and the remaining arguments are the same as were passed to __new__()
.
您应该有一个不同于 __init__
的特殊初始化方法,并在 _instance
创建时调用。
代码可以是(不需要父class,所以我省略了):
class SingletonA:
_instance = None
def __init__(self):
# some state
print("Creating dummy state in SingletonA")
def _init(self):
# some state
print("Creating state in SingletonA")
self.X = 1.
self.Y = 2.
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(SingletonA, cls).__new__(
cls, *args, **kwargs)
cls._instance._init()
return cls._instance
但实际上,您可以在声明时简单地构建实例:
class SingletonA:
def __init__(self):
# some state
print("Creating dummy state in SingletonA")
def _init(self):
# some state
print("Creating state in A")
self.X = 1.
self.Y = 2.
def __new__(cls, *args, **kwargs):
return cls._instance
SingletonA._instance = super(SingletonA, SingletonA).__new__(SingletonA)
SingletonA._instance._init()
两种方式都会导致以下输出(对于 SingletonA 部分):
Creating state in A
Creating dummy state in SingletonA
Creating dummy state in SingletonA
('Same', 1.0, 2.0)
完全删除 __init__
方法会导致一次初始化。
注释版本可以是:
class ClassB:
def __init__(self):
# some state
print("Creating state in B")
self.X = 1.
self.Y = 2.
def singleton(cls):
obj = cls()
# Always return the same object
cls._instance = obj
cls.__new__ = staticmethod(lambda cls: cls._instance)
# Disable __init__
cls.__init__ = (lambda self: None)
return cls
@singleton
class SingletonB(ClassB):
pass
简单地将单例实例存储在 class 本身
我正在尝试在 Python 中实现一个单例,在阅读 this post 之后,我发现自己比以前更加困惑。答案太多了,其中许多都获得了相当多的选票。现在的问题可能不是我有一个单例,而是状态只需要初始化一次。我尝试了几个实现 SingletonA
和 SingletonB
但我无法让它工作。对于我的实际问题,__init__
函数非常繁重,所以我只需要执行一次。这是我目前所拥有的:
class ClassA:
def __init__(self):
# some state
print("Creating state in A")
self.X = 1.
self.Y = 2.
class SingletonA(ClassA):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(SingletonA, cls).__new__(
cls, *args, **kwargs)
return cls._instance
class ClassB:
__shared_state = {}
def __init__(self):
if not bool(ClassB.__shared_state):
# some state
print("Creating state in B")
self.X = 1.
self.Y = 2.
self.__dict__ = self.__shared_state
def singleton(cls):
obj = cls()
# Always return the same object
cls.__new__ = staticmethod(lambda cls: obj)
# Disable __init__
try:
del cls.__init__
except AttributeError:
pass
return cls
@singleton
class SingletonB(ClassB):
pass
if __name__ == "__main__":
a1 = SingletonA()
a2 = SingletonA()
if (id(a1) == id(a2)):
print("Same",a1.X, a1.Y)
else:
print("Different",a1.X, a1.Y)
b1 = SingletonB()
b2 = SingletonB()
if (id(b1) == id(b2)):
print("Same",b1.X, b1.Y)
else:
print("Different",b1.X, b1.Y)
正在打印:
$ python singleton.py
Creating state in B
Creating state in B
Same 1.0 2.0
Creating state in A
Creating state in A
Same 1.0 2.0
指出我确实有一个单身人士class,但我想避免创建状态。
如果我没理解错的话,这就是你所需要的:
# edited according to discussion in comments
class C:
_shared_dict = None
def __init__(self):
if self._shared_dict is None:
print("initializing")
self.x = 1
self.y = 2
self.__class__._shared_dict = self.__dict__
else:
self.__dict__ = self._shared_dict
a=C()
b=C()
print(id(a), a.x, a.y)
print(id(b), b.x, b.y)
所有实例将共享相同的数据,并且该数据将只计算一次。
请注意,您可以在读取时将共享数据引用为self._shared_dict
,但在写入时必须使用class属性self.__class__._shared_dict
的全名。
这行不通,因为 __init__
方法是在对象创建后通过 __new__
调用的。摘自 Python Language Reference
If
__new__()
returns an instance of cls, then the new instance’s__init__()
method will be invoked like__init__(self[, ...])
, whereself
is the new instance and the remaining arguments are the same as were passed to__new__()
.
您应该有一个不同于 __init__
的特殊初始化方法,并在 _instance
创建时调用。
代码可以是(不需要父class,所以我省略了):
class SingletonA:
_instance = None
def __init__(self):
# some state
print("Creating dummy state in SingletonA")
def _init(self):
# some state
print("Creating state in SingletonA")
self.X = 1.
self.Y = 2.
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(SingletonA, cls).__new__(
cls, *args, **kwargs)
cls._instance._init()
return cls._instance
但实际上,您可以在声明时简单地构建实例:
class SingletonA:
def __init__(self):
# some state
print("Creating dummy state in SingletonA")
def _init(self):
# some state
print("Creating state in A")
self.X = 1.
self.Y = 2.
def __new__(cls, *args, **kwargs):
return cls._instance
SingletonA._instance = super(SingletonA, SingletonA).__new__(SingletonA)
SingletonA._instance._init()
两种方式都会导致以下输出(对于 SingletonA 部分):
Creating state in A
Creating dummy state in SingletonA
Creating dummy state in SingletonA
('Same', 1.0, 2.0)
完全删除 __init__
方法会导致一次初始化。
注释版本可以是:
class ClassB:
def __init__(self):
# some state
print("Creating state in B")
self.X = 1.
self.Y = 2.
def singleton(cls):
obj = cls()
# Always return the same object
cls._instance = obj
cls.__new__ = staticmethod(lambda cls: cls._instance)
# Disable __init__
cls.__init__ = (lambda self: None)
return cls
@singleton
class SingletonB(ClassB):
pass
简单地将单例实例存储在 class 本身