dict()和{}有什么区别?
所以我们假设我想写一本字典。 我们会叫它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 = dict()
时候,Python解释器的幕后会发生什么? 这只是两种方式来做同样的事情吗? 使用{}
是否有额外的dict()
调用? 是否有(甚至可以忽略不计)更多的开销? 虽然这个问题实际上完全不重要,但我很乐意回答这个问题。
>>> 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
字典()显然是一些内置的C语言。 一个非常聪明或有奉献精神的人(不是我)可以看翻译的来源,并告诉你更多。 我只想炫耀dis.dis。 🙂
就performance而言:
>>> from timeit import timeit >>> timeit("a = {'a': 1, 'b': 2}") 0.424... >>> timeit("a = dict(a = 1, b = 2)") 0.889...
@Jacob:分配对象的方式有所不同,但它们不是写入时拷贝。 Python分配一个固定大小的“空闲列表”,可以快速分配字典对象(直到它填充)。 通过{}
语法分配的字典(或者对PyDict_New
的C调用)可以来自这个空闲列表。 当字典不再被引用时,它会被返回到空闲列表中,并且内存块可以被重用(尽pipe字段被首先重置)。
这第一个字典立即返回到空闲列表,下一个将重用其内存空间:
>>> id({}) 340160 >>> id({1: 2}) 340160
如果你保留一个参考,下一个字典将来自下一个空闲插槽:
>>> x = {} >>> id(x) 340160 >>> id({}) 340016
但是我们可以删除对该字典的引用并再次释放它的插槽:
>>> del x >>> id({}) 340160
由于{}
语法是在字节码中处理的,所以可以使用上面提到的优化。 另一方面, dict()
像普通的类构造函数一样处理,而Python使用通用的内存分配器,它不像上面的空闲列表那样容易预测。
另外,从Python 2.6的compile.c文件中,用{}
语法来看,它似乎是根据它在存储过程中已知的项目数量来预先设置散列表的大小。
基本上,{}是语法,在语言和字节码级别上处理。 dict()只是另一个内置的更灵活的初始化语法。 请注意,dict()仅在2.x系列的中间添加。
更新 :谢谢你的回应。 消除了关于写入复制的猜测。
{}
和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
我并不是说你试图利用这个或不是,这取决于具体的情况,只是指出来。 (如果你理解操作码, 反汇编也可能是明显的)。
当你想从一个迭代器创build一个字典时使用dict(),如:
dict( generator which yields (key,value) pairs ) dict( list of (key,value) pairs )
为了创build一个空的集合,我们应该使用之前set()
的关键字,即set()
这将创build一个空集,在字典中只有花括号可以创build一个空的字典
让我们举一个例子
print isinstance({},dict) True print isinstance({},set) False print isinstance(set(),set) True