web-dev-qa-db-fra.com

Une fonction safe max () pour les listes vides

Évaluer,

max_val = max(a)

provoquera l'erreur,

ValueError: max() arg is an empty sequence

Existe-t-il un meilleur moyen de se protéger contre cette erreur autre qu'une capture try, except?

a = []
try:
    max_val = max(a)
except ValueError:
    max_val = default 
25

Dans Python 3.4+, vous pouvez utiliser l'argument de mot clé default :

>>> max([], default=99)
99

Dans la version inférieure, vous pouvez utiliser or:

>>> max([] or [99])
99

Remarque: la deuxième approche ne fonctionne pas pour tous les iterables. en particulier pour les itérateurs qui ne produisent rien, mais qui sont considérés comme une valeur de vérité.

>>> max(iter([]) or 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: max() arg is an empty sequence
35
falsetru

Dans les versions de Python antérieures à 3.4, vous pouvez utiliser itertools.chain() pour ajouter une autre valeur à la séquence éventuellement vide. Ceci gérera toutes les valeurs vides, mais il est à noter que ce n'est pas exactement la même chose que de fournir l'argument default car la valeur supplémentaire est toujours incluse:

>>> from itertools import chain
>>> max(chain([42], []))
42

Mais dans Python 3.4, la valeur par défaut est ignorée si la séquence n'est pas vide:

>>> max([3], default=42)
3
7
Duncan

Compte tenu de tous les commentaires ci-dessus, il peut s'agir d'un wrapper comme celui-ci:

def max_safe(*args, **kwargs):
    """
    Returns max element of an iterable.

    Adds a `default` keyword for any version of python that do not support it
    """
    if sys.version_info < (3, 4):  # `default` supported since 3.4
        if len(args) == 1:
            arg = args[0]
            if 'default' in kwargs:
                default = kwargs.pop('default')
                if not arg:
                    return default

                # https://stackoverflow.com/questions/36157995#comment59954203_36158079
                arg = list(arg)
                if not arg:
                    return default

                # if the `arg` was an iterator, it's exhausted already
                # so use a new list instead
                return max(arg, **kwargs)

    return max(*args, **kwargs)
0
tsionyx

Le maximum d'une séquence vide "devrait" être une chose infiniment petite, quel que soit le type des éléments de la séquence. Malheureusement, (1) avec une séquence vide, vous ne pouvez pas dire quel type les éléments étaient censés avoir et (2) il n’existe pas, par exemple, d’entier le plus négatif en Python.

Donc vous devez aider max si vous voulez que cela fasse quelque chose de sensé dans ce cas. Dans les versions récentes de Python, il existe un argument default à max (qui me semble un nom trompeur, mais cela ne fait rien) qui sera utilisé si vous passez une séquence vide. Dans les versions plus anciennes, il vous suffit de vous assurer que la séquence que vous avez passée n'est pas vide - par exemple, en lui donnant or avec une séquence singleton contenant la valeur que vous souhaitez utiliser dans ce cas.

[Édité longtemps après sa publication car Yaakov Belch avait gentiment fait remarquer dans des commentaires que j'avais écrit "infiniment grand" là où j'aurais dû écrire "infiniment petit".]

0
Gareth McCaughan