1087 votes

Comment Retournez-vous plusieurs valeurs en Python ?

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

Considérons 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.

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.

Considérez les points suivants:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

(edit - 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']

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(object):
  def __init__(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 dernières sont peut-être très similaires en termes de plomberie - Après tout, { y0, y1, y2 } seulement à la fin des entrées à l'interne __dict__ de la ResultValue.

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

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

À partir du Python Manuel de Référence:

L' __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é parce qu' __dict__ n'est pas créé pour chaque instance.

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. 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 mutables, wheras 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.

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?

646voto

Coady Points 11374
<p><a href="http://docs.python.org/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields">Tuples nommés</a> ont été ajoutés en 2.6 à cet effet. Voir aussi <a href="http://docs.python.org/library/os.html#os.stat">os.stat</a> pour un exemple de builtin similaire.<pre><code></code></pre></p>

238voto

too much php Points 27983

Pour les petits projets que j'ai trouver qu'il est plus facile de travailler avec des n-uplets. Quand cela devient trop difficile à gérer (et pas avant) je commence à grouper les choses dans des structures logiques, cependant, je pense que votre suggestion de l'utilisation de dictionnaires et de ReturnValue objets est mal (ou trop simpliste).

De retour d'un dictionnaire avec des touches de y0, y1, y2, etc n'offre aucun avantage par rapport à n-uplets. Retour d'un ReturnValue exemple avec des propriétés .y0 .y1 .y2 etc n'offre aucun avantage par rapport à n-uplets. Vous devez commencer à appeler les choses si vous voulez aller n'importe où, et vous pouvez le faire à l'aide des n-uplets de toute façon:

def getImageData(filename):
  [snip]
  return size, (format, version, compression), (width,height)
size, type, dimensions = getImageData(x)

À mon humble avis, la seule bonne technique au-delà de n-uplets est de retour réel des objets avec des méthodes appropriées et des propriétés, comme vous obtenez à partir d' re.match() ou open(file).

75voto

monkut Points 14549

Je vote pour le dictionnaire.

Je trouve que si je fais une fonction qui renvoie à quelque chose de plus que 2-3 variables, je vais le plier dans un dictionnaire. Sinon, j'ai tendance à oublier l'ordre et le contenu de ce que je suis de retour.

Aussi, l'introduction d'un "spécial" de la structure rend votre code plus difficile à suivre. (Quelqu'un d'autre est à rechercher dans le code pour savoir ce que c'est)

Si votre préoccupé par type rechercher, utiliser descriptif clés de dictionnaire, par exemple, "x-liste des valeurs'.

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

30voto

tzot Points 32224
<p>Je préfère utiliser des tuples chaque fois qu’un tuple se sent « naturel » ; les coordonnées sont un exemple typique, où les objets distincts peuvent se tenir sur leurs propres, par exemple dans un axe seulement des calculs mise à l’échelle.</p> <p>Utiliser les dictionnaires comme valeur de retour uniquement lorsque les objets groupés ne sont pas toujours les mêmes. Pense que les en-têtes de courriel en option.</p> <p>Pour le reste des cas, où les objets groupés ont une signification inhérente à l’intérieur du groupe, ou un objet part entière avec ses propres méthodes est nécessaire, j’utilise une classe.</p>

19voto

John Fouhy Points 14700
<p>+1 sur la proposition de S.Lott d’une classe de conteneur nommé.</p> <p>Pour python 2.6 et vers le haut, un <a href="http://docs.python.org/library/collections.html#collections.namedtuple">nommé tuple</a> constitue un moyen utile de facilement créer ces classes de conteneur, et les résultats sont « léger et n’exigent aucun davantage de mémoire que les n-uplets ordinaire ».</p>

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