【问题标题】:python indenting failure?python缩进失败?
【发布时间】:2011-12-10 12:10:28
【问题描述】:

我试图为我一直在研究的一个小程序编写一个类,但我遇到了一个奇怪的缩进失败。我想知道我写的内容是否真的有问题,或者是解析器的错。这在 Fedora 15 的 python 3.2 包中失败。

  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

【问题讨论】:

  • 仅供参考,python style guide 建议使用 4 空格缩进 - 这会使您的代码更具可读性。
  • 它完全按照您的指示行事。这当然不是解析器的错。

标签: python python-3.x


【解决方案1】:

如果我理解正确,你想抛出一个 KeyError 如果 usesSubStats 为 True 且 key 不在 subStats 中,或者如果 usesSubStats 为 错误和关键不在统计数据中。所以我认为问题在于 if/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 key in self.subStats”测试失败后,执行应该移回 if/elif 的下一个成员/else 向上分支一级并进行测试。但这根本不是它的工作原理。

有几种简单的方法可以获得您想要的行为:一种是将其展平,使其成为

    if CharacterStats.usesSubStats and key in self.subStats:

相反,它将评估为 False,因此将测试下一个分支 ,或者 - 正如您自己发现的那样 - 将 elif 设为 if,这再次导致该条件被独立测试, 或像之前的答案一样重写。

这有意义吗? if/elif/else 列表描述了一系列的可能性,条件依次测试,只有第一个真正的条件对应的分支(以最后的 else 为 'elif 1:')被执行。您不会移动到下一个分支,具体取决于分支发生的情况。

【讨论】:

  • 是的,我出于某种原因认为如果它进入第一个分支,并且其中的 if 失败,它会跳回 elif;而不是完全跳出来。半夜编码的可悲结果,有点宿醉。
【解决方案2】:

当且仅当CharacterStats.usesSubStats 为真且key in self.subStats 为假时,您才能在标记为otherwise we end up right here 的行上结束。

当您将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)

【讨论】:

  • 在原始问题中的实现中,唯一返回(或抛出)任何内容的时间是密钥在 self.subStats 中,否则不返回任何内容。如果我取出 else 语句,它会为任何不在 self.subStats 中的键提供 KeyError。我发现使这项工作正常工作的唯一方法是,您只需将 elif 替换为 if。
  • @Till:您能否将您的代码简化为我们可以运行的小型完整示例,并提供其行为与您的期望相反的输入?
  • 这并不是一个真正的小例子。你能把它归结为你的 getitem 方法和几个调用该方法的例子来测试结果吗?尝试将其编写为(失败的)单元测试。
【解决方案3】:

我认为您应该将 #otherwise..raise 缩进,因为后者在最终的 else 内,并且永远不会到达“外部块”。因此,IMO 是一个合理的 IndentationError。

【讨论】:

  • 我想你误解了里面发生了什么。
【解决方案4】:

由于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)

【讨论】:

  • 这行不通,因为只要CharacterStats.usesSubStats 为真,您的sn-p 就会假定密钥始终在self.subStats 中。但事实并非如此。但我开始看到我的班级安排是多么愚蠢。
猜你喜欢
  • 1970-01-01
  • 2016-08-22
  • 2010-11-09
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
相关资源
最近更新 更多