python3中使用__slots__限定实例属性操作分析

1. __slots__的作用

在Python中,类的实例可以动态地添加属性,这在某些情况下很方便,但在其他情况下,这可能是不必要的,甚至是危险的。Python提供了一种机制,即使用__slots__属性限制实例动态属性的创建。使用__slots__可以极大地减少内存的使用,提高类的运行效率。

2. __slots__的语法

在Python中,__slots__是一个特殊的类属性,它是一个由字符串组成的序列,其中每个字符串表示一个实例变量的名称。

class MyClass:

__slots__ = ['x', 'y']

上面这个例子中,MyClass类使用__slots__属性限制了它的实例可以拥有的属性只能是'x'和'y',如果试图在实例中创建其他属性,就会抛出AttributeError异常。

3. __slots__的特性

3.1 减少内存占用

在没有使用__slots__属性的情况下,每个实例对象都会有一个__dict__属性,用于存储实例的属性名和对应的值。__dict__是一个字典,会占用相当多的内存,而使用__slots__属性可以避免这个问题。

下面这个例子,使用__slots__属性和不使用__slots__属性的内存占用情况进行对比。

import sys

class A:

pass

class B:

__slots__ = ['x', 'y']

a = A()

b = B()

print(sys.getsizeof(a)) # 输出98

print(sys.getsizeof(b)) # 输出56

在上面的例子中,使用了sys.getsizeof()函数,可以查看对象占用内存的大小。可以看出,使用__slots__属性之后,B类的实例比A类的实例少了42个字节。

3.2 提高运行速度

除了减少内存占用之外,使用__slots__属性还可以提高类的运行速度。这是由于在创建实例时,Python不再需要为__dict__属性分配内存。

4. 使用__slots__的注意事项

4.1 如果定义了父类,子类也要定义__slots__

如果子类没有定义__slots__属性,那么它的实例将拥有父类中定义的所有实例变量以及__dict__属性。如果为了减少内存占用和提高运行速度而使用了__slots__属性,这样就会失去它的作用。

class A:

__slots__ = ['x', 'y']

class B(A):

pass

b = B()

b.z = 1 # 不会引发AttributeError异常

在上面的例子中,因为B类没有定义__slots__属性,所以可以在它的实例中添加一个z属性,这就打破了原来使用__slots__的限制。

因此,如果定义了父类,子类也要定义__slots__属性。

4.2 __slots__属性中不要包含__dict__属性

在使用__slots__属性时,可以指定实例变量的名称,但不能包含__dict__属性。如果包含了__dict__属性,在实例中创建任何属性都会抛出AttributeError异常。

class MyClass:

__slots__ = ['__dict__'] # 包含__dict__属性

mc = MyClass()

mc.x = 1 # 抛出AttributeError异常

在上面的例子中,因为MyClass类的__slots__属性中包含了__dict__属性,所以在实例中创建任何属性都会抛出AttributeError异常。

5. 总结

使用__slots__属性可以减少内存的占用和提高类的运行速度,但使用__slots__属性也有注意事项。在定义父类和子类时,子类也应该定义__slots__属性,而且在__slots__属性中不应该包含__dict__属性。

后端开发标签