python - tuple - ¿Es pitónico que una función devuelva valores múltiples?
return value from def python (9)
Absolutamente (para el ejemplo que proporcionó).
Tuplas son ciudadanos de primera clase en Python
Hay una función divmod()
que hace exactamente eso.
q, r = divmod(x, y) # ((x - x%y)/y, x%y) Invariant: div*y + mod == x
Hay otros ejemplos: 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()))
Por cierto, los paréntesis no son necesarios la mayor parte del tiempo. Citación de la Biblioteca de Python Referencia :
Las tuplas son construidas por el operador de coma (no entre corchetes), con o sin paréntesis que encierran, pero una tupla vacía debe tener los paréntesis adjuntos, como a, b, c o (). Una sola tupla de artículo debe tener una coma final, como (d,).
Las funciones deberían servir para un solo propósito
Por lo tanto, deberían devolver un solo objeto. En tu caso, este objeto es una tupla. Considere la tupla como una estructura de datos compuestos ad-hoc. Hay idiomas en los que casi todas las funciones devuelven múltiples valores (lista en Lisp).
A veces es suficiente para regresar (x, y)
lugar de Point(x, y)
.
Tuplas nombradas
Con la introducción de tuplas con nombre en Python 2.6, es preferible en muchos casos devolver tuplas con nombre en lugar de tuplas simples.
>>> 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
En python, puede tener una función devolver múltiples valores. Aquí hay un ejemplo artificial:
def divide(x, y):
quotient = x/y
remainder = x % y
return quotient, remainder
(q, r) = divide(22, 7)
Esto parece muy útil, pero parece que también se puede abusar ("Bueno ... la función X ya calcula lo que necesitamos como valor intermedio. Hagamos que X también devuelva ese valor").
¿Cuándo debes trazar la línea y definir un método diferente?
Definitivamente es pitónico. El hecho de que puede devolver múltiples valores de una función, la plantilla estándar que tendría en un lenguaje como C, donde necesita definir una estructura para cada combinación de tipos que devuelve en algún lugar.
Sin embargo, si llegas al punto en el que devuelves algo loco como 10 valores de una sola función, deberías considerar agruparlos en una clase porque en ese punto se vuelve difícil de manejar.
Devolver una tupla es genial. También tenga en cuenta el nuevo namedtuple que se agregó en Python 2.6 que puede hacer esto más agradable para usted: http://docs.python.org/dev/library/collections.html#collections.namedtuple
El ejemplo que das es en realidad una función incorporada de python, llamada divmod
. Entonces, alguien, en algún momento, pensó que era lo suficientemente pitónico como para incluirlo en la funcionalidad central.
Para mí, si hace que el código sea más limpio, es pitónico. Compare estos dos bloques de código:
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
En primer lugar, tenga en cuenta que Python permite lo siguiente (sin necesidad de paréntesis):
q, r = divide(22, 7)
Con respecto a su pregunta, no hay una regla rígida ni rápida de ninguna manera. Para ejemplos simples (y usualmente artificiales), puede parecer que siempre es posible para una función dada tener un único propósito, lo que resulta en un solo valor. Sin embargo, al usar Python para las aplicaciones del mundo real, se encontrará rápidamente con muchos casos en los que es necesario devolver varios valores, lo que da como resultado un código más limpio.
Por lo tanto, diría que haga lo que tenga sentido, y no intente ajustarse a una convención artificial. Python admite múltiples valores devueltos, así que úselos cuando sea apropiado.
Está bien devolver múltiples valores usando una tupla para funciones simples como divmod
. Si hace que el código sea legible, es Pythonic.
Si el valor de retorno comienza a ser confuso, verifique si la función está haciendo demasiado y divídala si es así. Si una gran tupla se usa como un objeto, conviértalo en un objeto. Además, considere usar tuplas con nombre , que formarán parte de la biblioteca estándar en Python 2.6.
OT: Algol68 de RSRE tiene el curioso operador "/: =". p.ej.
INT quotient:=355, remainder;
remainder := (quotient /:= 113);
Dando un cociente de 3, y un resto de 16.
Nota: normalmente el valor de "(x /: = y)" se descarta porque el cociente "x" se asigna por referencia, pero en el caso de RSRE, el valor devuelto es el resto.
Sí, devolver valores múltiples (es decir, una tupla) es definitivamente pitónico. Como han señalado otros, hay muchos ejemplos en la biblioteca estándar de Python, así como en proyectos de Python muy respetados. Dos comentarios adicionales:
- La devolución de valores múltiples a veces es muy, muy útil. Tomemos, por ejemplo, un método que maneja opcionalmente un evento (devolviendo algún valor al hacerlo) y también devuelve éxito o falla. Esto podría surgir en una cadena de patrones de responsabilidad. En otros casos, desea devolver datos múltiples y estrechamente vinculados, como en el ejemplo dado. En esta configuración, devolver varios valores es similar a devolver una única instancia de una clase anónima con varias variables miembro.
El manejo de Python de los argumentos del método requiere la capacidad de devolver directamente múltiples valores. En C ++, por ejemplo, los argumentos del método se pueden pasar por referencia, por lo que puede asignarles valores de salida, además del valor de retorno formal. En Python, los argumentos se pasan "por referencia" (pero en el sentido de Java, no de C ++). No puede asignar nuevos valores a los argumentos del método y tenerlos reflejados fuera del alcance del método. Por ejemplo:
// C++ void test(int& arg) { arg = 1; } int foo = 0; test(foo); // foo is now 1!
Comparar con:
# Python def test(arg): arg = 1 foo = 0 test(foo) # foo is still 0
Soy bastante nuevo en Python, pero la técnica de la tupla me parece muy pitónica. Sin embargo, he tenido otra idea que puede mejorar la legibilidad. El uso de un diccionario permite el acceso a los diferentes valores por nombre en lugar de posición. Por ejemplo:
def divide(x, y):
return {''quotient'': x/y, ''remainder'':x%y }
answer = divide(22, 7)
print answer[''quotient'']
print answer[''remainder'']