有时,我要确保序列或类似集合的数据结构(例如,列表,元组或集合或任何兼容的用户定义数据结构类型)仅包含一个元素,然后使用该元素,但代码会上升如果元素少于或多于一个,则为错误。
幼稚的方法是
def unpack_single(elements):
assert len(elements) == 1, f"expected exactly 1 element, found {len(elements)} elements"
return elements[0]
这适用于列表和元组:
>>> unpack_single([5])
5
>>> unpack_single((42,))
42
>>> unpack_single([]) # fails as expected
AssertionError: expected exactly 1 element, found 0 elements
>>> unpack_single(tuple()) # fails as expected
AssertionError: expected exactly 1 element, found 0 elements
>>> unpack_single([23, "foo"]) # fails as expected
AssertionError: expected exactly 1 element, found 2 elements
>>> unpack_single(tuple("foobar")) # fails as expected
AssertionError: expected exactly 1 element, found 6 elements
但是它不适用于集合,这些不能下标:
>>> unpack_single({"wat"}) # fails, but I want this to work, too!
TypeError: 'set' object is not subscriptable
替代
def unpack_single(elements):
assert len(elements) == 1, f"expected exactly 1 element, found {len(elements)} elements"
return elements.pop()
对集合有用,但对对元组和冻结集合不起作用,因为它们是不可变的,并且不实现pop()
方法。
一种优雅但可能更晦涩的方法是,对长度为1的变量列表使用解包(解构赋值):
def unpack_single(elements):
only_element, = elements
return only_element
这对于列表,元组,集合,frozenset甚至对于非容器可迭代变量(例如range
或itertools.takewhile
)都适用。 (甚至对于像itertools.count
这样的非限定值,因为它正确地报告了“太多的值无法解包”。)
尽管我担心最后一种方法对于代码的读者来说很难理解。 是否有不需要外部第三方依赖的更好的方法?甚至标准库都可以提供?
也许尝试next(iter(elements))
?