为什么在python中异常/错误的计算结果为True?
在一些地方,我必须从dict中检索一些值,但需要检查该值的键是否存在,如果不存在,则使用一些默认值:为什么在python中异常/错误的计算结果为True?,python,exception-handling,Python,Exception Handling,在一些地方,我必须从dict中检索一些值,但需要检查该值的键是否存在,如果不存在,则使用一些默认值: if self.data and self.data.has_key('key'): value = self.data['key'] else: value = self.default .... 我喜欢python的一点是and/or布尔运算符返回一个操作数。我不确定,但如果异常计算为false,则可以按如下方式重写上述代码:
if self.data and self.data.has_key('key'):
value = self.data['key']
else:
value = self.default
....
我喜欢python的一点是and/or布尔运算符返回一个操作数。我不确定,但如果异常计算为false,则可以按如下方式重写上述代码:
value = self.data['key'] or self.default
我认为错误应该计算为false是很直观的(就像在bash编程中一样)。python将异常视为真有什么特别的原因吗
编辑:
我只是想展示一下我对“异常处理”主题的观点。发件人:
"
从例程作者的角度来看,引发异常是表示例程无法正常执行的一种有用方式。例如,当输入参数无效(例如除法中的零分母)或它所依赖的资源不可用(如缺少文件或硬盘错误)时。在没有例外的系统中,例程需要返回一些特殊的错误代码。然而,这有时会因为半谓词问题而变得复杂,在这个问题中,例程的用户需要编写额外的代码来区分正常返回值和错误返回值。
"
正如我所说,引发异常只是从函数返回的一种奇特方式异常对象只是一个指向数据结构的指针,该数据结构包含有关错误的信息,在高级语言上如何处理该错误只取决于VM的实现。我决定通过查看“dis”模块的输出来了解python 2.6.6如何处理异常:
>>> import dis
>>> def raise_exception():
... raise Exception('some error')
...
>>> dis.dis(raise_exception)
2 0 LOAD_GLOBAL 0 (Exception)
3 LOAD_CONST 1 ('some error')
6 CALL_FUNCTION 1
9 RAISE_VARARGS 1
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
很明显,python在字节码级别有异常概念,但即使它没有,它仍然可以使异常处理结构像它们一样工作。执行以下功能:
def raise_exception():
... return Exception('some error')
...
>>> dis.dis(raise_exception)
2 0 LOAD_GLOBAL 0 (Exception)
3 LOAD_CONST 1 ('some error')
6 CALL_FUNCTION 1
9 RETURN_VALUE
这两个函数都以与0、3和6中所示相同的方式创建异常对象。不同之处在于,第一个调用对象上的RAISE_VARARGS指令(并且仍然返回None),第二个调用仅将异常对象返回给调用代码。现在使用以下字节码(我不确定这是否正确):
上述内容可转化为以下内容:
if isinstance(raise_exception(), Exception):
print 'Exception caught!'
else:
print 'No exceptions were raised'
但是,当编译器找到try块时,它可以生成类似上述指令的内容。使用此实现,可以测试块是否存在异常,也可以将返回异常的函数视为“False”值。您可以使用
get
:
value = self.data.get('key', self.default)
更新:您误解了那里的或关键字。self.default
值仅在self.data['key']
计算结果为False时使用,而不是在self.data中不存在'key'时使用。如果self.data不包含“键”,则仍会引发异常
在表达式中:
self.data['key'] or self.default
Python解释器将首先计算self.data['key']
,然后检查其计算结果是否为True。如果为真,则它是整个表达式的结果。如果为false,则self.default是表达式的结果。但是,在计算self.data['key']时,“key”不在self.data中,然后引发异常,中止对整个表达式的计算,实际上是终止包含块,直到在堆栈的某个位置找到匹配的块(除了
块)。在引发异常的情况下也不会执行赋值,value
保持其初始值
为什么在python中异常/错误的计算结果为True
Exception
的实例评估为True
(EDIT参见下面的注释。非常相关的信息)。这并不能阻止它们被扔掉
我不确定,但是如果异常被评估为false
在您的上下文中,将异常计算为False
是不够的。它们也不应该被抛出并传播到调用堆栈中。相反,它们必须当场“停止”,然后计算为False
我将让更有经验的Pythonistas来评论为什么异常不会(或不应该)被“停止”,并计算为True
或False
。我猜这是因为它们被期望被抛出和传播。事实上,如果他们被阻止和审问,他们将不再是“例外”
但需要检查该值的键是否存在,如果不存在,则使用一些默认值
我可以想出两个选项,两种方法在字典中没有键的情况下获取默认值。一种是使用defaultdict
。另一种方法是使用get
方法
>>> from collections import defaultdict
>>> d = defaultdict(lambda: "default")
>>> d['key']
'default'
>>> d = dict()
>>> d.get('key', 'default')
'default'
>>>
PS:如果dict中的键比dict.has\u键(key)
更可取。事实上,has_key()
已经出现在Python 3.0中。您误解了异常的使用。例外是出了问题。它不仅仅是一个返回值,也不应该这样对待
显式比隐式好
因为出现错误时会引发异常,所以必须显式编写代码来捕获它们。这是经过深思熟虑的——你不应该仅仅因为False
而忽略异常,因为它们不仅仅是这些
如果您按照您的建议吞并了异常,您将无法判断代码何时出错。如果引用未绑定的变量,会发生什么情况?这会给你一个名称错误
,但它会给你<代码>错误
考虑您的代码块:
value = self.data['key'] or self.default
如果key
不是self.data
的键,则希望self.data['key']
返回False
。你认为这种方法有什么问题吗?如果self.data=={'key':False}
呢?您无法区分存储在字典中的False
和由于缺少密钥而返回的False
此外,如果这是
value = self.data['key'] or self.default
try:
value = self.data['key']
except KeyError:
value = self.default
>>> import collections
>>> data = collections.defaultdict(lambda: False)
>>> data['foo'] = True
>>> data['foo']
True
>>> data['bar']
False
if self.data and self.data.has_key('key'):
value = self.data['key']
else:
value = self.default
if self.data.has_key('key'): # if it has the key, it's not empty anyways
value = self.data['key']
else:
value = self.default
if 'key' in self.data: # `in` does just what you expect
value = self.data['key']
else:
value = self.default
value = (self.data['key'] if 'key' in self.data else self.default)
value = self.data.get('key', self.default)
value = (self.data['key'] if 'key' in self.data else self.get_default('key'))
value = self.data.get('key', self.get_default('key'))