Python__slots__
用于减少实例的内存占用,这是通过将变量存储在“小型固定大小的数组 [s] 中来实现的,就像元组或列表一样”。实例属性是可变的,但您不能添加其他属性。
另一方面,有一些数据类(根据我收集的内容)通过定义一些 dunder(等)来帮助创建类,并且 PEP 557 将其描述为“具有默认值的可变命名元组”。
我了解它们的目的是不同的,实际上您可以同时使用它们。
Python__slots__
用于减少实例的内存占用,这是通过将变量存储在“小型固定大小的数组 [s] 中来实现的,就像元组或列表一样”。实例属性是可变的,但您不能添加其他属性。
另一方面,有一些数据类(根据我收集的内容)通过定义一些 dunder(等)来帮助创建类,并且 PEP 557 将其描述为“具有默认值的可变命名元组”。
我了解它们的目的是不同的,实际上您可以同时使用它们。
dataclass
装饰器不会影响属性的存储或检索方式。内存消耗和属性访问时间的行为与编写类时没有dataclass
.
与不使用的类似类相比,使用的类__slots__
将具有更少的内存消耗和稍快的属性访问(因为插槽描述符保存了一些字典查找)__slots__
,无论任何一个类是否使用dataclass
. 这是一个计时示例,显示dataclass
不影响属性查找时间,而__slots__
确实:
>>> import timeit
>>> import dataclasses
>>> @dataclasses.dataclass
... class Foo:
... a: int
... b: int
...
>>> class Bar:
... def __init__(self, a, b):
... self.a = a
... self.b = b
...
>>> foo = Foo(1, 2)
>>> bar = Bar(1, 2)
>>> timeit.timeit('foo.a', globals=globals())
0.08070236118510365
>>> timeit.timeit('bar.a', globals=globals())
0.07813134230673313
>>> timeit.timeit('foo.a', globals=globals(), number=10000000)
0.5699363159947097
>>> timeit.timeit('bar.a', globals=globals(), number=10000000)
0.5526750679127872
>>> @dataclasses.dataclass
... class FooSlots:
... __slots__ = ['a', 'b']
... a: int
... b: int
...
>>> class BarSlots:
... __slots__ = ['a', 'b']
... def __init__(self, a, b):
... self.a = a
... self.b = b
...
>>> fooslots = FooSlots(1, 2)
>>> barslots = BarSlots(1, 2)
>>> timeit.timeit('fooslots.a', globals=globals(), number=10000000)
0.46022069035097957
>>> timeit.timeit('barslots.a', globals=globals(), number=10000000)
0.4669580361805856