如何正确使用try / except / with内部函数和main

cod*_*nob 1 python with-statement try-except

我是一个相对的python新手,我对如何正确处理异常感到困惑。对于这个愚蠢的问题表示歉意。

在main()中,我遍历日期列表,并为每个日期调用一个函数,该函数从公共Web服务器下载csv文件。由于明显的原因,我想适当地捕获异常,但尤其是因为我不知道何时可以下载感兴趣的文件。我的程序将作为cron作业的一部分执行,并且将尝试每3小时下载一次这些文件(如果有)。

我想要的是下载日期列表中的第一个文件,如果结果为404,则该程序不应继续处理下一个文件,因为假设是如果列表中最旧的日期不可用,则没有一个之后的其他版本也将可用。

我有以下python伪代码。我在尝试下载文件的函数中有try / except块,但是如果函数中发生异常,我该如何在main()中正确处理它,以便我可以决定是否继续进行下一个日期。之所以创建一个执行下载的功能的原因是,我想稍后在同一main()块中针对其他文件类型重用该代码。

def main():
...
...
# datelist is a list of date objects
    for date in datelist:
        download_file(date)

def download_file(date):
    date_string = str(date.year) + str(date.strftime('%m')) + str(date.strftime('%d'))
    request = HTTP_WEB_PREFIX+ date_string + FILE_SUFFIX
    try: 
        response = urllib2.urlopen(request)
    except urllib2.HTTPError, e:
        print "HTTPError = " + str(e)
    except urllib2.URLError, e:
        print "URLError = " + str(e)
    except httplib.HTTPException, e:
        print "HTTPException = " + str(e)  
    except IOError:
        print "IOError = " + str(e)
    except Exception:
        import traceback
        print "Generic exception: " + traceback.format_exc()
    else: 
        print "No problem downloading %s - continue..." % (response)
        try: 
            with open(TMP_DOWNLOAD_DIRECTORY + response, 'wb') as f:
        except IOError:
            print "IOError = " + str(e)
        else:
            f.write(response.read())
        f.close()
Run Code Online (Sandbox Code Playgroud)

Joe*_*hon 5

这里的关键概念是,如果您可以解决问题,则应捕获异常;如果您做不到,那就是呼叫者要解决的问题。在这种情况下,如果文件不存在,则下载程序将无法修复问题,因此应将其异常通知调用方。如果有异常,调用者应该知道停止循环。

因此,让我们将所有异常处理从函数中移出到循环中,并对其进行修复,以确保在下载文件失败时可以消除异常,这是规范所要求的:

for date in datelist:
        date_string = str(date.year) + 
                      str(date.strftime('%m')) + 
                      str(date.strftime('%d'))
    try:
        download_file(date_string)
    except:
        e = sys.exc_info()[0]
        print ( "Error downloading for date %s: %s" % (date_string, e) )
        break
Run Code Online (Sandbox Code Playgroud)

download_file现在应该这样做,除非您想进行重试或类似的操作,否则根本不要捕获异常。由于您已经根据调用者的喜好对日期进行了解码,因此该代码也可以显示出来download_file,从而简化了代码

def download_file(date_string):
    request = HTTP_WEB_PREFIX + date_string + FILE_SUFFIX
    response = urllib2.urlopen(request) 
    print "No problem downloading %s - continue..." % (response)
    with open(TMP_DOWNLOAD_DIRECTORY + response, 'wb') as f:
        f.write(response.read())
        f.close()
Run Code Online (Sandbox Code Playgroud)

我建议该print语句是多余的,但是如果您真的想要它,则使用logger是一种更灵活的前进方式,因为这将允许您稍后根据需要通过更改配置文件而不是代码来打开或关闭它。