добавить необязательные элементы при создании кортежа в Python [дубликат]

Вопрос или проблема

Мне нужно создать кортеж (или массив) с переменным количеством элементов. Вот этот минимальный пример:

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 быть в кортеже, а затем отфильтруйте.

def do_something(foo: str):
    my_tuple = (
       "item",
       foo,
       "something"
    )

    return tuple(filter(bool, my_tuple))

более короткое, чем использовать оператор распаковки *([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, а затем применить фильтрацию. Это делает код более лаконичным, но требует дополнительной обработки:

def do_something(foo: str):
    my_tuple = (
        "item",
        foo,
        "something"
    )
    return tuple(filter(bool, my_tuple))

В данном случае 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, вернется пустой список, что не добавит никаких значений. Это решение чуть менее читабельно, но позволяет добиться нужного эффекта с минимальной длиной кода.

Заключение

Выбор метода создания кортежа с опциональными элементами зависит от ваших предпочтений в читаемости и сложности кода. Оба метода — распаковка и фильтрация — являются разумными выборами, но использование булевого трюка может восприниматься как менее интуитивно понятное. Если вы стремитесь к лаконичности и не против немного усложнить понимание, третий метод может быть хорошим выбором.

Каждый из представленных способов позволяет гибко добавлять опциональные элементы, при этом соблюдая ручные ограничения на минимизацию кода и упрощение логики.

Оцените материал
Добавить комментарий

Капча загружается...