Le moyen canonique de retourner plusieurs valeurs dans les langues qui le supportent est souvent l'utilisation des tuples.
Option : Utiliser un tuple
Considérez cet exemple trivial:
def f(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return (y0, y1, y2)
Cependant, cela devient rapidement problématique lorsque le nombre de valeurs retournées augmente. Et si vous voulez retourner quatre ou cinq valeurs ? Bien sûr, vous pourriez continuer à les mettre dans des tuples, mais il est facile d'oublier quelle valeur est où. C'est aussi plutôt laid de les déballer partout où vous voulez les recevoir.
Option : Utiliser un dictionnaire
La prochaine étape logique semble être d'introduire une sorte de 'notation de record'. En Python, la manière évidente de le faire est au moyen d'un dict
.
Considérez ce qui suit:
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0': y0, 'y1': y1 ,'y2': y2}
(Juste pour être clair, y0, y1 et y2 ne sont que des identifiants abstraits. Comme mentionné, en pratique vous utiliseriez des identifiants significatifs.)
Maintenant, nous avons un mécanisme permettant de projeter un membre particulier de l'objet retourné. Par exemple,
result['y0']
Option : Utiliser une classe
Cependant, il y a une autre option. Nous pourrions plutôt retourner une structure spécialisée. J'ai encadré cela dans le contexte de Python, mais je suis sûr que cela s'applique également à d'autres langues. En effet, si vous travailliez en C, cela pourrait bien être votre seule option. Voici comment procéder:
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)
En Python, les deux précédents sont peut-être très similaires en termes de plomberie - après tout { y0, y1, y2 }
finissent simplement par être des entrées dans le __dict__
interne du ReturnValue
.
Python offre cependant une fonctionnalité supplémentaire pour les petits objets, l'attribut __slots__
. La classe pourrait être exprimée comme suit:
class ReturnValue(object):
__slots__ = ["y0", "y1", "y2"]
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
D'après le Manuel de référence Python:
La déclaration
__slots__
prend une séquence de variables d'instance et réserve juste assez d'espace dans chaque instance pour contenir une valeur pour chaque variable. De l'espace est économisé car__dict__
n'est pas créé pour chaque instance.
Option : Utiliser un dataclass (Python 3.7+)
En utilisant les nouvelles dataclasses de Python 3.7, retournez une classe avec des méthodes spéciales ajoutées automatiquement, du typage et d'autres outils utiles:
@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)
Option : Utiliser une liste
Une autre suggestion que j'avais négligée vient de Bill the Lizard:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
C'est ma méthode préférée la moins. Je suppose que je suis influencé par mon exposition à Haskell, mais l'idée de listes à types mixtes m'a toujours mis mal à l'aise. Dans cet exemple particulier, la liste n'est pas de type mixte, mais elle pourrait l'être concevablement.
Une liste utilisée de cette manière ne gagne vraiment rien par rapport au tuple autant que je sache. La seule vraie différence entre les listes et les tuples en Python est que les listes sont mutables, tandis que les tuples ne le sont pas.
Je tends personnellement à transmettre les conventions de la programmation fonctionnelle: utiliser des listes pour un nombre quelconque d'éléments du même type, et des tuples pour un nombre fixe d'éléments de types prédéterminés.
Question
Après cette longue introduction, vient la question inévitable. Quelle méthode (selon vous) est la meilleure ?
10 votes
Dans vos exemples excellents, vous utilisez la variable
y3
, mais à moins que y3 ne soit déclaré global, cela entraînerait uneNameError: global name 'y3' is not defined
. Peut-être devriez-vous simplement utiliser3
?32 votes
De nombreuses grandes questions avec de grandes réponses sont fermées parce que le mot-clé 'opinion' apparaît. Vous pourriez argumenter que l'ensemble de SO est basé sur l'opinion, mais c'est une opinion informée par des faits, des références et une expertise spécifique. Juste parce que quelqu'un demande "lequel pensez-vous est le meilleur" ne signifie pas qu'ils demandent des opinions personnelles abstraites des faits réels, des références et de l'expertise spécifique. Ils demandent presque certainement ce genre d'opinion, basée complètement sur, et documentée avec, les faits, les références et l'expertise spécifique que la personne a utilisés pour former son opinion.
0 votes
@hetepeperfan pas besoin de changer 3, et définir y3 en global non plus, vous pouvez également utiliser un nom local
y3
, cela fera également l'affaire.