【问题标题】:How to navigate control to top level functions如何将控件导航到顶级功能
【发布时间】:2019-04-14 15:34:50
【问题描述】:

我被告知要在我的公司设计一个新的 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

作为“DRY”概念的忠实追随者,如果觉得使用异常以以下方式运行代码是最好的。

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。

【问题讨论】:

    标签: python python-3.x python-2.7 exception


    【解决方案1】:

    这可能不是一个很好的答案,其他方式可以提供更多帮助。

    尝试异常:

    这是一个基于意见的主题。如果他们说他们不喜欢你这样使用try exception,那么他们可能不相信“请求宽恕而不是允许” 原则。

    话虽如此,抛出Exception 还不错;但是,抓住一般Exception 被认为是不好的。如果某个软件未按预期运行(即以某种未知方式),您希望它失败,因此您应该只捕获您想要捕获的特定 Exception

    您可以在此处找到一份完整的可行例外列表,只需选择一个看起来合理的并使用它:Python Programming Exceptions

    如果您不想捕获预先存在的异常之一,您可以随时创建自己的异常:

    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】:

    The answer by Error - Syntactical Remorse is a good one。使用 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 中鼓励使用异常,并且与其他以不同方式实现它们的语言不同,它们不会引入性能损失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-20
      相关资源
      最近更新 更多