2010-01-22 75 views
9

選項1:哪種風格是首選?

def f1(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    if c in d: 
    return d[c] 

    return "N/A" 

選項2:

def f2(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    try: 
    return d[c] 
    except: 
    return "N/A" 

這樣我就可以調用:

for c in ("China", "Japan"): 
    for f in (f1, f2): 
    print "%s => %s" % (c, f(c)) 

的選項,其一是確定鍵是否在目錄前手(f1),或者只是回退到例外(f2)。哪一個是首選?爲什麼?

+8

除外:是惡業。始終要具體說明你對捕捉的興趣,在這種情況下KeyError – richo 2010-01-22 02:38:24

+2

你選了一個不好的例子。明顯的答案既不涉及風格。 – Omnifarious 2010-01-22 02:47:34

回答

9

通常情況下,異常會帶來一些開銷,並且意味着真正的「例外」情況。在這種情況下,這聽起來像是執行的正常部分,而不是「特殊」或「錯誤」狀態。

一般來說,我認爲你的代碼會受益於使用「if/else」約定,並且只在真正需要時才保存異常。

+2

這讓我想起了「你認爲的代碼」,「事情做得更好」。所以我將其標記爲答案。 – 2010-01-22 03:14:04

+0

當你說Exceptions帶有開銷時,你可能是正確的,但是python風格是'它比請求寬容'更好。這意味着你不檢查是否有東西存在。你試着去做,然後請求原諒。如果是我,我會用'try/except'去掉 – 2010-01-24 18:08:35

+2

這是一個好點的jeffjose。在Python中嘗試一下並看看有什麼作用是很明智的。但是,如果我們不期望任何異常情況,在這種情況下使用try/except子句並不是一個好主意。像里科說:「業障」。:-) – 2010-01-26 01:39:11

21

都不是,我會去

def f2(c): 
    d = { 
    "USA": "N.Y.", 
    "China": "Shanghai" 
    } 

    return d.get(c, "N/A") 

這種方式是短,「GET」是專爲工作。

另外一個除了沒有明確的例外是不好的實踐,所以使用except KeyError:不只是除外。

異常在Python中沒有太多開銷。如果沒有更好的選擇,或者有時甚至保存屬性查找(使用而不是hasattr),通常使用它們會更好。

編輯:清除關於例外的一般觀點。

paxdiablo在總體上是正確的。 Python主要是爲了「更容易請求原諒然後允許」,即嘗試然後看看什麼失敗(例外),然後「看看你跳躍」看看有什麼,然後應用。這是因爲Python中的屬性查找可能很昂貴,所以再次調用相同的東西(檢查邊界)會浪費資源。不過,python中的內部函數通常會有更好的幫助者,所以最好使用它們。

+0

這個問題不是特定的字典,它主要是爲了展覽。我想知道的是先檢查邊界或撤退到異常。 – 2010-01-22 02:38:24

+1

@Dyno:那麼你應該問*那*。一個好的經驗法則是「最好是要求寬恕而不是允許」,但我會補充說,如果常見的情況會導致很多人要求寬恕,那麼你應該首先要求寬恕。 – 2010-01-22 02:57:55

+0

你的意思是「只是做」。如果出問題了,那麼以後再處理? – 2010-01-22 03:00:23

7

都不是。

return d.get(c, 'N/A') 
11

總體而言(不一定是Python的),我更願意在所有的 「嘗試 - 當時告訴-ME-IF-IT-去-錯」 的方法(例外),但最簡單的情況。這是因爲,在線程環境或數據庫訪問期間,基礎數據可能在密鑰檢查和值提取之間發生變化。

如果你沒有改變當前線程之外的關聯數組,那麼你可以執行「check-first-then-extract」方法。

但這是一般情況。在這裏,特別是,你可以使用get方法,它允許你如果鍵不存在,指定一個默認:

return d.get (c, "N/A") 

我會澄清我在第一段說。在底層數據在檢查和使用之間可能發生變化的情況下,您應該總是使用使用異常類型操作(除非您有一個不會導致問題的操作,例如上面提到的d.get())。例如,考慮以下兩個線程時間線:

+------------------------------+--------------------+ 
| Thread1      | Thread2   | 
+------------------------------+--------------------+ 
| Check is NY exists as a key. |     | 
|        | Delete NY key/val. | 
| Extract value for NY.  |     | 
+------------------------------+--------------------+ 

當線程1嘗試提取值時,它會得到一個異常,所以你可能會爲的可能性,以及剛剛代碼刪除初始檢查。

關於數據庫的評論也是相關的,因爲這是底層數據可能改變的另一種情況。這就是爲什麼我傾向於更喜歡原子SQL(在可能的情況下),而不是像獲取一個鍵列表然後用單個語句處理它們。

+0

我總是打電話給他們。它更容易請求寬恕然後許可「和」在你跳躍之前「分別。但是我同意在python寬恕之後是你的。 – 2010-01-22 02:36:15

+0

我傾向於把這個和jweede的標記作爲答案,但是看起來這是不可行的。 – 2010-01-22 03:08:00

4

我與大衛就是在這一個:

def f2(c): 
    d = { 
     "USA": "N.Y.", 
     "China": "Shanghai" 
     } 

    return d.get(c, "N/A") 

...正是我怎麼會寫。

爲了解決您的其他選項:

在「F1()」,沒有什麼不對的,本身,而是字典有幾乎這個確切的使用情況下,get()方法:「從得到這個字典,如果它不在那裏,請改用其他的東西「。這就是你的代碼所說的,使用get()只是更簡潔。

在'f2()'中,使用'except'本身就是這樣,並且此外,對於異常的迴應,您並沒有做任何有用的事情 - 在您的情況下,調用代碼永遠不會知道有一個例外。那麼爲什麼使用這個構造,如果它沒有爲你的函數或調用它的代碼增加值呢?

1

我看到使用「get」的人,這是我推薦的。但是,如果在未來出現類似情況發現自己,抓住你的意思是例外:

try: 
    return d[k] 
except KeyError: 
    return "N/A" 

這樣,其他異常(包括KeyboardInterrupt)不被逮住。你幾乎不會想要趕上KeyboardInterrupt

0

我同意在這種情況下,dict.get是最好的解決方案。

一般而言,我認爲您的選擇取決於例外的可能性。如果你期望密鑰查找大部分通過,那麼try/catch是更好的選擇。同樣,如果他們經常失敗,那麼if語句更好。

在Python中,異常與屬性查找的性能並沒有太大差異,所以我更擔心使用異常/先行後看的邏輯而不是性能方面。

相關問題