Перейти к содержимому

Как распаковать список в python

  • автор:

10 трюков для мастеров Python

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

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

№1: Переворачивание строки

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

Как распаковать список в python

Распаковка ( unpacking , также называемая Деструктуризация ) представляет разложение коллекции (кортежа, списка и т.д.) на отдельные значения.

Так, как и многие языки программирования, Python поддерживает концепцию множественного присваивания. Например:

x, y = 1, 2 print(x) # 1 print(y) # 2

В данном случае присваивем значения сразу двум переменным. Присвоение идет по позиции: переменная x получает значение 1, а переменная y — значени 2.

Данный пример в действительности уже представляет деструктуризацию или распаковку. Значения 1, 2 фактически являются кортежом, поскольку именно запятые между значениями говорят о том, что это кортеж. И мы также могли бы написать следующим образом:

x, y = (1, 2) print(x) # 1 print(y) # 2

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

Подобным образом можно разложить другие кортежи, например:

name, age, company = ("Tom", 38, "Google") print(name) # Tom print(age) # 38 print(company) # Google

Только кортежами мы не ограничены и можем «распаковывать» и другие коллекции, например, списки:

people = ["Tom", "Bob", "Sam"] first, second, third = people print(first) # Tom print(second) # Bob print(third) # Sam

При разложении словаря переменные получают ключи словаря:

dictionary = r, b, g = dictionary print(r) # red print(b) # blue print(g) # green # получаем значение по ключу print(dictionary[g]) # зеленый

Деструктуризация в циклах

Циклы в Python позволяют разложить коллекции на отдельные составляющие:

people = [ ("Tom", 38, "Google"), ("Bob", 42, "Microsoft"), ("Sam", 29, "JetBrains") ] for name, age, company in people: print(f"Name: , Age: , Company: ")

Здесь мы перебираем список кортежей people. Каждый кортеж состоит из трех элементов, соответственно при переборе мы можем их передать в переменные name, age и company.

Другой пример — функция enumerate() . Она принимает в качестве параметра коллекцию, создает для каждого элемента кортеж и возвращает набор из подобных кортежей. Каждый кортеж содержит индекс, который увеличивается с каждой итерацией:

people = ["Tom", "Bob", "Sam"] for index, name in enumerate(people): print(f".") # результат # 0.Tom # 1.Bob # 2.Sam

Игнорирование значений

Если какой-то элемент коллекции не нужен, то обычно для него определяется переменная с именем _ (прочерк):

person =("Tom", 38, "Google") name, _, company = person print(name) # Tom print(company) # Google

Здесь нам не важен второй элемент кортежа, поэтому для него определяем переменную _. Хотя в реальности _ — такое же действительное имя, как name и company:

name, _, company = person print(_) # 38

Упаковка значений и оператор *

Оператор * упаковывает значение в коллекцию. Например:

num1=1 num2=2 num3=3 *numbers,=num1,num2,num3 print(numbers) #[1, 2, 3]

Здесь мы упаковываем значения из кортежа (num1,num2,num3) в список numbers. Причем, чтобы получить список, после numbers указывается запятая.

Как правило, упаковка применяется для сбора значений, которые остались после присвоения результатов деструктуризации. Например:

head, *tail = [1, 2, 3, 4, 5] print(head) # 1 print(tail) # [2, 3, 4, 5]

Здесь переменная head в соответствии с позицией получае первый элемент списка. Все остальные элементы передаются в переменную tail . Таким образом, переменная tail будет представлять список из оставшихся элементов.

Аналогичным образом можно получить все кроме последнего:

*head, tail = [1, 2, 3, 4, 5] print(head) # [1, 2, 3, 4] print(tail) # 5

Или элементы по середине, кроме первого и последнего:

head, *middle, tail = [1, 2, 3, 4, 5] print(head) # 1 print(middle) # [2, 3, 4] print(tail) # 5

Или все кроме первого и второго:

first, second, *other = [1, 2, 3, 4, 5] print(first) # 1 print(second) # 2 print(other) # [3, 4, 5]

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

Другой пример — нам надо получить только первый, третий и последний элемент, а остальные элементы нам не нужны. В общем случае мы должны предоставить переменные для всех элементов коллекции. Однако если коллекция имеет 100 элементов, а нам нужно только три, не будем же мы определять все сто переменных. И в этом случае опять же можно применить упаковку:

first, _, third, *_, last = [1, 2, 3, 4, 5, 6, 7, 8] print(first) # 1 print(third) # 3 print(last) # 8

Также можно получить ключи словаря:

red, *other, green = print(red) # red print(green) # green print(other) # ['blue', 'yellow']

Распаковка и операторы * и **

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

nums1 = [1, 2, 3] nums2 = (4, 5, 6) # распаковываем список nums1 и кортеж nums2 nums3 = [*nums1, *nums2] print(nums3) # [1, 2, 3, 4, 5, 6]

Здесь распаковывем значения из списка nums1 и кортежа nums2 и помещаем их в список nums3.

Подобным образом раскладываются словари, только применяется оператор ** :

dictionary1 = dictionary2 = # распаковываем словари dictionary3 = <**dictionary1, **dictionary2>print(dictionary3) #

Распаковка аргументов для передачи в функцию Python

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

Например, встроенная range() функция ожидает отдельные аргументы start и stop . Если они не доступны отдельно, то можно распаковать аргументы из списка list или кортежа tuple , вызвав функцию с переменной этого списка/кортежа, а впереди нее поставить символ одной звездочки * :

# обычный вызов с отдельными аргументами >>> list(range(3, 6)) # [3, 4, 5] >>> args = [3, 6] # вызов с аргументами, распакованными из списка >>> list(range(*args)) # [3, 4, 5] 

Таким же образом, из словаря dict в функцию можно передать ключевые аргументы, только в этом случае, перед переменной словаря ставится два символов звездочки ** :

>>> def parrot(voltage, state='a stiff', action='voom'): . print("-- This parrot wouldn't", action, end=' ') . print("if you put", voltage, "volts through it.", end=' ') . print("E's", state, "!") . >>> d = "voltage": "four million", "state": "bleedin' demised", "action": "VOOM"> >>> parrot(**d) # -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demis 
  • символом * — распаковывают последовательности в качестве элементов которых одно значение (списки, кортежи, множества)
  • два символа ** — распаковывают последовательности в качестве элементов которых имеется ключ и значение (словари)

Примеры распаковки списков и словарей с аргументами для функции:

date_inf = 'year': "2020", 'month': "12", 'day': "06"> f_name = " - - .txt".format(**date_inf) print(f_name) # 2020-12-06.txt fruits = ['lemon', 'orange', 'banana', 'tomato'] print(*fruits) # lemon orange banana tomato 

Распаковку аргументов можно использовать несколько раз в функции:

date_info = 'year': "2020", 'month': "01", 'day': "01"> track_info = 'artist': "Beethoven", 'title': 'Symphony No 5'> filename = " - - - - .txt".format(**date_info, **track_info) print(filename) # 2020-01-01-Beethoven-Symphony No 5.txt 
fruits = ['lemon', 'orange', 'banana', 'tomato'] first, second, *orher = fruits print(orher) # ['banana', 'tomato'] first, *orher = fruits print(orher) # ['orange', 'banana', 'tomato'] first, *middle, last = fruits print(middle) # ['orange', 'banana'] 
  • КРАТКИЙ ОБЗОР МАТЕРИАЛА.
  • Функции это объекты
  • Функции могут иметь атрибуты
  • Функции могут храниться в структурах данных
  • Функции могут быть вложенными
  • Передача функции в качестве аргумента другой функции
  • Область видимости переменных функции
  • Операторы global и nonlocal
  • Параметры (аргументы) функции
  • Ключевые аргументы в определении функции Python
  • Значение аргумента по умолчанию в функциях Python
  • Варианты передачи аргументов в функцию Python
  • Переменные аргументов *args и **kwargs в функции Python
  • Распаковка аргументов для передачи в функцию Python
  • Как оцениваются аргументы при вызове функции?
  • Строгие правила передачи аргументов в функцию Python
  • Инструкция return
  • Анонимные функции (lambda-выражения)
  • Строки документации в функциях Python
  • Рекурсия
  • Замыкания в функциях Python
  • Перегрузка функций

Простая и расширенная распаковка списков и кортежей

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

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

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *