通过观察下方代码运行结果,可以看到两次实例化的对象时同一个内存地址。
class SingleInstance(object):
__instance = None
def __new__(cls, *args, **kwargs):
print('__new__')
if cls.__instance is None:
if cls.__instance is None:
cls.__instance = super(SingleInstance, cls).__new__(cls, *args, **kwargs)
return cls.__instance
def __init__(self):
print('__init__')
if __name__ == '__main__':
single = SingleInstance()
single2 = SingleInstance()
print(single, single2)
# __new__
# __init__
# __new__
# __init__
# <__main__.SingleInstance object at 0x000000000499DEB0> <__main__.SingleInstance object at 0x000000000499DEB0>
一句话概括什么是元类:所有使用type()动态创建的类/对象或者继承type的类都是一个元类,type就是Python在背后用来创建所有类的元类。详细了解元类推荐文章:Python 元类。
元类的__new__
魔法方法有一个特征:只执行一次。通过运行结果可以看到,确实只执行了一次,而且还是在解释器读取所有模块时执行,并不是在实例化时执行。除了这个特性得到了验证,我还发现了另外一个特性,如果元类没有返回新的对象实例时,继承这个元类的类将不执行__new__
、__init__
直接跳过实例化的过程。由于这个特性,所以每次都需要初始化的单例类就不适合使用元类来做单例的控制了,相反就可以使用元类来控制单例类。
class SingleInstanceType(type):
__instance = None
__count = 0
def __new__(cls, *args, **kwargs):
print('type __new__')
return super(SingleInstanceType, cls).__new__(cls, *args, **kwargs)
def __call__(self, *args, **kwargs):
print('type __call__')
self.__count += 1
if self.__instance is None or self.__count == 5:
self.__instance = super(SingleInstanceType, self).__call__(*args, **kwargs)
return self.__instance
class SingleInstanceTypeObject(metaclass=SingleInstanceType):
def __new__(cls, *args, **kwargs):
print('obj __new__')
return super(SingleInstanceTypeObject, cls).__new__(cls, *args, **kwargs)
def __init__(self):
print('obj __init__')
if __name__ == '__main__':
single = SingleInstanceTypeObject()
single2 = SingleInstanceTypeObject()
single3 = SingleInstanceTypeObject()
single4 = SingleInstanceTypeObject()
single5 = SingleInstanceTypeObject()
print(single, single2, single3)
# type __new__
# type __call__
# obj __new__
# obj __init__
# type __call__
# type __call__
# type __call__
# type __call__
# obj __new__
# obj __init__
# <__main__.SingleInstanceTypeObject object at 0x0000000004A1F130> <__main__.SingleInstanceTypeObject object at 0x0000000004A1F130> <__main__.SingleInstanceTypeObject object at 0x0000000004A1F130>