Канонический способ возврата нескольких значений на языках, которые его поддерживают, часто бывает кортеж.
Вариант: использование кортежа
Рассмотрим этот тривиальный пример:
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}
(Для ясности, y0, y1 и y2 предназначены только как абстрактные идентификаторы. Как уже указывалось, на практике вы должны использовать значимые идентификаторы.)
Теперь у нас есть механизм, с помощью которого мы можем проецировать конкретный член возвращаемого объекта. Например,
result['y0']
Вариант: использование класса
Однако есть и другой вариант. Вместо этого мы могли бы вернуть специализированную структуру. Я сформулировал это в контексте Python, но уверен, что это применимо и к другим языкам. В самом деле, если бы вы работали на C, это вполне могло быть вашим единственным вариантом. Вот оно:
class ReturnValue:
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__
файла 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__
не создается для каждого экземпляра.
Вариант: использование класса данных (Python 3.7+)
Используя новые классы данных Python 3.7, верните класс с автоматически добавленными специальными методами, набором текста и другими полезными инструментами:
@dataclass
class Returnvalue:
y0: int
y1: float
y3: int
def total_cost(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
Вариант: использование списка
Еще одно предложение, которое я упустил из виду, исходит от Ящера Билла:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
Однако это мой наименее любимый метод. Полагаю, я испорчен знакомством с Haskell, но идея списков смешанного типа всегда казалась мне неудобной. В этом конкретном примере список не смешанного типа, но, возможно, это может быть.
Насколько я могу судить, список, используемый таким образом, на самом деле ничего не дает по отношению к кортежу. Единственная реальная разница между списками и кортежами в Python заключается в том, что списки изменяемы. , а кортежи - нет.
Лично я стараюсь перенести условности функционального программирования: использовать списки для любого количества элементов одного типа и кортежи для фиксированного количества элементов заранее определенных типов.
Вопрос
После пространной преамбулы возникает неизбежный вопрос. Как вы думаете, какой метод лучше?
y3
, но если y3 не объявлен глобальным, это приведет кNameError: global name 'y3' is not defined
, возможно, просто используйте3
? - person hetepeperfan   schedule 19.12.2013y3
, которое также будет выполнять ту же работу. - person okie   schedule 28.10.2019