问题
I could see several topics on try - catch but doesnt seem to discuss errors if any from finally block itself. I found that the error is not handled if it is in finally block. What would be the ideal way to manage finally?
For eg. below is a mail function. if there is any error in try block, finally will execute the quit
method which itself is not initiated so an unhandled error occurs. So is it better to ensure there is no errors occur in finally block?
def send_email(ldap, email_address, password, msg):
try:
message = MIMEMultipart('alternative')
message['To'] = email.utils.formataddr(('Recipient', '%s@abc.com'%email_address))
message['From'] = email.utils.formataddr(('Author', '%s@abc.com'%email_address))
message['Subject'] = 'Sample subject'
text = "%s"%msg
html = MIMEText('<html><head></head><h2>data</h2><body><p>%s</p></body></html>'%msg,'html')
message.attach(html)
server = smtplib.SMTP(host="ip",port=0)
server.set_debuglevel(True)
# identify ourselves, prompting server for supported features
server.ehlo()
if server.has_extn('STARTTLS'):
server.starttls()
server.ehlo()
server.login(ldap, password)
print "%s@abc.com, %s@abc.com, %s "%(email_address,email_address,message.as_string())
server.sendmail('%s@abc.com'%email_address, "%s@abc.com"%email_address, message.as_string())
finally:
server.quit()
回答1:
Dont put a bunch of code (doing different things) into one try/except block, but you can easily add an if/else condition in your finally block:
def send_email(ldap, email_address, password, msg):
server = None #make sure server variable is always defined.
try:
...
server = smtplib.SMTP(...)
...
finally:
if server and isinstance(x, smtplib.SMTP):
server.quit()
回答2:
Since your finally
block is only used to ensure the server connection is properly closed whatever, the obvious answer is to only wrap the relevant part in the try
block:
def send_email(ldap, email_address, password, msg):
message = MIMEMultipart('alternative')
message['To'] = email.utils.formataddr(('Recipient', '%s@abc.com'%email_address))
message['From'] = email.utils.formataddr(('Author', '%s@abc.com'%email_address))
message['Subject'] = 'Sample subject'
text = "%s"%msg
html = MIMEText('<html><head></head><h2>data</h2><body><p>%s</p></body></html>'%msg,'html')
message.attach(html)
server = smtplib.SMTP(host="ip",port=0)
# now you can start the try block:
try:
server.set_debuglevel(True)
# identify ourselves, prompting server for supported features
server.ehlo()
if server.has_extn('STARTTLS'):
server.starttls()
server.ehlo()
server.login(ldap, password)
print "%s@abc.com, %s@abc.com, %s "%(email_address,email_address,message.as_string())
server.sendmail('%s@abc.com'%email_address, "%s@abc.com"%email_address, message.as_string())
finally:
server.quit()
A still better solution would be to split this code in distinct functions each with a single well-defined responsability - preparing the message, getting a connection to the server etc, ie:
def prepare_message(sender, recipient, subject, msg):
message = MIMEMultipart('alternative')
message['To'] = email.utils.formataddr(('Recipient', recipient))
message['From'] = email.utils.formataddr(('Author', sender))
message['Subject'] = subject
#text = "%s" % msg # this one is useless
html = MIMEText("""
<html>
<head></head>
<body>
<h2>data</h2>
<p>%s</p>
</body>
</html>""" % msg,
'html'
)
message.attach(html)
return message
def connect(ldap, password):
server = smtplib.SMTP(host="ip",port=0)
server.set_debuglevel(True)
# identify ourselves, prompting server for supported features
server.ehlo()
if server.has_extn('STARTTLS'):
server.starttls()
server.ehlo()
server.login(ldap, password)
return server
def send_email(ldap, email_address, password, msg):
sender = recipient = "%s@abc.com" % email_address
message = prepare_message(sender, recipient, 'Sample subject', msg)
server = connect(ldap, password)
try:
server.sendmail(sender, recipient, message.as_string())
finally:
server.quit()
来源:https://stackoverflow.com/questions/43586041/how-to-catch-error-in-finally-block-in-python