Что значит звездочка перед переменной в python
Перейти к содержимому

Что значит звездочка перед переменной в python

  • автор:

Understanding the asterisk(*) of Python

mingrammer

I’m not a native speaker. Please understand.

Python has plentiful types of operations compared to other languages.

Especially, the Asterisk(*) that is one of the most used operators in Python allows us to enable various operations more than just multiplying the two numbers. In this post, we’ll look at the various operations that can be done with this Asterisk(*) to write Python more pythonically.

There are 4 cases for using the asterisk in Python.

  1. For multiplication and power operations.
  2. For repeatedly extending the list-type containers.
  3. For using the variadic arguments. (so-called “packing”)
  4. For unpacking the containers.

Let’s look at each case.

When used in multiplication and power operations

You may already know of this case. Python supports the built-in power operations as well as multiplication.

For repeatedly extending the list-type containers

Python also supports that multiply the list-type container (includes tuple) and int for extending container data by given number times.

For using the variadic arguments

We often need variadic arguments (or parameters) for some functions. For example, we need it if we don’t know number of passing arguments or when we should process something with arbitrary passing arguments for some reasons.

There are 2 kinds of arguments in Python, one is positional arguments and other is keyword arguments, the former are specified according to their position and latter are the arguments with keyword which is the name of the argument.

Before looking at the variadic positional/keyword arguments, we’ll talk about the positional arguments and keyword arguments simply.

Above function has 2 positional arguments: first , second and 2 keyword arguments: third , fourth . For positional arguments, it is not possible to omit it, and you must pass all positional arguments to the correct location for each number of arguments declared. However, for keyword arguments, you can set a default value of it when declaring a function, and if you omit the argument, the corresponding default value is entered as the value of the argument. That is, the keyword arguments can be omitted.

Thus, what you can see here is that keyword arguments can be omitted, so they can not be declared before positional arguments. So, the following code will raises exceptions:

But, in the third case, you can see that there are 3 positional arguments and 1 keyword argument. Yes, for keyword arguments, if the passed position is the same to declared position, the keyword can be excluded and passed as positional arguments. That is, in above, the mike will be passed to third key automatically.

So far we’ve talked about the basic of arguments. By the way, one problem can be met here. The function can not handle the arbitrary numbers of runners because the function has fixed numbers of arguments. So we need the variadic arguments for it. Both positional arguments and keyword arguments can be used as variadic arguments. Let’s see following examples.

Всё, что вам нужно знать о звёздочках в Python

Большинство разработчиков знают символ звёздочки как оператор умножения в Python:

Однако, звёздочка имеет особое значение для сложных структур данных, например списка или словаря.

*args и **kwargs

*args в объявлении функции

В Python оператор распаковки или оператор * наиболее широко используется в функциях.

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

Но что делать, если мы хотим сложить произвольное количество значений? Вы можете просто добавить звёздочку перед именем параметра следующим образом:

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

* при вызове функции

Мы посмотрели, что можем определить функцию таким образом, чтобы она принимала неопределенное количество аргументов. Но что, если у нас есть функция с фиксированным набором параметров, и мы хотим передать ей список значений? Рассмотрим такой вариант:

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

К счастью, оператор распаковки ( * ) работает в обоих направлениях. Мы уже видели его использование в объявлении функции, но и при вызове функции это тоже сработает:

**kwargs в объявлении функции

Распаковывать словари с помощью оператора ** можно точно так же, как и делали с * .

Рассмотрим следующую функцию:

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

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

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

** в вызове функции

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

Ограничение способов вызова функций

Только именованные аргументы

Одной из самых прикольных особенностей звёздочки в определениях функций является то, что ее можно использовать автономно, то есть без названия переменной (параметра). И в Python такое определение функции тоже будет абсолютно правильным:

Но что в этом случае делает самостоятельная звёздочка? Звёздочка упаковывает все аргументы (не являющиеся именованными), как мы видели выше. Но в нашем случае у неё нет названия (и ее нельзя использовать), а после * идёт переменная keyword_arg_1 . Поскольку * уже соответствует всем позиционным аргументам, у нас остается keyword_arg_1 , который обязан использоваться в качестве именованного аргумента.

Вызов функции с позиционными аргументами ( my_function(1) ) вызовет ошибку:

Только позиционные аргументы

Что, если мы хотим заставить пользователей использовать только позиционные аргументы, в отличие от именованных аргументов в предыдущем примере?

Есть очень простой способ. Мы используем знак / :

Удивительно, но немногие разработчики знают об этом приёме, который был введён в Python 3.8 с PEP 570 .

Если попытаться вызвать функцию с именованными аргументами only_positional_arguments(arg1=1, arg2=2) , это приведёт к ошибке TypeError.

Использование * и ** при создании объектов

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

Создание списков

Допустим, у нас есть два отдельных списка и мы хотим их объединить.

Конечно, мы можем сделать это с помощью оператора + :

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

Создание словарей

Опять же, принципы, актуальные для оператора * и списков, также актуальны и для оператора ** со словарями.

Распаковка объектов

Возможно, вы уже знаете, как разделить элементы последовательности на несколько переменных следующим образом:

Но знаете ли вы, что звездочки ( * ) можно использовать для назначения переменных, когда у вас есть последовательность произвольной длины?

Скажем, вам нужен первый элемент и последний элемент списка в определенных переменных.

Вы можете сделать это, используя звездочку следующим образом:

В этом примере a теперь содержит первый элемент, а c — последний элемент my_list . А что же в b ?

В b находится весь список, исключая первый и последний элемент, то есть [2] . Обратите внимание, что b теперь является списком.

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

Что такое *args и **kwargs в Python?

Функции — это жизнь. Правда? Если вы только начали осваивать Python, неважно — первый ли это ваш язык программирования, или вы пришли в Python из другого языка, то вы уже знаете о том, что количество параметров в объявлении функции соответствует количеству аргументов, которые передают функции при вызове.

Это — основы. Это то, что помогает людям понимать окружающий мир. Но утверждение «количество параметров равно количеству аргументов» закладывает в голову новичка бомбу замедленного действия, которая срабатывает после того, как он увидит в объявлении функции таинственные конструкции *args или **kwargs .

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

Позиционные и именованные аргументы

Для того чтобы разобраться с *args и **kwargs , нам нужно освоить концепции позиционных (positional) и именованных (keyword) аргументов.

Сначала поговорим о том, чем они отличаются. В простейшей функции мы просто сопоставляем позиции аргументов и параметров. Аргумент №1 соответствует параметру №1, аргумент №2 — параметру №2 и так далее.

Для вызова функции необходимы все три аргумента. Если пропустить хотя бы один из них — будет выдано сообщение об ошибке.

Если при объявлении функции назначить параметру значение по умолчанию — указывать соответствующий аргумент при вызове функции уже необязательно. Параметр становится опциональным.

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

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

Оператор «звёздочка»

Оператор * чаще всего ассоциируется у людей с операцией умножения, но в Python он имеет и другой смысл.

Этот оператор позволяет «распаковывать» объекты, внутри которых хранятся некие элементы. Вот пример:

Тут берётся содержимое списка a , распаковывается, и помещается в список b .

Как пользоваться *args и **kwargs

Итак, мы знаем о том, что оператор «звёздочка» в Python способен «вытаскивать» из объектов составляющие их элементы. Знаем мы и о том, что существует два вида параметров функций. Вполне возможно, что вы уже додумались до этого сами, но я, на всякий случай, скажу об этом. А именно, *args — это сокращение от «arguments» (аргументы), а **kwargs — сокращение от «keyword arguments» (именованные аргументы).

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

Я не использовал при объявлении функции конструкцию *args . Вместо неё у меня — *scores . Нет ли тут ошибки? Ошибки здесь нет. Дело в том, что «args» — это всего лишь набор символов, которым принято обозначать аргументы. Самое главное тут — это оператор * . А то, что именно идёт после него, особой роли не играет. Благодаря использованию * мы создали список позиционных аргументов на основе того, что было передано функции при вызове.

После того, как мы разобрались с *args , с пониманием **kwargs проблем быть уже не должно. Имя, опять же, значения не имеет. Главное — это два символа ** . Благодаря им создаётся словарь, в котором содержатся именованные аргументы, переданные функции при её вызове.

Итоги

Вот несколько советов, которые помогут вам избежать распространённых проблем, возникающих при работе с функциями, и расширить свои знания:

Распаковка переменных#

Распаковка переменных — это специальный синтаксис, который позволяет присваивать переменным элементы итерируемого объекта.

Достаточно часто этот функционал встречается под именем tuple unpacking, но распаковка работает на любом итерируемом объекте, не только с кортежами

Пример распаковки переменных:

Такой вариант намного удобней использовать, чем использование индексов:

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

Если переменных больше или меньше, возникнет исключение:

Замена ненужных элементов _ #

Часто из всех элементов итерируемого объекта нужны только некоторые. При этом синтаксис распаковки требует указать ровно столько переменных, сколько элементов в итерируемом объекте.

Если, например, из строки line надо получить только VLAN, MAC и интерфейс, надо все равно указать переменную для типа записи:

Если тип записи не нужен в дальнейшем, можно заменить переменную item_type нижним подчеркиванием:

Таким образом явно указывается то, что этот элемент не нужен.

Нижнее подчеркивание можно использовать и несколько раз:

Использование * #

Распаковка переменных поддерживает специальный синтаксис, который позволяет распаковывать несколько элементов в один. Если поставить * перед именем переменной, в нее запишутся все элементы, кроме тех, что присвоены явно.

Например, так можно получить первый элемент в переменную first, а остальные в rest:

При этом переменная со звездочкой всегда будет содержать список:

Если элемент всего один, распаковка все равно отработает:

Такая переменная со звездочкой в выражении распаковки может быть только одна.

Такая переменная может находиться не только в конце выражения:

Таким образом можно указать, что нужен первый, второй и последний элемент:

Примеры распаковки#

Распаковка итерируемых объектов#

Эти примеры показывают, что распаковывать можно не только списки, кортежи и строки, но и любой другой итерируемый объект.

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

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