Python:递归函数中的错误处理

时间:2013-11-12 17:13:38

标签: python exception recursion exception-handling error-handling

我:我正在运行Python 2.3.3,没有升级的可能性,我没有太多的Python经验。我的学习方法是谷歌搜索和阅读大量的stackoverflow。

背景:我正在创建一个python脚本,其目的是将两个目录作为参数,然后对两个目录中找到的所有文件执行比较/差异。这些目录的子目录也必须包含在diff中。 每个目录都是一个List,子目录是嵌套列表,依此类推......

the two directories:
oldfiles/
    a_tar_ball.tar
    a_text_file.txt
    nest1/
        file_in_nest
        nest1a/
            file_in_nest

newfiles/
    a_tar_ball.tar
    a_text_file.txt
    nest1/
        file_in_nest
        nest1a/

问题:通常一切都应该没问题,因为旧文件中的所有文件都应该存在于新文件中,但在上面的示例中,其中一个文件是' file_in_nest'新文件/'中缺少。 我希望打印一条错误消息,告诉我哪个文件丢失,但是当我使用我当前实例的代码结构时,比较'函数不知道除最近的目录之外的任何其他目录。我想知道是否有一个内置的错误处理,可以在递归阶梯中发送有关文件和目录的信息,在我们去的时候向它添加信息。如果我只打印丢失文件的文件名,我不知道它们可能是哪一个,因为有两个' file_in_nest'在&old;旧文件'

def compare(file_tree)
    for counter, entry in enumerate(file_tree[0][1:]):
        if not entry in file_tree[1]
            # raise "some" error and send information about file back to the 
            # function calling this compare, might be another compare.
        elif not isinstance(entry, basestring):
            os.chdir(entry[0])
            compare(entry)
            os.chdir('..')
        else:
            # perform comparison (not relevant to the problem)

        # detect if "some" error has been raised
            # prepend current directory found in entry[0] to file information
            break

def main()
    file_tree = [['/oldfiles', 'a_tar_ball.tar', 'a_text_file.txt', \
                [/nest1', 'file_in_nest', [/nest1a', 'file_in_nest']], \
                'yet_another_file'], \
                ['/newfiles', 'a_tar_ball.tar', 'a_text_file.txt', \
                [/nest1', 'file_in_nest', [/nest1a']], \
                'yet_another_file']]

    compare(file_tree)

    # detect if "some" error has been raised and print error message

这是我在stackoverflow上的第一个活动,除了读取som之外,请告诉我是否应该改进这个问题!

// Stefan

1 个答案:

答案 0 :(得分:1)

嗯,这取决于您是要将错误报告为异常还是某种形式的状态。

假设您想要采用“异常”方式,如果缺少一个文件,整个程序会崩溃,您可以定义自己的异常,将状态从被调用者保存到调用者:

class PathException(Exception):
    def __init__(self, path):
        self.path = path
        Exception.__init__(self)

def compare(filetree):
    old, new = filetree
    for counter, entry in enumerate(old[1:]):
        if entry not in new:
            raise PathException(entry)
        elif not isinstance(entry, basestring):
            os.chdir(entry[0])
            try:
                compare(entry)
                os.chdir("..")
            except PathException as e:
                os.chdir("..")
                raise PathException(os.path.join(entry, e.path))
        else:
            ...

try递归调用的位置,并使用调用者的信息更新任何传入的异常。

要在较小的示例上看到它,让我们尝试对两个列表进行深度比较,如果它们不相等则引发异常:

class MyException(Exception):
    def __init__(self, path):
        self.path = path
        Exception.__init__(self)

def assertEq(X, Y):
    if hasattr(X, '__iter__') and hasattr(Y, '__iter__'):
        for i, (x, y) in enumerate(zip(X, Y)):
            try:
                assertEq(x, y)
            except MyException as e:
                raise MyException([i] + e.path)
    elif X != Y:
        raise MyException([]) # Empty path -> Base case

这给了我们:

>>> L1 = [[[1,2,3],[4,5],[[6,7,8],[7,9]]],[3,5,[7,8]]]
>>> assertEq(L1, L1)

没有任何事情发生(列表相似),并且:

>>> L1 = [[[1,2,3],[4,5],[[6,7,8],[7,9]]],[3,5,[7,8]]]
>>> L2 = [[[1,2,3],[4,5],[[6,7,8],[7,5]]],[3,5,[7,8]]] # Note the [7,9] -> [7,5]
>>> try:
...     assertEq(L1, L2)
... except MyException as e: 
...     print "Diff at",e.path
Diff at [0, 2, 1, 1]
>>> print L1[0][2][1][1], L2[0][2][1][1]
9 5

这给出了完整的路径。

由于递归列表或路径基本相同,因此很容易使其适应您的用例。

解决这个问题的另一个简单方法是将文件中的这种差异报告为一个简单的差异,类似于其他:你可以将它作为旧文件和(不存在的)新文件之间的差异返回,或者返回 文件中的差异列表和文件的差异列表,在这种情况下,递归调用返回的值很容易递归更新。< / p>