Переполнение распаковки: фиктивная переменная vs index
Каков обычный/ясный способ написать это в Python?
value, _ = func_returning_a_tuple()
или
value = func_returning_a_tuple()[0]
Ответы
Ответ 1
value = func_returning_a_tuple()[0]
кажется яснее, а также может быть обобщен.
Что делать, если функция возвращала кортеж с более чем двумя значениями?
Что, если логика программы заинтересована в 4-м элементе множества кортежей?
Что делать, если размер возвращаемого кортежа меняется?
Ни один из этих вопросов не влияет на идиому на основе подзаголовка, но в случае многозадачности идиомы.
Ответ 2
Если вы оцените удобный способ сделать это в python3.x, ознакомьтесь с предложением по оптимизации python (PEP) 3132 на этой странице What New в Python:
Расширенная итерационная распаковка. Теперь вы можете писать такие вещи, как a, b, *rest = some_sequence
. И даже *rest, a = stuff
. Объект rest всегда является (возможно, пустым) списком; правая часть может быть любой итерабельной. Пример:
(a, *rest, b) = range(5)
Это устанавливает a
в 0
, b
в 4
и rest
в [1, 2, 3]
.
Ответ 3
Для извлечения одного элемента индексирование немного более идиоматично. Когда вы извлекаете два или более предмета, распаковка становится более идиоматичной. Это только эмпирическое наблюдение с моей стороны; Я не знаю ни одного руководства по стилю, рекомендующего или требующего выбора! -)
Ответ 4
Для понимания списка/генератора с парами ключ/значение я думаю, что использование фиктивной переменной может быть довольно аккуратным, особенно если нерациональное значение нужно использовать несколько раз (избегая повторной индексации), например:
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