Как можно передать словарь в аргументы функции используя операцию распаковки
Перейти к содержимому

Как можно передать словарь в аргументы функции используя операцию распаковки

  • автор:

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

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

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

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

Как можно передать словарь в аргументы функции используя операцию распаковки

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

Термины args и kwargs — это соглашения по программированию на Python, в реальности вместо них можно использовать любые именования. *args представляет параметры, которые передаются по позиции. А **kwargs означает параметры, которые передаются по имени. обозначает аргументы ключевого слова.

Оператор * применяется с любым итерируемым объектом (например, кортежем, списком и строками). Тогда как оператор ** можно использовать только со словарями.

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

Здесь функция fun принимает кортеж значений. При вызове мы можем передать ей различное количество значений. Так, в примере выше передается четыре строки, которые образуют кортеж. Консольный вывод программы:

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

Оператор **

Оператор ** упаковывает аргументы, переданные по имени, в словарь. Имена параметров служат ключами. Например, определим функцию, которая просто будет выводить все переданные параметры

Консольный вывод программы:

Поскольку аргументы передаются в функцию в виде словаря, то внутри функции через ключи мы можем получить их значения:

Консольный вывод программы:

Распаковка аргументов

Выше было описано, как операторы * и ** применяются для упаковки аругментов в кортеж и словарь соответственно. Но эти же операторы могут использоваться для распаковки.

Оператор * и распаковка

Сначала рассмотрим ситуацию, где это может пригодиться.Пусть мы передаем в функцию кортеж:

Здесь в вызов функции sum передается кортеж. Параметр *args по сути тоже представляет кортеж, и кажется, все должно работать. Тем не менее мы столкнемся с ошибкой

То есть в данном случае кортеж numbers передается как элемент кортежа *args .

И чтобы элементы кортежа были переданы в кортеж *args как отдельные значения, необходимо выполнить их распаковку:

Здесь при передачи кортежа numbers в функцию sym применяется распаковка: *numbers

Другим случаем распаковки может быть ситуация, когда функция принимает несколько параметров, а мы передаем один кортеж или список:

В данном случае выражение *person раскладывает кортеж person на отдельные значения, которые передаются параметрам name, age и company.

Оператор ** и распаковка

Оператор ** применяется для распаковки словарей:

Здесь выражение **tom раскладывает словарь на отдельные значения, которые передаются параметрам name, age и company по названию ключей.

Сочетание параметров

Параметры *args и *kwargs могут использоваться в функции вместе с другими параметрами. Например:

Операторы упаковки и распаковки — Python: Функции

В Python операторы * и ** используются, чтобы упаковывать и распаковывать итерабельные объекты и словари. Эти операторы обеспечивают гибкий способ обработки аргументов функций и позволяют писать функции, которые могут принимать переменное количество аргументов. В этом уроке мы узнаем, как пользоваться ими.

Оператор *

Оператор * используется для упаковки и распаковки итерируемых объектов, таких как списки или кортежи. При использовании перед итерируемым объектом, во время вызова функции, оператор * распаковывает его. Элементы итерируемого объекта передаются в качестве аргумента функции:

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

Также оператор * можно использовать, чтобы распаковывать итерабельные переменные. Это позволяет присваивать их отдельным переменным:

В этом примере оператор * используется не во время вызова функции, а для распаковки списка my_list в отдельные переменные a , b и c .

Оператор * можно использовать для распаковки итерируемого списка в новый список или кортеж:

В этих примерах оператор * используется для распаковки итераций my_list и my_tuple в новые списки и кортежи с добавлением дополнительных значений.

Оператор **

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

В этом примере оператор ** используется для распаковки словаря details и передачи его пар ключ-значение в качестве аргументов ключевых слов в функцию print_details .

Оператор ** также можно использовать для создания словаря из последовательности пар ключ-значение:

В приведенном выше коде определяются два словаря dict1 и dict2 . А оператор ** используется для распаковки их пар ключ-значение и объединения в один словарь combined_dict .

Если ключи дублируются, то значение из второго словаря перезапишет значение из первого словаря.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

Во что распаковывается словарь Python

Мы можем вызвать функцию, путем распаковки словаря d1:

Следовательно словарь d1, в качестве аргумента функции, распаковывается в конструкцию вида:

С другой стороны можно определить новый словарь как:

Но нельзя вот так:

Так во что именно распаковываются словари? Все зависит от контекста?

Вы верно предположили — всё зависит от контекста, давайте же рассмотрим это детальнее.

Примечание: Я использую Python 3.8 для испытаний

Создание словаря с помощью литералов

Рассмотрим для того, чтобы понять отличия в других ситуациях.

Это самый привычный способ, выглядит это так:

В данном примере словарь будет создан вызовом команды BUILD_CONST_KEY_MAP, которая является специализированной версией BUILD_MAP. Описание самое обыкновенное, не будем заострять на этом внимание.

Создание словаря с помощью распаковки в литералах

Этот способ отличается от первого. Главное, что нужно понять — это не имеет никакого отношения к именованным аргументам. Это специализированный способ. Python вызовет команду BUILD_MAP_UNPACK, чтобы осуществить такое создание. Описание команды гласит:

Берёт count словарей из стека, объединяет их в один словарь, и помещает результат в стек. Осуществляет распаковку словарей в словарь вида <**x, **y, **z>.

Новое в версии 3.5.

Примечание: Вольный перевод. Sorry for my English 🙂

Распаковка в конструктор класса

Python создаст кортеж из словаря, используя команду BUILD_TUPLE, а затем вызовет CALL_FUNCTION_EX, которая в свою очередь по необходимости может вызвать BUILD_MAP_UNPACK_WITH_CALL. Выдержка из описания последней команды гласит:

Это похоже на BUILD_MAP_UNPACK, но используется для f(**x, **y, **z) синтаксиса вызова.

Примечание: Вольный перевод. Sorry for my English 🙂

Распаковка словаря в именованные аргументы

Процесс абсолютно аналогичен варианту выше. В итоге можно сказать, что синтаксис ** в приведённых Вами примерах будет работать по-разному, и команды, которые он порождает, сильно отличаются.

nomnoms12's user avatar

Есть несколько разных синтаксисов для создания словаря.

Вариант 1: литерал

Инициализация словаря через литерал, элементы описываются парами ключ: значение через запятую:

Здесь и ключ, и значение – нормальные объекты Питона, поэтому ключ-имя должно быть строкой к кавычках (ну или другим hashable объектом).

Вариант 2: конструктор

Можно создать словарь через конструктор (который можно считать обычной функцией), обращаясь к классу:

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

function(**d1) – это распаковка элементов словаря в именованные (keyword) аргументы функции. Это встроенный функционал языка для передачи позиционных и именованных аргументов извне. Например, выражение func(**<'type':'Event'>) эквивалентно func(type=’Event’) – только словарь аргументов можно ещё где-то отдельно создавать, модифицировать, передавать, что бывает крайне полезно.

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

Вариант 3: comprehension

Есть ещё comprehension синтаксис, который позволяет лаконично создавать одни итерируемые объекты из других, например:

Насчёт выражения d3 = <**d1>точно не скажу, возможно это тоже comprehension, возможно вариант литерала, а возможно отдельный синтаксис; но суть понятна, тот же dict(**d1) .

Выражение неправильно потому, что ему не соответствует никакой корректной синтаксической конструкции. field=. можно писать лишь в вызове функций, а внутри фигурных скобок ожидается только что-то из вариантов выше.

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

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

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