Простая и расширенная распаковка списков и кортежей
Целевой ссылкой в операции присваивания может служить список, состоящий из двух и более ссылок, разделенных запятыми, которые могут заключаться в необязательные круглые или квадратные скобки.
a, b, c = iterable
Эта инструкция, в которой требуется, чтобы объект iterable был итерируемым и содержал ровно три элемента, связывает а с первым элементом, b — со вторым и c — с третьим. Операции такого рода носят название присваивание с распаковкой. Выражение в правой части должно быть итерируемым и содержать ровно столько элементов, сколько указано ссылок в левой части, в противном случае Python бросает исключение. Каждая из ссылок, указанных в левой части, связывается с соответствующим элементом из правой части.
Присваивание с распаковкой можно использовать для обмена значениями переменных:
a, b = b, a
Данная инструкция присваивания повторно связывает имя a со значением, с которым было связано имя b , и наоборот.
Если имеется несколько целевых ссылок, то разрешается помечать одну из них символом * — звездочка. Целевая ссылка, которой предшествует символ * , связывается со списком всех элементов, оставшихся не связанными с другими целевыми ссылками.
first, *middle, last = iterable # что эквивалентно записи без '*' звездочки (расширенной распаковки) first, middle, last = iterable[0], iterable[1:-1], iterable[-1]
В обеих инструкциях присваивания требуется, чтобы объект iterable имел по крайней мере два элемента. Эту форму операции присваивания называют расширенной распаковкой.
Глубокая или расширенная распаковка, в некотором смысле похожа на множественное присваивание. Множественное присваивание позволяет сопоставить длину итерации в правой части присваивания и получить каждый элемент в переменной. Подобным образом глубокая распаковка позволяет сопоставить форму того, что находится в правой части задания.
Например, используя множественное присваивание дважды, можно сделать следующее:
>>> colour_info = ("AliceBlue", (240, 248, 255)) >>> name, rgb_values = colour_info >>> name # 'AliceBlue' >>> r, g, b = rgb_values >>> g # 248
Но если необходимо получить отдельные значения RGB, то можно сразу использовать глубокую распаковку:
>>> colour_info = ("AliceBlue", (240, 248, 255)) >>> name, (r, g, b) = colour_info >>> name # 'AliceBlue' >>> g # 248
Обратите внимание, что переменные r , g и b группируются с помощью скобок () , для создания кортежа, имитирующего форму переменной colour_info . Если просто написать name, r, g, b = colour_info , то Python будет пытаться выполнить четыре присваивания, и ожидал бы от переменной colour_info последовательность из 4-х элементов:
>>> colour_info = ("AliceBlue", (240, 248, 255)) >>> name, r, g, b = colour_info # Traceback (most recent call last): # File "", line 1, in # ValueError: not enough values to unpack (expected 4, got 2)
Глубокая/расширенная распаковка также может использоваться в неявном назначении циклов for/in , она не обязательно должна быть в явном виде со знаком равенства!
Глубокая/расширенная распаковка при правильном использовании может улучшить читаемость вашего кода — убрав беспорядок при извлечении значений по индексу, а также может помочь протестировать код на наличие некоторых ошибок.
def greyscale(colour_info): # для вычисления оттенка, функция использует срезы return 0.2126*colour_info[1][0] + 0.7152*colour_info[1][1] + 0.0722*colour_info[1][2] colours = [ # . Ошибка в задании цвета `AliceBlue`. ("AliceBlue", (240, 248, 255, 127, 255, 212)), ("DarkCyan", (0, 139, 139)), ] # . функция отработала без ошибок. print(greyscale(colours[0])) # 246.8046
Однако, если написать функцию, которая использует глубокую/расширенную распаковку, то можно поймать ошибку:
def greyscale(colour_info): # код вычисления оттенка более лаконичный и короткий name, (r, g, b) = colour_info return 0.2126*r + 0.7152*g + 0.0722*b colours = [ # . Ошибка в задании цвета `AliceBlue`. ("AliceBlue", (240, 248, 255, 127, 255, 212)), ("DarkCyan", (0, 139, 139)), ] # вот и ошибка print(greyscale(colours[0])) # ValueError: too many values to unpack (expected 3)
Примеры распаковки/упаковки последовательностей.
>>> a, b, c = 0, 5, 10 >>> a, b, c # 0 5 10 >>> a, b, c = ['one', 'two', 'three'] >>> a, b, c # one two three >>> a, b = b, a >>> a, b # two one >>> a, *b = ['one', 'two', 'three'] >>> a, b # one ['two', 'three']
Пример реализации функции, похожей на функцию reduce из модуля functools при помощи распаковки последовательности.
def reduce(function, list_): """Уменьшение списка с помощью функции.""" if not list_: raise TypeError("Cannot reduce empty list.") value, *list_ = list_ while list_: val, *list_ = list_ value = function(value, val) return value
Распаковка итерируемых объектов в переменные с помощью расширенной распаковки:
>>> fruits = ['lemon', 'orange', 'banana', 'tomato'] >>> first, second, *orher = fruits >>> orher # ['banana', 'tomato'] >>> first, *orher = fruits >>> orher # ['orange', 'banana', 'tomato'] >>> first, *middle, last = fruits >>> middle # ['orange', 'banana']
Распаковка итерируемых объектов может быть вложенной:
>>> fruits = ['lemon', 'orange', 'banana', 'tomato'] >>> ((first_letter, *other_letter), *other) = fruits >>> first_letter, other_letter # l ['e', 'm', 'o', 'n'] >>> other # ['orange', 'banana', 'tomato']
Теперь представим, что есть список с несколькими цветами и нужно вычислить оттенки серого. Для этого можно использовать глубокую распаковку в цикле for/in (а также используя генератор списка):
colours = [ ("AliceBlue", (240, 248, 255)), ("Aquamarine", (127, 255, 212)), ("DarkCyan", (0, 139, 139)), ] greyscales = [ round(0.2126*r + 0.7152*g + 0.0722*b, 2) for name, (r, g, b) in colours ] print(greyscales) # [246.8, 224.68, 109.45]
Упаковка итерируемых объектов (сложение) в новый список:
>>> fruits = ['lemon', 'orange', 'banana', 'tomato'] >>> x = [*fruits, *reversed(fruits)] >>> x # ['lemon', 'orange', 'banana', 'tomato', 'tomato', 'banana', 'orange', 'lemon'] >>>x = [*fruits[2:], *fruits[:2]] >>> x # ['banana', 'tomato', 'lemon', 'orange'] # Здесь создадим кортеж >>> x = (*fruits[1:], fruits[0]) >>> x # ('orange', 'banana', 'tomato', 'lemon')
- ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
- Обычный способ присваивания значений
- Групповое присваивания значений
- Распаковка/упаковка последовательностей
- Присваивание значений на месте
- Присваивание значений в выражении walrus
Как правильно распаковать в список?
Да, это понятно. Я хотелось методом распаковки через * увидеть. Например: first, *mylist = stroka будет всё, кроме первого символа, вот и подумалось, может как то скобками можно изголица, чтобы всю строку засунуть в массив.
23 дек 2016 в 1:36
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Собственно, если внимательно прочитать сообщение об ошибке при использовании выражения
>>> s = "string" >>> *l = s *l = s ^ SyntaxError: starred assignment target must be in a list or tuple
то можно понять, что достаточно иметь слева кортеж или список:
>>> *l, = s >>> l ['s', 't', 'r', 'i', 'n', 'g'] >>> [*l] = s >>> l ['s', 't', 'r', 'i', 'n', 'g']
Так как в Python во многих случаях можно создавать кортеж, используя только запятую, то *l, = s просто является краткой формой записи выражения (*l, ) = s
10 трюков для мастеров Python
На первый взгляд Python может показаться простым языком, который любой может освоить, и многих удивляет, какого мастерства можно достичь в этом языке. Python один из тех языков, которые легко изучить, но крайне трудно добиться совершенства. В Python зачастую существует множество способов сделать что-то, но так же легко допустить ошибку. К примеру, можно заново изобрести стандартную библиотеку, потратив кучу времени просто потому, что вы и не подозревали о существовании модуля.
К сожалению, стандартная библиотека Python необъятна, и вдобавок её экосистема ужасающе огромна. Существует около двух миллионов гигабайт модулей Python, однако есть несколько практичных приёмов в работе со стандартной библиотекой и пакетами, обычно связанными с научными вычислениями в Python.
№1: Переворачивание строки
Хоть это и выглядит довольно просто, переворачивание строки с помощью литерного цикла может быть утомительным и раздражающим. К счастью, в Python есть встроенная операция для осуществления именно этой задачи — просто обращаемся к индексу ::-1 строки.
Как выпрямить (flatten) список в Python
Списки в Python используются постоянно, а иногда приходится работать с вложенными списками. В этой статье даны некоторые способы выравнивания (flatten) списков, когда вложенные списки выводят на один уровень вверх.
В чем заключается проблема
Возможно вы встречали такого рода вложенные списки (list), т.е. такие списки, которые сами содержат списки. А ваша задача вынести вложенные элементы в один единственный список. Например, исходный список в Python такой:
groups = [['Hong', 'Ryan'], ['Andry', 'Ross'], ['Mike', 'Smith']]
Нужно его преобразовать следующим образом:
['Hong', 'Ryan', 'Andry', 'Ross', 'Mike', 'Smith']
Задача сводится к выравниванию списка на один уровень. С другой стороны, распаковка списка, который содержит список, который в свою очередь также содержит список и т.д. подразумевает распаковку на n-й уровень, где n — уровень вложенности.
Способы выравнивания, о которых мы будем говорить, работают с любыми многоуровневыми итерируемыми структурами данных, в т.ч. используется и для кортежей (tuple), и для пользовательских структур.
Выравнивание с помощью циклов for
Самый простой способ — это использование цикла for. Мы можем пройтись по каждому уровню, чтобы достать вложенные списки. Получается это таким образом (для двухуровневого):
names = [] for group in groups: for name in group: names.append(name)
У объекта list есть метод extend , который принимает на вход итерируемый объект и добавляет его элемент к вызывающему списку:
names = [] for group in groups: names.extend(group)
Подготовка данных для Data Mining на Python
Код курса
DPREP
Ближайшая дата курса
по запросу
Длительность обучения
32 ак.часов
Стоимость обучения
66 000 руб.
Так, мы визуально избавляемся от вложенных циклов, тем самым соблюдая принцип Python: Flat is better than nested. Вместо extend мы можем использовать обычное сложение: сумма двух списков дает один список. Поэтому код переписать можно так:
names = [] for group in groups: names += group
А ещё мы можем воспользоваться list comprehension, о котором мы говорили тут. Он позволяет немного подсократить код. Код на Python с использованием list comprehension выглядит так:
names = [name for group in groups for name in group]
Можно ли использовать * в list comprehension?
В статье мы говорили об операторе * . Он предназначен для распаковки итерируемых объектов. Вот пример того, как его можно использовать:
>>> numbers = [3, 4, 7] >>> more_numbers = [2, 1, *numbers, 11, 18] >>> more_numbers [2, 1, 3, 4, 7, 11, 18]
Можем ли мы использовать данный оператор для распаковки итерируемых объектов внутри list comprehension? Ответ — нет.
>>> names = [*group for group in groups] SyntaxError: iterable unpacking cannot be used in comprehension
Python был лишен данной возможности из-за проблем с читаемостью такого кода (см. PEP448).
Можно ли использовать Python-функцию sum?
Существует ещё трюк для разворачивания списка. И он не самый очевидный и подразумевает использование функции sum :
names = sum(groups, [])
Поскольку данный способ контринтуитивен, мы не рекомендуем его использовать. К тому же, он очень медленный.
Модуль itertools на все времена
Модуль itertools имеет целый набор различных классов и функций, которые предназначены для работы с итерируемыми объектами. Одним из таких классов является chain , который принимает на вход любое количество итерируемых аргументов и возвращает iterator . Этот iterator представляет собой цепочку переданных аргументов. Пример разворачивания списка Python с помощью chain :
>>> from itertools import chain >>> chain(*groups) >>> list(chain(*groups)) ['Hong', 'Ryan', 'Anthony', 'Wilhelmina', 'Margaret', 'Adrian']
Класс chain имеет специальный метод, который не требует предварительной распаковки:
list(chain.from_iterable(groups))
Мы рекомендуем использовать именно этот способ, поскольку он работает быстрее.
Больше подробностей о работе с различными структурами данных вы узнаете на наших образовательных курсах в лицензированном учебном центре обучения и повышения квалификации руководителей и ИТ-специалистов (менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data) в Москве:
- FUNP: Основы языка Python для анализа данных и решения задач машинного обучения
- DPREP: Подготовка данных для Data Mining на Python
- PYML: Машинное обучение на Python
- https://treyhunner.com/2021/11/how-to-flatten-a-list-in-python/
- https://docs.python.org/3/library/itertools.html#itertools.chain
