-1

我经常发现自己从一个方法返回一个布尔值,该方法在多个位置使用,以便将围绕该方法的所有逻辑包含在一个地方。所有(内部)调用方法需要知道的是操作是否成功。

我正在使用 Python,但问题不一定特定于该语言。我能想到的只有两个选项引发异常,尽管情况并不例外,并且记住在每个调用函数的地方捕获该异常返回一个布尔值,就像我正在做的那样。

这是一个非常简单的例子,它演示了我在说什么。

import os

class DoSomething(object):

    def remove_file(self, filename):

        try:
            os.remove(filename)
        except OSError:
            return False

        return True

    def process_file(self, filename):

        do_something()

        if remove_file(filename):
            do_something_else()

虽然它有效,但它的设计很糟糕。我该如何改进呢?

4

5 回答 5

3

基于@Joran Beasley 的回答,我将其他内容放在 else 块中:

class DoSomething(object):

    def process_file(self, filename):

        do_something()

        try:
            os.remove(filename)
        except OSError:
            return False
        else:
            do_something_else()
于 2013-05-16T20:57:45.147 回答
3

我不确定我是否理解您要在这里解决的问题,但是此评论似乎很有启发性:

我可以os.path.exists(filename)在尝试删除之前使用,但不能保证文件在此期间不会被锁定,我仍然需要确定删除是否成功。

同时也不能保证该文件不会被删除或被其他文件替换等。所以,你是对的,你不应该使用os.path.exists.

但是这里有什么问题?只是尝试删除它。如果文件不存在,则会出现异常。如果文件被锁定或无法删除,则会出现异常。无论哪种方式,删除都失败了。

如果问题是将一个失败原因与其他原因区分开来,以便您可以专门处理它,那很容易:

try:
    os.remove(filename)
except FileNotFoundError:
    print("Oops, {} doesn't exist".format(filename))
except OSError as e:
    print('Got {} trying to delete {}'.format(e, filename))
else:
    do_something_else()

如果您使用的是比 3.3 更早的 Python 版本,则没有FileNotFoundError,所以……它有点不那么漂亮,但想法相同:

try:
    os.remove(filename)
except OSError as e:
    if e.errno == errno.ENOENT
        print("Oops, {} doesn't exist".format(filename))
    else:
        print('Got {} trying to delete {}'.format(e, filename))
else:
    do_something_else()
于 2013-05-16T21:02:59.500 回答
2

在这种情况下,允许(或引发)异常是可以的。整个想法是,流控制可以在理解“大局”的水平上进行处理,并且可能能够对此做点什么。内部部件在途中愉快地携带,而无需检查布尔标志。

例如,如果删除文件失败 - 它是灾难性的 - 大概你的内部函数不知道,所以它不应该掩盖堆栈跟踪。再往上说,它可能会重试,或者只是认为它实际上并没有那么糟糕,让我们继续吧。强制异常返回意味着信息丢失,并且需要用户记住实际检查返回结果 - 此外,某些函数可能具有真正的布尔返回结果,因此识别这些结果的唯一方法是通过处理异常。

于 2013-05-16T20:54:51.810 回答
2

我能想到 OP 设计不好的唯一原因是:通常在 python 中有两种思想流派Look before you jumpEasier to ask permit than sorry,但在你的代码中你两者都做。通常你只选择一个或另一个

class DoSomething(object):

    def process_file(self, filename):

        do_something()

        try:
            os.remove(filename)
        except OSError:
            return False
        else:
            do_something_else()

恕我直言,干净多了

于 2013-05-16T20:51:13.927 回答
0

好吧,我想如果你真的想去删除“布尔”,你可以使用像

def remove_file(self, filename, success):
    try:
        os.remove(filename)
    except OSError:
        //error stuff
    else:
        success()

def process_file(self, filename):
    do_something()
    remove_filename(filename, lambda: do_something_else())

您可以将所需的参数数量传递给函数,然后将其包装在 lambda 中,因此只有在删除填充成功时才会执行成功函数。不过,我认为您的初始代码没有任何问题。

于 2013-05-16T21:03:21.687 回答