Python断言列表中所有元素都不为None。

7

我在想是否可以断言列表中的所有元素都不是None,这样当a = None时就会产生一个错误。

示例列表为[a, b, c]

我尝试过assert [a, b, c] is not None,但如果任何一个元素不是None,它将返回True,但不能验证所有元素。你能帮我解决吗?谢谢!


1
即使[a,b,c]全部为“None”,assert [a,b,c]不为None也会通过。唯一是“None”的是...“None”。is表示相同的对象,而不是相等性检查。也无法创建更多的“None”类型实例。 - Karl Knechtel
断言 [a, b, c] 不为 None,如果任何一个元素不是 None,则返回 True。 ,这不是发生的事情,它正在进行 None 的标识检查。事实上,任何列表都不是 None,除了 None 以外的任何对象都不是 None。 - juanpa.arrivillaga
3个回答

8
除非您有一个声称等于None的奇怪元素:
assert None not in [a, b, c]

赞,因为这个版本似乎是最快的。如果有人好奇,它比“all”快约5倍,并检查每个元素是否不为“None”,但在性能方面非常接近于“all([a, b, c])”。 - rv.kvetch
5
@rv.kvetch all([a, b, c]) 的安全性要低得多,因为任何假值(例如零)都会使其返回 False - no comment
是的,我从来没有说过它是完美的;但不知何故,它的表现比那个显式的 None 检查要好得多,后者似乎相对较慢。 - rv.kvetch

4
您所说的“全部”是指什么呢?
>>> assert all(i is not None for i in ['a', 'b', 'c'])
>>>

或者简单地说:

assert None not in ['a', 'b', 'c']

顺便提一句,我刚刚注意到@don'ttalkjustcode添加了上面的内容。

或者使用min

>>> assert min(a, key=lambda x: x is not None, default=False)
>>>

“default”应该为“True”,但我发现对于这个来说,“min”非常奇怪。例如,即使没有None,它也会为[0,1,2]抛出AssertionError。顺便说一句,我认为你之前尝试的正确的更快的“all(...)”确实更快,可以看看@rv的基准测试。 - no comment

1
在性能上介于“不在”和“全部”之间。请注意,在这种特殊情况下,使用“全部”的明智(首选)版本最终会表现缓慢 - 但至少超过了“最小值”。
def assert_all_not_none(l):
    for x in l:
        if x is None:
            return False
    return True

编辑:以下是一些感兴趣的基准测试结果。
from timeit import timeit


def all_not_none(l):
    for b in l:
        if b is None:
            return False
    return True


def with_min(l):
    min(l, key=lambda x: x is not None, default=False)


def not_in(l):
    return None not in l


def all1(l):
    return all(i is not None for i in l)


def all2(l):
    return all(False for i in l if i is None)


def all_truthy(l):
    return all(l)


def any1(l):
    return any(True for x in l if x is None)


l = ['a', 'b', 'c'] * 20_000

n = 1_000

# 0.63
print(timeit("all_not_none(l)", globals=globals(), number=n))

# 3.41
print(timeit("with_min(l)", globals=globals(), number=n))

# 1.66
print(timeit('all1(l)', globals=globals(), number=n))

# 0.63
print(timeit('all2(l)', globals=globals(), number=n))

# 0.63
print(timeit('any1(l)', globals=globals(), number=n))

# 0.26
print(timeit('all_truthy(l)', globals=globals(), number=n))

# 0.53
print(timeit('not_in(l)', globals=globals(), number=n))

令人惊讶的获胜者: all(list) 因此,如果您确定列表不包含空字符串或零等假值,则使用此方法没有问题。


2
这些声明真的让我渴望看到一个基准测试 :-) - no comment
是的,我刚刚添加了一些快速而粗糙的代码,并附带了一个足够长的列表来进行测试。 - rv.kvetch
1
我认为这有点误导人,因为除了 all_not_none 之外,所有的都通常会在内联中使用(比如 if any(l):)而不需要额外的函数调用,而 all_not_none 则需要调用(比如 if all_not_none(l))。但是总体来说还可以。还可以包括我在评论中提到的 all(False ...),由于与 相同的原因,应该更快。 - no comment
哇,这是一个巨大的改进。我为“all”添加了另一个测试,速度真的快多了。很好的发现 :) - rv.kvetch
any 应该改为 not any - no comment

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接