# 类与对象深度问题与解决技巧
# 如何派生内置不可变类型并修改其实例化行为
# 我们想定义一种新类型的元组对于传入的可迭代对象 我们只保留其中int类型值大于0的元素
# 例如:
# IntTuple([2,-2,'jr',['x','y'],4]) #=> (2,4)
# 如何继承内置tuple实现IntTuple
# 2 如何为创建大量实例节省内存
# 在游戏中定义了玩家类player,每有一个在线玩家,在服务器内则有一个player的实例,
# 当在线人数很多时,将产生大量实例(百万级)
# 如何降低大量实例的内存开销
class IntTuple(tuple):
def __init__(self,iterable):
for i in iterable:
if isinstance(i,int) and i > 0:
super().__init__(i)
# print(self)
int_t =IntTuple ([2,-2,'jr',['x','y'],4])
print(int_t) # 2,4
# self 对象到底是谁创建的?
class A(object):
def __new__(cls, *args, **kwargs):
print('A.__new__',cls,args)
return object.__new__(cls)
# return super().__new__(cls) # 使用super()也可以但最好用object
def __init__(self,*args):
print('A.__init__')
a = A(1,2)
a = A.__new__(A,1,2)
A.__init__(a,1,2)
class IntTuple(tuple):
def __new__(cls,iterable):
# for i in iterable:
# if isinstance(i,int) and i > 0:
# super().__init__(i)
# 生成器
# f = (i for i in iterable if isinstance(i,int) and i > 0)
f = [i for i in iterable if isinstance(i,int) and i > 0]
return super().__new__(cls,f)
int_t =IntTuple([2,-2,'jr',['x','y'],4])
print(int_t) # 2,4
如何为创建大量实例节省内存
# 2 如何为创建大量实例节省内存
# 在游戏中定义了玩家类player,每有一个在线玩家,在服务器内则有一个player的实例,
# 当在线人数很多时,将产生大量实例(百万级)
# 如何降低大量实例的内存开销
import sys # 导入系统模块 查看占内存多少
import tracemalloc # 统计内存 跟踪内存使用
class Player1(object):
def __init__(self,uid,name,status=0,level=1):
self.uid = uid
self.name = name
self.status = status
self.level =level
class Player2(object):
__slots__ = ('uid','name','status','level')
def __init__(self,uid,name,status=0,level=1):
self.uid = uid
self.name = name
self.status = status
self.level =level
# p1 = Player1('0001','ellen')
# p2 = Player2('0002','ellen')
# print(dir(p1)) # 查看p1属性
# print(len(dir(p1))) # 查看属性长度 30
# print(dir(p2)) # 查看p2属性
# print(le(dir(p2))) # 29
# __weakref__ # 弱引用
# __dict__ # 动态绑定属性
# print(set(dir(p1))-set(dir(p2))) -->
# p1.x = 6 # 动态绑定添加属性 及其浪费内存
# p1.__dict__['y']=7 # 动态绑定添加属性
# print(p1.__dict__)
# print(p2.name) # p2添加__slots__后取值可以,
# p2.y = 7 # 动态添加属性会报错
# 导入系统模块 查看对象所占内存__dict__占内存最大
# print(sys.getsizeof(p1.__dict__)) --> 112
# print(sys.getsizeof(p1.name)) --> 54
# print(sys.getsizeof(p1.uid)) -- > 53
导入 tracemalloc 统计内存 跟踪内存使用
tracemalloc.start() # 开启
p1 = [Player1(1,2,3) for _ in range(100000)] # size=16.8 MiB _ in 不需要循环里的值 不想取变量名字用下划线代替。
p2 = [Player2(1,2,3) for _ in range(100000)] # size=7837 KiB
end = tracemalloc.take_snapshot()
# top = end.statistics('lineno')
top = end.statistics('filename')
for stat in top[:10]:
print(stat)
总结:
解决方案:
定义类的__slots__属性,声明实例有哪些属性(关闭动态绑定)