70

假设我想做一本字典。我们会调用它d。但是有多种方法可以在 Python 中初始化字典!例如,我可以这样做:

d = {'hash': 'bang', 'slash': 'dot'}

或者我可以这样做:

d = dict(hash='bang', slash='dot')

或者这个,奇怪的是:

d = dict({'hash': 'bang', 'slash': 'dot'})

或这个:

d = dict([['hash', 'bang'], ['slash', 'dot']])

以及具有该dict()功能的其他多种方式。所以很明显,其中一件事dict()是语法和初始化的灵活性。但这不是我要问的。

假设我d只做一本空字典。d = {}当我做vs时,Python 解释器的幕后发生了什么d = dict()?只是做同一件事的两种方法吗?using 是否{}额外的调用dict()?一个有(甚至可以忽略不计)比另一个更多的开销?虽然这个问题真的完全不重要,但我很想回答这个问题。

4

8 回答 8

78
>>> def f():
...     return {'a' : 1, 'b' : 2}
... 
>>> def g():
...     return dict(a=1, b=2)
... 
>>> g()
{'a': 1, 'b': 2}
>>> f()
{'a': 1, 'b': 2}
>>> import dis
>>> dis.dis(f)
  2           0 BUILD_MAP                0
              3 DUP_TOP             
              4 LOAD_CONST               1 ('a')
              7 LOAD_CONST               2 (1)
             10 ROT_THREE           
             11 STORE_SUBSCR        
             12 DUP_TOP             
             13 LOAD_CONST               3 ('b')
             16 LOAD_CONST               4 (2)
             19 ROT_THREE           
             20 STORE_SUBSCR        
             21 RETURN_VALUE        
>>> dis.dis(g)
  2           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_CONST               1 ('a')
              6 LOAD_CONST               2 (1)
              9 LOAD_CONST               3 ('b')
             12 LOAD_CONST               4 (2)
             15 CALL_FUNCTION          512
             18 RETURN_VALUE        

dict() 显然是一些 C 内置的。一个非常聪明或敬业的人(不是我)可以查看解释器源并告诉您更多信息。我只是想炫耀一下dis.dis。:)

于 2009-03-19T21:25:14.607 回答
42

就性能而言:

>>> from timeit import timeit
>>> timeit("a = {'a': 1, 'b': 2}")
0.424...
>>> timeit("a = dict(a = 1, b = 2)")
0.889...
于 2009-03-19T21:41:00.827 回答
29

@Jacob:对象的分配方式有所不同,但它们不是写时复制。Python 分配一个固定大小的“空闲列表”,它可以在其中快速分配字典对象(直到填满)。{}通过语法(或 C 调用)分配的字典PyDict_New可以来自这个空闲列表。当字典不再被引用时,它会返回到空闲列表,并且可以重用该内存块(尽管首先重置字段)。

第一个字典立即返回到空闲列表,下一个将重用其内存空间:

>>> id({})
340160
>>> id({1: 2})
340160

如果你保留一个引用,下一个字典将来自下一个空闲槽:

>>> x = {}
>>> id(x)
340160
>>> id({})
340016

但是我们可以删除对该字典的引用并再次释放它的槽:

>>> del x
>>> id({})
340160

由于{}语法是在字节码中处理的,它可以使用上面提到的这种优化。另一方面,dict()它像常规类构造函数一样处理,Python 使用通用内存分配器,它不像上面的空闲列表那样遵循易于预测的模式。

此外,查看 Python 2.6 中的 compile.c,它的{}语法似乎是根据解析时已知的它存储的项目数来预先调整哈希表的大小。

于 2009-03-25T12:28:03.537 回答
9

基本上,{} 是一种语法,并在语言和字节码级别进行处理。dict() 只是另一个具有更灵活初始化语法的内置函数。请注意,dict() 仅在 2.x 系列的中间添加。

于 2009-03-19T23:15:01.613 回答
7

更新:感谢您的回复。删除了关于写时复制的猜测。

{}和之间的另一个区别dict是它dict总是分配一个新字典(即使内容是静态的),而{}并不总是这样做(参见mgood 的回答何时和为什么):

def dict1():
    return {'a':'b'}

def dict2():
    return dict(a='b')

print id(dict1()), id(dict1())
print id(dict2()), id(dict2())

产生:

$ ./mumble.py
11642752 11642752
11867168 11867456

我并不是建议您尝试利用这一点,这取决于特定情况,只是指出来。(如果您了解操作码,反汇编也可能很明显)。

于 2009-03-20T18:44:30.367 回答
3

当您想从可迭代对象创建字典时使用 dict(),例如:

dict( generator which yields (key,value) pairs )
dict( list of (key,value) pairs )
于 2011-04-29T21:50:46.820 回答
1

有趣的用法:

def func(**kwargs):
      for e in kwargs:
        print(e)
    a = 'I want to be printed'
    kwargs={a:True}
    func(**kwargs)
    a = 'I dont want to be printed'
    kwargs=dict(a=True)
    func(**kwargs)

输出:

I want to be printed
a
于 2018-02-06T14:32:34.877 回答
-1

为了创建一个空集,我们应该在它之前使用关键字 set ,即set()这会创建一个空集,其中在 dicts 中只有花括号可以创建一个空 dict

让我们举个例子

print isinstance({},dict) 
True 
print isinstance({},set) 
False 
print isinstance(set(),set) 
True
于 2016-05-31T14:30:01.837 回答