Способствует ли метод clear() слова удалить все объекты, связанные с объектом из памяти?
Если словарь содержит измененные объекты или объекты пользовательских классов (например, набор запросов или даже DateTime), то вызывает ли clear()
в словаре удаление этих объектов из памяти?
Ведет ли он себя иначе, чем цикл через dict и del
для них?
например.
Рассмотрим
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]
?
Ответы
Ответ 1
Документация на языке python сообщает, что del d[key]
удаляет d[key]
из словаря, а d.clear()
удаляет каждый ключ, поэтому в основном их поведение то же самое.
В памяти проблема, в Python, когда вы "удаляете", вы в основном удаляете ссылку на объект. Когда объект не ссылается ни на какую переменную, ни на другой объект или не становится недоступным, он становится мусором и может быть удален из памяти. Python имеет сборщик мусора, который время от времени выполняет эту работу по проверке того, какие объекты являются мусором, и освобождает выделенную для них память.
Если объект, который вы удаляете из словаря, ссылается на другую переменную, то он по-прежнему доступен, поэтому он не является мусором, поэтому он не будет удален. Я оставляю здесь некоторые ссылки, если вы заинтересованы в том, чтобы читать сборку мусора вообще и сборку мусора python в частности.
Ответ 2
Ведет ли он себя иначе, чем цикл через dict и del
для них?
Здесь стоит отметить, что любой пользовательский класс, реализующий абстрактный базовый класс MutableMapping
, получает clear()
как "бесплатный" метод mixin.
Единственными методами, которые необходимо переопределить для создания подкласса MutableMapping
, являются:
__getitem__, __setitem__, __delitem__, __iter__, __len__
Так как вы можете хранить данные в своем классе сопоставления любым способом, единственным способом clear()
может понять, как реально очистить ваши данные, используя один или несколько из этих пяти методов. Теперь у вас может быть предположение о том, какие методы 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]
>>>
Другими словами, метод mixin clear()
в основном реализуется как for key in self: del self[key]
.
Теперь отказ от ответственности: встроенные типы, такие как dict
, реализованы на C, поэтому метод dict.clear
может быть не идентичен буквам for key in mydict: del mydict[key]
. Я бы ожидал некоторой оптимизации за кулисами, возможно, совершенно другой стратегии, но, надеюсь, этот пример дает вам некоторое представление о том, как можно ожидать, что метод clear()
будет работать в Python.
Ответ 3
На самом деле существует очень маленькая разница между ними. 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
Ответ 4
Это то же самое, что и вызов del d['foo']
- он просто удаляет записи, но не влияет на сами ключи или значения.
Конечно, они могут стать сборщиками мусора, если нет других ссылок на них.
Ответ 5
В вашем случае два объекта MyClass
являются общими. Они все равно будут доступны через my_obj_1
и my_obj_2
.
Ответ 6
команда del удаляет ссылку на конкретный элемент в списке, команда clear очищает все пары значений ключа в ходу, поэтому функциональность такая же, как и для разыменования и отдыха, задача удаления из памяти выполняется мусором коллектор
Ответ 7
Вы даже пытались запустить код? Следующий код с Python 3.7 вызывает исключение! "RuntimeError: словарь изменил размер во время итерации":
for key in my_dict.keys():
del my_dict[key]
Все предыдущие ответы хороши. Я просто хотел добавить еще пару моментов о различиях между del и clear:
- my_dict.clear(); удаляет все элементы в словаре и делает его эквивалентным пустому словарю. Примечание: вы все еще можете добавлять элементы к нему, если хотите!
- del my_dict; делает объект my_dict удаляемым и разрешает сборку мусора (my_dict больше не может использоваться)! Таким образом, если вы попытаетесь добавить/получить доступ к любому элементу, вы получите исключения.
-
Кроме того, вы объявили две переменные my_obj_1 и my_obj_2; Даже если вы удалите/очистите my_dict, эти две переменные содержат ссылки на объекты MyClass и не исчезнут, пока my_obj_1 и my_obj_2 не выйдут из области видимости; Итак, если объекты MyClass содержат память (скажем, список или что-то в этом роде), то если вы намереваетесь освободить память, удалив/очистив my_dict, этого не произойдет!
class MyClass (object): '' 'Тестовый класс.' ''
my_obj_1 = MyClass() my_obj_2 = MyClass()