Как перейти к управлению функциями верхнего уровня - PullRequest
1 голос
/ 14 апреля 2019

Мне сказали разработать новый API в моей компании, и я сталкиваюсь с дилеммой, когда дело доходит до практики кодирования.

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

Пока все здесь хорошо. Но большая часть моей функции проверки (от суб до суб) требует возврата основного API, ничего не делая. Почти все мои функции проверки должны возвращать некоторые данные, которые используются следующей функцией проверки, и в этом моя проблема. Из-за такой структуры я должен возвращать состояние в конце каждой функции проверки вместе с обработанными данными, а после вызова функции я должен проверять состояние перед переходом к следующей функции.

Пример кода:

def check1a():
    if some_process():
        return True, data_positive
    return False, data_negative
    #data_positive and data_negative cannot be used to identify whether the check passed or not.

def check1():
    stats,data = check1a()
    if not status:
        return False, data
    status, data = check1b(data)
    if not status:
        return False, data
    status, data = check1c(data)
    if not status:
        return False, data
    return status, data

def mainAPI():
    status, data = check1(data)
    if not status:
        return data
    status, data = check2(data)
    if not status:
        return data
    status, data = check3()
    if not status:
        return "Failed"
    return data

Будучи религиозным последователем концепции «СУХОЙ», было бы лучше использовать исключения для запуска кода следующим образом.

def check1a():
    if some_process():
        return data_positive
    exception1a = Exception("Error in check 1 a")
    exception.data = data_negative
    raise exception

def check1():
    data = check1a()
    data = check1b(data)
    data = check1c(data)
    return data

def mainAPI():
    try:
        data = check1(data)
        data = check2(data)
        data = check3(data)
        return data
    except Exception as e:
        return e.data #I know exceptions don't always have data, but this is an illustration of what I think I should implement

К сожалению, исключение в коде для реализации такого рода работы не принято в моей компании.

Итак, вот мои вопросы.

  1. Действительно ли неправильно использовать исключения таким образом?
  2. Есть ли недостатки в использовании исключений таким образом?
  3. Существует ли метод pythonic (или даже общего кодирования), который позволяет мне реализовать мой код и не требует от меня прекращения следования за DRY.

Ответы [ 2 ]

3 голосов
/ 14 апреля 2019

Это может быть не очень хороший ответ, кто-то еще сможет помочь больше.

Try-Exception:

Эта тема основана на мнении.Если они говорят, что им не нравится, что вы используете try exception, как это, то они, вероятно, не верят в «Лучше просить прощения, чем разрешения» .

Как говорится, бросать Exception неплохо;ОДНАКО поймать генерала Exception считается плохим.Если часть программного обеспечения не работает должным образом (то есть каким-то неизвестным образом), вы хотите, чтобы она не работала, поэтому вам нужно только поймать специфичный Exception, который вы хотите поймать.

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

Если вы не хотите перехватывать одно из существующих исключений, вы можетевсегда создавайте свои собственные:

class MyAPIException(Exception):
    def __init___(self, val):
        self.val = val
        Exception.__init__(self, "APIException with with arguments {0}".format(self.val))

def do_stuff(a,b,c):
    raise MyAPIException({
                'a' : a,
                'b' : b,
                'c' : c,
    })

try:
    do_stuff(1, 2, 3)
except MyAPIException as e:
    print("API Exception:", e)

Альтернатива:

Другим способом помочь с DRY может быть использование списка для совершения вызовов.

def check1():
    # List of functions you want to call in order
    calls = [check1a, check1b, check1c]
    for index, call in enumerate(calls):
        # If it is the first function we will not pass any data
        status, data = call() if index == 0 else call(data)
        if not status:
            return False, data
    return status, data

Эта реализация также позволяет легко реализовать его как генератор, если вы хотите вернуть результат каждого вызова функции.

2 голосов
/ 14 апреля 2019

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

class MyAPIException(Exception):
    pass

class SensorMiscalibrated(MyAPIException):
    pass

def mainAPI():
    try:
        data = check1(data)
        data = check2(data)
        data = check3(data)
        return True, data
    except SensorMiscalibrated as e:
        return False, data

Что приятно, так это то, чтолюбое другое исключение, вызванное check1, check2… в отношении прав доступа к файлу или ошибок процесса, будет просто всплывать и игнорироваться обработчиком исключений.

Исключения приветствуются в Python и не вносят снижения производительности в отличие от других языков, которыереализовать их по-другому.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...