【发布时间】:2011-08-13 01:09:54
【问题描述】:
我知道它们本质上是一样的,但就样式而言,哪个更好(更 Pythonic)用于创建空列表或字典?
【问题讨论】:
标签: python performance list dictionary
我知道它们本质上是一样的,但就样式而言,哪个更好(更 Pythonic)用于创建空列表或字典?
【问题讨论】:
标签: python performance list dictionary
在速度方面,空列表/字典没有竞争力:
>>> from timeit import timeit
>>> timeit("[]")
0.040084982867934334
>>> timeit("list()")
0.17704233359267718
>>> timeit("{}")
0.033620194745424214
>>> timeit("dict()")
0.1821558326547077
对于非空:
>>> timeit("[1,2,3]")
0.24316302770330367
>>> timeit("list((1,2,3))")
0.44744206316727286
>>> timeit("list(foo)", setup="foo=(1,2,3)")
0.446036018543964
>>> timeit("{'a':1, 'b':2, 'c':3}")
0.20868602015059423
>>> timeit("dict(a=1, b=2, c=3)")
0.47635635255323905
>>> timeit("dict(bar)", setup="bar=[('a', 1), ('b', 2), ('c', 3)]")
0.9028228448029267
此外,使用方括号表示法可以让您使用列表和字典推导,这可能就足够了。
【讨论】:
list(i for i in range(10) if i % 2)
timeit() 函数报告执行指定迭代次数的总时间,默认为1000000。所以上面的例子是运行代码 sn -p 一百万次的秒数。例如timeit('dict()', number=1) // -> 4.0531158447265625e-06(一次迭代)而timeit('dict()') // -> 0.12412905693054199(一百万次迭代)
在我看来,[] 和 {} 是创建空列表/字典的最 Pythonic 和可读性最强的方法。
请注意set(),例如:
this_set = {5}
some_other_set = {}
可能会令人困惑。第一个创建一个包含一个元素的集合,第二个创建一个空 dict 并且 not 一个集合。
【讨论】:
{} 总是创建一个空字典。 {1,2,3} 在 2.7+ 中创建了一个集合,但在 2.6 和旧版本中是一个语法错误。
some_epic_set 的变量,它指向一个空的dict 对象……它不是一个空集。对于空集,您需要使用set()。
{5} 创建一个包含一个元素的集合是一个常见的陷阱,5 和{} 是一个空字典。
{*()} 以文字语法创建一个空的set。我称它为独眼猴操作员。 :-)
dict 字面量可能tiny 快一点,因为它的字节码更短:
In [1]: import dis
In [2]: a = lambda: {}
In [3]: b = lambda: dict()
In [4]: dis.dis(a)
1 0 BUILD_MAP 0
3 RETURN_VALUE
In [5]: dis.dis(b)
1 0 LOAD_GLOBAL 0 (dict)
3 CALL_FUNCTION 0
6 RETURN_VALUE
同样适用于list 与 []
【讨论】:
CALL_FUNCTION 花费的时间至少与BUILD_MAP 一样多(被调用的函数本质上是BUILD_MAP),而LOAD_GLOBAL 花费的时间只是额外的开销。
注意list() 和[] 的工作方式不同:
>>> def a(p):
... print(id(p))
...
>>> for r in range(3):
... a([])
...
139969725291904
139969725291904
139969725291904
>>> for r in range(3):
... a(list())
...
139969725367296
139969725367552
139969725367616
list() 总是在堆上创建一个新对象,但[] 在许多情况下可以重用内存单元。
【讨论】:
恕我直言,使用 list() 和 dict() 会使您的 Python 看起来像 C。呃。
【讨论】:
在 [] 和 list() 之间的区别的情况下,有一个我没有看到其他人指出的陷阱。 如果你使用字典作为列表的成员,两者会给出完全不同的结果:
In [1]: foo_dict = {"1":"foo", "2":"bar"}
In [2]: [foo_dict]
Out [2]: [{'1': 'foo', '2': 'bar'}]
In [3]: list(foo_dict)
Out [3]: ['1', '2']
【讨论】:
list((foo_dict,))可以得到与[foo_dict]相同的结果。 list() 方法接受一个可迭代对象作为它的唯一参数,并对其进行迭代以将元素添加到列表中。这将通过执行list(some_list) 导致类似的陷阱,这将使列表变平。
list() 和 [] 之间没有这样的区别,但是如果将它与迭代器一起使用,它会给我们:
nums = [1,2,3,4,5,6,7,8]
在:打印([iter(nums)])
输出:[
在:打印(list(iter(nums)))
输出:[1、2、3、4、5、6、7、8]
【讨论】:
list() 和[] 之间没有任何人提及的区别在于,list() 会将例如元组转换为列表。而[] 会将所述元组放入列表中:
a_tuple = (1, 2, 3, 4)
test_list = list(a_tuple) # returns [1, 2, 3, 4]
test_brackets = [a_tuple] # returns [(1, 2, 3, 4)]
【讨论】:
[] 和 list() 之间的行为有一个区别,如下例所示。如果我们想要返回数字列表,我们需要使用 list() ,否则我们会得到一个地图对象!不过不知道怎么解释。
sth = [(1,2), (3,4),(5,6)]
sth2 = map(lambda x: x[1], sth)
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>
sth2 = [map(lambda x: x[1], sth)]
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>
type(sth2) # list
type(sth2[0]) # map
sth2 = list(map(lambda x: x[1], sth))
print(sth2) #[2, 4, 6]
type(sth2) # list
type(sth2[0]) # int
【讨论】:
方括号对表示列表对象或索引下标之一,如my_List[x]。
花括号对表示字典对象。
a_list = ['on', 'off', 1, 2]
a_dict = { on: 1, off: 2 }
【讨论】:
大多数时候这主要是一个选择问题。这是一个偏好问题。
但是请注意,例如,如果您有数字键,则不能这样做:
mydict = dict(1="foo", 2="bar")
你必须这样做:
mydict = {"1":"foo", "2":"bar"}
【讨论】:
mydict = {1:"foo", 2:"bar"}(不带引号的键)。