Мне нужно создать кортеж (или массив) с переменным количеством элементов. Вот этот минимальный пример:
def do_something(foo: str):
my_tuple = (
"item",
*([foo] if foo is not None else []),
"something"
)
...
Мне интересно, есть ли более короткое выражение, чем использование оператора распаковки *([foo] if foo is not None else []), чтобы необязательно добавить элемент в кортеж? Обратите внимание, что использование оператора if не является вариантом для создания различных кортежей. Время выполнения также можно не учитывать, предпочтение отдается минимизации кода и избыточности.
Сначала разрешите None быть в кортеже, а затем отфильтруйте.
более короткое, чем использовать оператор распаковки *([foo] if foo is not None else [])
Да, это можно сделать следующим образом
foo = "foo"
my_tuple = ("item",*[foo][:foo is not None],"something")
но это труднее понять. Это использует трюк с булевыми значениями как целыми числам, который используется для определения, будет ли использоваться префикс длиной 0 или 1 в списке, в первом случае это приводит к пустому списку.
Ответ или решение
Создание кортежей (tuples) в Python с переменным количеством элементов может стать вызовом, особенно если требуется добавление опциональных элементов на основе условий. Рассмотрим несколько способов по добавлению элементов в кортеж, при этом минимизируя сложность кода и избегая использования конструкций типа if.
1. Стандартный способ с использованием распаковки
Наиболее распространенный способ использования опциональных элементов в кортеже — это использование оператора распаковки *. Приведем пример, в котором мы будем добавлять элемент foo в кортеж только если он не равен None.
def do_something(foo: str):
my_tuple = (
"item",
*([foo] if foo is not None else []),
"something"
)
return my_tuple
В этом коде мы создаем временный список: если foo не равен None, в список включается foo, если же равен — мы создаем пустой список. Оператор * распаковывает значения, таким образом, добавляя условный элемент в кортеж.
2. Использование фильтрации
Как альтернативный метод, вы можете сразу добавить foo в кортеж со значением None, а затем применить фильтрацию. Это делает код более лаконичным, но требует дополнительной обработки:
В данном случае filter удаляет все ложные значения из кортежа, включая None. Это также позволяет избежать дополнительной логики и делает код компактным.
3. Использование булевого трюка
Существует еще один способ реализации, который основан на использовании булевого значения как индекса для среза списка:
def do_something(foo: str):
my_tuple = ("item", *[foo][:foo is not None], "something")
return my_tuple
Здесь foo is not None возвращает True или False (1 или 0), что позволяет использовать его в качестве индекса для создания среза списка. Если foo равен None, вернется пустой список, что не добавит никаких значений. Это решение чуть менее читабельно, но позволяет добиться нужного эффекта с минимальной длиной кода.
Заключение
Выбор метода создания кортежа с опциональными элементами зависит от ваших предпочтений в читаемости и сложности кода. Оба метода — распаковка и фильтрация — являются разумными выборами, но использование булевого трюка может восприниматься как менее интуитивно понятное. Если вы стремитесь к лаконичности и не против немного усложнить понимание, третий метод может быть хорошим выбором.
Каждый из представленных способов позволяет гибко добавлять опциональные элементы, при этом соблюдая ручные ограничения на минимизацию кода и упрощение логики.