Как вы возвращаете несколько значений в Python?


5 Answers

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

Возвращение словаря с ключами y0, y1, y2 и т. Д. Не дает никаких преимуществ перед кортежами. Возврат экземпляра ReturnValue со свойствами .y0 .y1 .y2 и т. Д. Также не дает преимуществ над кортежами. Вам нужно начать именовать вещи, если вы хотите попасть в любом месте, и вы можете сделать это, используя кортежи в любом случае:

def getImageData(filename):
  [snip]
  return size, (format, version, compression), (width,height)
size, type, dimensions = getImageData(x)

IMHO, единственный хороший метод, выходящий за рамки кортежей, - это возвращать реальные объекты с помощью надлежащих методов и свойств, например, вы получаете из re.match() или open(file) .

Question

Канонический способ возврата нескольких значений в поддерживающие его языки часто tupling .

Вариант: использование кортежа

Рассмотрим этот тривиальный пример:

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0,y1,y2)

Однако это быстро становится проблематичным по мере увеличения количества возвращаемых значений. Что делать, если вы хотите вернуть четыре или пять значений? Конечно, вы могли бы продолжать их переделывать, но легко забыть, какая именно ценность. Также довольно уродливо распаковывать их там, где вы хотите их получить.

Вариант: использование словаря

Следующим логическим шагом, похоже, является введение какой-то «записи записи». В python очевидный способ сделать это - с помощью dict .

Рассмотрим следующее:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

(edit) Только для того, чтобы быть ясным, y0, y1 и y2 называются только абстрактными идентификаторами. Как уже отмечалось, на практике вы должны использовать значащие идентификаторы)

Теперь у нас есть механизм, посредством которого мы можем проецировать определенный член возвращаемого объекта. Например,

result['y0']

Вариант: использование класса

Однако есть и другой вариант. Вместо этого мы могли бы вернуть специализированную структуру. Я создал это в контексте Python, но я уверен, что это относится и к другим языкам. Действительно, если вы работаете на C, это может быть вашим единственным вариантом. Вот оно:

class ReturnValue(object):
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return ReturnValue(y0, y1, y2)

В python предыдущие два, возможно, очень похожи в плане сантехники. После того, как все { y0, y1, y2 } просто __dict__ в записи во внутреннем __dict__ of ReturnValue .

Существует еще одна функция, предоставляемая Python, хотя для крошечных объектов - атрибут __slots__ . Класс может быть выражен как:

class ReturnValue(object):
  __slots__ = ["y0", "y1", "y2"]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

Из справочного руководства Python :

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

Вариант: использование списка

Еще одно предложение, которое я забыл, исходит от Билла Ящерицы:

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

Это мой наименее любимый метод. Я полагаю, что я испорчен контактом с Haskell, но идея смешанных списков всегда казалась мне неудобной. В этом конкретном примере список - не смешанный тип, но он, возможно, может быть. Насколько я могу судить, список, используемый таким образом, действительно ничего не получает по отношению к кортежу. Единственное реальное различие между списками и кортежами в Python заключается в том, что списки mutable , но кортежи не являются. Я лично склонен переносить условные обозначения из функционального программирования: использовать списки для любого количества элементов одного типа и кортежи для фиксированного количества элементов предопределенных типов.

Вопрос

После длинной преамбулы возникает неизбежный вопрос. Какой метод (как вы думаете) лучше всего?

Я, как правило, обнаружил, что иду по маршруту словаря, потому что он включает в себя меньше работы по настройке. Однако с точки зрения типов вам может быть лучше идти по маршруту класса, поскольку это может помочь вам избежать путаницы в том, что представляет собой словарь. С другой стороны, в сообществе Python есть некоторые, которые считают подразумеваемые интерфейсы предпочтительнее явных интерфейсов , и в этот момент тип объекта действительно не имеет значения, поскольку вы в основном полагаетесь на соглашение, что тот же атрибут всегда будет иметь то же значение.

Итак, как вы возвращаете несколько значений в Python?




я предпочитаю

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

кажется, что все остальное - просто дополнительный код, чтобы сделать то же самое.




В таких языках, как Python, я обычно использовал словарь, поскольку он требует меньше накладных расходов, чем создание нового класса.

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




+1 на предложение С.Лотта о названном классе контейнера.

Для python 2.6 и выше именованный кортеж предоставляет полезный способ легкого создания этих классов контейнеров, а результаты «легкие и требуют больше памяти, чем обычные кортежи».




>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3



Я проголосую за словарь.

Я нахожу, что если я создам функцию, которая возвращает что-то большее, чем 2-3 переменных, я сломаю их в словаре. В противном случае я склонен забывать порядок и содержание того, что я возвращаю.

Кроме того, введение «специальной» структуры затрудняет выполнение вашего кода. (Кому-то придется искать через код, чтобы узнать, что это такое)

Если вас беспокоит тип поиска, используйте дескриптивные словарные ключи, например, «список значений x».

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }



Related