In Python how should I test if a variable is None, True or False
我有一个函数可以返回以下三项之一:
- 成功(True)
- 故障(False)
- 读取/分析流时出错(None)
我的问题是,如果我不想对True或False进行测试,我该如何查看结果。以下是我目前的做法:
1 2 3 4 5 6 7
| 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部分一样简单,还是应该添加一个tri-bool数据类型。我不希望simulate函数抛出异常,因为我只希望外部程序处理一个错误,那就是记录并继续。
- 你问错了问题;你应该请求帮助定义你的结果…您认为"失败"和"错误分析流"有什么区别,它们是什么意思,后果是什么,调用方在每种情况下可能希望采取什么行动(通过、失败、分析错误)?
- 我在模拟一个电力系统,如果人们失去房子的电力,那就是一个故障。如果我不能读取模拟文件,那么这是一个完全不同的错误。
- 不清楚(可能是因为这不是一个好主意)为什么你要避免使用一个异常来表示一个异常情况。有什么东西让你相信例外是"重的"、慢的,还是这种情况有其他问题?保罗的答案显示了我们应该如何使用Python。
- 在simulate函数内,我捕获所有异常;我不希望模拟器内发生的任何事情停止程序的其余部分运行(并处理下一个元素)。但答案让我改变了主意。
- 例外是件好事。它们是您如何执行诸如验证输入、调试、修复设计、警告用户其问题受到限制等操作的。
- 问题是我要让这个程序在晚上运行。我不希望它在出错时停止,只要记录下来继续。然后在早上我可以修复错误并重新运行那些错误。
- @詹姆斯·布鲁克斯:对。这就是Try/Except处理的全部内容。如果你的simulate有它能捕捉并重试的东西,那就好了。但如果"失败",则不应返回None。它应该只对调用它的脚本引发一个异常。不管怎样,simulate都可以完成。返回None并不如引发一个适当的异常——或者允许异常通过simulate传播到调用脚本中进行处理那样有用。
- 我懂了。如果simulate是一个外部库,那么我希望它抛出一个异常。它正好更合身。在我的例子中,调用代码可以执行所有操作,记录并继续执行。(根据保罗·麦奎尔的回答)
- @詹姆斯,除了一个笼统的except:声明也是一个非常坏的主意。除其他问题外,它将捕获异常类层次结构中不是StandardError的后代的异常,而您几乎不想这样做。
- @彼得,为什么是个坏主意?如果有什么导致内部模拟器抛出,那么我想将其记录为一个错误。我真的不希望我的程序停止处理,仅仅是因为它模拟的某件事抛出了一个我没想到的错误。在这种情况下我该怎么办?
- @詹姆斯,用except Exception:代替。这捕获了所有"真正的"错误,以及Warning和StopIteration。它允许KeyboardInterrupt和SystemExit通过。如果你真的想抓住这些,最好是使用另一个外部的尝试/例外或者其他清晰地记录你意图的结构,因为这些不是"错误"。(但我确实说过"几乎从来没有"……也许在你的情况下,你真的想抓住一切,甚至阻止ctrl-c或sys.exit()退出,等等。)
- 谢谢你的澄清。我认为你是对的,我不应该抓住KeyboardInterrupt(或者其他人),但我不想冒险不抓住其他东西(也许那些不能从例外中正确继承的东西)。基本上我意识到这很糟糕,无论如何我都会这么做。
- 否决了请更正标题以反映基本问题和接受的答案。
1 2 3 4 5 6
| if result is None:
print"error parsing stream"
elif result:
print"result pass"
else:
print"result fail" |
保持简单和明确。当然,你可以预先定义一本字典。
1 2
| messages = {None: 'error', True: 'pass', False: 'fail'}
print messages[result] |
如果计划修改simulate函数以包含更多返回代码,那么维护此代码可能会有点问题。
simulate还可能引发解析错误的异常,在这种情况下,您要么在这里捕获它,要么让它向上传播一个级别,如果else语句,打印位将减少到一行。
- 后者是对真假的一种明确的检验,不是吗?
- 当然,但是知道这些只是可能的返回值,我认为这不是问题。
- 而且似乎也快了一点
- a='foo'如果a:print'its true'a实际上不是真的,它只是不是空的。
别害怕例外!让您的程序只需登录并继续,就可以轻松做到:
1 2 3 4 5 6 7 8 9 10 11
| 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 |
现在,您可以从Simulate方法得到更丰富的通知,了解到底出了什么问题,以防您发现错误/无错误信息不够丰富。
- 同意。比上面明显更流行的解决方案(闻起来太像C代码)要多得多。
- @布兰登不同意。这段代码比上面的解决方案(或下面的改进版本)更长,更糟糕,更不可读:更多缩进,更多不同的语句-猜猜为什么后者更流行,正如您所说…;-)如果这会导致更尴尬的代码,为什么要尝试成为"Python"?
- 现在打印跟踪而不是"错误分析流",你得到了我的投票。
- 好吧,不管怎样,你得到了我的选票,但我的意思是打印一些类似于traceback.format_exc() 的东西。看看这个答案。
- 打印一个回溯并不总是可行的,尤其是当这是一个将输出传输给最终用户的区域时。当然,记录跟踪,但对用户来说,它们是不受欢迎的gobbledygook——它们需要一条摘要错误消息,最好提供关于它们可以如何修复错误的建议(如果有的话)。
- 许多人都会来到这个页面,寻找标题问题的答案。对我们大多数人来说,"不要害怕例外!"与我们的处境无关。我们只需要测试真假。虽然您建议的备选方案对某些情况是有效的,但我认为最好在问题被问到时也包括一个答案。
从不,从不,从不说
从未。这太疯狂了,因为您要重复冗余地为if语句指定为冗余条件规则的内容。
更糟的是,永远,永远,永远,永远不要说
你有not。请随意使用。
最后,执行a == None是无效的。做a is None。None是一个特殊的单例对象,只能有一个。检查一下你是否有那个物体。
- 我知道这是一个坏主意,这就是为什么我发布了这个问题,从表面上看,它更多的是一种代码味道,而不是我想的。谢谢你的信息
- 与True的平等性测试并不是多余的(尽管我同意这是不明智的)。它可以调用__eq__或其他特殊的方法,这实际上可以做任何事情。
- @斯科特·格里菲斯:很好。这真是一个非常可怕的场景。如果事实上是这样的话,这个程序违反了我们的基本期望,在某种程度上,它需要简单地从零开始删除和重写,而不需要这种黑色魔法。
- "从不,从不,从不"…?有些情况下,虽然if something == True产生的结果与if something不同,例如,对于非布尔something。2==True产生假,而2的计算结果为真;None==False是假,但not None是真的!
- -1由于@rolf bartstra所说的是真的,所以这个答案误导了我们,完全不正确。虽然在这种情况下,您所说的可以应用。
- 有时有很好的理由来测试某物是True、False还是None,例如,从数据库打印值,其中NULL分别表示"未知状态"和"真/假"表示"是/否"。
- - 1。由于something的任何非零或非空或非零长度值返回bool(something)上的True。在这种情况下,如果您只想检查something的值是否为True,即bool。那你就得在我看来做一件事。
- 关于@rolfbartstra的评论:实际上,我认为这是不使用== True的一个很好的理由。如果有可能something不是布尔值,那么我们在那里实际测试什么?在python 2中,甚至不能保证1将等于True(见此处)。所以我觉得S.Lott的建议绝对明智。
我想强调的是,即使在某些情况下,由于要确保expr是True而不是仅仅与0或None不同,所以is也会因为同样的原因而优先于==。lott提到避免== None的原因。
它确实稍微更有效率,而且,蛋糕上的樱桃色,更具人类可读性。
输入:
1 2 3 4 5 6 7 8
| from time import time
t0 = time()
print ( ( 1 == 1 ) == True )
t1 = time()
print ( ( 1 == 1 ) is True )
t2 = time()
print '{:e}s
{:e}s'.format( t1-t0, t2-t1) |
输出:
1 2 3 4
| True
True
1.201630e-04s
8.797646e-05s |
- 你不能只运行一次基准测试就说其中一个比另一个更有效(即使可能如此)。运行多次(10000)以查看它的平均行为。
我认为对你的情况来说,提出例外是个更好的主意。另一种方法是返回元组的模拟方法。第一项是状态,第二项是结果:
1 2 3 4 5
| result = simulate(open("myfile"))
if not result[0]:
print"error parsing stream"
else:
ret= result[1] |
- 返回tuple通常与解包tuple一起使用;)
- 但是,您的代码没有多大意义,如果返回False,它将打印'error parsing stream'。
- Simulate方法应返回(false,"anything at all")或(true,ret),其中ret为false或true。
- 好吧,你在定义输出值以适应你的逻辑,没有解释就不清楚了