Python的低级性能与高级性能(回文函数的运行时分析)

Python的低级性能与高级性能(回文函数的运行时分析),python,python-2.7,Python,Python 2.7,我试图找到最有效的方法来检查给定字符串是否为回文。 首先,我尝试了运行时间为O(N)阶的蛮力。然后我对代码进行了一些优化,只进行了n/2比较,而不是n比较 代码如下: def palindrome(a): length=len(a) iterator=0 while iterator <= length/2: if a[iterator]==a[length-iterator-1]: iterator+=1 e

我试图找到最有效的方法来检查给定字符串是否为回文。
首先,我尝试了运行时间为O(N)阶的蛮力。然后我对代码进行了一些优化,只进行了n/2比较,而不是n比较

代码如下:

def palindrome(a):
    length=len(a)
    iterator=0
    while iterator <= length/2:
        if a[iterator]==a[length-iterator-1]:
            iterator+=1
        else:
            return False

    return True
def palindrome_py(a):
    return a==a[::-1]  
然后我对两者进行了运行时分析。结果如下:

我使用的代码可以在这里访问:

现在,我想知道为什么切片操作符(palindrome_py)的运行时间和回文函数之间存在差异。为什么我会得到这种类型的运行时间?
为什么切片操作符与回文函数相比效率如此之高,幕后发生了什么

我的观察-: 运行时间与乘数成正比,即乘数为2时的运行时间可通过将情况(n-1)的运行时间乘以乘数(n)ie.2得到


一般来说,我们得到运行时间(n)=运行时间(n-1)*乘数

基于切片的解决方案仍然是O(n),常数变小了(这就是乘数)。速度更快,因为用Python做的事情更少,而用C做的事情更多。字节码显示了这一切

In [1]: import dis

In [2]: %paste
def palindrome(a):
    length=len(a)
    iterator=0
    while iterator <= length/2:
        if a[iterator]==a[length-iterator-1]:
            iterator+=1
        else:
            return False

    return True

## -- End pasted text --

In [3]: dis.dis(palindrome)
  2           0 LOAD_GLOBAL              0 (len)
              3 LOAD_FAST                0 (a)
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 STORE_FAST               1 (length)

  3          12 LOAD_CONST               1 (0)
             15 STORE_FAST               2 (iterator)

  4          18 SETUP_LOOP              65 (to 86)
        >>   21 LOAD_FAST                2 (iterator)
             24 LOAD_FAST                1 (length)
             27 LOAD_CONST               2 (2)
             30 BINARY_TRUE_DIVIDE
             31 COMPARE_OP               1 (<=)
             34 POP_JUMP_IF_FALSE       85

  5          37 LOAD_FAST                0 (a)
             40 LOAD_FAST                2 (iterator)
             43 BINARY_SUBSCR
             44 LOAD_FAST                0 (a)
             47 LOAD_FAST                1 (length)
             50 LOAD_FAST                2 (iterator)
             53 BINARY_SUBTRACT
             54 LOAD_CONST               3 (1)
             57 BINARY_SUBTRACT
             58 BINARY_SUBSCR
             59 COMPARE_OP               2 (==)
             62 POP_JUMP_IF_FALSE       78

  6          65 LOAD_FAST                2 (iterator)
             68 LOAD_CONST               3 (1)
             71 INPLACE_ADD
             72 STORE_FAST               2 (iterator)
             75 JUMP_ABSOLUTE           21

  8     >>   78 LOAD_CONST               4 (False)
             81 RETURN_VALUE
             82 JUMP_ABSOLUTE           21
        >>   85 POP_BLOCK

 10     >>   86 LOAD_CONST               5 (True)
             89 RETURN_VALUE
这里没有涉及Python迭代(jumpers),您只得到3个调用(这些指令调用方法):
BUILD\u SLICE
BINARY\u SUBSCR
COMPARE\u OP
,都是用C完成的,因为
str
是一个内置类型,所有方法都是用C编写的。公平地说,我们在第一个函数中看到了相同的指令(还有更多的其他指令),但每个字符都会重复这些指令,方法调用开销乘以n。在这里,您只需支付Python函数调用开销一次,其余的用C完成


底线。你不应该手动在Python中做低级的事情,因为它的运行速度会比高级的慢(除非你有一个渐进更快的替代方案,它实际上需要低级的魔法).Python,与许多其他语言不同,大多数情况下鼓励您使用抽象,并以更高的性能奖励您。

很好的解释+1@EliKorvigo你能给我提供一些链接吗?我可以从这些链接了解更多关于反汇编程序和字节码的信息。@Divyanshu当然可以,这是我的文档
In [1]: import dis

In [2]: %paste
def palindrome(a):
    length=len(a)
    iterator=0
    while iterator <= length/2:
        if a[iterator]==a[length-iterator-1]:
            iterator+=1
        else:
            return False

    return True

## -- End pasted text --

In [3]: dis.dis(palindrome)
  2           0 LOAD_GLOBAL              0 (len)
              3 LOAD_FAST                0 (a)
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 STORE_FAST               1 (length)

  3          12 LOAD_CONST               1 (0)
             15 STORE_FAST               2 (iterator)

  4          18 SETUP_LOOP              65 (to 86)
        >>   21 LOAD_FAST                2 (iterator)
             24 LOAD_FAST                1 (length)
             27 LOAD_CONST               2 (2)
             30 BINARY_TRUE_DIVIDE
             31 COMPARE_OP               1 (<=)
             34 POP_JUMP_IF_FALSE       85

  5          37 LOAD_FAST                0 (a)
             40 LOAD_FAST                2 (iterator)
             43 BINARY_SUBSCR
             44 LOAD_FAST                0 (a)
             47 LOAD_FAST                1 (length)
             50 LOAD_FAST                2 (iterator)
             53 BINARY_SUBTRACT
             54 LOAD_CONST               3 (1)
             57 BINARY_SUBTRACT
             58 BINARY_SUBSCR
             59 COMPARE_OP               2 (==)
             62 POP_JUMP_IF_FALSE       78

  6          65 LOAD_FAST                2 (iterator)
             68 LOAD_CONST               3 (1)
             71 INPLACE_ADD
             72 STORE_FAST               2 (iterator)
             75 JUMP_ABSOLUTE           21

  8     >>   78 LOAD_CONST               4 (False)
             81 RETURN_VALUE
             82 JUMP_ABSOLUTE           21
        >>   85 POP_BLOCK

 10     >>   86 LOAD_CONST               5 (True)
             89 RETURN_VALUE
In [4]: %paste
def palindrome_py(a):
    return a==a[::-1]

## -- End pasted text --

    In [5]: dis.dis(palindrome_py)
      2           0 LOAD_FAST                0 (a)
                  3 LOAD_FAST                0 (a)
                  6 LOAD_CONST               0 (None)
                  9 LOAD_CONST               0 (None)
                 12 LOAD_CONST               2 (-1)
                 15 BUILD_SLICE              3
                 18 BINARY_SUBSCR
                 19 COMPARE_OP               2 (==)
                 22 RETURN_VALUE