【问题标题】:Difference between dict.clear() and assigning {} in PythonPython 中 dict.clear() 和分配 {} 的区别
【发布时间】:2010-09-27 01:28:08
【问题描述】:

在 python 中,调用clear() 和将{} 分配给字典有区别吗?如果是,那是什么? 示例:

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

【问题讨论】:

  • 我想知道这是否会对垃圾收集部分产生影响。我觉得 .clear() 应该对内存系统更好。

标签: python dictionary


【解决方案1】:

此外,有时 dict 实例可能是 dict 的子类(例如defaultdict)。在这种情况下,最好使用clear,因为我们不必记住dict的确切类型,也可以避免重复代码(将清除行与初始化行耦合)。

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

【讨论】:

  • 谢谢。这是一条有趣的信息。
【解决方案2】:
如果原始对象不在范围内,

变异方法总是有用的:

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

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

重新分配字典将创建一个新对象,并且不会修改原始对象。

【讨论】:

    【解决方案3】:

    d = {} 将为d 创建一个新实例,但所有其他引用仍将指向旧内容。 d.clear() 将重置内容,但对同一实例的所有引用仍然正确。

    【讨论】:

      【解决方案4】:

      没有提到的一件事是范围问题。不是一个很好的例子,但这是我遇到问题的情况:

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

      如果有人想出一个更实际的例子,请随时编辑这篇文章。

      【讨论】:

      • global c_kwargs 可能也可以工作,不是吗?虽然global 可能不是最好的使用方式。
      • @fantabolous 使用global 会使函数的行为有所不同——所有对 conf_decorator 的调用都将共享相同的 c_kwargs 变量。我相信 Python 3 添加了 nonlocal 关键字来解决这个问题,这会奏效。
      【解决方案5】:

      除了@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
      

      【讨论】:

      • 我不确定差异是否显着。无论如何,在我的机器上,结果是相反的!
      【解决方案6】:

      作为前面已经提到的事情的说明:

      >>> a = {1:2}
      >>> id(a)
      3073677212L
      >>> a.clear()
      >>> id(a)
      3073677212L
      >>> a = {}
      >>> id(a)
      3073675716L
      

      【讨论】:

      • 这表明.clear修改了对象但`= {}`创建了一个新对象。
      【解决方案7】:

      除了其他答案中提到的差异之外,还有速度差异。 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
      

      【讨论】:

      • 这并不是对所有情况都有效的速度测试,因为 dict 是空的。我认为制作一个大字典(或至少一些内容)会产生更小的性能差异......另外我怀疑垃圾收集器可能会给 d = {} (?)
      • @Rafe :我认为关键是如果我们知道没有其他变量指向字典 d,那么设置 d = {} 应该更快,因为清理整个可以留给垃圾收集器以备后用。
      【解决方案8】:

      如果你有另一个变量也引用同一个字典,那就有很大的不同了:

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

      这是因为分配d = {} 会创建一个新的空字典并将其分配给d 变量。这使得d2 指向旧字典,其中仍有项目。但是,d.clear() 清除了 dd2 都指向的同一个字典。

      【讨论】:

      • 谢谢。这是有道理的。我仍然必须习惯 = 在 python 中创建引用的心态......
      • = 复制对名称的引用。 python中没有变量,只有对象和名称。
      • 虽然您的“无变量”声明是迂腐正确的,但在这里并没有真正的帮助。只要 Python 语言文档仍然在谈论“变量”,我仍然会使用这个术语:docs.python.org/reference/datamodel.html
      • 我发现 tzot 的评论有助于调整我对名称、变量和副本类型的思考。称其为迂腐可能是您的看法,但我认为这是一个不公平的苛刻判断。
      • 另外 clear() 不会破坏 dict 中可能仍被其他人引用的已删除对象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-25
      • 2014-04-22
      • 1970-01-01
      • 2014-01-26
      • 2014-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多