Python中正确使用raise错误
描述:
我看过很多关于在Python中检查值类型的观点,大多数人说不应该检查类型,而是应该使用try和except。我想澄清一些事情。
问题:
当我有这样的一个方法:
def set_age(self, age):
self._age = age
我不能让用户传入除了整数以外的任何类型,因为在后面的代码中,这可能会导致一些更难调试的错误。而根据Python的编程理念,我又不能检查类型。那么我应该如何正确地使用try来处理这个问题呢?
def set_age(self, age):
try:
age = int(age)
except TypeError:
raise TypeError('First parameter must be of int type.')
self._age = age
或者直接
def set_age(self, age):
self._age = int(age)
让Python自己抛出错误。
我知道这可能是个傻问题,我只是想确认一下。
2 个回答
Python有个原则是“宁可事后道歉,也不要事前请求许可”。这就是说,很多时候,当你调用的函数出现错误时,这些错误信息已经足够让调用你函数的人知道出了什么问题。
不过在某些情况下,我会抛出一个更具体的错误,这样可以让调用者更清楚发生了什么。例如,当我在检查一个json响应时,如果在字典的某个元素上出现了“键错误”,这通常意味着我发送的请求失败了,因此我找不到我需要的数据。在这种情况下,我会抛出一个更符合我函数语义的错误,比如“查询失败”。
不过大多数时候,调用的函数抛出的错误,比如“类型错误”或“输入输出错误”,对调用我函数的人来说是很容易理解的,所以我就不再去捕捉和重新抛出这些错误了。
如果输入的不是整数,Python会自动报错,所以你不需要再自己加一层检查。
不过我们先退一步,这里还有其他问题。使用getter和setter在Python中并不是很常见——要么直接用属性,要么使用属性。
在这种情况下,我觉得你的思维方式可能有点问题。我们在Python中不进行类型检查的原因是,我们不应该关心某个东西是什么类型,而是它在特定情况下是否能正常工作。把所有东西都强制转换成你认为应该的类型,其实就是在进行类型检查。
你说这样会让调试变得更难,但大多数人的经验并不是这样。鸭子类型的设计就是允许任何能完成工作的东西去完成工作。把所有东西都转换成int
会限制你的程序。问题不在这里,问题在于你的代码传递了不合适的东西给你的类。根据我的经验,这种情况其实很少见——你不会随便把一些东西扔给类看看能不能用。
所以,我的建议是直接使用属性——就用x.age = ...
,而不是用set_age()
之类的。如果你真的需要一个int
(也就是说,只有整数才有意义),那么可以使用属性,在设置值的时候调用int()
,如果出错就让错误传递给调用者处理。