47 votes

Correspondance de modèles des listes dans Python

Je veux faire un filtrage sur les listes en Python. Par exemple, en Haskell, je peux faire quelque chose comme ce qui suit:

fun (head : rest) = ...

Alors, quand je passe dans une liste, head sera le premier élément, et rest sera la fuite des éléments.

De même, en Python, je peux décompresser automatiquement les tuples:

(var1, var2) = func_that_returns_a_tuple()

Je veux faire quelque chose de similaire avec les listes en Python. Maintenant, j'ai une fonction qui retourne une liste, et un morceau de code qui effectue les opérations suivantes:

ls = my_func()
(head, rest) = (ls[0], ls[1:])

Je me demandais si j'arrivais à le faire en une seule ligne en Python, au lieu de deux.

67voto

James Bennett Points 6318

Autant que je sache il n'y a pas moyen d'en faire un one-liner dans le courant Python sans introduire une autre fonction, par exemple:

split_list = lambda lst: (lst[0], lst[1:])
head, rest = split_list(my_func())

Toutefois, en Python 3.0 spécialisées syntaxe utilisée pour les variadic argument de signatures et de l'argument déballage seront disponibles pour ce type de séquence générale déballage ainsi, dans la version 3.0, vous serez en mesure d'écrire:

head, *rest = my_func()

Voir PEP 3132 pour plus de détails: http://www.python.org/dev/peps/pep-3132/

35voto

mweerden Points 4291

Tout d'abord, veuillez noter que le "pattern matching" des langages fonctionnels et l'affectation de n-uplets vous citez ne sont pas vraiment similaires. Dans les langages fonctionnels les modèles sont utilisés pour donner les définitions partielles d'une fonction. Donc, f (x : s) = e ne veut pas dire prendre la tête et la queue de l'argument de l' f et retour e à les utiliser, mais cela signifie que si l'argument de l' f est de la forme x : s (pour quelques - x et s), alors f (x : s) est égal à e.

La cession de python est plus comme une affectation multiple (je soupçonne que c'était son intention initiale). Si vous écrivez, par exemple, x, y = y, x de permuter les valeurs en x et y sans avoir besoin d'une variable temporaire (comme vous le feriez avec une simple instruction d'affectation). Cela a peu à voir avec la correspondance de motif que, fondamentalement, c'est un raccourci pour la "simultanée" de l'exécution de l' x = y et y = x. Bien que python permet arbitraire séquences au lieu d'une virgule-listes séparées, je ne voudrais pas suggérer à l'appel de cette correspondance. Avec la correspondance de motif vous vérifier si oui ou non quelque chose correspond à un modèle; dans le python affectation, vous devez vous assurer que les séquences sur les deux côtés sont les mêmes.

Pour faire ce que vous semblez vouloir vous aurait généralement (également dans les langages fonctionnels) soit utiliser une fonction auxiliaire (comme mentionné par d'autres) ou quelque chose de similaire let ou where des constructions (que l'on peut considérer que l'utilisation d'une fonction anonyme). Par exemple:

(head, tail) = (x[0], x[1:]) where x = my_func()

Ou en python:

(head, tail) = (lambda x: (x[0], x[1:]))(my_func())

À noter que c'est essentiellement la même que les solutions données par les autres avec une fonction auxiliaire, sauf que c'est le one-liner que tu voulais. Il est, cependant, pas nécessairement mieux qu'une fonction distincte.

(Désolé si ma réponse est un peu plus haut. Je pense juste que c'est important de faire la distinction claire.)

4voto

C'est un très un pur fonctionnelle " et en tant que tel est un bon langage en Haskell, mais ce n'est probablement pas approprié pour Python. Python n'est que concept limité de modèles de cette façon - et je soupçonne que vous pourriez avoir besoin d'un peu plus rigide type de système pour mettre en œuvre ce genre de construction (erlang les amateurs invités à être en désaccord ici).

Ce que vous avez est probablement aussi proche que vous obtiendrez à cet idiome, mais vous êtes probablement mieux d'utiliser une liste de compréhension ou l'impératif approche plutôt que de manière récursive l'appel d'une fonction avec la queue de la liste.

Comme il a été indiqué à quelques reprises avant de, Python n'est pas réellement un langage fonctionnel. Il a juste emprunte des idées à partir de la FP monde. Il n'est pas intrinsèquement Queue Récursive dans la façon dont vous pouvez vous attendre à voir intégré dans l'architecture d'un langage fonctionnel, de sorte que vous auriez quelques difficultés à faire ce genre de récursive opération sur un grand ensemble de données sans utiliser beaucoup d'espace de pile.

2voto

Brian Points 48423

De plus pour les autres réponses, notez que l'équivalent de la tête / queue de fonctionnement en Python, y compris python3 de l'extension de la syntaxe * est généralement va être moins efficace que Haskell pattern matching.

Python, les listes sont mises en œuvre sous la forme de vecteurs, de sorte que l'obtention de la queue aurez besoin de prendre une copie de la liste. Ce est O(n) par rapport à la taille de la liste, tandis qu'un implementaion à l'aide de listes liées, comme Haskell pouvez simplement utiliser l'indicateur de queue, un O(1) de l'opération.

La seule exception peut être itérateur en fonction des approches, où la liste n'est pas retourné, mais un itérateur est. Toutefois, cela peut ne pas être applicable à tous les lieux où une liste est souhaitée (par exemple. itérer plusieurs fois).

Par exemple, le Chiffrement de l' approche, si elle est modifiée pour renvoyer l'itérateur plutôt que de le convertir en un tuple ont ce comportement. À l'inverse, un simple 2-article unique méthode ne s'appuie pas sur le pseudo-code serait:

def head_tail(lst):
    it = iter(list)
    yield it.next()
    yield it

>>> a, tail = head_tail([1,2,3,4,5])
>>> b, tail = head_tail(tail)
>>> a,b,tail
(1, 2, <listiterator object at 0x2b1c810>)
>>> list(tail)
[3, 4]

Évidemment, si vous avez encore de les envelopper dans une fonction d'utilité plutôt que d'y être gentil sucre syntaxique pour elle.

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