Управление количеством возвращаемых переменных в функции

Есть ли способ определить функцию, которая знает, сколько переменных вернуть, основываясь на том, сколько результатов ожидает пользователь?

Позвольте мне проиллюстрировать идею. Предположим, следующая функция:

def function():
    a = 1
    b = 2
    c = 3
    return a, b, c

Тогда я бы хотел, чтобы моя функция вела себя так:

>>> x = function()
>>> x
1

>>> x, y = function()
>>> x
1
>>> y
2

>>> x, y, z = function()
>>> x
1
>>> y
2
>>> z
3

Есть ли в Python функция или концепция, которая может помочь мне достичь этого? Может быть, декораторы?

Любая идея приветствуется!

PD: Мой уровень Python все еще очень прост.


РЕДАКТИРОВАТЬ:

В настоящее время я перехожу из IDL в Python. Так что мне не хватает приятной функции в IDL, которую вы можете выбрать, чтобы возвращать столько переменных, сколько пожелаете, выполнив:

FUNCTION function, a=a, b=b, c=c

 a=1
 b=2
 c=3

RETURN, a

И тогда вы можете просто спросить, что вы хотите получить обратно

IDL> x=function()
IDL> print, x
1
IDL> x=function(y=b)
IDL> print, x
1
IDL> print, y
2
IDL> x=function(y=b, z=c)
IDL> print, x
1
IDL> print, y
2
IDL> print, c
3

4 ответа

Вместо того, чтобы возвращать разные значения, вы можете назвать это по-другому:

x, *_ = function()
x, y, *_ = function()
x, y, z, *_ = function()   # *_ is optional here if it only returns 3 things

При этом все неиспользуемые возвращаемые значения назначаются _ переменная, поэтому, если вы хотите, чтобы они получили gc'd рано, вы должны del _,

Вы можете вернуть только один объект. Обратите внимание, ваша функция возвращает tuple, Тем не менее, Python поддерживает синтаксис, который позволяет гибко распаковывать переменные

x,_,_ = function()

Или же

x,y,_ = function()

Или даже с расширенной распаковкой:

x, *_ = function()

Обратите внимание, используя _ в качестве одноразовой переменной это просто соглашение.

Несмотря на то, что Pythonic отличается от распаковки, вы можете создать декоратор и указать допустимое количество возвращаемых значений:

def filter_results(val):
  def outer(f):
    def wrapper(*args, **kwargs):
       v = f(*args, **kwargs)[:val]
       return v[0] if len(v) == 1 else v
    return wrapper
  return outer

@filter_results(1)
def function():
  a = 1
  b = 2
  c = 3
  return a, b, c

r = function()

Выход:

1

Полные результаты:

@filter_results(2)
def function():
   ...

x, y = function()

И, наконец:

@filter_results(3)
def function():
   ...

x, y, z = function()

Если не считать безумных уловок, таких как проверка байт-кода вашего вызывающего, чтобы увидеть, сколько значений он ожидает, это невозможно: интерпретатор не примет любое несоответствующее количество значений (он проверяет и перехватывает дополнительные значения).

Другие вопросы по тегам