try的簡單效能測試

faf4r發表於2024-08-24

# 1.測試對函式型別檢查使用捕捉異常和if先判斷方式的時間差
from timeit import timeit

def increment_lbyl(x):
    if isinstance(x, int):
        return x + 1
    elif isinstance(x, str) and x.isdigit():
        return int(x) + 1
    else:
        pass
        # raise ValueError("Invalid input")

def increment_eafp(x):
    try:
        return int(x) + 1
    except (TypeError, ValueError):
        pass
        # raise ValueError("Invalid input")

t_lbyl_75 = timeit(setup="from __main__ import increment_lbyl", stmt="increment_lbyl(75)", number=10_000_000)
t_eafp_75 = timeit(setup="from __main__ import increment_eafp", stmt="increment_eafp(75)", number=10_000_000)

print(f"lbyl_75: {t_lbyl_75:.4f} seconds")
print(f"eafp_75: {t_eafp_75:.4f} seconds")

t_lbyl_75_s = timeit(setup="from __main__ import increment_lbyl", stmt="increment_lbyl('75')", number=10_000_000)
t_eafp_75_s = timeit(setup="from __main__ import increment_eafp", stmt="increment_eafp('75')", number=10_000_000)

print(f"lbyl_'75': {t_lbyl_75:.4f} seconds")
print(f"eafp_'75': {t_eafp_75:.4f} seconds")

t_lbyl_invalid = timeit(setup="from __main__ import increment_lbyl", stmt="increment_lbyl('invalid')", number=10_000_000)
t_eafp_invalid = timeit(setup="from __main__ import increment_eafp", stmt="increment_eafp('invalid')", number=10_000_000)

print(f"lbyl_invalid: {t_lbyl_invalid:.4f} seconds")
print(f"eafp_invalid: {t_eafp_invalid:.4f} seconds")

# lbyl_75: 0.4216 seconds
# eafp_75: 0.5533 seconds
# lbyl_'75': 0.4216 seconds
# eafp_'75': 0.5533 seconds
# lbyl_invalid: 0.7271 seconds
# eafp_invalid: 5.6974 seconds

# 當前版本Python 3.11.0 可以看到使用異常捕獲方式始終比先判斷方式慢一點,可見異常捕獲會有額外的效能損耗
# 但是說實話二者差距非常小,只有異常時,異常捕獲方式明顯佔用更多時間,但也不到10倍差距
# 最重要的是,這是在1千萬次迴圈的情況下暴露出來的,實際上二者的差距非常小
# 如果基本保證函式輸入大部分是正確的,那麼使用異常捕獲方式可讀性更好、更易於維護




# 2.即使函式return了,finally也會執行,那麼會暫時保留區域性變數嗎,以及finally修改返回值內容影響返回
def f(x):
    try:
        x += 1
        return x
    finally:
        x = 0
        return x
    
print(f(0))

# amazing啊,這個函式返回的是0,去掉finally裡的return才能返回1
# 可見確實函式return後了也要執行finally,且finally甚至能重新return一個值
# 另外,finally的x=0並不會影響try裡的return。
# 我認為區域性變數x的值是被改變了的,但是執行順序上,return x中x應該已經被計算了,
# 所以finally如果沒有return的話,是不會覆蓋前面的return內容的


def g(x):
    try:
        x += '1'
        return x
    finally:
        x = '0'
        # return x
    
print(g('0'))

# 改為字串也是同理

# 檢視f函式的位元組碼
def f_bytecode(x): # 對比f函式的位元組碼
    x += 1
    return x
    
import dis
print(dis.dis(f))
print(dis.dis(f_bytecode))



def f():
    try:
        x = 1
        raise Exception
        y = 'y'
    except:
        print(x)
        # print(y)
    finally:
        x = 0
        print(x)
        # print(y)
f()

# except和finally都輸出了,說明try裡沒異常之前的內容都是真實存在的
# 但是異常之後的內容都沒有

相關文章