简体   繁体   English

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

[英]Python: error handling in recursive functions

Me: I am running Python 2.3.3 without possibility to upgrade and i don't have much experience with Python. 我:我正在运行Python 2.3.3,无法升级,并且我对Python没有太多经验。 My method for learning is googling and reading tons of stackoverflow. 我的学习方法是谷歌搜索和读取大量的stackoverflow。

Background: I am creating a python script whose purpose is to take two directories as arguments and then perform comparisons/diff of all the files found within the two directories. 背景:我正在创建一个python脚本,其目的是将两个目录用作参数,然后对两个目录中找到的所有文件进行比较/比较。 The directories have sub-directories that also have to be included in the diff. 目录中的子目录也必须包含在diff中。 Each directory is a List and sub-directories are nested Lists and so on... 每个目录是一个列表,子目录是嵌套的列表,依此类推...

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/

Problem: Normally all should go fine as all files in oldfiles should exist in newfiles but in the above example one of the 'file_in_nest' is missing in 'newfiles/'. 问题:通常所有文件都应该正常,因为旧文件中的所有文件都应存在于新文件中,但在上面的示例中,“新文件/”中缺少“ file_in_nest”之一。 I wish to print an error message telling me which file that is missing but when i'm using the code structure below the current instance of my 'compare' function doesn't know any other directories but the closest one. 我希望打印一条错误消息,告诉我缺少哪个文件,但是当我在“比较”功能的当前实例下方使用代码结构时,除了最接近的目录外,不知道其他任何目录。 I wonder if there is a built in error handling that can send information about files and directory up in the recursion ladder adding info to it as we go. 我想知道是否有一个内置的错误处理程序可以在递归阶梯中向上发送有关文件和目录的信息,并随即向其中添加信息。 If i would just print the filename of the missing file i would not know which one of them it might be as there are two 'file_in_nest' in 'oldfiles' 如果我只打印丢失文件的文件名,我将不知道是哪个文件,因为“ oldfiles”中有两个“ file_in_nest”

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

This is my first activity on stackoverflow other than reading som please tell me if i should improve on the question! 这是我关于stackoverflow的第一个活动,除了阅读som以外,请告诉我是否应该改善这个问题!

// Stefan // Stefan

Well, it depends whether you want to report an error as an exception or as some form of status. 好吧,这取决于您是要报告错误还是异常还是某种状态。

Let's say you want to go the 'exception' way and have the whole program crash if one file is missing, you can define your own exception saving the state from the callee to the caller: 假设您想采用“例外”方式,如果缺少一个文件,则整个程序都会崩溃,您可以定义自己的异常,将状态从被调用者保存到调用者:

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

Where you try a recursive call, and update any incoming exception with the information of the caller. 在这里try递归调用,并使用调用者的信息更新所有传入的异常。

To see it on a smaller example, let's try to deep-compare two lists, and raise an exception if they are not equal: 为了在一个较小的示例上看到它,让我们尝试对两个列表进行深度比较,如果它们不相等,则引发一个异常:

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

This gives us: 这给我们:

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

Nothing happens (lists are similar), and: 什么也没发生(列表相似),并且:

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

Which gives the full path. 给出了完整的路径。

As recursive lists or paths are basically the same thing, it is easy to adapt it to your use case. 由于递归列表或路径基本上是同一回事,因此很容易将其适应您的用例。

Another simple way of solving this would be to report this difference in files as a simple diff, similar to the others: you can return it as a difference between the old file and the (non-existent) new file, or return both the list of differences in files and the list of differences of files, in which case it is easy to update recursively the values as they are returned by the recursive calls. 解决此问题的另一种简单方法是将文件中的差异报告为简单的差异,与其他差异类似:您可以将其作为旧文件与(不存在的)新文件之间的差异返回,也可以同时返回列表文件之间的差异和文件差异列表,在这种情况下,它是很容易,因为他们是由递归调用返回的递归更新值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM