Python如何实现一个类只允许被实例化一次?这就要分两种情况:
在同一个脚本中实例化同一个类
1.这种有两种方法实现,一个是利用__new__
方法,需要知道的是__new__
方法运行的__init__
方法之前,所以我们可以控制如何实例化类,甚至返回其它类的实例。
class Test(object):
instance = None
def __new__(cls):
if cls.instance:
return cls.instance
cls.instance = object.__new__(cls)
return cls.instance
@classmethod
def getInstance(cls):
if cls.instance:
return cls.instance
cls.instance = cls()
return cls.instance
if __name__ == '__main__':
a = test()
b = test()
if a is b:
print("equal")
2.通过类方法来实现,如上getInstance方法,这种就不很完美,因为其它人依然可以直接通过Test()这种方式来实例化类。不过我们也有办法
class Test(object):
instance = None
def __init__(self):
raise Exception("该类不允许直接被实例化")
@classmethod
def getInstance(cls):
if cls.instance:
return cls.instance
cls.instance = super(Test, cls).__init__(cls)
return cls.instance
if __name__ == '__main__':
a = Test.getInstance()
在不同一个脚本中实例化同一个类
如何保证在不同的脚本中导入某个模块,并且得到的该模块中某个类的实例是相同的了?(前提是这两上脚本之间,有一个import了另外一个)
我们直接在该模块的脚本A中实例化该类,当两个脚本(B和C)import该脚本A时也直接导入该实例。说的有点绕口,直接上代码。
脚本A
class A(object):
pass
aInstance = A()
脚本B
import a
def testb():
print(a.aInstance)
return a.aInstance
脚本C
import a, b
def testc():
d = b.testb()
e = a.aInstance
print(e)
if d is e:
print("equal")
else:
print("not equal")
if __name__ == '__main__':
testc()
运行c.py文件输出:
<a.A object at 0x000000000337A390>
<a.A object at 0x000000000337A390>
equal
结果正是我们预计的。为什么了?
因为在Python中import时A脚本中的aInstance = A()会被自动执行,并且Python还有一个特性,在运行过程中当有Import模块时,它会把该模块对象放入sys.modules字典中,发现某个模块再次被Import时,它直接使用了sys.modules中已存在的对象。所以我们的aInstance = A()不会再次被执行,当然就只有一个实例了。
这种方式其实就是logging模块实例管理方式,大家可以看看logging源码
如果想再次Import某个模块也可以,就使用reload()函数: 比如在import a下面添加就可以reload(a)
需要注意的是在Python3中需要先from imp import reload导入reload模块。
不过就算reload(a),结果依然和上面一样。