Распаковка кортежа: фиктивная переменная против индекса - PullRequest
12 голосов
/ 06 апреля 2010

Какой самый обычный / понятный способ написать это на Python?

value, _ = func_returning_a_tuple()

или

value = func_returning_a_tuple()[0]

Ответы [ 4 ]

10 голосов
/ 06 апреля 2010

value = func_returning_a_tuple()[0] кажется более понятным и также может быть обобщено.

Что если функция возвращала кортеж с более чем двумя значениями?
Что если логика программы заинтересована в 4-м элементе множества кортежей?
Что если размер возвращаемого кортежа меняется?

Ни один из этих вопросов не влияет на идиому, основанную на подстрочных индексах, но не относится к идиоме с несколькими назначениями.

9 голосов
/ 06 апреля 2010

Если вы по достоинству оцените удобный способ сделать это в python3.x, ознакомьтесь с предложением 3132 по улучшению Python (PEP) на этой странице Что нового в Python:

Расширенная повторяемая распаковка. Теперь вы можете писать такие вещи, как a, b, *rest = some_sequence. И даже *rest, a = stuff. Остальной объект всегда является (возможно, пустым) списком; правая часть может быть любой итерируемой. Пример:

(a, *rest, b) = range(5)

Устанавливает a на 0, b на 4 и rest на [1, 2, 3].

6 голосов
/ 06 апреля 2010

Для извлечения одного элемента индексация немного более идиоматична. Когда вы извлекаете два или более предметов, распаковка становится более идиоматичной. Это просто эмпирическое наблюдение с моей стороны; Я не знаю ни одного руководства по стилю, рекомендующего или предписывающего какой-либо выбор! -)

2 голосов
/ 16 марта 2012

Для понимания списка / генератора с парами ключ / значение я думаю, что использование фиктивной переменной может быть довольно аккуратным, особенно когда распакованное значение необходимо использовать более одного раза (избегая повторного индексирования), например ::10000

l = [('a', 1.54), ('b', 4.34), ('c', 3.22), ('d', 6.43)]
s = [x * (1.0 - x) * (2.0 - x) for _, x in l]

против

s = [x[0] * (1.0 - x[0]) * (2.0 - x[0]) for x in l]

Еще одна вещь, которую стоит отметить, это то, что, хотя распаковка и индексация примерно такие же дорогие, как расширенная, распаковка кажется на порядок медленнее.

В Python 3.2 с использованием% timeit в IPython:

Обычная распаковка:

>>> x = (1, 2)
>>> %timeit y, _ = x
10000000 loops, best of 3: 50 ns per loop

>>> %timeit y, _ = x
10000000 loops, best of 3: 50.4 ns per loop

Расширенная распаковка:

>>> x = (1, 2, 3)
>>> %timeit y, *_ = x
1000000 loops, best of 3: 1.02 us per loop

>>> %timeit y = x[0]
10000000 loops, best of 3: 68.9 ns per loop
...