Python 空列表的安全 max() 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36157995/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 17:29:35  来源:igfitidea点击:

A safe max() function for empty lists

pythonlistexceptionerror-handlingmax

提问by Alexander McFarlane

Evaluating,

评估,

max_val = max(a)

will cause the error,

会导致错误,

ValueError: max() arg is an empty sequence

Is there a better way of safeguarding against this error other than a try, exceptcatch?

除了 a try, exceptcatch之外,还有没有更好的方法来防止这个错误?

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

回答by falsetru

In Python 3.4+, you can use defaultkeyword argument:

在 Python 3.4+ 中,您可以使用default关键字参数

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

In lower version, you can use or:

在较低版本中,您可以使用or

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

NOTE: The second approach does not work for all iterables. especially for iterator that yield nothing but considered truth value.

注意:第二种方法不适用于所有可迭代对象。特别是对于只产生被认为是真值的迭代器。

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

回答by Duncan

In versions of Python older than 3.4 you can use itertools.chain()to add another value to the possibly empty sequence. This will handle any empty iterable but note that it is not precisely the same as supplying the defaultargument as the extra value is always included:

在 3.4 之前的 Python 版本中,您可以使用itertools.chain()向可能为空的序列添加另一个值。这将处理任何空的可迭代对象,但请注意,它与提供default参数并不完全相同,因为总是包含额外的值:

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

But in Python 3.4, the default is ignored if the sequence isn't empty:

但是在 Python 3.4 中,如果序列不为空,则默认值将被忽略:

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

回答by Kurohige

Another solution could be by using ternary operators:

另一种解决方案是使用三元运算符:

nums = []
max_val = max(nums) if nums else 0

or

或者

max val = max(iter(nums) if nums else [0])

回答by Milo

_DEFAULT = object()

def max_default(*args, **kwargs):
    """
    Adds support for "default" keyword argument when iterable is empty.
    Works for any iterable, any default value, and any Python version (versions >= 3.4
    support "default" parameter natively).

    Default keyword used only when iterable is empty:

    >>> max_default([], default=42)
    42

    >>> max_default([3], default=42)
    3

    All original functionality is preserved:

    >>> max_default([])
    Traceback (most recent call last):
    ValueError: max() arg is an empty sequence

    >>> max_default(3, 42)
    42
    """

    default = kwargs.pop('default', _DEFAULT)
    try:
        return max(*args, **kwargs)
    except ValueError:
        if default is _DEFAULT:
            raise
        return default

Bonus:

奖金:

def min_default(*args, **kwargs):
    """
    Adds support for "default" keyword argument when iterable is empty.
    Works for any iterable, any default value, and any Python version (versions >= 3.4
    support "default" parameter natively).

    Default keyword used only when iterable is empty:

    >>> min_default([], default=42)
    42

    >>> min_default([3], default=42)
    3

    All original functionality is preserved:

    >>> min_default([])
    Traceback (most recent call last):
    ValueError: min() arg is an empty sequence

    >>> min_default(3, 42)
    3
    """

    default = kwargs.pop('default', _DEFAULT)
    try:
        return min(*args, **kwargs)
    except ValueError:
        if default is _DEFAULT:
            raise
        return default

回答by Zeeshan

Can create simple lambda to do this:

可以创建简单的 lambda 来做到这一点:

get_max = lambda val_list: max([ val for val in val_list if val is not None ]) if val_list else None

You can call it this way:
get_max(your_list)

你可以这样称呼它:
get_max(your_list)

回答by tsionyx

Considering all the comments above it can be a wrapper like this:

考虑到上面的所有评论,它可以是这样的包装器:

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)

回答by Gareth McCaughan

The max of an empty sequence "should" be an infinitely small thing of whatever type the elements of the sequence have. Unfortunately, (1) with an empty sequence you can't tell what type the elements were meant to have and (2) there is, e.g., no such thing as the most-negative integer in Python.

空序列的最大值“应该”是序列元素具有的任何类型的无限小东西。不幸的是,(1) 对于一个空序列,您无法判断元素的类型是什么,并且 (2) 例如,在 Python 中没有最负整数这样的东西。

So you need to help maxout if you want it to do something sensible in this case. In recent versions of Python there is a defaultargument to max(which seems to me a misleading name, but never mind) which will be used if you pass in an empty sequence. In older versions you will just have to make sure the sequence you pass in isn't empty -- e.g., by oring it with a singleton sequence containing the value you'd like to use in that case.

因此max,如果您希望它在这种情况下做一些明智的事情,则需要提供帮助。在 Python 的最新版本中,有一个default参数 to max(在我看来是一个误导性的名称,但没关系),如果您传入一个空序列,它将被使用。在旧版本中,您只需要确保传入的序列不是空的——例如,通过or使用包含您在这种情况下要使用的值的单例序列对其进行 ing。

[EDITED long after posting because Yaakov Belch kindly pointed out in comments that I'd written "infinitely large" where I should have written "infinitely small".]

[发布后很长时间编辑,因为 Yaakov Belch 在评论中友好地指出我写了“无限大”,而我应该写“无限小”。]