Является ли pythonic функцией для возврата нескольких значений?
В python вы можете вернуть функцию нескольким значениям. Здесь надуманный пример:
def divide(x, y):
quotient = x/y
remainder = x % y
return quotient, remainder
(q, r) = divide(22, 7)
Это кажется очень полезным, но похоже, что его также можно злоупотреблять ( "Ну.. функция X уже вычисляет то, что нам нужно в качестве промежуточного значения. Пусть X тоже вернет это значение" ).
Когда вы должны нарисовать линию и определить другой метод?
Ответы
Ответ 1
Абсолютно (для примера, который вы предоставили).
Кортежи являются гражданами первого класса в Python
Существует встроенная функция divmod()
, которая делает именно это.
q, r = divmod(x, y) # ((x - x%y)/y, x%y) Invariant: div*y + mod == x
Существуют и другие примеры: zip
, enumerate
, dict.items
.
for i, e in enumerate([1, 3, 3]):
print "index=%d, element=%s" % (i, e)
# reverse keys and values in a dictionary
d = dict((v, k) for k, v in adict.items()) # or
d = dict(zip(adict.values(), adict.keys()))
Кстати, скобки в большинстве случаев не нужны.
Ссылка из Справочник по библиотеке Python:
Кортежи создаются запятой оператор (не в квадратных скобках), с или без круглых скобок, но пустой кортеж должен иметь охватывающие круглые скобки, такие как a, b, c или(). Один кортеж должен иметь конечные запятые, такие как (d).
Функции должны обслуживать одноцелевые
Поэтому они должны возвращать один объект. В вашем случае этот объект является кортежем. Рассмотрим кортеж как составную структуру данных ad-hoc. Существуют языки, где почти каждая функция возвращает несколько значений (список в Lisp).
Иногда достаточно вернуть (x, y)
вместо Point(x, y)
.
Именованные кортежи
С введением названных кортежей в Python 2.6 во многих случаях предпочтительнее возвращать именованные кортежи вместо простых кортежей.
>>> import collections
>>> Point = collections.namedtuple('Point', 'x y')
>>> x, y = Point(0, 1)
>>> p = Point(x, y)
>>> x, y, p
(0, 1, Point(x=0, y=1))
>>> p.x, p.y, p[0], p[1]
(0, 1, 0, 1)
>>> for i in p:
... print(i)
...
0
1
Ответ 2
Во-первых, обратите внимание, что Python допускает следующее (нет необходимости в скобках):
q, r = divide(22, 7)
Относительно вашего вопроса, нет жесткого и быстрого правила в любом случае. Для простых (и обычно надуманных) примеров может показаться, что для данной функции всегда возможно иметь одну цель, в результате чего получается одно значение. Однако при использовании Python для реальных приложений вы быстро запускаете во многих случаях, когда требуется возвращать несколько значений, и в результате получается более чистый код.
Итак, я бы сказал, что имеет смысл, и не пытайтесь соответствовать искусственному соглашению. Python поддерживает несколько возвращаемых значений, поэтому используйте его, когда это необходимо.
Ответ 3
Пример, который вы даете, на самом деле является встроенной функцией python, называемой divmod
. Поэтому кто-то, в какой-то момент, подумал, что это достаточно pythonic, чтобы включить в основную функциональность.
Для меня, если он делает код чище, он является pythonic. Сравните эти два блока кода:
seconds = 1234
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
seconds = 1234
minutes = seconds / 60
seconds = seconds % 60
hours = minutes / 60
minutes = minutes % 60
Ответ 4
Да, возврат нескольких значений (т.е. кортежа) определенно является питоновым. Как отмечали другие, в стандартной библиотеке Python есть много примеров, а также в уважаемых проектах Python. Два дополнительных комментария:
- Возвращение нескольких значений иногда очень и очень полезно. Возьмем, например, метод, который необязательно обрабатывает событие (возвращая некоторое значение при этом), а также возвращает успех или сбой. Это может возникнуть в цепочке ответственности. В других случаях вы хотите вернуть несколько тесно связанных частей данных - как в приведенном примере. В этом параметре возвращение нескольких значений сродни возврату одного экземпляра анонимного класса с несколькими переменными-членами.
-
Обработка Python аргументов метода требует возможности прямого возврата нескольких значений. Например, в С++ аргументы метода могут передаваться по ссылке, поэтому вы можете назначать им выходные значения в дополнение к формальному возвращаемому значению. В Python аргументы передаются "по ссылке" (но в смысле Java, а не С++). Вы не можете назначать новые значения аргументам метода и отражать их вне области внешнего метода. Например:
// C++
void test(int& arg)
{
arg = 1;
}
int foo = 0;
test(foo); // foo is now 1!
Сравните с:
# Python
def test(arg):
arg = 1
foo = 0
test(foo) # foo is still 0
Ответ 5
Это определенно pythonic. Тот факт, что вы можете возвращать несколько значений из функции, которая была бы у вас на языке C, где вам нужно определить структуру для каждой комбинации типов, которые вы где-то возвращаете.
Однако, если вы достигнете точки, в которой вы возвращаете что-то сумасшедшее, как 10 значений из одной функции, вам следует серьезно подумать о том, чтобы связать их в классе, потому что в этот момент он становится громоздким.
Ответ 6
Возвращение кортежа круто. Также обратите внимание на новый namedtuple
который был добавлен в python 2.6, который может сделать это более приемлемым для вас:
http://docs.python.org/dev/library/collections.html#collections.namedtuple
Ответ 7
Я новичок в Python, но техника кортежа кажется мне очень pythonic. Однако у меня была другая идея, которая может повысить удобочитаемость. Использование словаря позволяет получить доступ к различным значениям по имени, а не положению. Например:
def divide(x, y):
return {'quotient': x/y, 'remainder':x%y }
answer = divide(22, 7)
print answer['quotient']
print answer['remainder']
Ответ 8
OT: RSRE Algol68 имеет любопытный оператор "/: =". например.
INT quotient:=355, remainder;
remainder := (quotient /:= 113);
Давая фактор из 3 и остаток 16.
Примечание: обычно значение "(x/: = y)" отбрасывается, поскольку значение "x" присваивается ссылкой, но в случае RSRE возвращаемое значение - это остаток.
c.f. Арифметика целых чисел - Algol68
Ответ 9
Прекрасно возвращать несколько значений с помощью кортежа для простых функций, таких как divmod
. Если это делает код читаемым, это Pythonic.
Если возвращаемое значение начинает запутываться, проверьте, делает ли функция слишком много, и разделите ее, если она есть. Если большой кортеж используется как объект, сделайте его объектом. Кроме того, рассмотрите возможность использования named tuples, который будет частью стандартной библиотеки в Python 2.6.