天天看點

Python的eval()和int()的幾點差別和性能差異

tags: Python Tips

寫在前面

今天刷幾道關于數的運算的題, 我發現了一個很匪夷所思的問題:

兩段幾乎完全一樣的代碼, 其運作時間差異怎麼會如此之大呢?(題目:​​415. 字元串相加 - 力扣(LeetCode)​​)

# 我的代碼
class Solution:
    def addStrings(self, num1: str, num2: str) -> str:
        na,nb=len(num1)-1,len(num2)-1
        add=0
        ans=''
        while na>=0 or nb>=0 or add:
            a=eval(num1[na]) if na>=0 else 0
            b=eval(num2[nb]) if nb>=0 else 0
            tmp=a+b+add
            ans+=str(tmp%10)
            add=tmp//10
            na-=1
            nb-=1
        return ans[::-1]      

下面是官方代碼:

class Solution:
    def addStrings(self, num1: str, num2: str) -> str:
        na,nb=len(num1)-1,len(num2)-1
        add=0
        ans=''
        while na>=0 or nb>=0:
            a=int(num1[na]) if na>=0 else 0
            b=int(num2[nb]) if nb>=0 else 0
            tmp=a+b+add
            ans=str(tmp%10)+ans
            add=tmp//10
            na-=1
            nb-=1
        return '1'+ans if add else ans      

乍一看沒什麼問題, 但是我的代碼就是​

​188ms​

​​, 而官方的是​

​36ms​

​, 這就很奇怪了…

分析

後來一番對比發現, 真正的罪魁禍首并不在代碼邏輯方面, 而在于一個小小的API函數​

​eval()​

​, 這個函數雖然也能将字元串轉換為整數, 但是其效率非常低…

其實從力扣的判題就能看出來了, 但是我還是想在本地試試:

from time import time 
st=time()
ans=[]
for i in range(10000000):
    ans.append(eval(str(i)))
print("ok")
print("time :", time()-st)      

上面的代碼運作時間為:​

​34.3s​

​​, 而将​

​eval​

​​換成​

​int​

​​之後程式運作時間隻有​

​3.6s​

​, 足可見其對運作效率的影響.

那麼, 到底是什麼原因導緻差異的呢?

eval()與int()比較

這裡參考了一些stack的回答​​1​​.

  1. ​int()​

    ​函數隻能對僅含有整數的字元串做處理, 而并不進行字元串的檢查, 當然, 這裡一個額外的情況如下:
In [1]: int('01')
Out[1]: 1

In [2]: eval('01')
  File <string>:1
    01
     ^
SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers      

可以看到前導零并不會影響​

​int​

​​, 但是​

​eval​

​​會首先将前導零認為是八進制數字, 這也是​

​int()​

​​和​

​eval()​

​在整數轉換時候不一樣的地方(int更勝一籌);

  1. 對于浮點數, 隻能使用​

    ​eval()​

    ​, 看下面的例子:
In [3]: int('1.1')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 int('1.1')

ValueError: invalid literal for int() with base 10: '1.1'

In [4]: eval('1.1')
Out[4]: 1.1      
  1. 在與​

    ​eval()​

    ​搭配使用​

    ​input()​

    ​的時候需要注意, 由于​

    ​eval()​

    ​會執行Python中的表達式, 那就會有下面的一個問題.

    一般的Python入門書中對于使用者輸入都是這樣寫的:

x=eval(input("Enter a number:"))      
x=eval(input("Enter a number:"))
# 此時輸入下面的内容
__import__('os').system("rm -rf *")      

ref

  1. ​​python - “eval”和“int”有什麼差別 - Stack Overflow​​; ↩︎