【发布时间】:2018-03-23 00:49:07
【问题描述】:
我有一个名为 Divider1 的类,它将分子除以分母,在初始化时设置:
class Divider1:
def __init__(self, numerator=0, denominator=1):
self.numerator = numerator
self.denominator = denominator
def divide(self):
return self.numerator / self.denominator
类很容易被错误的初始化滥用,但直到真正发生划分时才立即清楚:
>>> x = Divider1('hello', 5)
>>> x.divide()
TypeError: unsupported operand type(s) for /: 'str' and 'int'
看来提早引发异常对调试和维护很有好处,所以这是我的下一个合乎逻辑的步骤:
class Divider2:
def __init__(self, numerator=0, denominator=1):
try:
numerator = float(numerator)
except ValueError:
raise ValueError("Numerator must be numeric!")
try:
denominator = float(denominator)
except ValueError:
raise ValueError("Denominator must be numeric!")
if denominator == 0:
raise ValueError("Denominator must be non-zero!")
self.numerator = numerator
self.denominator = denominator
def divide(self):
return self.numerator / self.denominator
现在我们有了一些安全感:
>>> x = Divider2('hello', 5)
ValueError: Numerator must be numeric!
我很清楚,初始化时出了什么问题,但初始化后更改属性仍然可以滥用:
>>> x = Divider2(10, 5)
>>> x.numerator = 'hello'
>>> x.divide()
TypeError: unsupported operand type(s) for /: 'str' and 'int'
我正在尝试找出处理这些问题的 Pythonic 方式。我可能只是将分子和分母命名为 _numerator 和 _denominator,以表明它们应该被视为私有的。
或者,我可以使用属性:
class Divider4:
def __init__(self, numerator=0, denominator=1):
self.numerator = numerator
self.denominator = denominator
@property
def numerator(self):
return self._numerator
@numerator.setter
def numerator(self, value):
try:
value = float(value)
except ValueError:
raise ValueError("Denominator must be numeric!")
self._numerator = value
@property
def denominator(self):
return self._denominator
@denominator.setter
def denominator(self, value):
try:
value = float(value)
except ValueError:
raise ValueError("Denominator must be numeric!")
if value == 0:
raise ValueError("Denominator must be non-zero!")
self._denominator = value
def divide(self):
return self.numerator / self.denominator
那么现在:
>>> x = Divider4(10, 5)
>>> x.numerator = 'hello'
ValueError: Numerator must be numeric!
>>> x = Divider4(10, 0)
ValueError: Denominator must be non-zero!
它显然更安全,而且我立即知道错误的原因,无论该类如何使用 - Divider 都不可能达到不可能的状态。但是我必须编写更多的代码来实现这一点,尤其是与 Divider1 相比。但是我仍然认为应该始终达到这种安全性,尽管我没有看到人们在编写 Python 代码时一直这样做。我是否以意想不到的方式使用 Python?总是写这么繁琐的属性来保证安全,是不是 Pythonic?有没有应该做或不应该做的时候?
【问题讨论】:
-
投票结束是基于意见,这不是Stack Overflow 的主题。话虽如此,我的看法是:不要做任何事情。让
.divide()中的除法引发异常。使用您的类的程序员将按预期使用它或将收到异常。如果您确实希望早点发生异常,请从self.__init__()调用self.divide(),不带try,也不带except。 -
如果您想以不同的方式处理异常,我可以理解为什么要捕获异常。但在我看来,您仍在提出异常并终止程序,尽管是立即并提供更具体的信息(例如
ValueError: Numerator must be numeric!而不是通用的TypeError: unsupported operand type(s) for /: 'float' and 'str')。但这是否证明所有额外的tryexcept声明是合理的?我认为 Python 的想法是尽可能地依赖内置的异常处理。通用异常信息有什么不好>? -
“我有一个名为 Divider1 的类,它将分子除以分母”——这不是一个类的工作。如果要执行计算,请编写一个函数。如果你想表示一个事物,写一个类。
-
感谢 cmets。 Divider 类是一个简化的示例,我一直在考虑更普遍的问题,更复杂的类还有很多事情要做。
标签: python python-3.x exception