web-dev-qa-db-ja.com

辞書のclear()メソッドは、すべてのアイテム関連オブジェクトをメモリから削除しますか?

ディクショナリに可変オブジェクトまたはカスタムクラスのオブジェクト(クエリセット、またはDateTimeなど)が含まれている場合、ディクショナリでclear()を呼び出すと、これらのオブジェクトがメモリから削除されますか? dictをループしてdeletingすることとは異なる動作をしますか?

例えば。考える

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

my_obj_1 = MyClass()
my_obj_2 = MyClass()

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

その後です

my_dict.clear()

と同じ

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

23
0xc0de

dictsに関するPythonドキュメント は、_del d[key]_が辞書から_d[key]_を削除し、d.clear()がすべてのキーを削除するため、基本的にそれらの動作は同じであると述べています。

メモリの問題については、Python「削除」すると、基本的にオブジェクトへの参照を削除します。オブジェクトが変数や他のオブジェクトによって参照されないか、到達不能になると、garbageメモリから削除できますPythonガベージコレクターがあります随時これはこれを行いますどのオブジェクトがガベージであるかをチェックし、それらに割り当てられたメモリを解放します。辞書から削除しているオブジェクトが他の変数によって参照されている場合、それはまだ到達可能であるため、ガベージではないので削除されません。一般的なガベージコレクション、特にpythonのガベージコレクションについて読むことに興味がある場合は、ここにいくつかのリンクがあります。

45

実際には、両者には非常に小さな違いがあります。 clear()は、dictで使用されているハッシュセットのメモリを解放しますが、キーを削除しても解放されません。

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

Dictをループしてdeletingすることとは異なる動作をしますか?

ここで、MutableMapping抽象基本クラスを実装するカスタムクラスがclear()を「フリー」ミックスインメソッドとして取得することに注意してください。

MutableMappingサブクラスをインスタンス化するためにオーバーライドする必要があるメソッドは次のとおりです。

___getitem__, __setitem__, __delitem__, __iter__, __len__
_

マッピングクラスに任意の方法でデータを格納できるため、clear()が実際にデータをクリアする方法を見つける唯一の方法は、これら5つのメソッドの1つ以上を使用することです。さて、clear()が使用しているメソッドについて推測するかもしれませんが、なぜ実験できるのかを推測しますか?

_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())
_

上記で定義したクラスを使用すると、clear()の実装方法を簡単に確認できます。

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

つまり、clear() mixinメソッドは基本的に_for key in self: del self[key]_として実装されます。

免責事項:dictなどの組み込み型はCに実装されているため、_dict.clear_メソッドは文字通り_for key in mydict: del mydict[key]_と同一ではない場合があります。私は舞台裏での最適化、おそらく完全に異なる戦略を期待します-しかし、この例がexpect a clear()メソッドがPythonで動作する方法についてのアイデアを提供することを願っています。

5
Air

del d['foo']を呼び出すのと同じです。エントリを削除するだけですが、キーや値自体には影響しません。

もちろん、それらへの参照が他にない場合は、ガベージコレクタブルになる可能性があります。

3
Marcin

delコマンドはリスト内の特定の項目の参照を削除し、clearコマンドはすべてのキーと値のペアを一度にクリアします。そのため、メモリからの参照解除と残りのタスクの両方の機能はガベージコレクターによって行われます。

1
Dlucidone

あなたの場合、2つのMyClassオブジェクトは共有されます。 my_obj_1およびmy_obj_2から引き続きアクセスできます。

1
pepr

あなたもコードを実行しようとしましたか? Python 3.7で例外がスローされます!"RuntimeError:dictionary changed size during iteration"

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

以前の回答はすべて良いです。私は、delとclearの違いについてさらにいくつかのポイントを追加したかっただけです。

  1. my_dict.clear();辞書内のすべてのアイテムを削除し、空の辞書と同等にします。注:必要に応じてアイテムを追加できます!
  2. del my_dict; my_dictのオブジェクトを削除し、ガベージコレクションを有効にします(my_dictはもう使用できません)!そのため、アイテムを追加/アクセスしようとすると、例外が発生します。
  3. また、2つの変数my_obj_1とmy_obj_2を宣言しました。 my_dictを削除/クリアしても、これらの2つの変数はMyClassオブジェクトへの参照を保持しているため、my_obj_1とmy_obj_2が範囲外になるまで消えません。そのため、MyClassオブジェクトがメモリ(リストなど)を保持している場合、my_dictを削除またはクリアしてメモリを解放することを意図している場合は発生しません!

    クラスMyClass(object): '' 'テストクラス。' ''

    my_obj_1 = MyClass()my_obj_2 = MyClass()

0
Soby