Python:递归函数中的错误处理
我:我正在运行Python2.3.3,不可能升级,而且我没有太多的Python经验。我的学习方法是通过谷歌搜索和阅读大量的信息 背景:我正在创建一个python脚本,其目的是将两个目录作为参数,然后对两个目录中找到的所有文件执行比较/diff。目录中有子目录,这些子目录也必须包含在差异中。 每个目录都是一个列表,子目录是嵌套列表等等Python:递归函数中的错误处理,python,exception,recursion,exception-handling,error-handling,Python,Exception,Recursion,Exception Handling,Error Handling,我:我正在运行Python2.3.3,不可能升级,而且我没有太多的Python经验。我的学习方法是通过谷歌搜索和阅读大量的信息 背景:我正在创建一个python脚本,其目的是将两个目录作为参数,然后对两个目录中找到的所有文件执行比较/diff。目录中有子目录,这些子目录也必须包含在差异中。 每个目录都是一个列表,子目录是嵌套列表等等 the two directories: oldfiles/ a_tar_ball.tar a_text_file.txt nest1/
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/
问题:通常情况下,所有文件都应该正常运行,因为旧文件中的所有文件都应该存在于新文件中,但在上面的示例中,“newfiles/”中缺少一个“file\u in_nest”。
我希望打印一条错误消息,告诉我丢失了哪个文件,但是当我使用“compare”函数当前实例下面的代码结构时,除了最近的目录外,我不知道任何其他目录。我想知道是否有一个内置的错误处理,可以在递归阶梯中向上发送有关文件和目录的信息,并在执行时向其中添加信息。如果我只打印丢失文件的文件名,我就不知道它可能是其中的哪一个,因为“oldfiles”中有两个“file\u 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:
...
您可以尝试
递归调用,并使用调用方的信息更新任何传入的异常
为了在一个较小的示例中看到它,让我们尝试深入比较两个列表,如果它们不相等,则引发一个异常:
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)
没有发生任何事情(列表类似),并且:
这给出了完整的路径
由于递归列表或路径基本上是相同的,因此很容易根据您的用例对其进行调整
解决此问题的另一个简单方法是将文件中的差异报告为简单差异,与其他文件类似:您可以将其作为旧文件和(不存在的)新文件之间的差异返回,或者同时返回文件差异列表和文件差异列表,在这种情况下,递归调用返回的值很容易更新。您可以通过当前工作目录跟踪完整路径,因此可以使用
os.getcwd()
重建完整文件名。也就是说,在递归函数中修改全局状态通常被认为是一件坏事,所以考虑将绝对路径传递给os.walk()
,并将其与os.chdir()
进行比较,谢谢。我刚刚看到我上面的代码不会达到我想要的效果,所以如果你真的想看到一个有效的递归示例,请看val对下面两个列表的深入比较。谢谢你,这正是我想要的!
>>> 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