Comment puis-je retourner plusieurs valeurs à partir d'une fonction?

La manière canonique de renvoyer plusieurs valeurs dans des langues que les soutenir, il est souvent tupling.

Option: à l'Aide d'un tuple

Considérer cet exemple trivial:

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0, y1, y2)

Cependant, cela devient vite problématique que le nombre de valeurs renvoyées augmente. Que faire si vous souhaitez revenir à quatre ou cinq valeurs? Bien sûr, vous pourriez garder tupling eux, mais il est facile d'oublier que la valeur est où. Il est également assez moche pour décompresser où vous souhaitez les recevoir.

Option: à l'Aide d'un dictionnaire

La prochaine étape logique semble être d'introduire une sorte de record de notation". En Python, le moyen le plus évident de le faire est par le biais d'un dict.

De considérer les éléments suivants:

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 sont juste comme des identifiants abstraits. Comme l'a fait remarquer, dans la pratique, vous devriez utiliser des identificateurs significatifs.)

Maintenant, nous avons un mécanisme par lequel nous pouvons projeter un membre particulier de l'objet retourné. Par exemple,

result['y0']

Option: à l'Aide d'une classe

Cependant, il ya une autre option. Nous avons pu, au lieu de retourner une structure spécialisée. J'ai encadré dans le contexte de Python, mais je suis sûr que ça s'applique à d'autres langues. En effet, si vous travaillez en C, cela pourrait très bien être votre seule option. Va ici:

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édentes sont peut-être très similaires en termes de plomberie - après tout { y0, y1, y2 } juste à la fin des entrées à l'intérieur __dict__ de la ReturnValue.

Il y a une fonctionnalité supplémentaire fourni par Python, bien que pour de petits objets, la __slots__ attribut. La classe peut être exprimée comme:

class ReturnValue(object):
  __slots__ = ["y0", "y1", "y2"]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

De la Python Manuel De Référence:

La __slots__ déclaration prend une séquence de variables d'instance et les réserves de juste assez d'espace dans chaque cas pour contenir une valeur pour chaque variable. L'espace est sauvé grâce à __dict__ n'est pas créé pour chaque instance.

Option: à l'Aide d'un dataclass (Python 3.7+)

À l'aide de Python 3.7 nouveau dataclasses, de retour d'une classe avec automatiquement ajoutés à des méthodes spéciales, de dactylographie 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: à l'Aide d'une liste

Une autre suggestion que j'avais négligé vient de Bill le Lézard:

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

C'est au moins ma méthode préférée, cependant. Je suppose que je suis contaminé par l'exposition à Haskell, mais l'idée d'mixte-type de listes a toujours senti mal à l'aise pour moi. Dans cet exemple particulier, la liste n'est pas mixte, mais il pourrait, théoriquement, être.

Une liste utilisée de cette façon n'a vraiment pas de gagner quoi que ce soit avec le respect de la n-uplet d'aussi loin que je peux dire. La seule vraie différence entre les listes et les tuples en Python, c'est que les listes sont mutable, alors que les tuples ne sont pas.

Personnellement, j'ai tendance à porter sur les conventions de programmation fonctionnelle: utiliser des listes pour n'importe quel nombre d'éléments du même type, et les tuples pour un nombre fixe d'éléments prédéterminés types.

Question

Après le long préambule, vient l'inévitable question. La méthode (pensez-vous) est le meilleur?

J'ai généralement trouvé moi-même d'aller le dictionnaire de la route, car elle implique moins de travail. À partir d'un des types de point de vue cependant, vous pourriez être mieux de passer par la classe de route, car qui peut vous aider à éviter la confusion entre ce dictionnaire représente.

D'autre part, il y en a dans la communauté Python qui se sentent implicite interfaces doivent être préférés à des interfaces explicites, à quel point le type de l'objet n'est pas vraiment pertinente, puisque vous êtes essentiellement en s'appuyant sur la convention que le même attribut ont toujours le même sens.

Alors, comment faites -vous - retourner plusieurs valeurs en Python?

  • À vous d'excellents exemples vous utilisez une variable y3, mais à moins d'y3 est déclaré en global, cela donnerait NameError: global name 'y3' is not defined peut-être juste utiliser 3?
  • Est en effet une question de l'attrait pour les opinions, mais le petit résumé sur le retour des valeurs est assez utile. Je vous remercie pour tous les Modérateurs et l'utilisateur qui a demandé
InformationsquelleAutor saffsd | 2008-12-10