dict()和{}有什么区别?


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只是做一个空字典。发生的事情Python解释器的幕后当我这样做d = {}d = dict()?是做同一件事的两种简单方法吗?使用是否{}有的附加通话dict()?一个系统的开销(甚至可以忽略)是否比另一个系统大?虽然这个问题确实完全不重要,但我很想回答这个问题。


1
我发现的解释更加清晰的位置:doughellmann.com/blog/2012/11/12/...
theBuzzyCoder

Answers:


75
>>> 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。:)


1
不幸的是,没有人会g因为CALL_FUNCTION 512...而告诉你背后的原因
本杰明·图格

4
看看这个漂亮的文章由Doug赫尔曼:doughellmann.com/2012/11/12/...
ezdazuzena

2
较新的python{'a' : 1, 'b' : 2}提高了效率。例如,在蟒蛇2.7.10,拆卸替换ROT_THREE; STORE_SUBSCR; DUP_TOP的指令STORE_MAP。在python 3.5.1中,它摆脱了它们的全部,只有一个BUILD_MAP
danio

41

就性能而言:

>>> from timeit import timeit
>>> timeit("a = {'a': 1, 'b': 2}")
0.424...
>>> timeit("a = dict(a = 1, b = 2)")
0.889...

对于空字典,我得到类似的结果:'x = {}'的0.1usec与'x = dict()'的0.3usec。
John Fouhy

是的 函数调用很昂贵。但是该格式具有更多用途,例如dict(zip(...
DNS

究竟。函数调用在Python中比在C语言中要贵80-100倍
。– vartec

1
充分利用文档:docs.python.org/library/timeit.html import timeit t = timeit.Timer(“ a = {'a':1,'b':2}”)t.timeit()t = timeit.Timer(“ a = dict(a = 1,b = 2)”)t.timeit()秒耗时四倍
DrFalk3n

数字越小越好吧?因此C-buildin dict()比纯Python {}慢吗?
侯曼2014年

28

@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,它的{}语法似乎根据解析时已知的存储项数来预定义哈希表的大小。


9

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


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

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


2
这不是这里发生的事情。{}仍在分配新的字典(否则会很糟糕),但是您不让它保持活动状态的事实意味着id死后可以立即重用(在打印第一个字典后立即使用)。
布赖恩(Brian)

我怀疑函数调用的行为有所不同,因为它会进一步搅动id()空间,以便在第二次调用时获得不同的id。
布赖恩(Brian)2009年

我认为mgood的回答澄清了一些事情;我已经更新了我的条目。
Jacob Gabrielson

3

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

dict( generator which yields (key,value) pairs )
dict( list of (key,value) pairs )

1
是。可以使用的情况{…}应该这样做,因为它比对dict()构造函数的调用更为直接和快捷(在Python中,函数调用非常昂贵,为什么调用仅返回可以通过{…}语法直接构建的函数的函数?) 。
Eric O Lebigot

它已经在Python 2中运行了很长时间了。
Eric O Lebigot

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

1
不知道您的意思是“大声笑”还是“ bug”。请提供对此问题的某种评论或解释,因为此问题已在8年前得到了回答,这会使菜鸟感到困惑不解
Chris Schaller

-1

为了创建一个空集,我们应该在它之前使用关键字set,即set()创建一个空集,如字典中那样,只有花括号才能创建一个空字典。

让我们举个例子

print isinstance({},dict) 
True 
print isinstance({},set) 
False 
print isinstance(set(),set) 
True
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.