Python-类对象特殊属性__slots__

  1. 类对象特殊属性__slots__

类对象特殊属性__slots__

python是动态语言,所以,在创建对象之后,可以对其动态的绑定属性和方法。

如果想要对实例对象动态绑定的属性和方法的名称进行限制,可以在其对应的类对象中定义特殊属性__slots__,并给__slots__赋值一个所有元素都为字符串的列表或元组,这样,对实例对象动态绑定的属性和方法的名称就只能来自于__slots__中的元素。

#!/usr/bin/python3

class MyClass(object):
    __slots__ = ['attr', 'func']


mc = MyClass()


mc.attr = 'attr'
#mc.attr1 = 'attr1'                            # AttributeError: 'MyClass' object has no attribute 'attr1' 

print(mc.attr)
#print(mc.attr1)

def func():
    pass

def func1():
    pass

from types import MethodType

mc.func = MethodType(func, mc)

#mc.func1 = MethodType(func1, mc)              # AttributeError: 'MyClass' object has no attribute 'func1'
[root@lyucan ~]# ./31.py
attr

默认情况下,访问实例对象的属性时通过访问该实例对象的特殊属性__dict__来实现的。例如:访问“obj.x”其实访问的是obj.__dict__['x']
在类对象中定义了特殊属性__slots__后,其实例对象就不会再创建特殊属性__dict__了,而是为每个属性创建一个描述器,访问属性时就会直接调用这个描述器。调用描述器比访问__dict__要快,因此,在类对象中定义特殊属性__slots__可以提高属性的访问速度。
此外,在类对象中定义了特殊属性__slots__后,由于其实例对象不再创建特殊属性__dict__,同时,特殊属性__dict__是一个字典,字典的本质是哈希表,是一种用空间换时间的数据结构,因此,在类对象中定义特殊属性__slots__可以减少内存消耗。

#!/usr/bin/python3

class MyClass(object):
    pass


class MyClass1(object):
    __slots__ = ['attr', 'func']



print(MyClass().__dict__)
print(MyClass1().__dict__)
[root@lyucan ~]# ./31.py
{}                              # 没有__slots__属性
Traceback (most recent call last):
  File "./31.py", line 13, in <module>
    print(MyClass1().__dict__)
AttributeError: 'MyClass1' object has no attribute '__dict__'         # 有__slots__属性,就没有__dict__方法了

特殊属性__slots__只对其所在类对象的实例对象起作用,对其所在子类的实例对象是不起作用的。

如果父类定义了__slots__,但是子类没有定义__slots__,那么:

  • 父类的实例对象可以动态绑定的属性和方法的名称只有父类的__slots__
  • 子类的实例对象没有限制
#!/usr/bin/python3

class ParentClass(object):
    __slots__ = ['attr']

class ChildClass(ParentClass):
    pass


pc = ParentClass()
cc = ChildClass()

cc.attr1 = 'attr1'                   # 父类的__slots__的属性不会影响子类,因此可以绑定属性attr1
print(cc.attr1)

pc.attr1 = 'attr1'                   # 父类不能绑定__slots__之外的属性,因此不能绑定属性attr1
print(pc.attr1)
[root@lyucan ~]# ./31.py
attr1
Traceback (most recent call last):
  File "./31.py", line 16, in <module>
    pc.attr1 = 'attr1'
AttributeError: 'ParentClass' object has no attribute 'attr1'

如果父类子类都定义了特殊属性__slots__,那么:

  • 父类的实例对象可以动态绑定的属性和方法的名称只有父类的__slots__
  • 子类的实例对象可以动态绑定的属性和方法的名称为父类的__slots__加上子类的__slots__
#!/usr/bin/python3

class ParentClass(object):
    __slots__ = ['attr1']

class ChildClass(ParentClass):
    __slots__ = ['attr2']


pc = ParentClass()
cc = ChildClass()

# 父类
pc.attr1 = 'attr1'       # 绑定成功
pc.attr2 = 'attr2'       # 绑定失败
pc.attr3 = 'attr3'       # 绑定失败

# 子类
cc.attr1 = 'attr1'       # 绑定成功
cc.attr2 = 'attr2'       # 绑定成功
cc.attr3 = 'attr3'       # 绑定失败

如果父类没有定义特殊属性__slots__,但是子类定义了__slots__,那么:

  • 父类和子类都不会被限制。
#!/usr/bin/python3

class ParentClass(object):
    pass

class ChildClass(ParentClass):
    __slots__ = ['attr2']


pc = ParentClass()
cc = ChildClass()

pc.attr1 = 'attr1'                   # 绑定成功
pc.attr2 = 'attr2'                   # 绑定成功
pc.attr3 = 'attr3'                   # 绑定成功
print(pc.attr1, pc.attr2, pc.attr3)

cc.attr1 = 'attr1'                   # 绑定成功
cc.attr2 = 'attr2'                   # 绑定成功
cc.attr3 = 'attr3'                   # 绑定成功
print(cc.attr1, cc.attr2, cc.attr3)
[root@lyucan ~]# ./31.py
attr1 attr2 attr3
attr1 attr2 attr3

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 289211569@qq.com