Иногда я хочу убедиться, что последовательность или подобная множеству структура данных (например, список, кортеж или набор, или любой совместимый определенный пользователем тип структуры данных) содержит ровно один элемент, а затем использует этот элемент, но имеет код Ошибка появляется, если элементов меньше или больше, чем точно.
Наивный подход
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()
работает для наборов, но не работает для кортежей и frozensets , так как они не являются изменяемыми и не реализуют метод pop()
.
Элегантный, но, возможно, более неясный способ получить эту работу - использовать распаковку (присвоение структуры) списку переменных длины-1:
def unpack_single(elements):
only_element, = elements
return only_element
Это прекрасно работает для списков, кортежей, наборов, frozensets и даже для неконтейнерных итераций, таких как range
или itertools.takewhile
. (И даже для неконечных, таких как itertools.count
, так как правильно сообщает "слишком много значений для распаковки" для них.)
Хотя я боюсь, что последний подход трудно понять для читателей кода. Существуют ли более подходящие подходы, которые не требуют внешних сторонних зависимостей? Может быть, даже то, что предлагает стандартная библиотека?