Python类的创建过程比较复杂,我们一步步来进行分析。
首先,从实现一个Singleton做起,先看下面的代码
import copy
class Singleton:
def __new__(cls, *args, **kwargs):
print("In Singleton __new__")
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
_instance = None
class SubSingleton(Singleton):
def __init__(self):
self.x = 188
self.y = 2
if __name__ == '__main__':
s1 = SubSingleton()
s2 = SubSingleton()
s3 = copy.deepcopy(s1)
print(id(s1), id(s2), id(s1.x), id(s2.x))
输出:
In Singleton __new__
In Singleton __new__
In Singleton __new__
40697360 40697360 1457642880 1457642880
从输出我们可以看出无论通过何种方式新建SubSingleton的实例,返回的结果都只是一个相同的实例,为什么?
因为Python解释器在新建一个类的实例时new()是在init()前面的,而且init()的第一个参数self就是new()的返回结果;简单点说就是new是创建实例,init是初始化实例。
减少实例占用内存大小
Python对象实例都有一个dict存放attribute
class SubSingleton():
def __init__(self):
self.x = 188
self.y = 2
# __slots__ = ['x', 'y']
def func(self):
pass
if __name__ == '__main__':
s1 = SubSingleton()
print(s1.__dict__)
输出:
{'x': 188, 'y': 2}
我们可以使用sys.getsizeof(instance)去测试dict占用的内存,会发现随着成员的增长内存占用是非常可观的。Python提供了一个方法免去了dict
class SubSingleton():
def __init__(self):
self.x = 188
self.y = 2
__slots__ = ['x', 'y'] # 注意这里
def func(self):
pass
if __name__ == '__main__':
s1 = SubSingleton()
print(s1.__dict__)
s1.z = 1 # 这一句同样会报错,没有__dict__的类是不能动态加入attribute的。
Traceback (most recent call last):
File “E:/QQSyncFolder/prj/mysite/pattern/customer_class.py”, line 32, in
print(s1.dict)
AttributeError: ‘SubSingleton’ object has no attribute ‘dict’
“`
Python类定义语句运行的流程如下:
- the appropriate metaclass is determined
- the class namespace is prepared
- the class body is executed
- the class object is created