Функция, возвращающая кортеж или None: как правильно вызвать эту функцию? - PullRequest
13 голосов
/ 10 августа 2010

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

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, чтобы вызывающая сторона могла легко распаковать ....

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

Ответы [ 6 ]

12 голосов
/ 10 августа 2010

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

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

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

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

10 голосов
/ 10 августа 2010

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

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

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

8 голосов
/ 10 августа 2010

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

class AIsTooSmallError( ArgumentError ): pass

, а затем

raise AIsTooSmallError( "a must be positive." )

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

4 голосов
/ 10 августа 2010

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

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

1 голос
/ 02 июля 2015

Это похоже на предыдущий ответ.Вы можете вернуть либо экземпляр объекта, либо 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
1 голос
/ 10 августа 2010

Если вы хотите, чтобы объекты 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. Он каким-то образом стоит между первыми двумя случаями, потому что сбой сопоставления является ожидаемым результатом, в то время как возвращаемый объект по умолчанию не будет очень полезным в любом случае.

...