2010-09-16 19 views
6

我有一個函數按照首選項的順序返回了幾個組的隨機成員。它繼續是這樣的:除了「pass:pass」,還有一個更好的選擇嗎?

def get_random_foo_or_bar(): 
    "I'd rather have a foo than a bar." 

    if there_are_foos(): 
     return get_random_foo() 

    if there_are_bars(): 
     return get_random_bar() 

    raise IndexError, "No foos, no bars" 

然而,第一件事get_random_foo確實是驗證有FOOS併發出IndexError如果不是,那麼there_are_foos是多餘的。此外,涉及數據庫並使用單獨的函數會產生併發問題。因此,我重寫它是這樣的:

def get_random_foo_or_bar(): 
    "Still prefer foos." 

    try: 
     return get_random_foo() 
    except IndexError: 
     pass 

    try: 
     return get_random_bar() 
    except IndexError: 
     pass 

    raise IndexError, "No foos, no bars" 

但我覺得這更易讀,因爲我從來沒有理由使用pass以前感覺instictively錯誤。

有沒有更好的高效模式,還是應該學會接受pass

注:我想避免任何嵌套,因爲其他類型可能稍後添加。


編輯

感謝大家誰說,pass是罰款 - 這是令人欣慰!

也感謝那些建議用返回值None替換異常的人。我可以看到這是一種有用的模式,但我認爲在這種情況下它的語義錯誤:函數被要求執行一個不可能完成的任務,因此他們應該引發一個異常。我更願意遵循random模塊的行爲(例如,random.choice([]))。

+1

在'except'語句的使用可能是在Python中最常見的用途pass'的'。所以我會習慣它。 – 2010-09-16 02:47:21

+0

「但是我覺得這樣的可讀性差得多......它感覺在本質上是錯誤的」 - 把它看作是一個文化問題。現在看起來很奇怪,但它是使用該語言的最乾淨的方式。 – detly 2010-09-16 04:47:18

回答

13

這正是我如何寫它。這很簡單,它很有意義。我認爲聲明沒有問題。

如果您想減少重複次數,並且您預計會添加未來類型,則可以將其轉換爲循環。然後你可以改變pass的功能等同continue聲明,如果這更令人高興的眼睛:

for getter in (get_random_foo, get_random_bar): 
    try: 
     return getter() 
    except IndexError: 
     continue # Ignore the exception and try the next type. 

raise IndexError, "No foos, no bars" 
1

如果只是這兩個,總是可以只...

try: 
    return get_random_foo() 
except IndexError: 
    try: 
     return get_random_bar() 
    except IndexError: 
     raise IndexError, "No foos, no bars" 

如果是兩個以上的,你寫什麼,似乎完全可以接受的。

2

pass是好的(有一個原因它在語言 - !),但pass-免費的替代只是需要多一點的嵌套:

try: return get_random_foo() 
except IndexError: 
    try: return get_random_bar() 
    except IndexError: 
     raise IndexError "no foos, no bars" 

Python的禪(import this從交互式解釋提示)說:「平板比嵌套好」,但嵌套在日e語言,當你決定(大概是開悟)時,你可以使用你比這個明智的koan做得更好! - )(例如,「如果你在路上遇見佛陀......」)。

2

對於我來說,get_random_foo()在沒有將索引作爲參數(但在上下文中可能更有意義)時會引發IndexError,這看起來有點奇怪。爲什麼不用get_random_foo()或者一個包裝器來捕獲錯誤並返回None?

def get_random_foo_wrapper(): 
    try: 
     return get_random_foo() 
    except IndexError: 
     return None 

def get_random_foo_or_bar(): 
    "I'd rather have a foo than a bar." 

    return get_random_foo_wrapper() or get_random_bar_wrapper() or None 

編輯:我應該指出,如果FOO &欄是可以評估爲False對象(0或「」說),那麼or比較將跳過它們這是壞

+0

我從隨機模塊中提取了我的提示 - 嘗試運行'random.choice([])'。有趣的解決方案,謝謝! – 2010-09-16 12:29:30

0

建立在彼得吉布森的建議,你可以創建一個吞噬給定異常的通用包裝函數。然後你可以編寫一個函數返回這樣一個通用的包裝提供的例外。或者,對於提供的列表的例外情況。

def maketrap(*exceptions): 
    def trap(func, *args, **kwargs): 
     try: 
      return func(*args, **kwargs) 
     except exceptions: 
      return None 
    return trap 

def get_random_foo_or_bar(): 
    mytrap = maketrap(IndexError) 
    return mytrap(get_random_foo) or mytrap(get_random_bar) or None 
0

如果你不真正需要的異常消息(只是類型):

def get_random_foo_or_bar(): 
    try: 
     return get_random_foo() 
    except IndexError: 
     return get_random_bar() # if failing at this point, 
            # the whole function will raise IndexError 
+0

我想我寧願明確地從'get_random_foo_or_bar'提出錯誤,而不是依靠發生的錯誤是相同的並且需要評論。也允許我從'get_random_foo_or_bar'返回適當的異常消息。 – 2010-09-16 12:43:35

0

是否有必要get_random_foo /條()拋出一個IndexError如果它不能成功?

如果他們回到沒有,你可以這樣做:

def get_random_foo_or_bar(): 
    return get_random_foo() or get_random_bar() 
相關問題