switch的python實現

dwzb發表於2019-03-04

本文首發於知乎

我們知道,python是沒有switch語句的,所以當我們要實現這樣結構的邏輯時:

var index = 10

switch index {
   case 100  :
      print( "index 的值為 100")
   case 10,15  :
      print( "index 的值為 10 或 15")
   case 5  :
      print( "index 的值為 5")
   default :
      print( "預設 case")
}
複製程式碼

經常需要用多個if-else來實現。除此之外,我們還可以考慮用字典對應提取的方式來實現,下面我們給出四種實現switch的方法,並對比這四種方法的執行時間

something = `something`

# 第一種,多次使用if-else結構
if something == `this`:
    the_thing = 1
elif something == `that`:
    the_thing = 2
elif something == `there`:
    the_thing = 3
else:
    the_thing = 4
    
# 第二種,用get設定預設值的字典提取
options = {`this`: 1, `that`: 2, `there`: 3}
the_thing = options.get(something, 4)

# 第三種,用if-else配合不設定預設值的字典提取
options = {`this`: 1, `that`: 2, `there`: 3}
if something in options:
    the_thing = options[something]
else:
    the_thing = 4
    
# 第四種,用collections模組設定預設值進行字典提取
from collections import defaultdict
default_options = defaultdict(lambda: 4, {`this`: 1, `that`: 2, `there`: 3})
the_thing = default_options[something]
複製程式碼

下面我們對比一下這幾種方式提取的速度,分成兩種情況

  • 判斷的內容在字典中
  • 判斷的內容不在字典中

在ifelse.py檔案中輸入如下內容

import time
from collections import defaultdict

# 計算執行時間的裝飾器
def run_time(func):
    def wrapper(*args, **kw):
        start = time.time()
        func(*args, **kw)
        end = time.time()
        print(`running`, end-start, `s`)
    return wrapper

# 準備好兩個字典
options = {`this`: 1, `that`: 2, `there`: 3}
default_options = defaultdict(lambda: 4, {`this`: 1, `that`: 2, `there`: 3})


# 四種方法都定義成函式
# 接受引數something即待判斷值
# 每次迴圈10000000次
@run_time
def first(something):
    for i in range(10000000):
        if something == `this`:
            the_thing = 1
        elif something == `that`:
            the_thing = 2
        elif something == `there`:
            the_thing = 3
        else:
            the_thing = 4

@run_time
def second(something):
    for i in range(10000000):
        the_thing = options.get(something, 4)


@run_time
def third(something):
    for i in range(10000000):
        if something in options:
            the_thing = options[something]
        else:
            the_thing = 4

@run_time
def forth(something):
    for i in range(10000000):
        the_thing = default_options[something]

# 呼叫函式
if __name__ == `__main__`:
	# 判斷的內容不在字典中
	first(`something`)
	second(`something`)
	third(`something`)
	forth(`something`)
	print(`-`*20)
	# 判斷的內容在字典中
	first(`this`)
	second(`this`)
	third(`this`)
	forth(`this`)
複製程式碼

在命令列多次執行

python ifelse.py
複製程式碼

得到結果如下

-------------第一次---------------
running 1.8487958908081055 s
running 1.63755202293396 s
running 0.7807505130767822 s
running 0.6786513328552246 s
--------------------
running 0.7807483673095703 s
running 2.075996160507202 s
running 1.0349910259246826 s
running 0.740731954574585 s

-------------第二次---------------

running 1.7757258415222168 s
running 1.6395549774169922 s
running 0.8408102989196777 s
running 0.7977871894836426 s
--------------------
running 0.710662841796875 s
running 1.9098539352416992 s
running 1.042982578277588 s
running 0.8197875022888184 s

-------------第三次---------------

running 1.5885050296783447 s
running 1.8237719535827637 s
running 0.9819226264953613 s
running 0.78375244140625 s
--------------------
running 0.6226155757904053 s
running 1.634549617767334 s
running 0.947911262512207 s
running 0.6586313247680664 s
複製程式碼

從結果中可以看出
1.四種方法之間的對比,後兩種方法明顯比前兩種方法快,且最後一種方法總是最快的。
2.待判斷內容是否在字典中設定的對比

  • 第一種全程if-else判斷的情況下,早判斷出來程式就會早結束,所以if-else判斷的內容順序是有講究的
  • 而從字典裡提取則沒有看出顯著的不同

由於使用collections模組中的defaultdict雖然最快,但是會佔用較多記憶體,所以最推薦的是第三種方法,使用if-else配合無預設字典提取方法。

參考stackoverflow上的這篇回答

歡迎關注我的知乎專欄

專欄主頁:python程式設計

專欄目錄:目錄

版本說明:軟體及包版本說明

相關文章