用 Python 實現簡單的 switch/case 語句
在Python中是沒有Switch / Case語句的,很多人認為這種語句不夠優雅靈活,在Python中用字典來處理多條件匹配問題字典會更簡單高效,對於有一定經驗的Python玩家不得不承認,的確如此。
但今天我們還是來看看如果一定要用Python來Switch / Case,可以怎麼玩。
語法約束
我們先定義一下Switch/Case應該怎麼表達,為了簡單我們可以讓它長成這樣。
def cn(): print('cn') def us(): print('us') switch(lang).case('cn',cn) .case('us',us) .default(us)
類實現一
通過以上約束,我們可以把switch當成一個類來實現,傳入的引數在建構函式裡處理,然後再分別實現case和default方法即可。
class switch(object): def __init__(self, case_path): self.switch_to = case_path self._invoked = False def case(self, key, method): if self.switch_to == key and not self._invoked: self._invoked = True method() return self def default(self, method): if not self._invoked: self._invoked = True method()
在建構函式中我們記住了case_path
和執行狀態_invoked
,在case()
裡如果當前的key
和switch_to
匹配並且函式沒有被執行過,那麼就更新_invoked
並執行對應的方法。在default()
裡檢查一下_invoked
,如果從沒執行過,那麼就呼叫default
分支的函式。
看上去還不錯,我們來試用一下。
switch('cn').case('cn',cn).case('us',us).default(fail) >>> cn switch('us').case('cn',cn).case('us',us).default(fail) >>> cn switch('jp').case('cn',cn).case('us',us).default(fail) >>> fail switch('cn').case('cn',cn).case('us',us) >>> cn
讓我們來看幾個奇葩一點的case。
# duplicate case
switch('us').case('us',cn).case('us',us).default(fail)
>>> cn
def cn() return 'cn'
def us() return 'us'
# return value
result = switch('cn').case('cn',cn).case('us',us)
result
>>> <python_switch_case.switch object at 0x11034fb70>
發現了沒有,上面的實現不會處理重複的case,當然你可以加強一下case方法,最好是丟擲異常,其他程式語言通常都這樣做。
第二個問題,你希望從case裡拿到返回值,像上面的寫法是沒希望了,因為扔掉了。我們可以考慮在switch類里加一個result的變數來儲存執行結果。
class switch(object):
def __init__(self, case_path):
...
self.result = None
def case(self, key, method):
...
self.result = method()
...
在呼叫結束後,就可以通過result
拿到結果了。
_ = switch('cn').case('cn',cn).case('us',us)
_.result
>>> cn
類實現二
我大概在網上搜了一下,你還可以參考Brian Beck通過類來實現Swich/Case。
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
"""Return the match method once, then stop"""
yield self.match
raise StopIteration
def match(self, *args):
"""Indicate whether or not to enter a case suite"""
if self.fall or not args:
return True
elif self.value in args:
self.fall = True
return True
else:
return False
c = 'z'
for case in switch(c):
if case('a'): pass # only necessary if the rest of the suite is empty
if case('c'): pass
# ...
if case('y'): pass
if case('z'):
print("c is lowercase!")
break
if case('A'): pass
# ...
if case('Z'):
print("c is uppercase!")
break
if case(): # default
print("I dunno what c was!")
這種實現相對複雜一點,而且用起來也不是很舒服,又需要for又需要if(還不如直接if/else痛快)。當然也有好處,就是可以把相同結果的case放一起,而且case裡可以寫更多東西,不僅僅是一個方法名。
寫在最後
最後我們還是回到Python推崇的方法來處理switch/case問題,一般我們可以通過字典來處理這種多分支的問題,舉例說明。
MAPPING = {
'cn': cn,
'us': us
}
lang = 'cn'
result = MAPPING.get(lang, default=us)
是不是一目瞭然,不僅易於閱讀也易於維護。在字典中key是唯一的,value可以是任意型別的資料,可以是類或者是方法,所以足夠靈活。
關於作者:Toby Qin, Python 技術愛好者,目前從事測試開發相關工作,轉載請註明原文出處。