python - sistema - Una función segura max() para listas vacías
sistema de recomendacion python (4)
El máximo de una secuencia vacía "debería" ser una cosa infinitamente pequeña de cualquier tipo que tengan los elementos de la secuencia. Desafortunadamente, (1) con una secuencia vacía no se puede saber qué tipo de elementos debían tener y (2) no existe, por ejemplo, el entero más negativo en Python.
Por lo tanto, debe ayudar a max
si desea que haga algo sensato en este caso. En las versiones recientes de Python hay un argumento default
para max
(que me parece un nombre engañoso, pero no importa) que se usará si se pasa una secuencia vacía. En versiones anteriores, solo tendrá que asegurarse de que la secuencia que transmita no esté vacía, por ejemplo, con una secuencia de un solo elemento que contenga el valor que le gustaría usar en ese caso.
[EDITADO mucho después de la publicación porque Yaakov Belch amablemente señaló en los comentarios que había escrito "infinitamente grande" donde debería haber escrito "infinitamente pequeña".]
Evaluando,
max_val = max(a)
causará el error,
ValueError: max() arg is an empty sequence
¿Hay una mejor manera de protegerse contra este error que no sea un try
, except
captura?
a = []
try:
max_val = max(a)
except ValueError:
max_val = default
En Python 3.4+, puedes usar default
argumento de palabra clave por default
:
>>> max([], default=99)
99
En la versión inferior, puede utilizar or
:
>>> max([] or [99])
99
NOTA: El segundo enfoque no funciona para todos los iterables. especialmente para iteradores que no dan más que valor de verdad considerado.
>>> max(iter([]) or 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: max() arg is an empty sequence
En versiones de Python anteriores a 3.4 puede usar itertools.chain()
para agregar otro valor a la secuencia posiblemente vacía. Esto manejará cualquier iterable vacío, pero tenga en cuenta que no es precisamente lo mismo que proporcionar el argumento default
ya que el valor adicional siempre se incluye:
>>> from itertools import chain
>>> max(chain([42], []))
42
Pero en Python 3.4, el valor predeterminado se ignora si la secuencia no está vacía:
>>> max([3], default=42)
3
Teniendo en cuenta todos los comentarios anteriores, puede ser una envoltura como esta:
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://.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)