2012-01-17 54 views
11

我已經嘗試在python中創建類似語句的開關,而不是使用大量的if語句。在Python中切換

的代碼看起來是這樣的:

def findStuff(cds): 
    L=[] 
    c=0 
    for i in range(0, len(cds), 3): 
     a=differencesTo(cds[i:i+3]) 
     result = { 
      a[2][0]==1: c=i+1, 
      a[2][1]==1: c=i+2, 
      a[2][2]==1: c=i+3, 
      a[1]==1: L.append((cds[i:i+3], a[0], c)) 
     } 
    return L 

我的問題是,這是行不通的。 (與if語句一起工作,但這在我看來會更漂亮)。

我在Python中找到了一些開關的例子,他們遵循這個結構。誰能幫我?

+7

到底是什麼這就意味着做?!?! (它可能失敗,因爲'list.append'返回'None'並且修改了原始列表。) – katrielalex

+7

請告訴我你打電話給這個「更漂亮」的時候開玩笑吧... – NPE

+0

可讀代碼是非常漂亮的代碼。不要擔心這一點,使用if語句... –

回答

18

(一)我看不出有什麼問題,如果... ELIF ......否則

(B)我認爲蟒蛇不具備同樣的原因,Smalltalk中沒有switch語句:它幾乎完全是多餘的,並且在您想要切換類型的情況下,可以爲您的類添加適當的方法;同樣開啓數值應該在很大程度上是多餘的。

備註:我在評論中得知,無論Guido沒有創建交換機的原因,首先要添加交換機的PEP都被拒絕,因爲支持添加這樣的語句非常有限。請參閱:http://www.python.org/dev/peps/pep-3103/

(c)如果您確實需要切換行爲,請使用散列表(dict)來存儲可調用對象。其結構是:

switch_dict = { 
    Foo: self.doFoo, 
    Bar: self.doBar, 
    } 

func = switch_dict[switch_var] 
result = func() # or if they take args, pass args 
+0

,我認爲這就是算法要做的事情......但是沒有做到。 – tito

+7

這個。 Python沒有按設計*開關語句。 – Doches

+0

@Doches:是否有任何文件記錄選擇的原因?我有興趣知道這是否是我的猜測。 – Marcin

0

我不知道你已經發現這樣做哪些文章,但是這是真的很亂:整個結果文辭將始終評估,而不是僅做部分工作(作爲開關/如果這樣做),你會每次做完整個工作。 (即使你只使用結果的一部分)。

真的,Python中的快速開關語句是使用「如果」:

if case == 1: 
    pass 
elif case == 2: 
    pass 
elif case == 3: 
    pass 
else: 
    # default case 
    pass 
+1

字典切換是一種合法的技術,但它用於其他事情。 –

1

分配在Python是一個語句,並且不能表達的一部分。此外,以這種方式使用文字一次評估所有內容,這可能不是你想要的。只需使用if即可,使用此功能不會獲得任何可讀性。

5

這沒有什麼錯用長if

if switch == 'case0': 
    do_case0() 
elif switch == 'case1': 
    do_case1() 
elif switch == 'case2': 
    do_case2() 
... 

如果這太長篇大論,或者如果你有很多的情況下,把它們放在一個字典:

switch = {'case0': do_case0, 'case1': do_case1, 'case2': do_case2, ...} 
switch[case_variable]() 
// Alternative: 
(switch[case_variable]).__call__() 

如果你的條件有點複雜,你需要考慮一下你的數據結構。例如:

switch = {(0,21): 'never have a pension', 
      (21,50): 'might have a pension', 
      (50,65): 'definitely have a pension', 
      (65, 200): 'already collecting pension'} 
for key, value in switch: 
    if key[0] < case_var < key[1]: 
     print(value) 
0

以 「get」 方法,你可以有 「switch..case」 同樣的效果在C.

馬爾辛 - 例如:

switch_dict = { 
    Foo: self.doFoo, 
    Bar: self.doBar, 
} 

func = switch_dict.get(switch_var, self.dodefault) 
result = func() # or if they take args, pass args 
0

可以做像你想要的東西,但你不應該。這就是說,這是如何;你可以看到它如何改善事情。

您擁有它的最大問題是Python在您聲明字典時會評估一次您的測試和結果。你必須做的是讓所有條件和結果報表起作用;通過這種方式,評估被推遲到你給他們打電話。幸運的是,有一種方法可以使用lambda關鍵字爲簡單函數內聯執行此操作。其次,賦值語句不能用作Python中的一個值,因此我們的動作函數(如果相應的條件函數返回真值,則執行)必須返回一個值,用於增加c;他們不能自己分配到c

另外,字典中的項目沒有排序,因此您的測試不一定按您定義的順序執行,這意味着您可能應該使用保留順序的字典以外的其他東西,例如元組或一個列表。我假設你只想執行一個案例。

所以,在這裏我們去:

def findStuff(cds): 

    cases = [ (lambda: a[2][0] == 1, lambda: i + 1), 
       (lambda: a[2][1] == 1, lambda: i + 2), 
       (lambda: a[2][2] == 1, lambda: i + 3), 
       (lambda: a[1] == 1, lambda: L.append(cds[i:i+3], a[0], c) or 0) 
      ] 

    L=[] 
    c=0 
    for i in range(0, len(cds), 3): 
     a=differencesTo(cds[i:i+3]) 
     for condition, action in cases: 
      if condition(): 
       c += action() 
       break 
    return L 

這是比if/elif語句序列更具可讀性? Nooooooooooooo。特別是,第四種情況比它應該更難理解,因爲我們不得不依賴函數返回c的增量來修改一個完全不同的變量,然後我們必須弄清楚如何讓它返回一個0,這樣c實際上不會被修改。 Uuuuuugly。

不要這樣做。事實上,這個代碼可能不會按原樣運行,因爲我認爲它太難以測試。

-1

雖然if..else並沒有錯,但我發現「在Python中切換」仍然是一個有趣的問題陳述。在這一點上,我認爲Marcin的(不推薦)選項(c)和/或Snim2的第二個變體可以用更易讀的方式編寫。

爲此,我們可以聲明switch類,和利用__init__()宣佈我們要切換case,而__call__()幫助交出字典列出(的情況下,函數)對:

class switch(object): 
    def __init__(self, case): 
     self._case = case 

    def __call__(self, dict_): 
     try: 
      return dict_[self._case]() 
     except KeyError: 
      if 'else' in dict_: 
       return dict_['else']() 
      raise Exception('Given case wasn\'t found.') 

或者,分別,因爲只有兩個方法,其中之一是__init__()一類,是不是一個真正的類:

def switch(case): 
    def cases(dict_): 
     try: 
      return dict_[case]() 
     except KeyError: 
      if 'else' in dict_: 
       return dict_['else']() 
      raise Exception('Given case wasn\'t found.') 
    return cases 

(注:選擇一些更聰明比Exception

隨着例如

def case_a(): 
    print('hello world') 

def case_b(): 
    print('sth other than hello') 

def default(): 
    print('last resort') 

你可以叫

switch('c') ({ 
    'a': case_a, 
    'b': case_b, 
    'else': default 
}) 

其中,爲這個特殊的例子將打印

不得已

這不像C開關那樣,因爲對於不同情況沒有break,因爲每個情況只執行鍼對特定情況聲明的函數(即,隱含地總是調用break)。其次,每個案例只能列出一個將在一個案例中執行的函數。

0

這裏是另一種方法做一個開關語句lambda函數和字典

for caseVar in range(0,3): 
    answer=(lambda switch: ({ 
      0:'a', 
      1:'b', 
      2:'c', 
      }[switch]))(caseVar) 
    print("switch",answer)