2011-12-10 67 views
2

我正在嘗試爲我正在編寫的一個小程序編寫一個類,並且遇到了縮進的奇怪失敗。我想知道我寫的東西是否真的有問題,或者是解析器的錯。這在Fedora 15的python 3.2包中失敗了。python縮進失敗?

def __getitem__(self, key): 
    if CharacterStats.usesSubStats: 
     if key in self.subStats: 
     return self.subStats[key] 
    elif key in self.stats: #change this to 'if' and it works 
     return self.stats[key] 
    else: 
     raise KeyError(key) 
    #otherwise we end up right here. 

按照要求,所以你可以運行它:http://pastebin.com/d8yQUm3U

+3

僅供參考,[蟒蛇風格指南](http://www.python.org/dev/peps/pep -0008 /)建議使用4空格縮進 - 這使您的代碼更具可讀性。 – ThiefMaster

+3

它正在做你已經告訴過的。這當然不是解析器的錯。 –

回答

3

如果我理解正確的話,你想拋出一個KeyError異常,如果 usesSubStats是真正的和關鍵不在subStats或者usesSubStats是 假和關鍵不在統計。所以我認爲問題在於如果/ elif/else鏈接不能像你認爲的那樣工作,那麼就是 。

考慮:

def f(x): 
    if x == 1: 
     return 'first' 
    elif x == 2: 
     return 'second' 
    else: 
     return 'other' 

產生

>>> f(1), f(2), f(3), f(4) 
('first', 'second', 'other', 'other') 

,我希望做什麼的預期,是你應該記住的格局。因爲在你的測試代碼useSubStats爲True,只有第一個分支測試過:

def condition(lab, val): 
    print('testing condition', lab); 
    return val 

def g(): 
    if condition(1, True): 
     return 'first branch' 
    elif condition(2, False): 
     return 'second branch' 
    else: 
     return 'other branch' 
    return 'fallthrough' 


>>> g() 
testing condition 1 
'first branch' 

所以你的代碼的行爲就像這樣:

def h(): 
    if condition(1, True): 
     if condition('1b', False): 
      return 'first branch' 
    elif condition(2, False): 
     return 'second branch' 
    else: 
     return 'other branch' 
    return 'fallthrough' 

>>> h() 
testing condition 1 
testing condition 1b 
'fallthrough' 

我不完全相信你怎麼認爲它應該表現得很好,但是你似乎認爲在「if self.subStats中的鍵」測試失敗之後,執行應該返回到上一級的if/elif/else分支的下一個成員並測試它。但是,這根本不是它的工作方式。

有幾種簡單的方法來得到你想要的行爲:一個就是擊敗它,這樣它的

if CharacterStats.usesSubStats and key in self.subStats: 

代替,這將評估爲False,因此下一個分支進行測試,或 - 當你發現自己 - 讓elif變成一個if,這又會導致這種情況被獨立測試,或者如之前的答案那樣重寫。

這有道理嗎?if/elif/else列表描述了一系列可能性,其中條件依次測試,並且僅執行對應於第一個真實條件的分支(將最終else取爲'elif 1:')被執行。你不會移動到下一個分支,這取決於分支內發生了什麼。

+1

是的,我出於某種原因認爲,如果它進入第一個分支,並且那裏的「if」失敗了,它會跳回到elif;而不是完全跳出來。半夜編碼帶來一點宿醉的悲慘結果。 – Till

2

你可以上線結束標記otherwise we end up right here當且僅當CharacterStats.usesSubStats是真實的,key in self.subStats是假的。

當您將elif更改爲if時,可以消除這種可能性:代碼永遠無法到達otherwise we end up right here行。

很難說這兩個版本中的哪一個是正確的。提供我猜中你的意圖,也許下面將是他們兩人有更明確的選擇:

def __getitem__(self, key): 
    if CharacterStats.usesSubStats: 
     if key in self.subStats: 
      return self.subStats[key] 
    elif key in self.stats: 
     return self.stats[key] 
    raise KeyError(key) 
+0

與原始問題一樣,唯一的時間返回(或拋出)是如果關鍵是在self.subStats否則沒有返回。如果我將else語句取出,它會爲不在self.subStats中的任何鍵提供KeyError。我發現正確工作的唯一方法就是如果你用if替換elif。 – Till

+0

@Till:您能否將您的代碼縮減爲我們可以運行的小型完整示例,並提供與您的期望相反的輸入? – NPE

+0

完成並完成,在主要問題中添加了一個鏈接。 – Till

0

我想你應該與raise縮進#otherwise..,因爲後者是最終else和內「外部塊」永遠不會到達。因此,一個合理的IMO,IndentationError。

+0

我想你誤解了那裏發生的事情。 – Till

0

由於self.statsself.subStats是詞典,因此如果它們不包含key,它們都會提高KeyError

那麼,爲什麼不只是寫:

def __getitem__(self, key): 
    if CharacterStats.usesSubStats: 
     return self.subStats[key] 
    return self.stats[key] 

或許:

def __getitem__(self, key): 
    try: 
     if CharacterStats.usesSubStats: 
      return self.subStats[key] 
     return self.stats[key] 
    except KeyError: 
     raise CharacterStatsError(key) 
+0

這是行不通的,因爲只要CharacterStats.usesSubStats爲真,你的代碼片斷就會假定鍵總是在'self.subStats'中。但情況並非如此。但我開始看到我的班級佈局是多麼愚蠢。 – Till