Методы класса Python, когда возвращать себя?

Я смущен, когда возвращаю себя внутри класса и когда нужно вернуть значение, которое может или не может быть использовано для проверки правильности метода.

def api_request(self, data):
 #api web request code
 return response.text
def connect(self):
 #login to api, set some vars defined in __init__
 return self
def send_message(self, message):
 #send msg code
 return self

Таким образом, выше нескольких примеров. api_request Я знаю, что текстовый ответ является обязательным. Но с send_message, что я должен вернуть?

который затем преобразуется в dict, чтобы проверить, что ключ существует, иначе повышайте ошибку).

Если он вернет True, response-> dict или self?

заранее спасибо

2 ответа

Поскольку ошибки, как правило, поставляются как исключения, и, следовательно, значения возврата к неудаче/неудачи редко бывают полезны, многие функции объекта-модификатора заканчиваются без возвращаемого значения вообще или, точнее, возвращают None, поскольку вы не можете вернуть ничего - вообще. (Рассмотрим некоторые из встроенных объектов Python, например list, где append и extend возвращают None и dict, где dict.update возвращает None.)

Тем не менее, возвращение self удобно для цепочки вызовов метода, даже если некоторым Pythonistas это не нравится. См. Любопытный ответ. Если внутренние методы класса возвращают значения или просто изменяют переменные экземпляра в 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 вообще и не иметь все свои собственные ошибки; возможно, вы можете сжать свои ошибки в ValueError и KeyError и т.д., например.

Эти варианты - вот что такое программирование!


Как правило, объекты в python изменяемы. Поэтому вы не возвращаете self, так как изменения, внесенные вами в метод, отражаются в самом объекте.

Чтобы использовать ваш пример:

api = API() # initialise the API
if api.connect(): # perhaps return a bool, indicating that the connection succeeded
 api.send_message() # you now know that this API instance is connected, and can send messages

licensed under cc by-sa 3.0 with attribution.