断言和测试可迭代对象的空洞性

Assertions and testing emptiness of iterables

使用内置的 assert 语句,是否有一种好的 Pythonic 方法来检查可迭代对象中的空值?我看过:

但我正在寻找使用断言的解决方案。以下 看起来 可以工作,但我不确定我是否遗漏了一些重要的可能异常:

a = [1, 2, 3]
b = []

assert a, 'a is empty'
assert b, 'b is empty'

这引发了这个 AssertionError:

Traceback (most recent call last):
  File "<ipython-input-9-185714f6eb3c>", line 5, in <module>
    assert b, 'b is empty'
AssertionError: b is empty

怎么样:

assert len(a), "a is empty"

对于 listdictset 对象,它与 assert a, ... 具有相同的效果,但您可能会发现它看起来 clearer/more 可维护。

assert a, ...assert len(a), ... 都不能保证适用于 任意 可迭代对象,尽管您可能会发现后者更可取,因为它会为可迭代对象抛出异常没有 __len__,而不是可能让断言以误报通过。看起来没有完全通用的解决方案(即您无法构造一个会打败它的可迭代的解决方案)。

切记不要将 container(例如列表、集合、元组、字典等)与 iterable(任何可以产生新状态的东西)混淆。检查 iterable 是否为 "empty" 的唯一方法是尝试对其进行迭代并确定它是否不会产生至少一个新状态。您可以自由地将其解释为 iterable 为 "empty"。

像这样

def test_thing_is_empty(self):  # We are in a unittest.Testcase
    foo = iter([])  # Or any other iterable thing
    try:
        item = next(foo)
    except StopIteration:
        pass  # This is what should happen
    else:
        self.fail("Expected foo to be empty, got %s" % (item, ))

还要记住 iterable 在技术上永远不会是真正的 "empty"。尽管不鼓励,但允许 iterable 有时抛出 StopIteration,如果再次尝试,突然开始生成新元素。

所以没办法assert这个。你必须尝试看看你是否失败了。如果你失败了,唯一真实的知识是 iterable 现在没有产生新的状态(无论出于何种原因)。如果你拿回了一个项目,iterable 只是产生了一个独特的、珍贵的雪花,可能永远无法再复制(想想从堆栈下方某处的网络套接字读取)。