在Python中我应该如何测试变量是否为None,True或False


146

我有一个可以返回以下三项之一的函数:

  • 成功(True
  • 失败(False
  • 错误读取/解析流(None

我的问题是,如果不应该针对True或进行测试False,应该如何查看结果。以下是我目前的操作方式:

result = simulate(open("myfile"))
if result == None:
    print "error parsing stream"
elif result == True: # shouldn't do this
    print "result pass"
else:
    print "result fail"

它真的像删除== True零件一样简单,还是应该添加一个三布尔数据类型。我不希望该simulate函数引发异常,因为我希望外部程序对错误进行的所有操作均将其记录并继续。


您问错了问题;您应该寻求帮助来定义您的结果……您对“故障”和“错误解析流”的理解是什么?它们的含义是什么,后果是什么,呼叫者可能想采取什么行动?在每种情况下(通过,失败,解析错误)?
John Machin 2010年

我正在模拟一个电力系统,如果人们失去房屋电源,那将是一次失败。如果我无法读取模拟文件,那是完全不同的错误。
James Brooks 2010年

2
simulate函数内部,我捕获了所有异常;我不希望模拟器内部发生任何事情来停止其余程序的运行(并处理下一个元素)。但是答案使我改变了主意。
詹姆斯·布鲁克斯

1
@詹姆斯·布鲁克斯:对。这就是try / except处理的全部内容。如果您simulate有可以捕获并重试的东西,那就很好。但是,如果“失败”,则不应返回None。它应该只对调用它的脚本引发异常。无论哪种方式,simulate都完成了。返回None并不像引发适当的异常那样有用-或允许异常传播simulate到调用脚本中进行处理。
S.Lott 2010年

1
@James,请except Exception:改用。这将捕获所有“实际”错误以及WarningStopIteration。它允许KeyboardInterruptSystemExit通过。如果您真的想抓住这些问题,那么最好使用另一个外部try / except或其他清楚记录您意图的结构,因为这些不是“错误”。(但我确实说过“几乎从不” ...也许在您的情况下,您确实想抓取一切,甚至阻止Ctrl-C或sys.exit()退出等)
Peter Hansen 2010年

Answers:


119

不要害怕例外!让您的程序仅记录并继续操作很容易:

try:
    result = simulate(open("myfile"))
except SimulationException as sim_exc:
    print "error parsing stream", sim_exc
else:
    if result:
        print "result pass"
    else:
        print "result fail"

# execution continues from here, regardless of exception or not

现在,如果您发现错误/没有错误的信息不足,那么您可以从模拟方法中获得更丰富的通知类型,以了解确切的错误原因。


同意 比上面显然更流行的解决方案(它闻起来像C代码的气味)多得多。
布兰登2010年

7
@布兰登不同意。此代码比上面的解决方案(或下面的改进版本)更长,更糟糕的是,其可读性更差:更多的缩进,更多的不同语句-如您所说,猜测为什么后者更受欢迎... ;-)为什么要成为'Pythonic'是否导致更尴尬的代码...?
罗尔夫·巴斯特拉

现在打印回溯,而不是“错误解析流”,您得到了我的投票。
CivFan 2015年

好的,无论如何我都可以投票,但我的意思是打印类似的文字traceback.format_exc() 看到这个答案。
CivFan

10
很多人会到此页面寻找标题问题的答案。对于我们大多数人来说,“不要害怕例外!” 与我们的情况无关。我们只需要测试True,False和None。尽管您建议的替代方法在某些情况下是有效的,但我认为最好也包含对所提出问题的回答。
greatlysuperiorman '16

161
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

保持简单明了。您当然可以预定义字典。

messages = {None: 'error', True: 'pass', False: 'fail'}
print messages[result]

如果您打算修改simulate函数以包含更多的返回代码,则维护此代码可能会有点问题。

simulate还可以在解析错误引发异常,在这种情况下,你要么就在这里抓住它还是让它传播水平并打印位将减少到单行if-else语句。


1
后者是对True或False的显式测试,不是吗?
Peter Eisentraut 2010年

1
当然,但是知道这些只是可能的返回值,所以我认为这不是问题。
SilentGhost 2010年

而且似乎也更快
SilentGhost 2010年

a ='foo'如果a:打印'
true'a

17

从来没有,从来没有说过

if something == True:

决不。这太疯狂了,因为您要重复地重复为if语句重复指定为冗余条件规则的内容。

更糟糕的是,仍然,永远,永远,永远不要说

if something == False:

你有not。随意使用它。

最后,这样做a == None效率低下。做a is NoneNone是一个特殊的单例对象,只能有一个。只需检查看看是否有该对象。


3
测试是否相等True不是多余的(尽管我同意这并不明智)。它可能正在调用__eq__或其他特殊方法,实际上可以执行任何操作。
Scott Griffiths 2010年

5
@Scott Griffiths:好点。那是一个真实而深刻的场景。如果真的是这样,该程序将违反我们的基本期望,这使得它需要简单地删除并重新编写,而无需使用此类黑魔法。
S.Lott

78
'从不,从不,从不'...?在某些情况下,if something == True产生的结果与if something例如非布尔值产生的结果不同something2==True得出false,而得出2true;None==False是错误的,但却not None是真实的!
罗尔夫·巴斯特拉

9
-1这个答案具有误导性,并且完全不正确,因为@Rolf Bartstra所说的是正确的。尽管在这种情况下,您所说的可以应用。
HelloGoodbye 2014年

3
-1。由于任何非零,非空或非零长度的值something都会True在上返回bool(something)。在这种情况下,如果您只想检查something值是否为Trueie bool。然后,您必须执行if something == TrueIMO。
Samarth Shah 2015年

2

我想强调的是,即使身在何处的情况下if expr :,因为一个要确保不充分exprTrue,不只是从不同0/ None/不管,is是从者优先== 由于同样的原因美国洛特mentionned避免== None

确实,它效率更高,而且蛋糕上的樱桃更易被人阅读。

In [1]: %timeit (1 == 1) == True
38.1 ns ± 0.116 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [2]: %timeit (1 == 1) is True
33.7 ns ± 0.141 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

1
您不能一次运行基准测试并说一个基准比另一个基准更有效(即使可能会更高)。运行多次(10.000),以查看其平均行为。\
user1767754(18.19)

1

我认为抛出异常对您的情况更好。一种替代方法是返回元组的模拟方法。第一项是状态,第二项是结果:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]

1
返回元组通常与拆开元组一起使用很不错;)
SilentGhost 2010年

2
但是,您的代码并没有多大意义,如果False返回,它将打印出来'error parsing stream'
SilentGhost 2010年

模拟方法应返回(False,“所有内容”)或(True,ret),其中ret是False或True。
kgiannakakis 2010年

2
嗯,你重新定义输出值,以满足您的逻辑,它是不明确的w / o的解释
SilentGhost
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.