2011-12-10 11 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

、[Pythonのスタイルガイド](http://www.python.org/dev/peps/pep -0008 /)は、4-spaceインデントを使用することを示唆しています。これにより、コードが読みやすくなります。 – ThiefMaster

+3

これはあなたが言ったことを正確にしています。確かにパーサーのせいではありません。 –

答えて

3

は、あなたが usesSubStatsがTrueで、キーがsubStatsにない場合はKeyError例外をスローする場合、またはusesSubStatsが Falseの場合とキーが統計ではありません。だから私はあなたが思うように/ elif/else chainingが動作しない場合、問題は だと思います。

は考えてみましょう:

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に真である、唯一の最初の分岐は、これまでテストされたバージョン:

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 key in self.subStats"テストが失敗した後、if/elif/elseブランチの次のメンバーにレベルアップしてテストを実行し、それをテストする必要があるようです。それは単にそれがどのように動作するかではありません。

あり、あなたが望む行動を取得するには、いくつかの簡単な方法です。一つは、それは

代わり
if CharacterStats.usesSubStats and key in self.subStats: 

だように、Falseに評価されますので、次の分岐テストされる、それを平坦化することであるが、かあなたが自分自身を発見したので、elifをifにすると、それは再び独立してテストされる状態につながり、以前の答えと同じように書き直されます。

それは意味がありますか?if/elif/elseリストには一連の可能性が記述され、条件は連続してテストされ、であり、最初の真条件に対応するブランチ(最後のelseを 'elif 1:'とする)が実行されます。。何が起こるかに応じて、次の支店に移動することはありません支店内。

+1

ええ、私は何らかの理由で、最初のブランチに入り、そこの 'if'が失敗した場合、それがエリフに戻ってくることを考えていました。一緒に飛び降りることはありません。夜中にコーディングして、ちょっとした二日酔いで悲しい結果になった。 – Till

2

があればotherwise we end up right hereをマークし、CharacterStats.usesSubStatsは真であるとkey in self.subStatsがfalseの場合のみ。

elififに変更すると、コードがotherwise we end up right here行に届かない可能性があります。

2つのバージョンのどちらが正しいと言うのは難しいです。私は後者が最終elseと内部にあるとして、あなたは、raise#otherwise..をインデントすべきだと思う

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が返されます。私がこの作業を適切に行うために見つけた唯一の方法は、elifをifに置き換えるだけです。 – Till

+0

@Till:あなたのコードを実行可能な小さな完全な例に減らして、それがあなたの期待に反して動作する入力を提供できますか? – NPE

+0

完了して、メインの質問にリンクを追加しました。 – Till

0

:提供私は、おそらく次は、それらの両方に明確な選択肢になり、正しく意図を推測しました"外側のブロック"は決して到達しません。したがって、合理的な、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] 

それともを:

FYI
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

関連する問題