__ slots__ allow us to explicitly declare data members (like properties) and deny the creation of __ dict__ and __ weakref__ (unless explicitly declared in __ slots__ or available in a parent.)
The space saved over using __ dict__ can be significant.
object.__ slots__
This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. __ slots__ reserves space for the declared variables and prevents the automatic creation of __ dict__ and __ weakref__ for each instance.
由于这种方法创建的实例没有属性字典, 因此无法创建在slots变量规定以外的属性.例如:
class Tests1:
__slots__ = ['name', 'age']
def shit(self):
print('shit')
t1 = Tests1()
print(Tests1.__dict__) # 类字典依然存在
t1.name = 'sabi'
#t1.gender = 'male' # 不可新增属性
#print(t1.__dict__) # 实例属性字典不存在
print(t1.name)
#result
{'__module__': '__main__', '__slots__': ['name', 'age'], 'shit': <function Tests1.shit at 0x0000022ABA3E99D8>, 'age': <member 'age' of 'Tests1' objects>, 'name': <member 'name' of 'Tests1' objects>, '__doc__': None}
sabi
class Tests1:
__slots__ = ['name', 'age']
def __init__(self, height):
self.height = height # 不在slots中实例无法初始化
•When inheriting from a class without __ slots__, the __ dict__ and __ weakref__ attribute of the instances will always be accessible.
实例:
class Test0:
def ppt(self):
print('ppt')
class Tests1(Test0):
__slots__ = ['name', 'age']
def shit(self):
print('shit')
t1 = Tests1()
print(Tests1.__dict__)
t1.name = 'sabi'
t1.gender = 'male'
print(t1.__dict__)
print(t1.name)
#result
{'__module__': '__main__', '__slots__': ['name', 'age'], 'shit': <function Tests1.shit at 0x000002C69A999A60>, 'age': <member 'age' of 'Tests1' objects>, 'name': <member 'name' of 'Tests1' objects>, '__doc__': None}
{'gender': 'male'}
sabi
•The action of a slots declaration is not limited to the class where it is defined. slots declared in parents are available in child classes. However, child subclasses will get a dict and weakref unless they also define slots (which should only contain names of any additional slots).
实例:
class Tests1:
__slots__ = ['name', 'age']
def shit(self):
print('shit')
class Test2(Tests1):
height = '175'
t2 = Test2()
t2.name = 'sabi2' # 属性name并没有被加入字典,而是存在slots中
t2.gender = 'male' # 属性gender被加入属性字典
print(t2.__dict__) # 但子类有属性字典
print(t2.__slots__) # 子类可继承父类的slots属性
•If a class defines a slot also defined in a base class, the instance variable defined by the base class slot is inaccessible (except by retrieving its descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this.
•如果类定义了也在基类中定义的槽,则基类槽定义的实例变量不可访问(除非直接从基类检索其描述符)。 这使得程序的含义未定义。 将来,可能会添加一项检查以防止这种情况发生。
class Tests1:
__slots__ = ['name', 'age']
def shit(self):
print('shit')
class Test2(Tests1):
__slots__ = ['a123','b456', 'age']
height = '175'
t2 = Test2()
t2.name = 'sabi2' # 但依然可以指定父类的slots值
t2.age = '28'
print(t2.__slots__) # 只寻找自己的slot
print(t2.name, t2.age)
#result
['a123', 'b456', 'age']
sabi2 28
1)•Nonempty __ slots__ does not work for classes derived from “variable-length” built-in types such as int, bytes and tuple.
•非空__ slots__不适用于从“可变长度”内置类型派生的类,如int,bytes和tuple
2)•Any non-string iterable may be assigned to __ slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.
•可以将任何非字符串的可迭代对象分配给__ slots__。 也可以使用映射; 但是,将来可以为与每个键对应的值分配特殊含义。
3)__ class__ assignment works only if both classes have the same __ slots__.
__class__赋值仅在两个类具有相同__slots__时有效。
3)实例:
class Test0:
__slots__ = ['abc','def']
def ppt(self):
print('ppt')
class Tests1:
__slots__ = ['abc','def']
age = '222'
t1 = Tests1()
print(t1.__class__)
t1.__class__ = Test0
print(t1.__class__)
#result
<class '__main__.Tests1'>
<class '__main__.Test0'>
4)•Multiple inheritance with multiple slotted parent classes can be used, but only one parent is allowed to have attributes created by slots (the other bases must have empty slot layouts) - violations raise TypeError.
具有多slots的父类的多继承也可以使用,但只有一个父类允许有slots创建的属性,其他父类必须时空的slots, 否则会引起TypeError.
4)实例:
class Test0:
__slots__ = ['abc','def']
def ppt(self):
print('ppt')
class Tests1:
__slots__ = []
def shit(self):
print('shit')
class Test2(Tests1,Test0):
# __slots__ = ['a123','b456', 'age']
height = '175'
t2 = Test2()
t2.abc = 'fuck'
print(t2.__slots__)
#result
[]
5)•Without a __ dict__ variable, instances cannot be assigned new variables not listed in the __ slots__ definition. Attempts to assign to an unlisted variable name raises AttributeError. If dynamic assignment of new variables is desired, then add ‘__ dict__’ to the sequence of strings in the __ slots__ declaration.
•如果没有__ dict__变量,则无法为实例分配__ slots__定义中未列出的新变量。 尝试分配slots中没有变量名称会引发AttributeError。 如果需要动态分配新变量,则将“__ dict__”添加到__ slots__声明中的字符串序列中。
6)•Without a __ weakref__ variable for each instance, classes defining __ slots__ do not support weak references to its instances. If weak reference support is needed, then add ‘__ weakref__’ to the sequence of strings in the __ slots__ declaration.
•如果没有每个实例的__ werefref__变量,则定义__ slots__的类不支持对其实例的弱引用。 如果需要弱引用支持,则将“__ weakref__”添加到__ slots__声明中的字符串序列。
6)__ slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __ slots__; otherwise, the class attribute would overwrite the descriptor assignment.
__ slots__是通过为每个变量名创建描述符(实现描述符)在类级别实现的。 因此,类属性不能用于为__ slots__定义的实例变量设置默认值; 否则,class属性将覆盖描述符赋值。