Python 中处理外部异常的最佳实践 (是否使用 raise?)

29 阅读2分钟

在 Python 中编写一个过程,该过程在其基本层面上与电机控制器通信。控制器有可能抛出标志,指示出现错误。试图弄清楚如何最好地处理这些错误。

在下面的示例中,有三个可能的错误,温度故障、电流限制故障和电压故障。以不同的方式处理它们。是否有正确的方法,还是这是主观的?

class motor_fault(Exception):
    def __init__(self,error):
        motor.move_at = 0  #Stop motor
        self.error = error
    def __str__(self):
        return repr(self.value)

motor.velocity_limit = motor.slow
motor.velocity_limit_enable = True
try:
    motor.move_to_absolute = motor.instrument_pos
    while motor.in_position == 0:
        if motor.current_limit == 1:
            motor.move_at = 0 #Stop motor
            print('Motor current error')
            break
        if motor.temp_fault == 1: raise motor_fault('Temperature Fault')
        if motor.voltage_fault == 1: raise voltage_fault:
        time.sleep(0.5)
    else:
        print('reached desired instrument position with no faults')
except motor_temp_fault as e:
    #Not sure what I'd do here...
    print('My exception occurred, value:', e.error)
    pass
except:
    motor.move_at = 0 #Stop motor just in case
    print(' some other fault, probably voltage')
else:
    print (' this is only printed if there were no errors')
finally:
    print ('this is printed regardless of how the try exits')

使用一个标志并中断 try 语句似乎更简单。在循环之后,查看标志并查看 while 循环是否成功退出。

fault = False
while motor.in_position == 0:
    if motor.current_limit == 1:
        fault = 'Motor current error'
        break
    if motor.temp_fault == 1:
        fault = 'Motor temperature error'
        break
    if motor.voltage_fault == 1:
        fault = 'Motor voltage error'
        break
    time.sleep(0.5)
else:
    print('reached waterline with no faults')
if fault:
    motor.move_at = 0 #Stop motor
    print(fault)
    # Now look at the fault string to determine the next course of action.

但使用术语“非 Python 的”不知怎么感觉有点不对。这样做真的有问题吗?

2、解决方案

一种潜在的解决方案是在 Python 中定义一个小型的异常层次结构,如下所示:

class MotorFaultError(Exception) # top level exception
class MotorTempFault(MotorFaultError)
class MotorVoltageFault(MotorFaultError)
# etc

然后,在出现任何错误时,确保 API 抛出其中一个错误。如果 API 本身必须从底层电机 API 捕获异常,则将其异常包装在自己的异常中。

基本原理:

  • 自己的异常层次结构是 API 的一部分,它可以将调用代码与底层电机 API 的具体细节隔离。
  • 通过抛出一组定义的异常,而不是允许电机 API 的异常冒泡,可以进一步隐藏底层 API。
  • 这样做可以更容易地替换另一个电机 API,原因包括:
    • 找到一个更好的。
    • 想使用模拟的电机 API 做一些测试。

此外,异常(而不是标志)与其他 Python API 的行为方式更加一致。