首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python列表-理解和多次引用一个对象

Python列表-理解和多次引用一个对象
EN

Stack Overflow用户
提问于 2012-07-02 19:16:58
回答 3查看 319关注 0票数 2

这是一个人为设计的示例,用于演示在for循环和列表理解中多次引用相同的字典项。首先,for循环:

代码语言:javascript
复制
dict_index_mylists = {0:['a', 'b', 'c'], 1:['b', 'c', 'a'], 2:['c', 'a', 'b']}

# for-loop
myseq = []
for i in [0, 1, 2]:
    interim = dict_index_mylists[i]
    if interim[0] == 'b' or interim[1] == 'c' or interim[2] == 'a':    
        myseq.append(interim)

在for循环中,从字典对象引用临时列表,然后在if条件中多次引用临时列表,这在字典非常大和/或存储的情况下可能更有意义。不过,“临时”引用可能不必要,因为Python字典针对性能进行了优化。

这是对for循环的列表理解:

代码语言:javascript
复制
# list-comprehension
myseq = [dict_index_mylists[i] for i in [0, 1, 2] if dict_index_mylists[i][0] == 'b' or dict_index_mylists[i][1] == 'c' or dict_index_mylists[i][2] == 'a']

问题是:

a.列表理解是多次引用字典条目,还是引用并保留一个本地“临时”列表来处理?

b.在字典非常大的情况下,在同一字典项上包含多个条件句的最佳列表理解表达式是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-07-02 20:34:47

您似乎只问了通用子表达式的优化。在您的列表理解中,它将多次索引到字典中。CPython是动态的,很难知道像Python这样的操作可能会有什么副作用,所以Python只是简单地执行您告诉它多次的操作。

其他实现,如PyPy,使用JIT并可能优化子表达式,但很难提前确定它将做什么。

如果您非常关心性能,则需要对不同的选项进行计时,以确定哪个选项最好。

票数 1
EN

Stack Overflow用户

发布于 2012-07-02 19:42:55

我不是研究python字节码的专家,但是今天早上我尝试学习一些新的东西:

代码语言:javascript
复制
def dostuff():
    myseq = [dict_index_mylists[i] for i in [0, 1, 2] if dict_index_mylists[i][0] == 'b' or dict_index_mylists[i][1] == 'c' or dict_index_mylists[i][2] == 'a']

import dis
dis.dis(dostuff)

如果您看一下输出(如下所示),就会发现有4次对LOAD_GLOBAL的调用,所以看起来python不像是在存储临时列表。至于你的第二个问题,你所拥有的可能已经是你能做的最好的了。不过,这并不像你想象的那么糟糕。dict对象通过哈希函数访问项,因此无论字典大小如何,它们的查找复杂度都是O(1)的。当然,您可以始终使用timeit并比较两种实现(使用循环和列表组件),然后选择速度更快的实现。分析(一如既往)是您的朋友。

APENDIX (dis.dis(Dostuff)的输出)

代码语言:javascript
复制
5           0 BUILD_LIST               0
            3 DUP_TOP             
            4 STORE_FAST               0 (_[1])
            7 LOAD_CONST               1 (0)
           10 LOAD_CONST               2 (1)
           13 LOAD_CONST               3 (2)
           16 BUILD_LIST               3
           19 GET_ITER            
      >>   20 FOR_ITER                84 (to 107)
           23 STORE_FAST               1 (i)
           26 LOAD_GLOBAL              0 (dict_index_mylists)
           29 LOAD_FAST                1 (i)
           32 BINARY_SUBSCR       
           33 LOAD_CONST               1 (0)
           36 BINARY_SUBSCR       
           37 LOAD_CONST               4 ('b')
           40 COMPARE_OP               2 (==)
           43 JUMP_IF_TRUE            42 (to 88)
           46 POP_TOP             
           47 LOAD_GLOBAL              0 (dict_index_mylists)
           50 LOAD_FAST                1 (i)
           53 BINARY_SUBSCR       
           54 LOAD_CONST               2 (1)
           57 BINARY_SUBSCR       
           58 LOAD_CONST               5 ('c')
           61 COMPARE_OP               2 (==)
           64 JUMP_IF_TRUE            21 (to 88)
           67 POP_TOP             
           68 LOAD_GLOBAL              0 (dict_index_mylists)
           71 LOAD_FAST                1 (i)
           74 BINARY_SUBSCR       
           75 LOAD_CONST               3 (2)
           78 BINARY_SUBSCR       
           79 LOAD_CONST               6 ('a')
           82 COMPARE_OP               2 (==)
           85 JUMP_IF_FALSE           15 (to 103)
      >>   88 POP_TOP             
           89 LOAD_FAST                0 (_[1])
           92 LOAD_GLOBAL              0 (dict_index_mylists)
           95 LOAD_FAST                1 (i)
           98 BINARY_SUBSCR       
           99 LIST_APPEND         
          100 JUMP_ABSOLUTE           20
      >>  103 POP_TOP             
          104 JUMP_ABSOLUTE           20
      >>  107 DELETE_FAST              0 (_[1])
          110 STORE_FAST               2 (myseq)
          113 LOAD_CONST               0 (None)
          116 RETURN_VALUE 
票数 0
EN

Stack Overflow用户

发布于 2012-07-02 19:44:03

第一点:这里没有“创建”任何东西(‘myseq’除外),既不是在forloop中,也不是在你的代码的listcomp版本中--它只是对现有dict项的引用。

现在来回答您的问题: list comp版本将进行查找(调用每个dict_index_mylists[i]表达式的dict.__getitem__。这些查找中的每一个都将返回对同一列表的引用。您可以通过保留对字典项的本地引用来避免这些额外的查找,例如:

代码语言:javascript
复制
myseq = [
    item for item in (dict_index_mylists[i] for i in (0, 1, 2)) 
    if item[0] == 'b' or item[1] == 'c' or item[2] == 'a'
    ]

但是仅仅为了编写listcomp而编写listcomp是没有意义的。

请注意,如果您不关心原始排序,并希望将其应用于整个字典,则使用dict.itervalues()会更简单。

wrt/第二个问题,“最优”不是绝对的。您希望针对什么进行优化?太空?时间?可读性?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11292578

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档