函数的多个“结尾” - 返回一个对象,返回一个字符串,引发一个异常?

时间:2011-07-05 12:34:57

标签: python

我想这是一个结构设计问题。回来一些建议。

开始:我正在写一个模块。因此努力使其尽可能地为潜在的开发人员使用。

在对象内部(让我们称之为Swoosh)我有一个方法,当被调用时,可能会导致成功(返回一个新对象 - 洞察:它是httplib.HTTPResponse)或者失败(令人惊讶,不是吗?)。

我无法决定如何处理故障。这里有两个主要案例:

  1. 用户提供的数据不正确
  2. 数据还可以,但是需要用户交互() - 我需要向用户传递一个他或她需要以某种方式使用的字符串。
  3. 在(1)中,我决定raise ValueError()有适当的描述。 在(2)中,因为我需要实际将str传递给用户..我不确定是否最好只是return一个字符串并留给用户检查函数返回的内容(httplib.HTTPResponsestr)或raise自定义异常?通过提高异常来传递数据是一个好主意吗?我不认为我已经在任何地方看到过这种情况,但另一方面 - 我没有看到太多。

    作为开发人员,您希望从这样的对象/函数中获得什么?

    或许你发现整个设计都很荒谬 - 让我知道,我会很高兴地学习。

4 个答案:

答案 0 :(得分:6)

尽管我喜欢使用特定类型异常处理这两种情况的方法,但我会提供一种不同的方法,以防它有所帮助:回调。

如果你已经使用像Twisted这样的异步框架,回调往往会更好,但这不是他们唯一的地方。所以你可能有一个方法,为每个结果采用一个函数,如:

def do_request(on_success, on_interaction_needed, on_failure):
    """
    Submits the swoosh request, and awaits a response.

    If no user interaction is needed, calls on_success with a
    httplib.HTTPResponse object.

    If user interaction is needed, on_interaction_needed is
    called with a single string parameter.

    If the request failed, a ValueError is passed to on_failure
    """
    response = sumbit_request()
    if response.is_fine():
        on_success(response)
    elif response.is_partial()
        on_interaction_needed(response.message)
    else:
        on_failure(ValueError(response.message))

作为Python,有一百万种方法可以做到这一点。您可能不喜欢将异常传递给函数,因此您可能只需对用户输入方案进行回调。此外,您可以将回调传递到Swoosh初始化设备。

但也有缺点,例如:

  • 粗心大意可能导致意大利面条代码
  • 您允许调用者将逻辑注入您的函数(例如,回调中引发的异常将从Swoosh传播出来)
  • 我的例子很简单,你的实际功能可能不是

像往常一样,仔细考虑和良好的文档应该避免这些问题。从理论上讲。

答案 1 :(得分:4)

我认为在这种情况下提出异常实际上可能是个好主意。由于鸭子打字,在Python中将多个信号压缩成函数的单个返回值并不理想。它不是非常Pythonic;每次你需要做的事情:

result = some_function(...)
if isinstance(result, TypeA):
    do_something(result)
elif isinstance(result, TypeB):
    do_something_else(result)

你应该考虑它是否真的是最好的设计(正如你所做的那样)。

在这种情况下,如果您实现自定义异常,那么调用您的函数的代码可以将返回的值视为HTTPResponse

通过抛出异常来处理函数无法返回其调用者可以通过这种方式处理的内容的任何路径。

同样,捕获异常并提示用户输入消息的代码不必担心其获取的事物的确切类型。它只是知道它已被明确指示(例外)向用户显示内容。

答案 2 :(得分:3)

如果用户交互案例意味着调用代码必须显示提示,获取一些输入并将控制权传递给您的函数,那么尝试处理异常情况可能会很难看。例如,

try:
    Swoosh.method()
except UserInteraction, ex:
    # do some user interaction stuff
    # pass it back to Swoosh.method()?
    # did Swoosh need to save some state from the last call?
except ValueError:
    pass # whatever

如果此用户交互是控制流的正常部分,那么首先将用户交互功能传递到您的方法可能更清晰 - 然后它可以将结果返回到Swoosh代码。例如:

# in Swoosh
def method(self, userinteractor):
    if more_info_needed:
        more_info = userinteractor.prompt("more info")
    ...

ui = MyUserInteractor(self) # or other state
Swoosh.method(ui)

答案 3 :(得分:1)

您可以返回(httplib.HTTPResponse,str)的元组,其中str可选地为None。 肯定会为1)引发例外。

如果你不喜欢返回一个元组,你也可以创建一个“响应对象”,即一个新类的实例(比如说SomethingResponse),它将HTTPResponse和可选消息封装到最终用户(最简单的)案例,只是一个str)。