在Python中设置变量时正确抛出错误的方法
在一个类里,检查错误的正确方法是什么呢?是抛出异常吗?还是设置一个叫“errors”的实例变量字典,把所有错误都放里面,然后返回这个字典呢?
从一个类里打印错误信息是不是不太好?如果我抛出异常,是否一定要返回False呢?
我只是想确认一下自己做的是否正确。下面是一些示例代码:
@property
def password(self):
return self._password
@password.setter
def password(self,password):
# Check that password has been completed
try:
# Check that password has a length of 6 characters
if (len(password) < 6):
raise NameError('Your password must be greater \
than 6 characters')
except NameError:
print 'Please choose a password'
return False
except TypeError:
print 'Please choose a password'
return False
#Set the password
self._password = password
#Encrypt the password
password_md5 = md5.new()
password_md5.update(password)
self._password_md5 = password_md5.hexdigest()
3 个回答
一般来说,当出现错误时,你应该用异常来表示这些错误。如果你通过检查发现了一个错误,并且可以立即处理它,那就没必要抛出异常。
以设置器为例,返回 False
或其他任何东西都没有帮助。检查实例变量的设置是非常不理想的,因为这样你可能会不小心漏掉一个错误。
用 print
来应对错误通常不是个好主意。在这种情况下,听起来你想告诉最终用户他们需要使用不同的密码。你应该调用一个方法,让网页上的表单向用户解释发生了什么错误;你可以在你的类中调用这个方法,或者抛出一个异常,让它传播出去,最终被捕获并用于这个目的。(这是一般性的建议。我对 Pylons 了解不够,无法告诉你它希望你怎么做。)
你不应该自己抛出 NameError
异常。NameError
通常表示你的程序中有拼写错误,因此你通常不想捕获它。捕获它会给程序带来不必要的不确定性。这种情况更像是 ValueError
或它的子类(class InvalidPasswordError(ValueError): pass
)。
我不明白你为什么要检查 TypeError
。你应该始终理解导致你捕获的异常的原因。如果你在这种情况下理解了,那很好;但我搞不清楚是什么错误会引发 TypeError
,而你又能通过提示用户来合理处理。
你以明文形式接收密码并存储其 md5 哈希的做法并不是很安全。你应该考虑使用像 AuthKit 这样的工具,可以让这个过程更安全、更抽象。
在Python中,标准的错误处理方式是抛出一个异常,让调用这个函数的代码来处理这个错误。你可以选择让像NameError和TypeError这样的错误继续向上抛出,或者捕获这些错误,然后抛出一个你自己定义的InvalidPassword异常。
虽然你可以像现在这样从函数返回一个成功或失败的标志,或者错误代码,但其实不太推荐这样做。因为调用这个函数的人可能会忘记检查返回值,导致错误被忽略。而且,你是在一个属性设置器中返回值,这在Python中是没有意义的,因为赋值不是表达式,不能返回值。
另外,在处理异常时,你也不应该直接给用户打印信息。如果你以后想在一个图形界面程序中使用这个函数或类,那你的打印语句就没有地方可以输出了。不过,把错误记录到日志文件中(使用Python的日志模块)通常对调试是很有帮助的。
你的代码缺少上下文,所以很难判断哪个选择是正确的。这里有一些建议:
不要使用
NameError
异常,这个异常只在找不到名字时使用,正如它的名字所说的那样。如果异常是关于参数的值或类型,应该使用ValueError
或TypeError
;不要打印错误信息。应该抛出有意义的异常,并附上清晰的错误信息:
raise ValueError("password must be longer than 6 characters")
从一个设置器(setter)返回值是没有意义的,因为赋值不是一个表达式,也就是说你不能检查赋值的结果:
if (user.password = 'short'): ...
在设置器中直接抛出异常,让设置属性的代码来处理这个异常。
示例:
class Test:
minlen = 6
@property
def password(self):
return self._password
@password.setter
def password(self, value):
if not isinstance(value, basestring):
raise TypeError("password must be a string")
if len(value) < self.minlen:
raise ValueError("password must be at least %d character len" % \
self.minlen)
self._password = value
你还可以看看 这个表单处理库,在这里,验证器 这里有一个例子 是独立的实体:它们可以动态设置,提供更高的控制力和更少的耦合代码,但这可能超出了你的需求。