Значение по умолчанию в распаковке Python

Есть ли способ получить значение по умолчанию, если количество распаковываемых значений слишком мало по сравнению со списком переменных?

Например:

a, b, c = read_json(request)

Это работает, если read_json возвращает массив из трех или более переменных. Если он возвращает только два, я получаю исключение при назначении c, Итак, есть ли способ установить c к значению по умолчанию, если его нельзя распаковать правильно? Что-то вроде:

a, b, (c=2) = read_json(request)

Что похоже на то, что вы делаете при определении функции с аргументами по умолчанию.

Спасибо!

5 ответов

Решение

Вы могли бы попробовать * распаковка с последующей обработкой:

a, b, *c = read_json(request)
c = c[0] if c else 2

Это назначит a а также b как обычно. Если c назначено что-то, это будет list с одним элементом. Если были распакованы только два значения, оно будет пустым list, Второе утверждение присваивает c его первый элемент, если он есть, или значение по умолчанию 2 иначе.

>>> a, b, *c = 1, 2, 3
>>> c = c[0] if c else 2
>>> a
1
>>> b
2
>>> c
3
>>> a, b, *c = 1, 2
>>> c = c[0] if c else 2
>>> a
1
>>> b
2
>>> c
2

Вы можете использовать цепную функцию из itertools, которая является частью стандартной библиотеки Python. Он служит заполнителем по умолчанию в случае, если в первом списке нет значений. Переменная списка 'defaults' в моем примере может иметь количество различных значений для каждой распаковываемой переменной (в примере у меня значение по умолчанию для всех трех значений равно 0).

from itertools import chain

defaults = [0] * 3
data = []

a, b, c, *_ = chain(data, defaults)
print(a, b, c)

data.append(1)
a, b, c, *_ = chain(data, defaults)
print(a, b, c)

data.append(2)
a, b, c, *_ = chain(data, defaults)
print(a, b, c)

data.append(3)
a, b, c, *_ = chain(data, defaults)
print(a, b, c)

data.append(4)
a, b, c, *_ = chain(data, defaults)
print(a, b, c)

Выходы:

0 0 0
1 0 0
1 2 0
1 2 3
1 2 3

Если вам нужно однострочное решение, сработает следующий трюк с использованием параметров по умолчанию в лямбда-функциях, но он несколько сбивает с толку и его трудно читать:

      a, b, c = (lambda a, b, c=3: (a, b, c))(*(1, 2))
print(a, b, c)
a, b, c = (lambda a, b, c=3: (a, b, c))(*(1, 2, 4))
print(a, b, c)

Выход:

      1 2 3
1 2 4

В ответ на вопрос нет, вы не можете сделать это.

Кроме того, я бы рекомендовал не возвращать различное количество аргументов из функций - это вызовет только дальнейшие проблемы с компиляциями (в данном случае речь идет об этом). Каждый раз, когда вы вызываете эту функцию, вам нужно будет проверить, были ли возвращены 2 или 3 значения. (Распаковка может быть полезна здесь, но вам все равно нужно будет проверить эти возвращаемые переменные). например:

a, b, *others = read_json(request)
if others:
    c = others[0]

Было бы разумнее, если бы считал, что read_json - ваша функция, если функция может вернуть dict с установленными значениями по умолчанию:

def read_json(request):
    ret = { 'c': 2 }
    # ... set 'a' and 'b' and 'c' if possible

    return ret

res = read_json(request)
c = res['c']

Я знаю, что опаздываю, но об этом стоит упомянуть.

если все значения по умолчанию, которые вам нужны, одинаковы, вы можете использовать этот ловкий трюк:

def return_tuple():
    return (1, 2)

def return_list():
    return [1, 2]

a, b, c = return_tuple() + (0,)
print(a, b, c)
# 1 2 0

a, b, c = return_list() + [0]
print(a, b, c)
# 1 2 0

a, b, c, d = return_list() + [0, 0]
print(a, b, c, d)

вы можете иметь значения по умолчанию для других типов:

a, b, c, d = list(range(1, 3)) + [0, 0]
print(a, b, c, d)

Однако, если значения по умолчанию не совпадают, есть еще одна хитрость:

defaults = [10, 11, 12, 13]
result = [1, 2]
a, b, c, d = result + defaults[len(result):]
print(a, b, c, d)
# 1, 2, 12, 13

# other types
result = range(2)
a, b, c, d = list(result) + defaults[len(result):]
print(a, b, c, d)
# 0 1 12 13

надеюсь, кто-то еще сочтет это полезным

Другие вопросы по тегам