Python >> Tutoriel Python >  >> Python

python:classe vs tuple surcharge de mémoire énorme (?)

Comme d'autres l'ont dit dans leurs réponses, vous devrez générer différents objets pour que la comparaison ait un sens.

Alors, comparons quelques approches.

tuple

l = [(i, i) for i in range(10000000)]
# memory taken by Python3: 1.0 GB

class Person

class Person:
    def __init__(self, first, last):
        self.first = first
        self.last = last

l = [Person(i, i) for i in range(10000000)]
# memory: 2.0 GB

namedtuple (tuple + __slots__ )

from collections import namedtuple
Person = namedtuple('Person', 'first last')

l = [Person(i, i) for i in range(10000000)]
# memory: 1.1 GB

namedtuple est essentiellement une classe qui étend tuple et utilise __slots__ pour tous les champs nommés, mais il ajoute des getters de champs et d'autres méthodes d'assistance (vous pouvez voir le code exact généré s'il est appelé avec verbose=True ).

class Person + __slots__

class Person:
    __slots__ = ['first', 'last']
    def __init__(self, first, last):
        self.first = first
        self.last = last

l = [Person(i, i) for i in range(10000000)]
# memory: 0.9 GB

Ceci est une version allégée de namedtuple au dessus. Un gagnant clair, encore meilleur que les tuples purs.


Utilisation de __slots__ diminue un peu l'empreinte mémoire (de 1,7 Go à 625 Mo dans mon test), puisque chaque instance n'a plus besoin de contenir un dict pour stocker les attributs.

class Person:
    __slots__ = ['first', 'last']
    def __init__(self, first, last):
        self.first = first
        self.last = last

L'inconvénient est que vous ne pouvez plus ajouter d'attributs à une instance après sa création; la classe ne fournit de la mémoire que pour les attributs listés dans le __slots__ attribut.


Il existe encore un autre moyen de réduire la quantité de mémoire occupée par les objets en désactivant la prise en charge de la récupération de place cyclique en plus de désactiver __dict__ et __weakref__ . Il est implémenté dans la bibliothèque recordclass :

$ pip install recordclass

>>> import sys
>>> from recordclass import dataobject, make_dataclass

Créez la classe :

class Person(dataobject):
   first:str
   last:str

ou

>>> Person = make_dataclass('Person', 'first last')

Résultat :

>>> print(sys.getsizeof(Person(100,100)))
32

Pour __slot__ basée sur la classe que nous avons :

class Person:
    __slots__ = ['first', 'last']
    def __init__(self, first, last):
        self.first = first
        self.last = last

>>> print(sys.getsizeof(Person(100,100)))
64

En conséquence, une plus grande économie de mémoire est possible.

Pour dataobject -basé :

l = [Person(i, i) for i in range(10000000)]
memory size: 681 Mb

Pour __slots__ -basé :

  l = [Person(i, i) for i in range(10000000)]
  memory size: 921 Mb