使用python中的构造函数限制在单例类中创建对象
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用python中的构造函数限制在单例类中创建对象相关的知识,希望对你有一定的参考价值。
我正在为python中的一个需求编写单例类。我可以意识到,我无法限制该类的对象创建,如果某个客户端在使用单例类方法之前首先使用构造函数进行调用(意味着返回该类的唯一实例的方法)。
我的意思是什么?让我用一些代码片段解释一下。考虑我有下面的一个示例:
import threading
class MyClass:
__instance = None
def __init__(self):
if self.__instance:
raise ValueError("Already exist")
@classmethod
def getInstance(cls):
lock = threading.Lock()
with lock:
if cls.__instance == None:
cls.__instance = MyClass()
return cls.__instance
def printObjInfo(self,obj):
print(id(obj))
if __name__ == '__main__':
ob4 = MyClass()
ob4.printObjInfo(ob4)
obj1 = MyClass.getInstance()
obj1.printObjInfo(obj1)
obj2 = MyClass.getInstance()
obj2.printObjInfo(obj2)
# Create a thread
obj3 = MyClass.getInstance()
obj3.printObjInfo(obj3)
t1 = threading.Thread(target=obj3.printObjInfo, args=(obj3))
如果我运行上面的代码片段,我会得到如下结果:
44824952 - Object created by constructor.
44826240 - Object created by getInstance() method.
44826240 - Object created by getInstance() method.
44826240 - Object created by getInstance() method.
有一点需要注意 - 如果有人在调用getInstance()方法之后调用构造函数,那么我们可以很容易地限制其他对象的创建。但如果它首先被调用,那么我们将无法控制它。
现在的问题是 - 1)我不能在__init __()中放任何进一步的条件,没有人调用它或2)不能使我的构造函数私有 - 我可以吗?
我在这里找到了一些参考 - Program to restrict object creation in Python但不确定,我们如何限制第一个对象创建本身。有没有更好的方法让你这样做?
有什么想法或参考?
谢谢。
答案
您可以改为覆盖__new__
:
class Singleton:
_instance = None
def __init__(self, arg):
self.arg = arg
def __new__(cls, arg):
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance
else:
return cls._instance
print(Singleton(None))
print(Singleton(None))
print(Singleton(None))
输出:
<__main__.Singleton object at 0x1207fa550>
<__main__.Singleton object at 0x1207fa550>
<__main__.Singleton object at 0x1207fa550>
这样做的好处是,有一个统一的界面可用于创建和获取Singleton的单个实例:构造函数。
请注意,除非您编写自己的C扩展或类似的东西,否则您将永远无法在Python中创建真正的单例:
print(object.__new__(Singleton))
print(object.__new__(Singleton))
print(object.__new__(Singleton))
输出:
<__main__.Singleton object at 0x120806ac8>
<__main__.Singleton object at 0x1207d5b38>
<__main__.Singleton object at 0x1207d5198>
另一答案
基于gmds的答案的线程安全单例版本
from multiprocessing.dummy import Pool as ThreadPool
import threading
import time
class ThreadSafeSingleton:
__instance = None
__lock = threading.Lock()
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __str__(self):
return 'id: {}, args: {}, kwargs: {}'.format(id(self), self.args, self.kwargs)
def __new__(cls, *args, **kwargs):
with cls.__lock:
if cls.__instance is None:
# sleep just simulate heavy class initialization !!
# process under concurrency circumstance !!
time.sleep(1)
print('created')
cls.__instance = super(ThreadSafeSingleton, cls).__new__(cls)
return cls.__instance
class ThreadUnsafeSingleton:
__instance = None
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __str__(self):
return 'id: {}, args: {}, kwargs: {}'.format(id(self), self.args, self.kwargs)
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
time.sleep(1)
print('created')
cls.__instance = super(ThreadUnsafeSingleton, cls).__new__(cls)
return cls.__instance
def create_safe(*args, **kwargs):
obj = ThreadSafeSingleton(*args, **kwargs)
print(obj)
def create_unsafe(*args, **kwargs):
obj = ThreadUnsafeSingleton(*args, **kwargs)
print(obj)
if __name__ == '__main__':
pool = ThreadPool(4)
print('---- test thread safe singleton ----')
pool.map(create_safe, range(10))
print('
---- test thread unsafe singleton ----')
pool.map(create_unsafe, range(10))
输出:
---- test thread safe singleton ----
created
id: 4473136352, args: (0,), kwargs: {}
id: 4473136352, args: (1,), kwargs: {}
id: 4473136352, args: (2,), kwargs: {}
id: 4473136352, args: (4,), kwargs: {}
id: 4473136352, args: (5,), kwargs: {}
id: 4473136352, args: (3,), kwargs: {}
id: 4473136352, args: (6,), kwargs: {}
id: 4473136352, args: (7,), kwargs: {}
id: 4473136352, args: (8,), kwargs: {}
id: 4473136352, args: (9,), kwargs: {}
---- test thread unsafe singleton ----
created
id: 4473136968, args: (0,), kwargs: {}
created
created
created
id: 4473136968, args: (4,), kwargs: {}
id: 4473137024, args: (2,), kwargs: {}
id: 4473137080, args: (1,), kwargs: {}
id: 4473137136, args: (3,), kwargs: {}
id: 4473137136, args: (5,), kwargs: {}
id: 4473137136, args: (7,), kwargs: {}
id: 4473137136, args: (6,), kwargs: {}
id: 4473137136, args: (8,), kwargs: {}
id: 4473137136, args: (9,), kwargs: {}
以上是关于使用python中的构造函数限制在单例类中创建对象的主要内容,如果未能解决你的问题,请参考以下文章