所以我想说我想写一本字典。我们称之为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 = {}
对d = dict()
时,Python解释器幕后会发生什么?它只是两种方式来做同样的事情?使用{}
使用追加调用dict()
吗?是否有一个(甚至可以忽略不计)比另一个更多的开销?虽然这个问题真的完全不重要,但我很乐意回答这个好奇心。
答案 0 :(得分:71)
>>> 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 :(得分:37)
就性能而言:
>>> from timeit import timeit
>>> timeit("a = {'a': 1, 'b': 2}")
0.424...
>>> timeit("a = dict(a = 1, b = 2)")
0.889...
答案 2 :(得分:26)
@Jacob:对象的分配方式不同,但它们不是写时复制。 Python分配一个固定大小的“空闲列表”,它可以快速分配字典对象(直到它填满)。通过{}
语法(或对PyDict_New
的C调用)分配的字典可以来自此空闲列表。当字典不再被引用时,它将返回到空闲列表,并且可以重用该内存块(尽管首先重置字段)。
第一个字典立即返回到空闲列表,下一个字典将重用其内存空间:
>>> id({})
340160
>>> id({1: 2})
340160
如果您保留引用,则下一个字典将来自下一个空闲插槽:
>>> x = {}
>>> id(x)
340160
>>> id({})
340016
但我们可以删除对该词典的引用并再次释放其插槽:
>>> del x
>>> id({})
340160
由于{}
语法是在字节码中处理的,因此它可以使用上面提到的这种优化。另一方面,dict()
像常规类构造函数一样处理,Python使用通用内存分配器,它不遵循上面的空闲列表这样容易预测的模式。
另外,从Python 2.6查看compile.c,使用{}
语法,它似乎根据它存储的项目数量预先调整哈希表的大小,这在分析时已知。
答案 3 :(得分:8)
基本上,{}是语法,在语言和字节码级别上处理。 dict()只是另一种具有更灵活的初始化语法的内置函数。请注意,dict()仅添加在2.x系列的中间。
答案 4 :(得分:6)
更新:感谢您的回复。删除了关于写时复制的猜测。
{}
和dict
之间的另一个区别是dict
总是分配一个新字典(即使内容是静态的),而{}
不是总是这样做(有关何时和为何,请参阅mgood's answer):
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
我并不是说你试图利用这个与否,这取决于具体情况,只是指出来。 (如果您理解操作码,也可能从disassembly明显看出。)
答案 5 :(得分:3)
当您想要从迭代中创建字典时使用dict(),例如:
dict( generator which yields (key,value) pairs )
dict( list of (key,value) pairs )
答案 6 :(得分: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
答案 7 :(得分:-1)
为了创建一个空集,我们应该在它之前使用关键字set
即set()
这会创建一个空集,其中只有花括号可以创建一个空字典
让我们来看一个例子
print isinstance({},dict)
True
print isinstance({},set)
False
print isinstance(set(),set)
True