【问题标题】:Returning None on Python在 Python 上返回 None
【发布时间】:2018-08-14 19:55:00
【问题描述】:

我的学生正在为课堂制作石头、纸、剪刀模拟。一组有一个错误,他们的一个函数不会返回任何东西。我已经检查过它是否所有分支都有返回语句,它们确实有。我也试过可视化工具,但功能停止了,我不知道为什么。

def Win_Loss(my_history, their_history):
    if len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 's' and my_history[-1] == 'r'):
            return 'p'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 'r' and my_history[-1] == 'p'):
            return 's'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 'p' and my_history[-1] == 's'):
            return 'r'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 's' and my_history[-1] == 'p'):
            return 'r'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 'r' and my_history[-1] == 's'):
            return 'p'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 'p' and my_history[-1] == 'r'):
            return 's'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 's' and my_history[-1] == 's'):
            return 'r'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 'r' and my_history[-1] == 'r'):
            return 'p'

    elif len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 'p' and my_history[-1] == 'p'):
            return 's'
    else:
        return "p"
print(Win_Loss(['s','p','p'],['s','p','p']))

这应该是打印's',但它打印的是None。

【问题讨论】:

  • 所以,所有的分支肯定没有return 声明。所有elif 分支都有一个if 语句。如果其中任何一个 ifs 不正确,该函数将返回 None
  • 所有条件都一样:elif len(my_history) > 1 and len(their_history) > 1:.....尝试删除每个elif
  • 另外,你所有的外部条件都是一样的:len(my_history) > 1 and len(their_history) > 1 所以只有第一个 if 块会执行...
  • 试着用简单的英语表达你想要的逻辑。
  • 鉴于这个问题(和您的个人资料),听起来您也可以在这个社区中找到一些用途:Computer Science Educators

标签: python python-3.x return


【解决方案1】:

如果任何内部ifs 失败,它将返回None,因为外部if/elif 被采用,因此else: 块将不会被执行。

要清楚,它们的整个功能相当于:

def Win_Loss(my_history, their_history):
    if len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 's' and my_history[-1] == 'r'):
            return 'p'
    else:
        return "p"

因为一旦第一个if 被占用,其他所有elifs 就不能被占用。由于它们具有相同的条件,因此永远不会到达所有elifs。

如果你把else:取出来,只是默认return "p",它会保证一个返回值:

elif len(my_history) > 1 and len(their_history) > 1:
    if (their_history[-1] == 'p' and my_history[-1] == 'p'):
        return 's'
# If anything else happens
return "p"

但这并不能解决根本问题。

或者,他们可以结合条件:

if len(my_history) > 1 and len(their_history) > 1 and
    (their_history[-1] == 's' and my_history[-1] == 'r'):
        return 'p'

这也将避免该问题,因为没有内部条件可以跳过返回,else: 将按预期工作。


正如其他人所提到的,整个外部 if 块是多余的。对于我的女孩(我教 11-13 岁/os),我建议他们将默认返回移到顶部......然后你不必检查每个列表是否足够大:

if not (len(my_history) > 1 and len(their_history) > 1):
    return "p"  # default value
elif their_history[-1] == 's' and my_history[-1] == 'r':
    return 'p'
elif their_history[-1] == 'r' and my_history[-1] == 'p':
    return 's'
elif their_history[-1] == 'p' and my_history[-1] == 's':
    return 'r'
elif their_history[-1] == 's' and my_history[-1] == 'p':
    return 'r'
elif their_history[-1] == 'r' and my_history[-1] == 's':
    return 'p'
elif their_history[-1] == 'p' and my_history[-1] == 'r':
    return 's'
elif their_history[-1] == 's' and my_history[-1] == 's':
    return 'r'
elif their_history[-1] == 'r' and my_history[-1] == 'r':
    return 'p'
elif their_history[-1] == 'p' and my_history[-1] == 'p':
    return 's'

如果我们失败了,在最后添加一个异常:

raise AssertionError, "a combination not covered was encountered"

这将确保我们知道我们是否忘记了一种可能性。


其他风格点可能值得讨论,也可能不值得讨论,具体取决于他们的能力:

通过嵌套条件,他们可以减少重复,但如果他们想调整他们的机器人,这是一个障碍而不是好处。

if not len(my_history) > 1 and len(their_history) > 1:
    return "p"  # default value

elif their_history[-1] == 's':  # if they threw scissors
    if my_history[-1] == 'r':       # and I threw rock
        return 'p'                      # throw paper
    return 'r'                      # otherwise throw rock

elif their_history[-1] == 'r':
    if my_history[-1] == 'p':
        return 's'
    return 'p'

elif their_history[-1] == 'p': 
    if my_history[-1] == 's':
        return 'r'
    return 's'

【讨论】:

  • Niggle:我不确定这会达到她预期的效果。她可能预计,如果内部的if 失败,它将落入下一个elif
  • OP 只需要测试一次if len(my_history) > 1 and len(their_history) > 1
  • 这正是我所期望的。但既然已经下了一枝,就回不去了。谢谢!
  • @JohnnyMopp 我同意这将是最好的方法,但这大概是为学生准备的,因此获得工作代码的最小更改将是有帮助的。我在这些方面添加了一个更好的选择。
【解决方案2】:

您的elif 语句处于错误级别,as explained by @SiongThyeGoh。下面的工作正常,虽然不优雅。

def Win_Loss(my_history, their_history):
    if len(my_history) > 1 and len(their_history) > 1:
        if (their_history[-1] == 's' and my_history[-1] == 'r'):
            return 'p'
        elif (their_history[-1] == 'r' and my_history[-1] == 'p'):
            return 's'
        ...

但这将是我最喜欢的解决方案:

def Win_Loss(my_history, their_history):

    d = {frozenset({'s', 'r'}): 'p',
         frozenset({'r', 'p'}): 's',
         frozenset({'s', 'p'}): 'r',
         frozenset({'s', 's'}): 'r',
         frozenset({'r', 'r'}): 'p',
         frozenset({'p', 'p'}): 's'}

    if len(my_history) > 1 and len(their_history) > 1:
        return d.get(frozenset({their_history[-1], my_history[-1]}))

    else:
        return "p"

print(Win_Loss(['s','p','p'],['s','p','p']))

【讨论】:

    【解决方案3】:
    if len(my_history) > 1 and len(their_history) > 1:
            if (their_history[-1] == 's' and my_history[-1] == 'r'):
                return 'p'
    

    看前三行,如果第一个 if 条件满足而第二个不满足,那么你什么都不返回,也就是你得到 None。

    如果这个条件通过:

    if len(my_history) > 1 and len(their_history) > 1:
    

    那么它将进入前三行,否则,另一个elif语句将被忽略,因为它是相同的条件,它只会到达else部分并返回p。

    它只能返回 p 或 None。

    【讨论】:

      猜你喜欢
      • 2022-01-21
      • 2022-12-12
      • 2013-04-07
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多