簡體   English   中英

Python:遞歸函數中的錯誤處理

[英]Python: error handling in recursive functions

我:我正在運行Python 2.3.3,無法升級,並且我對Python沒有太多經驗。 我的學習方法是谷歌搜索和讀取大量的stackoverflow。

背景:我正在創建一個python腳本,其目的是將兩個目錄用作參數,然后對兩個目錄中找到的所有文件進行比較/比較。 目錄中的子目錄也必須包含在diff中。 每個目錄是一個列表,子目錄是嵌套的列表,依此類推...

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”之一。 我希望打印一條錯誤消息,告訴我缺少哪個文件,但是當我在“比較”功能的當前實例下方使用代碼結構時,除了最接近的目錄外,不知道其他任何目錄。 我想知道是否有一個內置的錯誤處理程序可以在遞歸階梯中向上發送有關文件和目錄的信息,並隨即向其中添加信息。 如果我只打印丟失文件的文件名,我將不知道是哪個文件,因為“ 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

這是我關於stackoverflow的第一個活動,除了閱讀som以外,請告訴我是否應該改善這個問題!

// Stefan

好吧,這取決於您是要報告錯誤還是異常還是某種狀態。

假設您想采用“例外”方式,如果缺少一個文件,則整個程序都會崩潰,您可以定義自己的異常,將狀態從被調用者保存到調用者:

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

給出了完整的路徑。

由於遞歸列表或路徑基本上是同一回事,因此很容易將其適應您的用例。

解決此問題的另一種簡單方法是將文件中的差異報告為簡單的差異,與其他差異類似:您可以將其作為舊文件與(不存在的)新文件之間的差異返回,也可以同時返回列表文件之間的差異和文件差異列表,在這種情況下,它是很容易,因為他們是由遞歸調用返回的遞歸更新值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM