что значит звездочка в питоне перед переменной
Простая и расширенная распаковка списков и кортежей.
Целевой ссылкой в операции присваивания может служить список, состоящий из двух и более ссылок, разделенных запятыми, которые могут заключаться в необязательные круглые или квадратные скобки.
Присваивание с распаковкой можно использовать для обмена значениями переменных:
В обеих инструкциях присваивания требуется, чтобы объект iterable имел по крайней мере два элемента. Эту форму операции присваивания называют расширенной распаковкой.
Глубокая или расширенная распаковка, в некотором смысле похожа на множественное присваивание. Множественное присваивание позволяет сопоставить длину итерации в правой части присваивания и получить каждый элемент в переменной. Подобным образом глубокая распаковка позволяет сопоставить форму того, что находится в правой части задания.
Например, используя множественное присваивание дважды, можно сделать следующее:
Но если необходимо получить отдельные значения RGB, то можно сразу использовать глубокую распаковку:
Однако, если написать функцию, которая использует глубокую/расширенную распаковку, то можно поймать ошибку:
Примеры распаковки/упаковки последовательностей.
Пример реализации функции, похожей на функцию reduce из модуля functools при помощи распаковки последовательности.
Распаковка итерируемых объектов в переменные с помощью расширенной распаковки:
Распаковка итерируемых объектов может быть вложенной:
Теперь представим, что есть список с несколькими цветами и нужно вычислить оттенки серого. Для этого можно использовать глубокую распаковку в цикле for/in (а также используя генератор списка):
Оператор звездочка в Python
Достаточно универсальным и при этом удобным оператором в Python является оператор *. Давайте рассмотрим его, но для начала вспомним о множественном присваивании в Python.
Код ниже распределяет значения по переменным в соответствии с их порядком.
a, b, c = 1, 2, 3
print(a,b,c)
То же самое будет и со значением в виде списка.
a, b, c = [«hi», 2, False]
print(a,b,c)
Но если мы добавим четвертый параметр в список, то получим ошибку, то же самое и с меньшим количеством параметров.
a, b, c = [«hi», 2, False, True] #слишком много значений для распаковки.
a, b, c = [«hi», 2] #слишком мало значений.
Вот здесь-то нам и пригодится вышеупомянутый оператор *. Просто поставим его перед одной из наших переменных:
a, b, *c = [«hi», 2, False, True, 10, 11]
При этом присваивание произведется по порядку, начиная с первого, а вывод будет следующим:
*a, b, c = [«hi», 2, False, True, 10, 11]
# вывод:
[«hi», 2, False, True,], 10, 11
Подобные операции присваивания справедливы для любых объектов последовательностей, в том числе для строк
*a, b, с = «Hello World»
print(a,b,с)
#Также возможно присваивание переменным меньшего количества значений:
*a, b, с = 1, 2
Минимальное количество значений здесь равно 2, т.е. присваивание одного единственного значения в данном случае вызовет ошибку.
*a, b, с = 1 # недостаточно значений
Еще один пример, но уже с функцией:
def f(a, b, с, d):
print(a, b, с, d)
Но если попытаться передать в функцию список:
a = [«hello», True, 70, [4,6,8]]
f(a) # то выйдет ошибка т.к. требуется передать четыре параметра:
f(*a) # здесь наш оператор распаковывает массив и передает его элементы по порядку в функцию.
Следующий вариант предполагает использование нашего оператора при определении функции, что позволяет передавать в нее произвольное количество неименованных аргументов. Сама же функция будет возвращать эти аргументы в виде кортежа. Следует заметить, что в качестве параметра функции передается слово args.
def f (*args):
print(args)
f() # можно вызвать функции без передачи аргументов
#обход элементов кортежа по значению
def f (*args):
print(i)
# нахождение суммы чисел в кортеже:
def f (*args):
s = 0
for i in args:
s+=i
return s
Т.о. сегодня мы свами узнали, как с помощью всего одного оператора упростить написание кода.
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 0 ):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.
Что такое *args и **kwargs в Python?
Функции — это жизнь. Правда? Если вы только начали осваивать Python, неважно — первый ли это ваш язык программирования, или вы пришли в Python из другого языка, то вы уже знаете о том, что количество параметров в объявлении функции соответствует количеству аргументов, которые передают функции при вызове.
Не позволяйте всяким значкам загонять себя в ступор. Тут нет ничего архисложного. В общем-то, если эти конструкции вам незнакомы — предлагаю с ними разобраться.
Позиционные и именованные аргументы
Сначала поговорим о том, чем они отличаются. В простейшей функции мы просто сопоставляем позиции аргументов и параметров. Аргумент №1 соответствует параметру №1, аргумент №2 — параметру №2 и так далее.
Для вызова функции необходимы все три аргумента. Если пропустить хотя бы один из них — будет выдано сообщение об ошибке.
Если при объявлении функции назначить параметру значение по умолчанию — указывать соответствующий аргумент при вызове функции уже необязательно. Параметр становится опциональным.
Опциональные параметры, кроме того, можно задавать при вызове функции, используя их имена.
В следующем примере установим три параметра в значение по умолчанию None и взглянем на то, как их можно назначать, используя их имена и не обращая внимания на порядок следования аргументов, применяемых при вызове функции.
Оператор «звёздочка»
Оператор * чаще всего ассоциируется у людей с операцией умножения, но в Python он имеет и другой смысл.
Этот оператор позволяет «распаковывать» объекты, внутри которых хранятся некие элементы. Вот пример:
Как пользоваться *args и **kwargs
Итак, мы знаем о том, что оператор «звёздочка» в Python способен «вытаскивать» из объектов составляющие их элементы. Знаем мы и о том, что существует два вида параметров функций. Вполне возможно, что вы уже додумались до этого сами, но я, на всякий случай, скажу об этом. А именно, *args — это сокращение от «arguments» (аргументы), а **kwargs — сокращение от «keyword arguments» (именованные аргументы).
Каждая из этих конструкций используется для распаковки аргументов соответствующего типа, позволяя вызывать функции со списком аргументов переменной длины. Например — создадим функцию, которая умеет выводить результаты, набранные учеником в тесте:
Итоги
Вот несколько советов, которые помогут вам избежать распространённых проблем, возникающих при работе с функциями, и расширить свои знания:
Звезды в Python
Звездочка (этот символ называется «астериск») – один из самых многоликих операторов в Python. Едва ли хватит пальцев руки, чтобы перечислить все его применения. Давайте по порядку.
Умножение и размножение
Самое простое применение одиночного астериска: умножение чисел. Двойного – возведение числа в степень.
Если мы умножим список (или кортеж) на целое число, то получим новый список (или кортеж), где элементы исходного повторены несколько раз. Подобное случится и со строкой. Если мы умножаем на ноль (0) или на число меньше ноля, то получим пустой список, кортеж или строку.
Звезды в аргументах функций
Одна звездочка позволяет получить все или некоторые позиционные аргументы функции в виде кортежа. Позиционные – это те, которые просто подряд передаются без указания имени. Те, что с именем, это аргументы ключевого слова. Разберемся сначала с первыми. Ниже идут два примера. В первом мы получаем все позиционные аргументы в кортеж с названием args. Во втором случае мы обязуем пользователя наших функций передать как минимум 2 аргумента (они попадут в x и y) и дополнительно произвольное число (можно ни одного) аргументов, которые попадут в кортеж rest. Я специально развал их по-разному, не обязательно всегда называть их args. Обратите внимание, что это всегда будет кортеж, даже если мы передадим один аргумент, то получим кортеж из одного элемента.
Пример такой функции мы недавно рассматривали – это хорошо знакомый нам print. Как известно, он принимает произвольное число аргументов, пользуясь выше описанным механизмом. Можете пройти по ссылке и увить его сигнатуру.
Важно, чтобы «звездная переменная» была после всех позиционных аргументов, иначе мы получим ошибку SyntaxError.
Две звездочки перед названием аргумента позволяют нам получить произвольное число произвольно названных именованных аргументов (еще их называют аргументами ключевых слов). Такую переменную часто называют **kwargs (от key-word arguments). В нее будет записан словарик (dict) из пар название ключевого слова (строка) и значение аргумента. Давайте обратимся к примерам:
Как видно, без аргументов мы получили пустой словарь. А с именованными аргументами получили словарь, где их имена – ключи-строки, а их значения – собственно сами переданные значений. В функцию baz нельзя передать аргументы без имен, будет ошибка, потому что без имен – позиционные аргументы, а мы никак их не обозначили.
Тут мы требуем ровно два позиционных аргумента (x и y – обязательные аргументы) и любое количество аргументов ключевых слов, которые попадут в kwargs. Нюанс: мы может передать x и y по именам (последний пример), но они не попадут в kwargs, а останутся только в своих соответствующих переменных x и y, и только z попал в kwargs, потому что мы заранее его не объявили.
Можно сочетать *args и **kwags в одной функции, причем именно в этом порядке.
Еще одно применение звездочки – заставить вызывать функцию, указывая название аргументов в обязательном порядке.
Имя x мы можем и не указывать, просто передадим значение, но cat и dog мы обязаны указать по имени. Зачем это надо? Если функция принимает много разных аргументов, то мы можем принудить указывать имена, чтобы пользователь не перепутал их порядок. Еще такой код просто выглядит более читаемым.
Раскрытие коллекций в аргументах функций при вызове
Также звездочка и двойная звездочка находят применение по другую сторону баррикад – при вызове функции. В предыдущем разделе мы обсуждали, как получать аргументы, а сейчас говорим о том, как их передавать.
Передавая кортеж или список со одной звездочкой – он раскроется в череду позиционных аргументов. Справа от звездочки может быть как имя переменной, так и литерал коллекции или даже вызов функции. Определим две функции: в одной foo – переменное число позиционных аргументов, в другой fixed_foo – фиксированное (три).
В foo мы вольны передать список или кортеж любой длины, а в fixed_foo мы обязаны передать список или кортеж длины 3, не больше, не меньше.
Допускается использовать в одном вызове звездочку несколько раз:
Можно догадаться, что двойная звездочка несет схожую функциональность – раскрывает словарь в именованные аргументы функции.
Если у нас нет **kwargs, то передаваемый словарь должен содержать ровно столько пар ключ-значение, сколько есть аргументов в функции (без значения по-умолчанию, естественно), причем ключи должен совпадать по именам с названиями аргументов (а вот порядок не важен). То есть при ‘a’: 1 в a попадет 1 и так далее.
В примерах выше мы передаем один аргумент явно и два аргумента словарем.
Возможны разнообразные варианты вызова функции. Даже такие:
Склеивание списков и словарей
Мы можем «встраивать» одни списки, кортежи и словари в другие с помощью астерисков. Это значит, что мы добавляем элементы одной коллекции в другую. Одинарная звездочка – для списков и кортежей:
Это похоже на то, как мы склеиваем коллекции оператором плюс (+), вот только плюсом нельзя соединить кортеж и список, будет ошибка. А через звездочку можно. Но согласитесь, сложение читается понятнее и легче.
Со словарями это немного полезнее. Применение двойной звезды (**) позволяет обновить один словарь элементами другого или нескольких других.
Работает похоже, как метод update, но не меняет исходные словари, а создает новый. Если есть совпадающие ключи, то будет взято значение последнего из них:
Распаковка
Позволяет раскидывать по переменным содержимое сложных структур из списков и кортежей. В переменную со звездочкой попадут в виде списка все остальные значения распакуемой структуры, кроме указанных явно. Лучше это понять на примерах:
Имя со звездочкой может быть как в начале, так и в конце кортежа и даже в середине. В последнем и в предпоследнем примере мы берем первый (a), второй (b) элементы; потом все, кроме последнего в middle пойдут как список, и последний в – c.
Если у нас один элемент со звездочкой и ни одного без звездочки – мы должны после него указать запятую (признак кортежа).
Не важно в какие скобки мы обернем верхний уровень: в круглые, квадратные или в никакие. Обычно скобки опускают.
На одном уровне может быть только 1 элемент со звездой.
На нескольких уровней могут быть свои звездные выражения:
При таком присваивании значения переменных копируются.
Справа от звездного присваиванию могут быть любые итераблы, например range:
Пока это все применения звездочки в Python, которые мне удалось вспомнить или найти.
Звёздный Python: где и как используются * и **
Авторизуйтесь
Звёздный Python: где и как используются * и **
Что мы не собираемся обсуждать
Речь пойдёт о префиксных, а не об инфиксных операторах. То есть мы не собираемся обсуждать умножение и возведение в степень:
О чём пойдёт речь
Прим. перев. Примеры кода в статье предполагают использование Python 3.
Звёздочки для распаковки в аргументы функции
При вызове функции можно использовать оператор * для распаковки итерируемого объекта в аргументы вызова:
Строка print(*fruits) передаёт все элементы списка fruits в вызов print() как отдельные аргументы, поэтому нам даже не нужно знать, сколько элементов в списке.
Здесь мы принимаем список со списками и возвращаем «транспонированный» список.
Оператор ** делает что-то похожее, только с именованными аргументами. Он позволяет взять словарь с парами ключ-значение и распаковать его в именованные аргументы в вызове функции:
Начиная с Python 3.5 * и ** можно использовать несколько раз в вызове функции.
Порой бывает полезно использовать * несколько раз:
Похожим образом используются ** :
Звёздочки для упаковки аргументов, переданных в функцию
Эта функция принимает любое количество аргументов:
Стандартные функции Python print() и zip() принимают любое количество позиционных аргументов. Благодаря * мы можем написать свою функцию, работающую похожим образом.
В схожих целях можно применить и ** : если использовать этот оператор в объявлении функции, то он соберёт все переданные именованные аргументы в словарь:
Оператор ** соберёт все переданные именованные аргументы в словарь, на который ссылается аргумент attributes :
Позиционные аргументы с только именованными аргументами
В Python 3 появился специальный синтаксис для только именованных (keyword-only) аргументов. Такие аргументы нельзя указать позиционно, только по имени.
Чтобы принимать только именованные аргументы, при определении функции мы можем расположить именованные аргументы после * :
Эту функцию можно использовать следующим образом:
Такое поведение было добавлено в PEP 3102.
Только именованные аргументы без позиционных
Описанный выше пример выглядит здорово, но что, если мы хотим получить только именованные аргументы без захвата неограниченного количества позиционных?
Прим. перев. Если к этому моменту вы задались вопросом, зачем вообще нужны только именованные аргументы, то всё просто: вызов функции с именованными аргументами выглядит гораздо лучше — сразу можно понять, какой аргумент за что отвечает. Более того, при использовании позиционных аргументов вы вынуждены соблюдать их порядок, в то время как именованные аргументы можно расположить как угодно. Также они позволяют не указывать значения аргументов, у которых есть значения по умолчанию.
Python позволяет сделать это с помощью одинокой звёздочки:
Встроенная функция sorted() использует этот подход. Если посмотреть справку по этой функции, мы увидим следующее:
Звёздочки для распаковки
В Python 3 также появилась возможность использовать оператор * для распаковки итерируемых объектов:
Распаковка может быть даже вложенной:
Вряд ли вам представится возможность так сделать, но, возможно, это и к лучшему.
Tакая функциональность была добавлена в PEP 3132.
Звёздочки в литералах списков
В Python 3.5 появились новые способы использования звёздочек. Одной из ключевых новых фич являлась возможность сложить итерируемый объект в новый список.
Допустим, у вас есть функция, которая принимает любую последовательность и возвращает список, состоящий из этой последовательности и её обратной копии, сконкатенированных вместе:
Здесь нам требуется несколько раз преобразовывать последовательности в списки, чтобы получить конечный результат. В Python 3.5 можно поступить по-другому:
Этот вариант избавляет нас от необходимости лишний раз вызывать list и делает наш код более эффективным и читаемым.
Эта функция возвращает новый список, в котором первый элемент переданного списка (или другой последовательности) перемещается в конец нового списка.
Такой вариант использования оператора * является отличной возможностью для конкатенации итерируемых объектов разных типов. Оператор * работает с любым итерируемым объектом, в то время как оператор + работает только с определёнными последовательностями, которые должны быть одного типа.
Мы не ограничены созданием списков. Мы также можем создавать новые кортежи или множества:
Обратите внимание, что в последней строке мы создаём новое множество из списка и генератора. До того как появилась возможность использовать * подобным образом, не было другого простого способа сделать это в одну строку кода. Да, это было возможно, но до такой конструкции было непросто додуматься и сложно запомнить:
Двойные звёздочки в литералах словарей
Однако это можно использовать не только для объединения двух словарей.
Например, мы можем скопировать словарь, параллельно добавляя в него новое значение:
Или скопировать/объединить словари, параллельно перезаписывая определённые значения: