如果我们想要限制实例的属性,Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class实例能添加的属性。
使用slots要注意,slots定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
除非在子类中也定义slots,这样,子类实例允许定义的属性就是自身的slots加上父类的slots。
# coding:utf-8
class Player(object):
def __init__(self, uid, name, stat=0, level=1):
self.uid = uid
self.name = name
self.stat = stat
self.level = level
class Player2(object):
__slots__ = ['uid', 'name', 'stat', 'level', 'sex']
def __init__(self, uid, name, stat=0, level=1):
self.uid = uid
self.name = name
self.stat = stat
self.level = level
class Player3(Player2):
def __init__(self, uid, name):
super(Player3, self).__init__(uid, name)
class Player4(Player2):
__slots__ = ['age']
def __init__(self, uid, name):
super(Player4, self).__init__(uid, name)
# 创建实例
p1 = Player('001', 'Jim')
p2 = Player2('002', 'Jim2')
p3 = Player3('003', 'Jim3')
p4 = Player4('004', 'Jim4')
# p1实例
print(p1.name) # jim
p1.age = 16
print(p1.age) # 16
# p2实例
print(p2.name) # Jim2
p2.sex = 'boy'
print(p2.sex) # boy
# p2.age = 16
# print(p2.age) # 错误异常 AttributeError
# p3实例 __slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
print(p3.name) # Jim3
p3.age = 16
print(p3.age) # 16
# p4实例
# 子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
print(p4.name) # Jim4
p4.age = 16
print(p4.age) # 16
p4.sex = 'girl'
print(p4.sex) # girl
# p4.date = '2019'
# print(p4.date) # 错误异常 AttributeError
slots应用实例
如何为创建大量实例节省内存?
问题:某游戏中,定义了玩家类Player(uid, name, status...),每有一个在线玩家,在服务器程序内则有一个Player的实例,当在线人数很多时,将产生大量实例(如百万级)
解决方案:定义类的slots属性,它时用来声明实例属性名字的列表。
交互模式下看到p1和p2的属性,p1比p2使用的内存多,为什么呢,通过对比发现,属性多了__dict__
和__weakref__
p1中的
p1.__dict__
中是一个为实例动态绑定属性的字典也可以直接往字典中给添加、删除属性
这种动态绑定属性是以牺牲内存为代价的
我们可以导入sys模块查看占用字节数
所以,在创建对象的时候提前使用
__slots__
提前声明好了所需的属性,就可以达到节省内存的目的