83 votes

Est-ce pythonique pour une fonction de renvoyer plusieurs valeurs?

En python, vous pouvez faire en sorte qu'une fonction retourne plusieurs valeurs. Voici un exemple artificiel:

 def divide(x, y):
    quotient = x/y
    remainder = x % y
    return quotient, remainder  

(q, r) = divide(22, 7)
 

Cela semble très utile, mais il semble qu’on puisse aussi en abuser ("Bien ... la fonction X calcule déjà ce dont nous avons besoin en tant que valeur intermédiaire. Laissons alors X renvoyer cette valeur").

Quand faut-il tracer la ligne et définir une méthode différente?

109voto

J.F. Sebastian Points 102961

Absolument (pour l'exemple que vous avez fournies.

Les Tuples sont des citoyens à part entière en Python

Il y a une fonction builtin divmod() qui fait exactement cela.

q, r = divmod(x, y) # ((x - x%y)/y, x%y) Invariant: div*y + mod == x

Il y a d'autres exemples: 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()))

BTW, les parenthèses ne sont pas nécessaires la plupart du temps. Citation de Python de Référence de la Bibliothèque:

Les Tuples sont construits par la virgule opérateur (pas dans les crochets), avec ou sans trouvant entre parenthèses, mais un tuple vide doit avoir la se trouvant entre parenthèses, tels que a, b, c ou (). Un seul élément d'un tuple doit avoir un virgule, tels que (d,).

Les fonctions doivent servir un but unique

Par conséquent, ils devraient retourner un objet unique. Dans votre cas, cet objet est un n-uplet. Envisager tuple ad-hoc composé de structure de données. Il y a des langues où presque chaque fonction renvoie plusieurs valeurs (liste en Lisp).

Parfois, il suffit de retourner (x, y) au lieu de Point(x, y).

Nommé tuples

Avec l'introduction de uplets nommé dans la version 2.6 de Python, il est préférable dans de nombreux cas, pour revenir uplets nommé à la place de la plaine des n-uplets.

>>> 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

27voto

Jason Etheridge Points 3879

Tout d'abord, notez que Python permet pour la suite (pas besoin de la parenthèse):

q, r = divide(22, 7)

Concernant votre question, il n'y a aucune règle dure et rapide. Pour la simple (et le plus souvent fictive) des exemples, il peut sembler que c'est toujours possible pour une fonction donnée d'avoir un but unique, résultant en une seule valeur. Cependant, lors de l'utilisation de Python pour les applications du monde réel, vous réalisez rapidement dans de nombreux cas où les retourner plusieurs valeurs est nécessaire, et plus propre code.

Donc, je dirais de faire quelque chose, et ne pas essayer de se conformer à une artificielle de la convention. Python prend en charge plusieurs valeurs de retour, afin de l'utiliser au moment opportun.

13voto

Nathan Jones Points 1480

L'exemple que vous donnez est en fait une fonction intégrée à Python, appelée divmod . Donc, quelqu'un, à un moment donné, a pensé que c'était assez pythonique pour l'inclure dans les fonctionnalités de base.

Pour moi, si cela rend le code plus propre, il est pythonique. Comparez ces deux blocs de code:

 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
 

4voto

zweiterlinde Points 5984

Oui, retourner plusieurs valeurs (c'est à dire, un n-uplet) est certainement pythonic. Comme d'autres l'ont souligné, il y a beaucoup d'exemples dans le Python standard library, ainsi que dans bien respecté Python projets. Deux observations complémentaires:

  1. Retourner plusieurs valeurs est parfois très, très utile. Prenez, par exemple, une méthode qui éventuellement gère un événement (la restitution d'une partie de la valeur) et retourne également le succès ou l'échec. Cela peut survenir dans un modèle chaîne de responsabilité. Dans d'autres cas, vous voulez retourner plusieurs, étroitement liée morceaux de données---comme dans l'exemple donné. Dans ce cadre, les retourner plusieurs valeurs s'apparente à un retour à une seule instance d'une classe anonyme avec plusieurs variables de membre.
  2. Python traitement des arguments de méthode nécessite la possibilité de renvoyer plusieurs valeurs. En C++, par exemple, la méthode des arguments peuvent être passés par référence, de sorte que vous pouvez affecter des valeurs de sortie, en outre à la mise en valeur de retour. En Python, les arguments sont passés "par référence" (mais dans le sens de Java, pas du C++). Vous ne pouvez pas affecter de nouvelles valeurs pour les arguments de méthode et l'ont traduit en dehors de la portée de la méthode. Par exemple:

    // C++
    void test(int& arg)
    {
        arg = 1;
    }
    
    int foo = 0;
    test(foo); // foo is now 1!
    

    Comparer avec:

    # Python
    def test(arg):
        arg = 1
    
    foo = 0
    test(foo) # foo is still 0
    

1voto

indentation Points 2178

C'est définitivement pythonique. Le fait que vous puissiez renvoyer plusieurs valeurs d'une fonction que vous auriez dans un langage tel que C où vous devez définir une structure pour chaque combinaison de types que vous renvoyez quelque part.

Cependant, si vous atteignez le point où vous renvoyez quelque chose de fou comme 10 valeurs d'une seule fonction, vous devriez sérieusement envisager de les regrouper dans une classe, car à ce stade, cela devient difficile à manier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X