Каноническим способом возврата нескольких значений в языках, которые его поддерживают, часто является 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}
(Чтобы было понятно, 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__
не создается для каждого экземпляра.
Использование новых dataclasses в 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)
Еще одно предложение, которое я упустил из виду, поступило от Bill the Lizard:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
Это мой наименее любимый метод. Возможно, я испорчен знакомством с Haskell, но идея списков смешанного типа всегда казалась мне некомфортной. В данном конкретном примере список не является списком смешанного типа, но, возможно, мог бы им быть.
Список, используемый таким образом, действительно ничего не выигрывает по сравнению с кортежем, насколько я могу судить. Единственное реальное различие между списками и кортежами в Python заключается в том, что списки являются изменяемыми, а кортежи - нет.
Лично я склонен переносить соглашения из функционального программирования: использовать списки для любого количества элементов одного типа, а кортежи - для фиксированного количества элементов заранее определенных типов.
После длинной преамбулы следует неизбежный вопрос. Какой метод (по вашему мнению) является лучшим?
Я обычно выбираю путь словаря, потому что он требует меньше работы по настройке. Однако, с точки зрения типов, вам, возможно, лучше пойти по пути классов, поскольку это может помочь вам избежать путаницы в том, что представляет собой словарь.
С другой стороны, некоторые представители сообщества Python считают, что подразумеваемые интерфейсы должны быть предпочтительнее явных интерфейсов, и в этом случае тип объекта действительно не имеет значения, поскольку вы полагаетесь на соглашение, что один и тот же атрибут всегда будет иметь одно и то же значение.
Итак, как - вы - возвращаете несколько значений в Python?
Кортежей были добавлены в 2.6 для этой цели. Также см. ОС.стат для аналогичного примера строение.
>>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, y=2)
>>> p.x, p.y
1 2
>>> p[0], p[1]
1 2
В последние версии Python 3 (3.6+, я думаю), библиотека нового ввод
у NamedTuple
класс, чтобы сделать именованных кортежей легче создать и более мощные. Унаследовав от печати.NamedTuple позволяет использовать комментарии, значения по умолчанию, аннотации типов.
Пример (из документации):
class Employee(NamedTuple): # inherit from collections.NamedTuple
name: str
id: int = 3 # default value
employee = Employee('Guido')
assert employee.id == 3
Для небольших проектов я считаю, что проще работать с кортежами. Когда это становится слишком трудно управлять (и не раньше) я начну группировки вещей в логические структуры, однако я думаю, что ваш предложил использовать словари и аргумент returnvalue
объекты-это неправильно (или слишком упрощенно).
Возвращает словарь с ключами то"У0"
в, в "У1"
в, в "Х2"
В и т. д. не'т предложить какое-либо преимущество над кортежами. Возвращая аргумент returnvalue
экземпляр с недвижимостью.У0,
.У1,
.У2 и т. д. не'т предлагаем любое преимущество над кортежами либо. Вам нужно, чтобы начать называть вещи, если вы хотите получить в любом месте, и вы можете это сделать с помощью кортежей:
def get_image_data(filename):
[snip]
return size, (format, version, compression), (width,height)
size, type, dimensions = get_image_data(x)
ИМХО, единственная хорошая техника за кортежи, чтобы вернуть реальные объекты с правильными методами и свойствами, как вы получаете от повторного.матч()или
открыть(файл)`.
Много ответов предлагаю вам должны возвращать набор какой-то, как словарь или список. Вы можете оставить лишние синтаксис и просто выписать возвращаемых значений, разделенных запятыми. Примечание: это технически возвращает кортеж.
def f():
return True, False
x, y = f()
print(x)
print(y)
дает:
True
False
Я голосую за словарь.
Я считаю, что если я сделаю функцию, которая возвращает что-нибудь более 2-3 переменных I'МР сложите их в словаре. В противном случае я, как правило, забывают порядок и содержание того, что я'м возвращаясь.
Также представляем 'специальные' структура делает ваш код более сложным для понимания. (Кому-то еще придется искать через код, чтобы выяснить, что это такое)
Если ваш обеспокоены тип искать, использовать описательные ключи, словарь, например, 'х-значения из списка'.
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0':y0, 'y1':y1 ,'y2':y2 }
Другим вариантом может быть использование генераторов:
>>> def f(x):
y0 = x + 1
yield y0
yield x * 3
yield y0 ** 4
>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296
Хотя ИМХО кортежи, как правило, за исключением случаев, когда ценности были возвращены являются кандидатами для инкапсуляции в классе.
Я предпочитаю использовать кортежи, когда кортеж чувствует, что "естественный" и; координаты типичный пример, где отдельные объекты могут стоять на своих собственных, например, в одну ось только расчеты масштабирования, и порядок важен. Примечание: если я могу сортировать и тасовать элементы без ущерба к смыслу группы, то я, наверное,'т использовать кортеж.
Я использую словари в качестве возвращаемого значения, только когда сгруппированные объекты не't всегда то же самое. Думаю необязательные заголовки электронной почты.
Для остальных случаев, где сгруппированы объекты имеют неотъемлемое значение внутри группы или полноценный объект со своими методами необходимо, я использую класс.
Я предпочитаю:
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0':y0, 'y1':y1 ,'y2':y2 }
Кажется, что все остальное - это просто дополнительный код, чтобы сделать то же самое.
Вообще, "специализированная структура" на самом деле является разумным текущим состоянием объекта, со своими собственными методами.
class Some3SpaceThing(object):
def __init__(self,x):
self.g(x)
def g(self,x):
self.y0 = x + 1
self.y1 = x * 3
self.y2 = y0 ** y3
r = Some3SpaceThing( x )
r.y0
r.y1
r.y2
Мне нравится находить имена для анонимных структур, когда это возможно. Осмысленные имена делают вещи более понятными.
Питон'ы кортежи, предсказывает, и объекты предлагают программисту гладкой компромисс между формальной и удобство для небольших структур данных (на"вещи", у). Для меня, выбор, как представлять вещи диктуется в основном, как я'м собирается использовать структуру. В C++, это'ы часто использовать структура
для сведения-только те элементы и "класс" для объектов с методами, хотя вы можете легально положить методов на структура
; моя привычка похожа на Python, с дикт
и кортеж
в месте структура
.
Для набора координат, я'будете использовать Кортеж
, а не класс
или словарь
(и обратите внимание, что вы можете использовать кортеж
как ключ словаря, так дикт сделаем большие разреженные многомерные массивы).
Если я'м собираюсь быть перебираете список вещей, я предпочитаю распаковка `Кортеж на итерации:
for score,id,name in scoreAllTheThings():
if score > goodScoreThreshold:
print "%6.3f #%6d %s"%(score,id,name)
...как объект версия более захламленной читать:
for entry in scoreAllTheThings():
if entry.score > goodScoreThreshold:
print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)
...не говоря уже о словарь
.
for entry in scoreAllTheThings():
if entry['score'] > goodScoreThreshold:
print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])
Если вещь широко используется, и вы найдете себе делать подобные нетривиальные операции на нем в нескольких местах в коде, то это'ы, как правило, стоит сделать из него объект класса с соответствующими методами.
Наконец, если я'м собирается быть обмен данными с питона компонентов системы, я'МР чаще всего хранить их в словарь, потому что это'ы лучше всего подходит для сериализации JSON.
+1 на С. Лотт'ы предложению именованный контейнер класса.
Для Python 2.6 и выше, именованный кортеж предоставляет удобный способ создания этих контейнерных классов, а результаты "не легкий и требует больше памяти, чем обычные кортежи и".
В таких языках, как Python, я обычно использую словарь, поскольку это требует меньших затрат, чем создание нового класса.
Однако, если я обнаружил, что постоянно возвращаю один и тот же набор переменных, то это, вероятно, повлечет за собой создание нового класса, от которого я откажусь.
Я хотел бы использовать dict, чтобы передавать и возвращать значения из функции:
Использование переменной формы, как определено в форме.
form = {
'level': 0,
'points': 0,
'game': {
'name': ''
}
}
def test(form):
form['game']['name'] = 'My game!'
form['level'] = 2
return form
>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}
Это самый эффективный способ для меня и для обработки блока.
Вы должны пройти всего один указатель и возвращать только один пойнтер.
Вам не придется менять функции' (тысячи их) аргументы всякий раз, когда вы вносите изменения в свой код.
и"самое лучшее" это частично субъективное решение. Использовать кортежи для малых возврата устанавливает в общем случае неизменный приемлемо. Кортеж всегда предпочтительнее списка, когда изменчивость-это не требование.
Для более сложных возвращаемые значения, или для случая, когда формальность ценной (т. е. высокое значение кода) именованный кортеж лучше. Для наиболее сложном случае объект, как правило, лучше. Однако, это's действительно ситуация, что имеет значение. Если есть смысл возвращать объект, потому что вы, естественно, в конце функции (например, узор на заводе) тогда возврат объект.
Как мудрый человек сказал:
преждевременная оптимизация-это корень всех зол (или, по крайней мере большинство > это) в программировании.