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

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

Распаковка аргументов для передачи в функцию 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
  • Перегрузка функций

Как передать список в качестве аргумента функции?

Занимаюсь реализацией решения ОДУ.
В функцию необходимо передать 4 аргумента , два из них — массивы (списки в моём случае, допустимо же? )
Как это сделать? Видимо, неверно поняла фишку с использованием символа * при передаче в функцию списка )
(def explicitEulerMethod(n, h, *x, *y) не прокатило )

  • Вопрос задан более трёх лет назад
  • 19546 просмотров

Комментировать
Решения вопроса 1
Александр @fireSparrow

Звёздочка в данном случае — это распаковка. Её нужно использовать в противоположной ситуации — когда нужно передать не сам список, а его элементы в качестве отдельных аргументов.

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

Ответ написан более трёх лет назад
Нравится 4 2 комментария
dr sbtn @dawasaturday Автор вопроса
Theodore_Codeman @Theodore_Codeman
Снимаю перед вами шляпу за данную помощь)
Ответы на вопрос 1

fox_12

Владимир Куц @fox_12 Куратор тега Python
Расставляю биты, управляю заряженными частицами

Ну так и передавайте:
def explicitEulerMethod(n, h, x, y)

где x и y — массивы

Ответ написан более трёх лет назад
Нравится 2 2 комментария
dr sbtn @dawasaturday Автор вопроса
То бишь только потом при их использовании с индексами и размерностями работать?

fox_12

Владимир Куц @fox_12 Куратор тега Python

Дарья Субботина: В смысле «только потом»? Опишите более внятно какие затруднения вы видите. Вы передаете в функцию 4 аргумента. 2 — переменные и 2 массива x и y. Первый — размерностью len(x), второй — len(y). Пробежаться по всем индексам первого массива — for element in x: . второго — for element in y: Исходя из этих знаний выполняете в функции действия нам массивами.

Как передать список в аргумент функции Python

как мне сделать чтобы функции список(num_my) передавался через аргумент? что я делаю не так? нужно чтобы функция отрабатывала как пример выше.

def result(num_my): num = [54,24,34,1,2,3] num_res = [] for number in num: if number in num_my: num_res.append(number) return num_res num_1 = (result([54,24,1,2,3])) num_2 = (result([34,1,3])) print(num_1) print(num_2) 

Отслеживать
UserNameAK
задан 31 янв 2020 в 19:48
UserNameAK UserNameAK
47 1 1 золотой знак 1 1 серебряный знак 8 8 бронзовых знаков
Сейчас что не так? Сдвинь return на уровень влево.
31 янв 2020 в 19:53

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

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

def result(num_my): num = [54,24,34,1,2,3] num_res = [] for number in num: if number in num_my: num_res.append(number) return num_res 

А еще лучше, если вы используете «pythonicway»:

def result(num_my): num = [54,24,34,1,2,3] return [number for number in num if number in num_my] 

Отслеживать
ответ дан 31 янв 2020 в 19:57
11.8k 2 2 золотых знака 10 10 серебряных знаков 28 28 бронзовых знаков

Огромное спасибо, все моя не внимательность(( просидел час точно думал что не так делаю, а тут такая мелочь))))) Спасибо за подсказку!)

Операторы * и ** в Питоне. Что это и как использовать

Операторы (operators) * и ** встречаются в питоне очень часто. Иногда они немного непонятны и новичкам, и опытным ребятам, переходящим на питон с ряда других языков программирования (в которых операторы могут использоваться немного иначе). Статья известного питон-коуча Трея Ханнера (Trey Hunner), который помогает девелоперам расширять свои знания. Дата написания статьи: 10.11.2018.

Функционал операторов * и ** развивается уже много лет. Я хочу рассмотреть все способы их использования по состоянию на текущий момент. Буду указывать, что конкретно работает только в современных версиях питона. Поэтому, если вы изучали операторы * и ** еще во времена питона 2 (Python 2), советую хотя бы проглядеть данную статью, потому что в питоне 3 (Python 3) этим операторам добавили много новых возможностей.

Если вы начали изучать питон недавно и еще не освоили аргументы ключевых слов (keyword arguments; также известные как именованные аргументы, named arguments), предлагаю сперва прочитать мою статью про аргументы ключевых слов в питоне.

Что мы обсуждать не будем

В данной статье, говоря про операторы * и **, я имею в виду операторы-префиксы (prefix operators), а не инфиксы (infix). То есть, функции умножения и возведения в степень не входят в тему статьи.

Тогда про что же мы говорим

Мы говорим про операторы-префиксы * и **, которые используются перед переменной (variable). Например:

>>> numbers = [2, 1, 3, 4, 7]
>>> more_numbers = [*numbers, 11, 18]
>>> print(*more_numbers, sep=’, ‘)
2, 1, 3, 4, 7, 11, 18

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

В сферу применения рассматриваемых операторов входит:
1. Операторы * и **: передача аргументов в функцию.
2. Операторы * и **: захват аргументов, переданных в функцию.
3. Оператор *: принятие аргументов, содержащих только ключевые слова.
4. Оператор *: захват элементов во время распаковки кортежа (tuple).
5. Оператор *: распаковка итерируемых объектов в списке или кортеже.
6. Оператор **: + распаковка словарей в других словарях.

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

Операторы * и ** при распаковке во время вызова функции

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

>>> fruits = [‘lemon’, ‘pear’, ‘watermelon’, ‘tomato’]
>>> print(fruits[0], fruits[1], fruits[2], fruits[3])
lemon pear watermelon tomato
>>> print(*fruits)
lemon pear watermelon tomato

В строке print(*fruits) производится вызов всех элементов списка fruits в функции print. Они становятся отдельными аргументами. При этом нам даже не надо знать, сколько всего аргументов окажется в списке.

В данном примере оператор * – не просто синтактический выверт (syntactic sugar). Без * отправить все элементы конкретного итерируемого объекта в качестве отдельных аргументов было бы невозможно (это не касается списков с сфиксированной длиной).

Еще один пример:

def transpose_list(list_of_lists):
return [
list(row)
for row in zip(*list_of_lists)
]

В данном случае мы принимаем список со списками в качестве элементов и возвращаем «преобразованный» список со списками:

>>> transpose_list([[1, 4, 7], [2, 5, 8], [3, 6, 9]])
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

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

>>> date_info = <'year': "2020", 'month': "01", 'day': "01">
>>> filename = «—.txt».format(**date_info)
>>> filename
‘2020-01-01.txt’

Скажу из своего опыта. Оператор ** не часто используется для распаковки аргументов ключевых слов при вызове функции. Чаще всего я вижу такие примеры при работе с наследованием: вызовы super() часто включают в себя оба оператора.

Операторы * и ** можно использовать неоднократно при вызове функции. Данная возможность появилась в питоне 3.5. Иногда это может оказаться очень уместным:

>>> fruits = [‘lemon’, ‘pear’, ‘watermelon’, ‘tomato’]
>>> numbers = [2, 1, 3, 4, 7]
>>> print(*numbers, *fruits)
2 1 3 4 7 lemon pear watermelon tomato

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

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

Операторы * и ** при упаковке аргументов, переданных функции

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

from random import randint
def roll(*dice):
return sum(randint(1, die) for die in dice)

Данная функция принимает любое количество аргументов.

>>> roll(20)
18
>>> roll(6, 6)
9
>>> roll(6, 6, 6)
8

Функции питона print и zip принимают любое количество позиционных аргументов. Такое использование оператора * при упаковке аргументов позволяет нам создавать свои функции, которые (аналогично print и zip) принимают любое количество аргументов.

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

def tag(tag_name, **attributes):
attribute_list = [
f’=»»‘
for name, value in attributes.items()
]
return f» >»

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

>>> tag(‘a’, href=»http://treyhunner.com»)
>>> tag(‘img’, height=20, width=40, src=»https://kirill-sklyarenko.ru/face.jpg»)

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

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

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

def get_multiple(*keys, dictionary, default=None):
return [
dictionary.get(key, default)
for key in keys
]

Данную функцию можно использовать так:

Аргументы dictionary и default поставлены после *keys. То есть, их можно только в качестве аргументов ключевых слов. Если мы попытаемся определить их позиционно, то увидим ошибку:

>>> fruits = <'lemon': 'yellow', 'orange': 'orange', 'tomato': 'red'>
>>> get_multiple(‘lemon’, ‘tomato’, ‘squash’, fruits, ‘unknown’)
Traceback (most recent call last):
+ File «», line 1, in
TypeError: get_multiple() missing 1 required keyword-only argument: ‘dictionary’

Данное поведение внедрено в питон с помощью предложения PEP 3102.

Аргументы, содержащие только ключевые слова и не содержащие позиционные аргументы

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

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

def with_previous(iterable, *, fillvalue=None):
«»»Yield each iterable item along with the item before it.»»»
previous = fillvalue
for item in iterable:
yield previous, item
previous = item

Данная функция принимает аргумент, содержащий итерируемый объект (iterable). Его можно определить позиционно (то есть, первым) или с помощью названия и аргумента fillvalue, который входит в число аргументов, допускающих только ключевые слова. Это означает, что мы можем вызвать функцию with_previous вот так:

>>> list(with_previous([2, 1, 3], fillvalue=0))
[(0, 2), (2, 1), (1, 3)]

>>> list(with_previous([2, 1, 3], 0))
Traceback (most recent call last):
File «», line 1, in
TypeError: with_previous() takes 1 positional argument but 2 were given

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

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

На самом деле, данный подход используется встроенной функцией питона sorted. Если посмотреть справку для sorted, можно увидеть следующее:

>>> help(sorted)
Help on built-in function sorted in module builtins:
sorted(iterable, /, *, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customize the sort order, and the reverse flag can be set to request the result in descending order.

Пример использования оператора * как самого по себе прямо в документации по аргументам функции sorted.

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

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

Оператор * теперь можно использовать при распаковке кортежа:

>>> fruits = [‘lemon’, ‘pear’, ‘watermelon’, ‘tomato’]
>>> first, second, *remaining = fruits
>>> remaining
[‘watermelon’, ‘tomato’]
>>> first, *remaining = fruits
>>> remaining
[‘pear’, ‘watermelon’, ‘tomato’]
>>> first, *middle, last = fruits
>>> middle
[‘pear’, ‘watermelon’]

Если вы задаете себе вопрос: как же мне использовать это в своем коде, посмотрите примеры в моей статье про распаковку кортежей в питоне. В этой статье я показал, каким образом такое использование оператора * может, в некоторых случаях, стать альтернативой для срезания последовательностей (sequence slicing).

Обычно во время своих лекций об операторе * я говорю, что можно использовать только одно выражение с ним в отдельном вызове многократного присвоения (multiple assignment). Технически это некорректно, потому что можно его использовать два раза при вложенной распаковке (nested unpacking). Данный вопрос я рассмотрел подробно в статье про распаковку кортежей.

>>> fruits = [‘lemon’, ‘pear’, ‘watermelon’, ‘tomato’]
>>> ((first_letter, *remaining), *other_fruits) = fruits
>>> remaining
[‘e’, ‘m’, ‘o’, ‘n’]
>>> other_fruits
[‘pear’, ‘watermelon’, ‘tomato’]

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

Данная возможность добавлена в питон на основе предложения PEP 3132. Следует отметить, что оно не относится к очень длинным.

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

В питоне 3.5 добавлено очень много возможностей, связанных с оператором *, на основе предложения PEP 448. Одной из самых заметных новых возможностей стало использование * для вывода итерируемого объекта в новый список.

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

def palindromify(sequence):
return list(sequence) + list(reversed(sequence))

Данная функция должна пару раз провести конвертацию в список, чтобы объединить списки и вернуть результат. Начиная с питона 3.5, мы можем, вместо вышеприведенного примера, написать следующее:

def palindromify(sequence):
return [*sequence, *reversed(sequence)]

В данном коде больше нет нескольких ненужных вызовов списков. Поэтому он стал эффективнее и лучше читается.

def rotate_first_item(sequence):
return [*sequence[1:], sequence[0]]

Данная функция возвращает новый список, в котором первый элемент переданного списка (или другой последовательности) перенесен в конец нового списка.

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

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

Обратите внимание, что последняя строка принимает список и генератор (generator), а потом выводит их в новое множество. Перед появлением этой возможности для оператора * было непросто сделать это в одну строку кода. Разумеется, способ сделать это существовал, но его было непросто вспомнить или обнаружить:

>>> set().union(fruits, uppercase_fruits)

Оператор ** в литерале словаря

Помимо вышеприведенного на основе предложения PEP 448 в функционал ** добавлен вывод пар ключ/значение (key/value) из словаря в новый словарь:

>>> date_info =
>>> track_info =
>>> all_info = <**date_info, **track_info>
>>> all_info

Про это я написал еще одну статью. Сейчас ее можно найти под новым названием про идиоматический способ сливать словари в питоне. Данную возможность можно использовать не только для сливания двух словарей. Например, можно скопировать словарь, параллельно добавляя в него новые значения:

>>> date_info =
>>> event_info = <**date_info, 'group': "Python Meetup">
>>> event_info

Еще можно скопировать или слить словари, переписывая определенные значения:

>>> event_info =
>>> new_info = <**event_info, 'day': "14">
>>> new_info

Операторы * и ** обладают немалыми возможностями в питоне

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

Прочитав обо всех возможностях * и **, вы, возможно, удивитесь названиям, под которыми используются эти странные операторы. К сожалению, для них нет лаконичных названий. Я слышал, как * называли оператором для упаковки и распаковки. Еще слышал, как его называли «splat» (это из мира Руби) и просто звездой.

Чаще всего я называю их звездой (star) и двойной звездой (double star) (или звездой-звездой (star star)). В данном случае разделения с их функциями как инфиксов не проводится (речь идет про операции умножения и возведения в степень). Но обычно из контекста очевидно, о чем идет речь, про префиксы или инфиксы.

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

  • перевод с английского
  • python
  • операторы

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

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