简体   繁体   中英

What is the (memory-wise and access-time-wise) comparison of Python's __slots__ and dataclasses

Python's __slots__ serve to lessen the memory footprint of instances, and this is achieved by storing variables in "small fixed-sized array[s], much like a tuple or a list". Instance attributes are mutable, but you cannot add additional attributes.

On the other hand, there are dataclasses which (from what I gathered) help with class creation by defining some dunders (etc), and are characterized by PEP 557 as "mutable namedtuples with defaults".

I understand their purposes are different, and that you can in fact use both of them .

The dataclass decorator does not affect how attributes are stored or retrieved. Memory consumption and attribute access times will behave exactly as if the class was written without dataclass .

A class that uses __slots__ will have less memory consumption and slightly faster attribute access (because slot descriptors save a few dict lookups) than a similar class that does not use __slots__ , regardless of whether either class uses dataclass . Here's a timing example, showing that dataclass doesn't affect attribute lookup times, while __slots__ does:

>>> 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM