67 votes

Pourquoi n'y a-t-il pas de première fonction intégrée (itérable) en Python?

Je me demandais si il y a une raison qu'il n'y a pas d' first(iterable) dans le Python intégré dans les fonctions de, quelque peu similaire à l' any(iterable) et all(iterable) (il peut être glissé dans un stdlib module quelque part, mais je ne vois pas en itertools). first effectuer un court-circuit générateur d'évaluation, de telle sorte que les inutiles (et un nombre potentiellement infini d'opérations peuvent être évités; c'est à dire

def identity(item):
    return item

def first(iterable, predicate=identity):
    for item in iterable:
        if predicate(item):
            return item
    raise ValueError('No satisfactory value found')

De cette façon, vous pouvez exprimer des choses comme:

denominators = (2, 3, 4, 5)
lcd = first(i for i in itertools.count(1)
    if all(i % denominators == 0 for denominator in denominators))

Clairement, vous ne pouvez pas faire list(generator)[0] dans ce cas, puisque le générateur n'est pas arrêter.

Ou si vous avez un tas de regexes de match contre (utile quand ils ont tous le même groupdict interface):

match = first(regex.match(big_text) for regex in regexes)

Vous économisez beaucoup d'inutiles de traitement en évitant list(generator)[0] et de court-circuit sur une correspondance positive.

47voto

liori Points 13629

Si vous avez un itérable, vous pouvez simplement appeler sa méthode next . Quelque chose comme:

 In [3]: (5*x for x in xrange(2,4)).next()
Out[3]: 10
 

14voto

Flimm Points 8870

Il y a un Pypi paquet appelé "première" qui fait cela:

>>> from first import first
>>> first([0, None, False, [], (), 42])
42

C'est un très petit paquet: il contient seulement cette fonction, il n'a pas de dépendances, et il fonctionne sur Python 2 et 3. C'est un fichier unique, de sorte que vous n'avez même pas à l'installer pour l'utiliser.

En fait, ici, est presque l'intégralité du code source (à partir de la version 2.0.1, par Hynek Schlawack, publié sous la licence MIT):

def first(iterable, default=None, key=None):
    if key is None:
        for el in iterable:
            if el:
                return el
    else:
        for el in iterable:
            if key(el):
                return el
    return default

10voto

Alfe Points 12023

J'ai posé une question similaire récemment (il a obtenu marqué comme un double de cette question, maintenant). Ma préoccupation était aussi que j'avais bien aimé utiliser built-ins seulement de résoudre le problème de trouver la première vraie valeur d'un générateur. Ma propre solution, alors c'était ça:

x = next((v for v in (f(x) for x in a) if v), False)

Pour l'exemple de trouver le premier regexp match (pas le premier motif de reconnaissance!) cela devrait ressembler à ceci:

patterns = [ r'\d+', r'\s+', r'\w+', r'.*' ]
text = 'abc'
firstMatch = next(
  (match for match in
    (re.match(pattern, text) for pattern in patterns)
   if match),
  False)

Il n'a pas d'évaluer le prédicat à deux reprises (que vous auriez à le faire si le modèle a été remis) et de ne pas utiliser des hacks comme les habitants des compréhensions.

Mais il dispose de deux générateurs de imbriquées où la logique voudrait utiliser qu'un seul. Ainsi, une meilleure solution serait de nice.

6voto

Coady Points 11374

Il y a une certaine ambiguïté dans votre question. Votre définition de first et l'exemple de regex impliquent qu'il existe un test booléen. Mais l'exemple des dénominateurs a explicitement une clause if; alors ce n'est que par coïncidence que chaque entier est vrai.

Cela ressemble à la combinaison de next et itertools.ifilter vous donnera ce que vous voulez.

 match = next(itertools.ifilter(None, (regex.match(big_text) for regex in regexes)))
 

4voto

Mark Rushakoff Points 97350

Haskell utilise ce que vous venez de décrire, en tant que fonction take (ou en tant que fonction partielle take 1 , techniquement). Python Cookbook a des wrappers générés qui génèrent les mêmes fonctionnalités que take , takeWhile et drop en Haskell.

Mais quant à la raison pour laquelle ce n'est pas intégré, votre hypothèse est aussi bonne que la mienne.

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