动态添加属性的问题
通过前面的学习中我们知道, 由于 pytyon 的动态语言的特性, 我们可以动态的给对象添加属性和方法.
但是这种方式添加的属性和方法, 只在当前对象上有用, 在其他对象上是没用.
class A:
pass
a1 = A()
a1.name = "李四" #给 a1 对象添加一个属性
print(a1.name)
a2 = A()
print(a2.name) # a2中没有 name 属性, 所以抛异常
__slot__
的基本使用
添加属性和方法最好直接在类中添加, 这样所有的对象都可以拥有了.
如果我想避免把某些属性直接添加到实例对象上, 可以使用一个特殊属性:__slot__
类实现.
给__slot__
定义一个元组, 则元组内的属性名允许在实例对象上直接添加, 其他的都不允许.
class A:
__slots__ = ("name", )
a1 = A()
a1.name = "李四" # 给 a1 对象添加一个属性 name 属性是允许的
print(a1.name)
a1.age = 20 # age 不允许, 所以抛异常
print(a1.age)
注意:
我们的
__init__()
中添加属性是在self
上添加的, 其实也是直接在对象上添加, 所以没有在元组中的属性名, 也是不允许的.对于我们直接在类中添加方法是没有任何的影响的.
class A:
__slots__ = ("name",)
def __init__(self):
self.age = 30 # 也是不允许的
a = A()
继承中的__slot__
__slot__
只对当前类有用, 对他的子类不起作用. 所以子类也要有自己的__slot__
class A:
__slots__ = ("name",)
def __init__(self):
self.age = 30 # 也是不允许的
class B(A):
def __init__(self):
self.age = 30 # 子类是允许的
b = B()
print(b.age)
__slot__
对性能上的提升
一些人把__slot__
作为一种安全的特性来实现, 然后实际上他对内存和执行速度上的性能优化才是最重要的.
不使用__slot__
, python 使用字典的方式去存储实例数据的, 如果一个程序使用大量的实例, 则内存占用和执行效率都会影响比较大.
使用__slot__
后, python 存储实例数据的时候, 不再使用字典, 而是使用一种更加高效的基于数组的数据结构. 可以显著减少内存占用和执行时间.