2

我知道内联,并且从我检查的内容来看,它不是由 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中没有内联一样,这是要避免的事情(很多函数)?

4

2 回答 2

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)
于 2012-11-14T14:57:25.763 回答
1

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

亲自查看,import dis并使用您所询问的代码反汇编一个函数:dis.dis(func).

没有优化的原因是,一个属性(甚至是类似的方法__len__)在下次访问时完全有可能成为一个完全不同的对象。当然,这种情况很少发生,但 Python 支持它。

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

归根结底,如果性能是最重要的,那么您首先会使用 Python 以外的东西,不是吗?

于 2012-11-14T14:59:24.093 回答