我已经创建了python函数来从ftp站点提取数据。它运作良好。但是,有很多try / except语句。我读到了使用python"和#34;声明使这更好,但我不清楚这将如何改善功能。这是代码:
HOST = 'ftp.osuosl.org'
DIRN = 'debian/tools'
FILE = 'loadlin.txt'
def func(HOST, DIRN, FILE):
import ftplib
from StringIO import StringIO
import os
import socket
try:
f = ftplib.FTP(HOST)
except (socket.error, socket.gaierror), e:
print 'ERROR: cannot reach "%s"' % HOST
return "None"
print '*** Connected to host "%s"' % HOST
try:
f.login()
except ftplib.error_perm:
print 'ERROR: cannot login anonymously'
f.quit()
return "None"
print '*** Logged in as "anonymous"'
try:
f.cwd(DIRN)
except ftplib.error_perm:
print 'ERROR: cannot CD to "%s"' % DIRN
f.quit()
return "None"
print '*** Changed to "%s" folder' % DIRN
try:
r = StringIO()
f.retrbinary('RETR %s' % FILE, r.write)
except ftplib.error_perm:
print 'ERROR: cannot read file "%s"' % FILE
return "None"
else:
print '*** Downloaded "%s" to CWD' % FILE
f.quit()
return r.getvalue()
print func(HOST, DIRN, FILE)
答案 0 :(得分:0)
一般来说这种风格效果很好。每个有趣的代码段都有一个try / except块,因此您可以将有关错误的特定详细信息传达给调用者。
代码在几个地方有f.quit()
。这很好,但很容易忘记哪些案例应该quit
哪些不应该。{1}}。很容易错过一个。
使用finally
块考虑此样式。如果RETR
成功或失败,则始终执行此块。它更安全。
try:
r = StringIO()
f.retrbinary('RETR %s' % FILE, r.write)
except ftplib.error_perm:
print 'ERROR: cannot read file "%s"' % FILE
return "None"
else:
print '*** Downloaded "%s" to CWD' % FILE
finally:
f.quit()
答案 1 :(得分:0)
使用上下文管理器有一种略微更好的方法。因为您在except
分支中以及在运行命令后立即采取的操作基本上是样板文件,您可以将其抽象到上下文管理器的__exit__
部分。唯一的复杂因素是您希望在捕获异常后返回,这不能隐藏在上下文管理器中。所以我们必须在上下文对象本身设置一个标志,并在调用代码中检查(因此if h.err:
检查):
import ftplib
from StringIO import StringIO
import os
import socket
class HandleExc(object):
""" Context manager for exception handling.
exc_types is a tuple of exception types we want to handle
"""
def __init__(self, handle=f, exc_types=(ftplib.error_perm,), msg="", errmsg=""):
self.err = False
self.f = f
self.msg = msg
self.errmsg = errmsg
def __enter__(self):
return self
def __exit__(exc_type, exc_value, traceback):
if exc_type in exc_types:
# Got an exception we want to handle.
print(self.errmsg)
if self.f:
self.f.close()
self.err = True # Set the err flag so the caller can check it.
elif exc_type:
# Unhandled exception, let it raise (though you may want to call f.close() first).
return
else:
# All good print success message
print(self.msg)
def func(HOST, DIRN, FILE):
with HandleExc(exc=(socket.errror, socket.gaierror),
msg='*** Connected to host "%s" ' % HOST,
errmsg='ERROR: cannot reach "%s"' % HOST) as h:
f = ftplib.FTP(HOST)
if h.err:
return "None"
with HandleExc(f, msg='*** Logged in as "anonymous"',
errmsg='ERROR: cannot CD to "%s"' % DIRN) as h:
f.login()
if h.err:
return "None"
with HandleExc(f, msg='*** Changed to "%s" folder' % DIRN,
errmsg='ERROR: cannot login anonymously') as h:
f.cwd(DIRN)
if h.err:
return "None"
with HandleExc(f, msg='*** Downloaded "%s" to CWD' % FILE,
errmsg='ERROR: cannot read file "%s"') as h:
r = StringIO()
f.retrbinary('RETR %s' % FILE, r.write)
if h.err:
return "None"
f.quit()
return r.getvalue()
print func(HOST, DIRN, FILE)
这有点减少func
中的样板代码,但不完全。