使用字典字面量和字典构造函数之间有区别吗?

使用PyCharm,我注意到它提供了转换dict文字:

d = {
'one': '1',
'two': '2',
}

< / p >

转换为dict类型构造函数:

d = dict(one='1', two='2')

< / p >

这些不同的方法是否在某些重要的方面有所不同?

(在写这个问题时,我注意到使用dict()似乎不可能指定一个数字键..d = {1: 'one', 2: 'two'}是可能的,但是,显然,dict(1='one' ...)不是。还有别的事吗?)

158473 次浏览

我想你已经指出了最明显的区别。除此之外,

第一个不需要查找dict,这应该会让它更快一点

第二个在locals()中查找dict,然后在globals()中查找内置,所以你可以通过定义一个名为dict的局部来切换行为,例如,尽管我想不出除了调试时之外的任何地方这将是一个好主意

这两种方法生成的字典完全相同,只是,正如您所注意到的,Python的词法规则有影响。

字典字面量是更明显的字典,您可以创建任何类型的键,但您需要引用键名。另一方面,如果你出于某种原因需要,你可以使用变量作为键:

a = "hello"
d = {
a: 'hi'
}

dict()构造函数提供了更大的灵活性,因为它采用多种形式的输入。例如,您可以为它提供一个对迭代器,它将把它们视为键/值对。

我不知道为什么PyCharm会提供将一种形式转换为另一种形式。

它们在Python 3.2中看起来基本相同。

正如gnibbler指出的那样,第一个不需要查找dict,这应该会使它更快一点。

>>> def literal():
...   d = {'one': 1, 'two': 2}
...
>>> def constructor():
...   d = dict(one='1', two='2')
...
>>> import dis
>>> dis.dis(literal)
2           0 BUILD_MAP                2
3 LOAD_CONST               1 (1)
6 LOAD_CONST               2 ('one')
9 STORE_MAP
10 LOAD_CONST               3 (2)
13 LOAD_CONST               4 ('two')
16 STORE_MAP
17 STORE_FAST               0 (d)
20 LOAD_CONST               0 (None)
23 RETURN_VALUE
>>> dis.dis(constructor)
2           0 LOAD_GLOBAL              0 (dict)
3 LOAD_CONST               1 ('one')
6 LOAD_CONST               2 ('1')
9 LOAD_CONST               3 ('two')
12 LOAD_CONST               4 ('2')
15 CALL_FUNCTION          512
18 STORE_FAST               0 (d)
21 LOAD_CONST               0 (None)
24 RETURN_VALUE

来自python 2.7教程:

一对花括号创建一个空对象 字典:{}。放置一个 以逗号分隔的键:值列表 对括号内添加初始值 键:值对到字典; 这也是字典的方式

tel = {'jack': 4098, 'sape': 4139}
data = {k:v for k,v in zip(xrange(10), xrange(10,20))}

而:

构建dict()构造函数 字典直接从列表 键值对存储为元组。当 这些对形成了一个模式,列表 推导式可以紧凑地指定 键值列表。

tel = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127}
data = dict((k,v) for k,v in zip(xrange(10), xrange(10,20)))

当键是简单字符串时,它 有时更容易指定对吗 使用关键字参数:

dict(sape=4139, guido=4127, jack=4098)
>>>  {'sape': 4139, 'jack':4098, 'guido': 4127}

因此,{}和dict()都生成字典,但提供的字典数据初始化方式略有不同。

Literal更快,因为它使用优化的BUILD_MAP和STORE_MAP操作码,而不是通用的CALL_FUNCTION:

> python2.7 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.958 usec per loop


> python2.7 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.479 usec per loop


> python3.2 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.975 usec per loop


> python3.2 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.409 usec per loop

我发现字典文字d = {'one': '1'}更具可读性,你的定义数据,而不是为事物分配值并将它们发送给dict()构造函数。

另一方面,我看到有人将字典文本错误地输入为d = {'one', '1'},这在现代python 2.7+中将创建一个集合。

尽管如此,我仍然更喜欢使用集合文字,因为我认为它更可读,我认为个人偏好。

python 3.4 + pycharm的一个重大区别是dict()构造函数

.如果键的数量超过256,则产生“语法错误”消息

我现在更喜欢使用字典字面。

当你从其他东西复制粘贴值时,dict()文字很好(非python) 例如,环境变量列表。 如果您有一个bash文件,输入

FOO='bar'
CABBAGE='good'

你可以很容易地将其粘贴到dict()文本中并添加注释。它也使它更容易做相反的事情,复制到其他东西。而{'FOO': 'bar'}语法对于python和json来说是非常独特的。因此,如果你经常使用json,你可能想要使用双引号的{}字面量。

还要考虑这样一个事实:与运算符匹配的令牌不能在构造函数语法中使用,即dasherized key。

>>> dict(foo-bar=1)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression


>>> {'foo-bar': 1}
{'foo-bar': 1}

没有字典文字来创建字典继承类,自定义字典类与额外的方法。在这种情况下,应该使用自定义dict类构造函数,例如:

class NestedDict(dict):


# ... skipped


state_type_map = NestedDict(**{
'owns': 'Another',
'uses': 'Another',
})

这是一个非常晚的聚会,但如果你有一个kwargs函数:

def foo(a=None, b=None):
...

你的飞溅dict像这样:

d_1 = { 'a': 1, 'b': 2 }
d_2 = dict(a=1, b=2)


# This works
foo(**d_1)


# And this as well
foo(**d_2)

但是d_2可能更适合重构在你的foo签名中可能会改变的参数名。因为在d_1中它们是字符串。

此外,当涉及到阅读代码时(这是很多),我觉得文字的认知负担更小(因为我们把文字联系为不那么“活跃”的东西)。而不是说dict(),它看起来像一个函数调用,让大脑怀疑…与dict()相比,至少有一微秒:)),不可否认,部分原因是编辑器中的语法高亮显示,但在日常生活中仍然非常相关(至少对我来说)。

如果我关注以...表示的dict语句周围的代码,文字dict使我更容易理解周围的代码:)。

...
...
...
config = {
'key1':"value1",
'key2':"value2",
'key3':"value3",
'key4':"value4",
}
...
...
...


#****VS *****


...
...
...
config =dict(
key1 = 'value1',
key2 = 'value2',
key3 = 'value3',
key4 = 'value4',


)
...
...
...