Лучшие практики в Python для обработки внешних исключений (я использую повышение?) - PullRequest
2 голосов
/ 30 декабря 2010

Я пишу процедуру на 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 и прервитесь. После цикла посмотрите на флаг и посмотрите, успешно ли завершился цикл 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.

Но это как-то неправильно или непитонно использовать термин, который я не совсем понимаю. Есть ли что-то не так с этим? Спасибо и, пожалуйста, имейте в виду, что я не майор CS, и я не посещал курсы программирования с 1982 года.

Ответы [ 4 ]

2 голосов
/ 30 декабря 2010

Мой подход, для чего бы это ни стоило, было бы определить небольшую иерархию исключений, скажем:

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

Затем, при любой ошибке, убедитесь, что ваш API выдает один из них. Если ваш API сам должен перехватить исключение из базового API мотора, поместите это исключение в одно из ваших собственных исключений.

Обоснование:

Ваша собственная иерархия исключений является частью API и служит для изоляции вызывающего кода от особенностей базового API мотора. Выбрасывая определенный набор исключений, вместо того, чтобы допускать всплытие исключений API мотора, вы еще больше скрываете базовый API. Это облегчает установку другого API двигателя по любой причине, включая:

  • Вы нашли лучший вариант.
  • Вы хотите провести некоторое тестирование с использованием смоделированного мотора API.

Кроме того, исключения (а не флаги) более соответствуют поведению других API-интерфейсов Python.

1 голос
/ 30 декабря 2010

Есть ли правильный путь

Да.

или это субъективно?

Количество

Используйте оператор raise.

Во-первых, пожалуйста, используйте CapitalLetters для ваших уникальных исключений

class Motor_Fault( Exception ): pass
class Temperature_Fault( Motor_Fault ): pass
class Voltage_Fault( Motor_Fault ): pass
class Current_Fault( Motor_Fault ): pass

Во-вторых, отделите обнаружение ошибок от остальной части вашей обработки.

В-третьих, не делайте ничего в классе исключений. Обработайте остановку двигателя в вашем приложении.

В-четвертых, проверка состояния двигателя не относится к контуру двигателя вашего приложения. Это все часть функции метода, которая реализует motor.move_to_absolute.

    if motor.current_limit == 1: raise Current_Fault()
    if motor.temp_fault == 1: raise Temperature_Fault()
    if motor.voltage_fault == 1: raise Voltage_Fault()

В-пятых, ваш цикл приложения должен выглядеть следующим образом.

motor.velocity_limit = motor.slow
motor.velocity_limit_enable = True
try:
    motor.move_to_absolute = motor.instrument_pos
    while motor.in_position == 0:
        time.sleep(0.5)
    print('reached desired instrument position with no faults')
except Motor_Fault, e:
    motor.move_at = 0 #Stop motor
    print(fault)

Двигатель должен вызывать свои собственные исключения. Если по какой-то причине это невозможно, то вы можете «обернуть» двигатель с помощью некоторой проверки состояния. Это не идеально, так как двигатель должен вызывать свои собственные исключения.

 def check():
    if motor.current_limit == 1: raise Current_Fault()
    if motor.temp_fault == 1: raise Temperature_Fault()
    if motor.voltage_fault == 1: raise Voltage_Fault()

Вызовите эту функцию непосредственно перед sleep.

0 голосов
/ 30 декабря 2010

Я не вижу ничего плохого ни в одном из подходов.Лично я предпочитаю попробовать, кроме одного, но это просто предпочтение.

0 голосов
/ 30 декабря 2010

Я бы пошел за исключениями со многими, за исключением предложений для всех различных исключений, которые вы хотели бы обработать на данном этапе, поскольку эти случаи кажутся исключительными / неудачными сценариями.

Я бы не использовал флаги для представленияэти сценарии, поскольку это добавит больше полей к двигателю, которые не кажутся полезными / релевантными вне этого варианта использования.

Насколько известно, является ли это «правильным» способом справиться с этим хорошо, если оба решенияработает они оба правильные!

Надеюсь, я достаточно ясно ...; -)

...