由于错误往往作为异常传递,因此成功/失败返回值很少有用,许多对象修饰符函数最终根本没有返回值 - 或者更准确地说, return None
,因为你不能返回任何东西 - 在-全部。(考虑一些 Python 的内置对象,例如list
, whereappend
和extend
return None
,以及dict
, where dict.update
returns None
。)
尽管如此,返回self
对于链接方法调用来说还是很方便的,即使一些 Pythonistas 不喜欢它。请参阅 Kindall 在内部类方法应返回值还是仅修改 python 中的实例变量?例如。
编辑以根据评论添加一些示例:
你“应该”返回什么——或引发异常,在这种情况下,“什么异常”——取决于问题。是否要send_message()
等待响应、验证响应并验证它是否良好?如果是这样,如果没有响应、验证失败或响应有效但显示“消息被拒绝”,您是否希望它引发错误?如果是这样,您是否希望每次失败都出现不同的错误等?一种合理的(对于某种合理的价值)方法是用“基本”异常捕获所有失败,并使每种“类型”的失败都衍生出:
class ZorgError(Exception): # catch-all "can't talk via the Zorg-brand XML API"
pass
class ZorgRemoteDown(ZorgError): # connect or send failed, or no response/timeout
pass
class ZorgNuts(ZorgError): # remote response incomprehensible
pass
class ZorgDenied(ZorgError): # remote says "permission denied"
pass
# add more if needed
现在你的一些函数可能看起来像这样(注意,这些都没有经过测试):
def connect(self):
"""connect to server, log in"""
... # do some prep work
addr = self._addr
try:
self._sock.connect(addr)
except socket.error as err:
if err.errno == errno.ECONNREFUSED: # server is down
raise ZorgRemoteDown(addr) # translate that to our Zorg error
# add more special translation here if needed
raise # some other problem, propagate it
... # do other stuff now that we're connected, including trying to log in
response = self._get_response()
if response == 'login denied' # or whatever that looks like
raise ZorgDenied() # maybe say what exactly was denied, maybe not
# all went well, return None by not returning anything
def send_message(self, msg):
"""encode the message in the way the remote likes, send it, and wait for
a response from the remote."""
response = self._send_and_wait(self._encode(msg))
if response == 'ok':
return
if response == 'permission denied':
raise ZorgDenied()
# don't understand what we got back, so say the remote is crazy
raise ZorgNuts(response)
然后你需要一些像这样的“内部”函数:
def _send_and_wait(self, raw_xml):
"""send raw XML to server"""
try:
self._sock.sendall(raw_xml)
except socket.error as err:
if err.errno in (errno.EHOSTDOWN, errno.ENETDOWN) # add more if needed
raise ZorgRemoteDown(self._addr)
raise
return self._get_response()
def _get_response(self):
"""wait for a response, which is supposedly XML-encoded"""
... some code here ...
if we_got_a_timeout_while_waiting:
raise ZorgRemoteDown(self._addr)
try:
return some_xml_decoding_stuff(raw_xml)
except SomeXMLDecodeError:
raise ZorgNuts(raw_xml) # or something else suitable for debug
您可能会选择根本不翻译socket.error
s,并且不会有自己的错误;例如,也许您可以将错误压缩到ValueError
等等KeyError
。
这些选择就是编程的全部内容!