保存我多次使用的列表的长度是否更好?

时间:2012-11-14 14:54:34

标签: python list

我知道内联,并且从我检查过的内容不是由Python的编译器完成的。

我的问题是:是否对python的编译器进行了任何优化:

print myList.__len__()
for i in range(0, myList.__len__()):
    print i + myList.__len__()

l = myList.__len__()
print l
for i in range(0, l):
    print i + l

它是由编译器完成的吗? 如果不是:我自己这样做是否值得?

奖金问题(不那么相关):我喜欢有很多功能(更好的可读性恕我直言)...就像Python中没有内联这样可以避免(很多功能)?

2 个答案:

答案 0 :(得分:6)

不,没有。您可以使用dis模块将代码编译为字节码来检查Python的功能:

>>> def test():
...     print myList.__len__()
...     for i in range(0, myList.__len__()):
...         print i + myList.__len__()
... 
>>> import dis
>>> dis.dis(test)
  2           0 LOAD_GLOBAL              0 (myList)
              3 LOAD_ATTR                1 (__len__)
              6 CALL_FUNCTION            0
              9 PRINT_ITEM          
             10 PRINT_NEWLINE       

  3          11 SETUP_LOOP              44 (to 58)
             14 LOAD_GLOBAL              2 (range)
             17 LOAD_CONST               1 (0)
             20 LOAD_GLOBAL              0 (myList)
             23 LOAD_ATTR                1 (__len__)
             26 CALL_FUNCTION            0
             29 CALL_FUNCTION            2
             32 GET_ITER            
        >>   33 FOR_ITER                21 (to 57)
             36 STORE_FAST               0 (i)

  4          39 LOAD_FAST                0 (i)
             42 LOAD_GLOBAL              0 (myList)
             45 LOAD_ATTR                1 (__len__)
             48 CALL_FUNCTION            0
             51 BINARY_ADD          
             52 PRINT_ITEM          
             53 PRINT_NEWLINE       
             54 JUMP_ABSOLUTE           33
        >>   57 POP_BLOCK           
        >>   58 LOAD_CONST               0 (None)
             61 RETURN_VALUE        

如您所见,每次都会查找并调用__len__属性。

Python无法知道给定方法在调用之间返回什么,__len__方法也不例外。如果python试图通过假设来优化它,那么返回的值在调用之间是相同的,你会遇到无数不同的问题,我们甚至都没有尝试使用多线程。

请注意,使用len(myList)会更好,而不是直接调用__len__()挂钩:

print len(myList)
for i in xrange(len(myList):
    print i + len(myList)

答案 1 :(得分:1)

不,您询问的优化不是由CPython编译器完成的。事实上,CPython编译器几乎没有做任何优化。

要亲眼看看,import dis并使用您正在询问的代码反汇编函数:dis.dis(func)

未优化的原因是,下次访问属性(即使像__len__这样的方法)完全可能是一个完全不同的对象。当然,这很少发生,但Python支持它。

属性访问确实消耗时间,因此存储对将要重复使用的属性的引用(尤其是在局部变量中)可以使代码运行得更快。但是,它降低了可读性,所以我要等到你知道给定的代码片段在应用它之前是一个瓶颈。在您的情况下,打印所花费的时间很容易超过属性访问。

归根结底,如果性能最重要的话,你首先要使用的不是Python,不是吗?