Разница между dict.clear () и назначением {} в Python

В python есть ли разница между вызовом clear()и назначением {}словаря? Если да, что это? Пример:

d = {"stuff":"things"}
d.clear()   #this way
d = {}      #vs this way

15.12.2008 22:23:18
Интересно, имеет ли это значение в части сбора мусора. Я чувствую, что .clear () должен быть лучше для системы памяти.
Xavier Nicollet 15.11.2018 09:19:45
8 ОТВЕТОВ
РЕШЕНИЕ

Если у вас есть другая переменная, также ссылающаяся на тот же словарь, есть большая разница:

>>> d = {"stuff": "things"}
>>> d2 = d
>>> d = {}
>>> d2
{'stuff': 'things'}
>>> d = {"stuff": "things"}
>>> d2 = d
>>> d.clear()
>>> d2
{}

Это связано с тем, что назначение d = {}создает новый пустой словарь и присваивает его dпеременной. Это оставляет d2указание на старый словарь с предметами, все еще в нем. Однако, d.clear()очищает и тот же словарь , что dи d2как точку.

279
15.12.2008 22:30:29
Спасибо. Это имеет смысл. Я все еще должен привыкнуть к мышлению, которое = создает ссылки в python ...
Marcin 15.12.2008 22:33:59
= копирует ссылки на имена. В Python нет переменных, только объекты и имена.
tzot 16.12.2008 01:43:19
Хотя ваше утверждение «без переменных» педантически верно, здесь оно не очень полезно. Пока в документации по языку Python все еще говорится о «переменных», я все еще буду использовать термин: docs.python.org/reference/datamodel.html
Greg Hewgill 16.12.2008 09:34:24
Я нашел комментарий tzot полезным для корректировки моего мышления об именах, переменных и типах копий. Называть это педантичным может быть вашим мнением, но я считаю, что это несправедливо суровое суждение.
cfwschmidt 7.07.2014 20:16:09
Также clear () не уничтожает удаленный объект в dict, на который может ссылаться кто-то еще.
Lorenzo Belli 26.01.2017 10:09:14

d = {}создаст новый экземпляр для, dно все другие ссылки будут по-прежнему указывать на старое содержимое. d.clear()сбросит содержимое, но все ссылки на один и тот же экземпляр будут по-прежнему правильными.

30
25.11.2015 10:23:43

В дополнение к различиям, упомянутым в других ответах, есть также разница в скорости. d = {} более чем в два раза быстрее:

python -m timeit -s "d = {}" "for i in xrange(500000): d.clear()"
10 loops, best of 3: 127 msec per loop

python -m timeit -s "d = {}" "for i in xrange(500000): d = {}"
10 loops, best of 3: 53.6 msec per loop
21
16.12.2008 11:31:10
Это не совсем правильный тест скорости для всех случаев, так как dict пуст. Я думаю, что создание большого dict (или, по крайней мере, некоторого контента) приведет к гораздо меньшей разнице в производительности ... плюс я подозреваю, что сборщик мусора может добавить немного собственного вреда к d = {} (?)
Rafe 3.07.2013 16:43:18
@Rafe: Я думаю, что смысл в том, что если мы знаем, что никакая другая переменная не указывает на словарь d, то установка d = {}должна быть более быстрой, поскольку очистка целого может быть оставлена ​​для сборщика мусора на потом.
ViFI 23.11.2016 22:37:35

В качестве иллюстрации для вещей, уже упомянутых ранее:

>>> a = {1:2}
>>> id(a)
3073677212L
>>> a.clear()
>>> id(a)
3073677212L
>>> a = {}
>>> id(a)
3073675716L
7
8.12.2011 08:34:25
Это показывает, что .clearизменяет объект, но `= {}` создает новый объект.
wizzwizz4 14.04.2017 16:39:11

В дополнение к ответу @odano, кажется, использовать d.clear()быстрее, если вы хотите очистить голос много раз.

import timeit

p1 = ''' 
d = {}
for i in xrange(1000):
    d[i] = i * i
for j in xrange(100):
    d = {}
    for i in xrange(1000):
        d[i] = i * i
'''

p2 = ''' 
d = {}
for i in xrange(1000):
    d[i] = i * i
for j in xrange(100):
    d.clear()
    for i in xrange(1000):
        d[i] = i * i
'''

print timeit.timeit(p1, number=1000)
print timeit.timeit(p2, number=1000)

Результат:

20.0367929935
19.6444659233
7
25.12.2012 08:41:33
Я не уверен, что разница значима. В любом случае, на моей машине результаты противоположные!
Aristide 15.02.2016 18:53:15

Одна вещь, не упомянутая, является вопросами определения объема. Не хороший пример, но вот случай, когда я столкнулся с проблемой:

def conf_decorator(dec):
    """Enables behavior like this:
        @threaded
        def f(): ...

        or

        @threaded(thread=KThread)
        def f(): ...

        (assuming threaded is wrapped with this function.)
        Sends any accumulated kwargs to threaded.
        """
    c_kwargs = {}
    @wraps(dec)
    def wrapped(f=None, **kwargs):
        if f:
            r = dec(f, **c_kwargs)
            c_kwargs = {}
            return r
        else:
            c_kwargs.update(kwargs) #<- UnboundLocalError: local variable 'c_kwargs' referenced before assignment
            return wrapped
    return wrapped

Решение состоит в том, чтобы заменить c_kwargs = {}сc_kwargs.clear()

Если кто-то придумает более практичный пример, не стесняйтесь редактировать этот пост.

4
26.08.2013 01:53:11
global c_kwargsвероятно, тоже будет работать нет? Хотя, вероятно, globalэто не лучшая вещь для использования.
fantabolous 4.07.2014 05:45:08
Использование @fantabolous globalприведет к тому, что функция будет вести себя по-разному - все вызовы conf_decorator будут совместно использовать одну и ту же переменную c_kwargs. Я считаю, что Python 3 добавил nonlocalключевое слово для решения этой проблемы, и это будет работать.
Ponkadoodle 4.07.2014 05:54:14

Методы мутации всегда полезны, если исходный объект не находится в области видимости:

def fun(d):
    d.clear()
    d["b"] = 2

d={"a": 2}
fun(d)
d          # {'b': 2}

Повторное назначение словаря создаст новый объект и не изменит исходный.

7
25.11.2015 10:27:12

Кроме того, иногда экземпляр dict может быть подклассом dict ( defaultdictнапример). В этом случае использование clearявляется предпочтительным, так как нам не нужно запоминать точный тип dict, а также избегать дублирования кода (связывание строки очистки с линией инициализации).

x = defaultdict(list)
x[1].append(2)
...
x.clear() # instead of the longer x = defaultdict(list)
1
3.07.2017 11:47:11