类对象特殊属性__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