如何派生内置不可变类型并修改其实例化行为

本文探讨了如何通过继承Python内置的tuple类来创建只包含正整数元素的元组,并介绍了如何使用__slots__来减少游戏服务器中大量Player实例的内存消耗。
# 类与对象深度问题与解决技巧
# 如何派生内置不可变类型并修改其实例化行为
# 我们想定义一种新类型的元组对于传入的可迭代对象 我们只保留其中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__属性,声明实例有哪些属性(关闭动态绑定)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值