__slots__节省内存空间

动态语言:可以在运行的过程中,修改代码

静态语言:编译时已经确定好代码,运行过程中不能修改

如果我们想要限制实例的属性怎么办?比如,只允许对Person实例添加name和age属性。

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性。注意:使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

__slots__的作用:

  • 指明对象可以绑定的属性,限制对象任意绑定属性
  • 节省内存空间,每个对象都有__dict__属性,该字典存放着属性与值的映射关系。使用slots可以省去这个字典

1.绑定属性

class Foo(object):
    __slots__ = ("name", "age")

    def __init__(self):
        self.name = 'book'
        self.age = 18
        self.email = '[email protected]'

foo = Foo()

输出

Traceback (most recent call last):
  File "/Users/Liang/Documents/PyProject/demo1.py", line 11, in 
    foo = Foo()
  File "/Users/Liang/Documents/PyProject/demo1.py", line 7, in __init__
    self.email = '[email protected]'
AttributeError: 'Foo' object has no attribute 'email'

2.节省内存

在默认情况下,Python的新类和旧类的实例都有一个字典__dict__来存储属性值。这对于那些没有实例属性的对象来说太浪费空间了,当需要创建大量实例的时候,这个问题变得尤为突出(Python内置的字典本质是一个哈希表,它是一种用空间换时间的数据结构。为了解决冲突的问题,当字典使用量超过2/3时,Python会根据情况进行2-4倍的扩容。由此可预见,取消__dict__的使用可以大幅减少实例的空间消耗。)。因此这种默认的做法可以通过在新式类中定义了一个__slots__属性从而得到了解决。__slots__声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量,因此没有为每个实例都创建一个字典,从而节省空间。以下是用元祖来存储实例属性,这样Python会在实例中使用类似元祖的结构存储实例变量。

class Foo1(object):
    __slots__ = ("name", "age")  # 也可以用列表存储

    def __init__(self):
        self.name = 'book'
        self.age = 18

class Foo2(object):

    def __init__(self):
        self.name = 'book'
        self.age = 18

foo1 = Foo1()
foo2 = Foo2()
print(dir(foo1))  # 没有__dict__属性
print(dir(foo2))

3.slots的副作用

  1. 每个继承的子类都要重新定义一遍__slots__
  2. 实例只能包含哪些在__slots__定义的属性,这对写程序的灵活性有影响,比如你由于某个原因新网给instance设置一个新的属性,比如instance.a = 1, 但是由于a不在__slots__里面就直接报错了,你得不断地去修改__slots__或者用其他方法迂回的解决
  3. 实例不能有弱引用(weakref)目标,否则要记得把__weakref__放进__slots__

你可能感兴趣的:(__slots__节省内存空间)