Pythonic способ эффективно обрабатывать переменное число возвращаемых аргументов

Итак, у меня есть функция, которая может работать тихо или многословно. В тихом режиме он производит выход. В подробном режиме он также сохраняет промежуточные вычисления в списке, хотя это делает дополнительные вычисления сами по себе.

Прежде чем спросить, да, это идентифицированное узкое место для оптимизации, и подробный вывод редко необходим, так что это нормально.

Итак, вопрос в том, какой самый пифонический способ эффективно обрабатывать функцию, которая может или не может вернуть второе значение? Я подозреваю, что питонический путь будет называться кортежами или выходом словаря, например.

def f(x,verbose=False):
    result = 0
    verbosity = []
    for _ in x:
        foo = # something quick to calculate
        result += foo
        if verbose:
            verbosity += # something slow to calculate based on foo
    return {"result":result, "verbosity":verbosity}

Но для этого требуется построить dict, если это не требуется.

Некоторые альтернативы:

# "verbose" changes syntax of return value, yuck!
return result if verbose else (result,verbosity)

или используя изменяемый аргумент

def f(x,verbosity=None):
    if verbosity:
        assert verbosity==[[]]
    result = 0
    for _ in x:
        foo = # something quick to calculate
        result += foo
        if verbosity:
            # hard coded value, yuck
            verbosity[0] += # something slow to calculate based on foo
    return result

# for verbose results call as
verbosity = [[]]
f(x,verbosity)

Любые лучшие идеи?

Ответ 1

Не возвращайте verbosity. Сделайте это необязательным аргументом функции, переданным вызывающим, мутированным в функции, если не пустым.

Непифонной частью некоторых ответов является необходимость проверки структуры возвращаемого значения. Передача измененных аргументов для дополнительной обработки позволяет избежать этого уродства.

Ответ 2

Мне нравится первый вариант, но вместо передачи параметра verbose в вызове функции верните кортеж быстрого результата и ленивую оценку:

import time

def getResult(x):
    quickResult = x * 2

    def verboseResult():
        time.sleep(5)
        return quickResult * 2

    return (quickResult, verboseResult)

# Returns immediately
(quickResult, verboseResult) = getResult(2)

print(quickResult)     # Prints immediately
print(verboseResult()) # Prints after running the long-running function