Функция возвращает кортеж или None: как хорошо называть эту функцию?

Предположим следующее:

def MyFunc(a):
  if a < 0:
    return None
  return (a+1, a+2, a+3)

v1, v2, v3 = MyFunc()
# Bad ofcourse, if the result was None

Каков наилучший способ определения функции, возвращающей кортеж, и все же можно красиво назвать. В настоящее время я могу это сделать:


r = MyFunc()
if r:
  v1, v2, v3 = r
else:
  # bad!!
  pass

Что мне не нравится в этом, так это то, что я должен использовать одну переменную, а затем распаковать ее.

Другим решением является то, что функция может возвращать кортеж, полный Nones, так что вызывающий может красиво распаковать....

Кто-нибудь может предложить лучший дизайн?

Ответ 1

Как насчет повышения ArgumentError? Затем вы можете try вызвать его и обработать исключение, если аргумент неверен.

Итак, что-то вроде:

try:
    v1, v2, v3 = MyFunc()
except ArgumentError:
    #deal with it

Также см. ответ katrielalex для использования подкласса ArgumentError.

Ответ 2

Это должно хорошо работать:

v1, v2, v3 = MyFunc() or (None, None, None)

Когда MyFunc() возвращает кортеж, он будет распакован, иначе он заменит 3-кортеж None.

Ответ 3

recursive имеет действительно элегантное и питоновское решение. НО: зачем вы хотите вернуть None? У Python есть способ обработки ошибок, и это связано с созданием исключения:

class AIsTooSmallError( ArgumentError ): pass

а затем

raise AIsTooSmallError( "a must be positive." )

Причина, по которой это лучше, заключается в том, что возврат значения означает, что вы завершили обработку и передаете ответ. Это нормально, если вы сделали некоторую обработку, но это глупо, если вы немедленно возвращаете None.

Ответ 4

Другим решением является то, что функция может возвращать кортеж, полный Nones, так что вызывающий может красиво распаковать....

Что не так с этим? Согласованность - это хорошо.

Ответ 5

Если вы хотите, чтобы объекты v1, v2, v3 существовали и в случае ошибки были установлены значение по умолчанию, верните значения по умолчанию самостоятельно. Это упростит код вызова, не полагаясь на вызывающего абонента, чтобы установить их вручную:

def MyFunc(a):
    if a < 0:
        # can't use a negative value; just return some defaults
        return (None, None, None)
    return (a+1, a+2, a+3)

С другой стороны, если возврат по умолчанию не подходит, а отрицательный аргумент считается серьезной ошибкой, создайте исключение:

def MyFunc(a):
    if a < 0:
        # sorry, negative values are unacceptable
        raise ValueError('cannot accept a negative value')
    return (a+1, a+2, a+3)

На третьем жестком возврате None может быть предпочтительнее иногда при возврате одного объекта, как в случае с функциями search() и match() модуля re. Это как-то стоит между первыми двумя случаями, потому что совпадение неудачи является ожидаемым результатом, в то время как объект возврата по умолчанию в любом случае не будет очень полезен.

Ответ 6

Это похоже на предыдущий ответ. Вы можете вернуть экземпляр объекта или None

def MyFunc(a):
    class MyFuncClass(object):
        def __init__(self, **kwargs):
            self.__dict__.update(kwargs)
    if a < 0:
        return None
    return MyFuncClass(one=a+1, two=a+2, three=a+3)

o = MyFunc(1)
if o is not None:
    print o.one, o.two, o.three