web-dev-qa-db-fra.com

La méthode clear () du dictionnaire supprime-t-elle tous les objets liés aux éléments de la mémoire?

Si un dictionnaire contient des objets modifiables ou des objets de classes personnalisées (par exemple un ensemble de requêtes, ou même un DateTime), l'appel de clear() sur le dictionnaire supprimera-t-il ces objets de la mémoire? Se comporte-t-il différemment que de parcourir le dict et de del les supprimer?

par exemple. considérer

class MyClass(object):
    '''Test Class.'''

my_obj_1 = MyClass()
my_obj_2 = MyClass()

my_dict = { 'foo' : my_obj_1, 'bar' : my_obj_2 }

alors c'est

my_dict.clear()

pareil que

for key in my_dict.keys():
    del my_dict[key]

?

23
0xc0de

documentation Python sur les dict indique que del d[key] Supprime d[key] Du dictionnaire tandis que d.clear() supprime chaque clé, donc fondamentalement leur comportement est le même.

Sur le problème de mémoire, dans Python lorsque vous "supprimez", vous supprimez essentiellement une référence à un objet. Lorsqu'un objet n'est référencé par aucune variable ni aucun autre objet ou devient inaccessible, il devient ordures et peut être supprimé de la mémoire. Python a un garbage collector qui de temps en temps il fait ce travail pour vérifier quels objets sont des ordures et libère la mémoire qui leur est allouée. Si l'objet que vous supprimez du dictionnaire est référencé par une autre variable alors il est toujours accessible, donc ce n'est pas des ordures donc il a gagné " t être supprimé. Je vous laisse ici quelques liens si vous êtes intéressé à lire sur la collecte des ordures en général et la collecte des ordures de python en particulier.

45

Il y a en fait une très petite différence entre les deux. clear() libérera la mémoire du hashset utilisé dans le dict, tandis que le retrait de la clé ne le sera pas.

a = dict.fromkeys(range(1000))

In [10]: sys.getsizeof(a)
Out[10]: 49432

In [11]: a.clear()

In [12]: sys.getsizeof(a)
Out[12]: 280

In [13]: a = dict.fromkeys(range(1000))

In [14]: for i in range(1000):
   ....:     del a[i]
   ....:     

In [15]: sys.getsizeof(a)
Out[15]: 49432
5
317070

Se comporte-t-il différemment que de parcourir le dict et de del les supprimer?

Il convient de noter ici que toute classe personnalisée implémentant la classe de base abstraite MutableMapping obtient clear() comme méthode de mixage "gratuite".

Les seules méthodes que vous devez remplacer pour instancier une sous-classe MutableMapping sont:

__getitem__, __setitem__, __delitem__, __iter__, __len__

Comme vous pouvez stocker les données dans votre classe de mappage comme vous le souhaitez, la seule façon dont clear() peut comprendre comment effacer réellement vos données consiste à utiliser une ou plusieurs de ces cinq méthodes. Maintenant, vous pourriez avoir une idée des méthodes que clear() utilise, mais pourquoi deviner quand nous pouvons expérimenter?

import collections

class MyMap(collections.MutableMapping):
    def __init__(self, mydict):
        self._top_secret_data = mydict

    def __getitem__(self, key):
        print 'getitem'
        return self._top_secret_data[key]

    def __setitem__(self, key, value):
        raise Exception('where did you want that?')

    def __len__(self):
        raise Exception('a gentleman never tells')

    def __delitem__(self, key):
        print '[shredding intensifies]'
        del self._top_secret_data[key]

    def __iter__(self):
        def keygen():
            for key in self._top_secret_data:
                print 'faster! faster!'
                yield key
        return iter(keygen())

En utilisant la classe définie ci-dessus, il est facile de voir comment clear() est implémenté:

>>> m = MyMap({1:'a', 2:'b', 3:'c'})
>>> m.clear()
faster! faster!
getitem
[shredding intensifies]
faster! faster!
getitem
[shredding intensifies]
faster! faster!
getitem
[shredding intensifies]
>>> 

En d'autres termes, la méthode mixin clear() est fondamentalement implémentée comme for key in self: del self[key].

Désormais, un avertissement: les types intégrés tels que dict sont implémentés en C, donc la méthode dict.clear Peut ne pas être littéralement identique à for key in mydict: del mydict[key]. Je m'attendrais à une optimisation dans les coulisses, peut-être une stratégie complètement différente - mais j'espère que cet exemple vous donne une idée de la façon dont vous pourriez attendre une méthode clear() pour travailler en Python.

5
Air

C'est la même chose que d'appeler del d['foo'] - il supprime simplement les entrées, mais il n'affecte pas les clés ou les valeurs elles-mêmes.

Bien sûr, ils peuvent alors devenir poubelles s'il n'y a aucune autre référence à eux.

3
Marcin

la commande del supprime la référence de l'élément particulier dans la liste, la commande clear efface toutes les paires de valeurs clés en une seule fois afin que la fonctionnalité soit la même, elles déréférencent et la tâche de repos de la supprimer de la mémoire est effectuée par le garbage collector

1
Dlucidone

Dans votre cas, les deux objets MyClass sont partagés. Ils seront toujours accessibles via le my_obj_1 et my_obj_2.

1
pepr

Avez-vous même essayé d'exécuter le code? Le code suivant avec Python 3.7 lève une exception! "RuntimeError: le dictionnaire a changé de taille pendant l'itération":

for key in my_dict.keys():
    del my_dict[key]

Toutes les réponses précédentes sont bonnes. Je voulais juste ajouter quelques points supplémentaires sur les différences de del et clear:

  1. my_dict.clear (); supprime tous les éléments du dictionnaire et le rend équivalent au dictionnaire vide. Remarque: vous pouvez toujours y ajouter des éléments si vous le souhaitez!
  2. del my_dict; rend l'objet de my_dict à supprimer et éligible à la collecte des ordures (my_dict n'est plus utilisable)! Donc, si vous essayez d'ajouter/d'accéder à un élément, vous obtiendrez des exceptions.
  3. De plus, vous avez déclaré deux variables my_obj_1 et my_obj_2; Même si vous supprimez/effacez my_dict, ces deux variables contiennent des références aux objets MyClass et ne disparaîtront pas tant que my_obj_1 et my_obj_2 ne seront pas hors de portée; donc, si les objets MyClass contiennent de la mémoire (disons une liste ou quelque chose), alors si votre intention est de libérer la mémoire en supprimant/effaçant my_dict, cela ne se produit pas!

    class MyClass (object): '' 'Test Class.' ''

    my_obj_1 = MyClass () my_obj_2 = MyClass ()

0
Soby